Back to index

lightning-sunbird  0.9+nobinonly
CertReader.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is XPInstall Signing.
00015  *
00016  * The Initial Developer of the Original Code is Doug Turner.
00017  * Portions created by the Initial Developer are Copyright (C) 2002
00018  * the Initial Developer. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  *
00022  * Alternatively, the contents of this file may be used under the terms of
00023  * either the GNU General Public License Version 2 or later (the "GPL"), or
00024  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00025  * in which case the provisions of the GPL or the LGPL are applicable instead
00026  * of those above. If you wish to allow use of your version of this file only
00027  * under the terms of either the GPL or the LGPL, and not to allow others to
00028  * use your version of this file under the terms of the MPL, indicate your
00029  * decision by deleting the provisions above and replace them with the notice
00030  * and other provisions required by the GPL or the LGPL. If you do not delete
00031  * the provisions above, a recipient may use your version of this file under
00032  * the terms of any one of the MPL, the GPL or the LGPL.
00033  *
00034  * ***** END LICENSE BLOCK ***** */
00035 
00036 #include "zlib.h"
00037 #include "zipstruct.h"
00038 
00039 #include "CertReader.h"
00040 
00041 #include "nsCRT.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsISignatureVerifier.h"
00044 #include "nsIInputStream.h"
00045 #include "nsIPrincipal.h"
00046 #include "nsIURI.h"
00047 #include "nsPICertNotification.h"
00048 
00049 
00050 #include "nsNetUtil.h"
00051 
00052 // just a guess at the max size of the cert.
00053 #define MAX_SIGNATURE_SIZE (32*1024)
00054 
00055 
00056 /*
00057  *  x t o i n t
00058  *
00059  *  Converts a two byte ugly endianed integer
00060  *  to our platform's integer.
00061  *
00062  */
00063 
00064 static unsigned int xtoint (unsigned char *ii)
00065 {
00066   return (int) (ii [0]) | ((int) ii [1] << 8);
00067 }
00068 
00069 /*
00070  *  x t o l o n g
00071  *
00072  *  Converts a four byte ugly endianed integer
00073  *  to our platform's integer.
00074  *
00075  */
00076 
00077 static unsigned long xtolong (unsigned char *ll)
00078 {
00079   unsigned long ret;
00080 
00081   ret =  ((((unsigned long) ll [0]) <<  0) |
00082           (((unsigned long) ll [1]) <<  8) |
00083           (((unsigned long) ll [2]) << 16) |
00084           (((unsigned long) ll [3]) << 24) );
00085 
00086   return ret;
00087 }
00088 
00089 static int my_inflate(unsigned char* compr, PRUint32 comprLen, unsigned char* uncompr, PRUint32 uncomprLen)
00090 {
00091   int err;
00092   z_stream d_stream; /* decompression stream */
00093   memset (&d_stream, 0, sizeof (d_stream));
00094 
00095   // buffer is way to small to even deal with.
00096   if (uncomprLen < 10)
00097     return -1;
00098 
00099   *uncompr = '\0';
00100 
00101   if (inflateInit2 (&d_stream, -MAX_WBITS) != Z_OK)
00102     return -1;
00103 
00104   d_stream.next_in  = compr;
00105   d_stream.avail_in = (uInt)comprLen;
00106 
00107   d_stream.next_out = uncompr;
00108   d_stream.avail_out = (uInt)uncomprLen;
00109 
00110   err = inflate(&d_stream, Z_NO_FLUSH);
00111 
00112   if (err != Z_OK && err != Z_STREAM_END) {
00113     inflateEnd(&d_stream);
00114     return -1;
00115   }
00116 
00117   err = inflateEnd(&d_stream);
00118   if (err != Z_OK) {
00119     return -1;
00120   }
00121   return 0;
00122 }
00123 
00124 CertReader::CertReader(nsIURI* aURI, nsISupports* aContext, nsPICertNotification* aObs):
00125   mContext(aContext),
00126   mURI(aURI),
00127   mObserver(aObs)
00128 {
00129 }
00130 
00131 CertReader::~CertReader()
00132 {
00133 }
00134 
00135 NS_IMPL_ISUPPORTS2(CertReader, nsIStreamListener, nsIRequestObserver)
00136 
00137 NS_IMETHODIMP
00138 CertReader::OnStartRequest(nsIRequest *request, nsISupports* context)
00139 {
00140   mVerifier = do_GetService(SIGNATURE_VERIFIER_CONTRACTID);
00141   if (!mVerifier)
00142     return NS_BINDING_ABORTED;
00143 
00144   mLeftoverBuffer.Truncate();
00145   return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP
00149 CertReader::OnDataAvailable(nsIRequest *request,
00150                             nsISupports* context,
00151                             nsIInputStream *aIStream,
00152                             PRUint32 aSourceOffset,
00153                             PRUint32 aLength)
00154 {
00155   if (!mVerifier)
00156     return NS_BINDING_ABORTED;
00157 
00158   char buf[4096];
00159   PRUint32 amt, size;
00160   nsresult rv;
00161 
00162   while (aLength)
00163   {
00164     size = PR_MIN(aLength, sizeof(buf));
00165 
00166     rv = aIStream->Read(buf, size, &amt);
00167     if (NS_FAILED(rv))
00168       return rv;
00169 
00170     aLength -= amt;
00171 
00172     mLeftoverBuffer.Append(buf, amt);
00173 
00174     if (mLeftoverBuffer.Length() < ZIPLOCAL_SIZE)
00175       continue;
00176 
00177     const char* caret = mLeftoverBuffer.get();
00178 
00179     ZipLocal_* ziplocal = (ZipLocal_*) caret;
00180 
00181     if (xtolong(ziplocal->signature) != LOCALSIG)
00182       return NS_BINDING_ABORTED;
00183 
00184     // did we read the entire file entry into memory?
00185     PRUint32 fileEntryLen = (ZIPLOCAL_SIZE +
00186                              xtoint(ziplocal->filename_len) +
00187                              xtoint(ziplocal->extrafield_len) +
00188                              xtolong(ziplocal->size));
00189 
00190 
00191     // prevent downloading a huge file on an unsigned cert
00192     if (fileEntryLen > MAX_SIGNATURE_SIZE)
00193       return NS_BINDING_ABORTED;
00194 
00195     if (mLeftoverBuffer.Length() < fileEntryLen)
00196     {
00197       // we are just going to buffer and continue.
00198       continue;
00199     }
00200 
00201     // the assumption here is that we have the fileEntry in mLeftoverBuffer
00202 
00203     int err = 0;
00204     unsigned char* orgData = nsnull;
00205     unsigned char* sigData = nsnull;
00206     const char* data = (caret +
00207                         ZIPLOCAL_SIZE +
00208                         xtoint(ziplocal->filename_len) +
00209                         xtoint(ziplocal->extrafield_len));
00210 
00211     PRUint32 sigSize = 0;
00212     PRUint32 orgSize = xtolong ((unsigned char *) ziplocal->orglen);
00213     PRUint32 cSize   = xtolong ((unsigned char *) ziplocal->size);
00214 
00215     switch (xtoint(ziplocal->method))
00216     {
00217       case STORED:
00218         // file is uncompressed, can use the data where it is
00219         sigSize = cSize;
00220         sigData = (unsigned char*)data;
00221         break;
00222 
00223       case DEFLATED:
00224         if (orgSize == 0 || orgSize > MAX_SIGNATURE_SIZE)
00225           return NS_BINDING_ABORTED;
00226 
00227         orgData = (unsigned char*)malloc(orgSize);
00228         if (!orgData)
00229           return NS_BINDING_ABORTED;
00230 
00231         err = my_inflate((unsigned char*)data,
00232                          cSize,
00233                          orgData,
00234                          orgSize);
00235 
00236         sigSize = orgSize;
00237         sigData = orgData;
00238         break;
00239 
00240       default:
00241         // unsupported compression method
00242         err = Z_DATA_ERROR;
00243         break;
00244     }
00245 
00246     if (err == 0)
00247     {
00248       PRInt32 verifyError;
00249       rv = mVerifier->VerifySignature((char*)sigData, sigSize, nsnull, 0,
00250                                  &verifyError, getter_AddRefs(mPrincipal));
00251     }
00252     if (orgData)
00253         free(orgData);
00254 
00255     // Cancel the load now that we've verified the signature
00256     return NS_BINDING_ABORTED;
00257   }
00258 
00259   return NS_OK; // continue reading
00260 }
00261 
00262 NS_IMETHODIMP
00263 CertReader::OnStopRequest(nsIRequest *request, nsISupports* context,
00264                           nsresult aStatus)
00265 {
00266     mObserver->OnCertAvailable(mURI,
00267                                mContext,
00268                                aStatus,
00269                                mPrincipal);
00270 
00271     return NS_OK;
00272 }
00273 
00274