Back to index

lightning-sunbird  0.9+nobinonly
nsNSSCertificateDB.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 the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Ian McGreer <mcgreer@netscape.com>
00023  *   Javier Delgadillo <javi@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsNSSComponent.h"
00040 #include "nsNSSCertificateDB.h"
00041 #include "nsCOMPtr.h"
00042 #include "nsNSSCertificate.h"
00043 #include "nsNSSHelper.h"
00044 #include "nsNSSCertHelper.h"
00045 #include "nsNSSCertCache.h"
00046 #include "nsCRT.h"
00047 #include "nsICertificateDialogs.h"
00048 #include "nsNSSCertTrust.h"
00049 #include "nsILocalFile.h"
00050 #include "nsPKCS12Blob.h"
00051 #include "nsPK11TokenDB.h"
00052 #include "nsOCSPResponder.h"
00053 #include "nsReadableUtils.h"
00054 #include "nsArray.h"
00055 #include "nsNSSShutDown.h"
00056 #include "nsIPrefService.h"
00057 #include "nsIPrefBranch.h"
00058 #include "nsIPrompt.h"
00059 #include "nsIProxyObjectManager.h"
00060 #include "nsProxiedService.h"
00061 
00062 #include "nspr.h"
00063 extern "C" {
00064 #include "pk11func.h"
00065 #include "certdb.h"
00066 #include "cert.h"
00067 #include "secerr.h"
00068 #include "nssb64.h"
00069 #include "secasn1.h"
00070 #include "secder.h"
00071 }
00072 #include "ssl.h"
00073 #include "ocsp.h"
00074 #include "plbase64.h"
00075 
00076 #ifdef PR_LOGGING
00077 extern PRLogModuleInfo* gPIPNSSLog;
00078 #endif
00079 
00080 #include "nsNSSCleaner.h"
00081 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
00082 NSSCleanupAutoPtrClass(CERTCertList, CERT_DestroyCertList)
00083 NSSCleanupAutoPtrClass(CERTCertificateList, CERT_DestroyCertificateList)
00084 
00085 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00086 
00087 
00088 NS_IMPL_ISUPPORTS2(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
00089 
00090 nsNSSCertificateDB::nsNSSCertificateDB()
00091 {
00092 }
00093 
00094 nsNSSCertificateDB::~nsNSSCertificateDB()
00095 {
00096 }
00097 
00098 NS_IMETHODIMP
00099 nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken,
00100                                       const nsAString &nickname,
00101                                       nsIX509Cert **_rvCert)
00102 {
00103   nsNSSShutDownPreventionLock locker;
00104   CERTCertificate *cert = NULL;
00105   char *asciiname = NULL;
00106   NS_ConvertUCS2toUTF8 aUtf8Nickname(nickname);
00107   asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
00108   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
00109 #if 0
00110   // what it should be, but for now...
00111   if (aToken) {
00112     cert = PK11_FindCertFromNickname(asciiname, NULL);
00113   } else {
00114     cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
00115   }
00116 #endif
00117   cert = PK11_FindCertFromNickname(asciiname, NULL);
00118   if (!cert) {
00119     cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
00120   }
00121   if (cert) {
00122     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
00123     nsCOMPtr<nsIX509Cert> pCert = new nsNSSCertificate(cert);
00124     CERT_DestroyCertificate(cert);
00125     *_rvCert = pCert;
00126     NS_ADDREF(*_rvCert);
00127     return NS_OK;
00128   }
00129   *_rvCert = nsnull;
00130   return NS_ERROR_FAILURE;
00131 }
00132 
00133 NS_IMETHODIMP 
00134 nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken,
00135                                    nsIX509Cert **_cert)
00136 {
00137   nsNSSShutDownPreventionLock locker;
00138   SECItem keyItem = {siBuffer, nsnull, 0};
00139   SECItem *dummy;
00140   CERTIssuerAndSN issuerSN;
00141   unsigned long moduleID,slotID;
00142   *_cert = nsnull; 
00143   if (!aDBkey || !*aDBkey)
00144     return NS_ERROR_INVALID_ARG;
00145 
00146   dummy = NSSBase64_DecodeBuffer(nsnull, &keyItem, aDBkey,
00147                                  (PRUint32)PL_strlen(aDBkey)); 
00148   if (!dummy || keyItem.len < NS_NSS_LONG*4) {
00149     PR_FREEIF(keyItem.data);
00150     return NS_ERROR_INVALID_ARG;
00151   }
00152 
00153   CERTCertificate *cert;
00154   // someday maybe we can speed up the search using the moduleID and slotID
00155   moduleID = NS_NSS_GET_LONG(keyItem.data);
00156   slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
00157 
00158   // build the issuer/SN structure
00159   issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
00160   issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
00161   if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0
00162       || issuerSN.serialNumber.len + issuerSN.derIssuer.len
00163          != keyItem.len - NS_NSS_LONG*4) {
00164     PR_FREEIF(keyItem.data);
00165     return NS_ERROR_INVALID_ARG;
00166   }
00167   issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
00168   issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
00169                                               issuerSN.serialNumber.len];
00170 
00171   cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
00172   PR_FREEIF(keyItem.data);
00173   if (cert) {
00174     nsNSSCertificate *nssCert = new nsNSSCertificate(cert);
00175     CERT_DestroyCertificate(cert);
00176     if (nssCert == nsnull)
00177       return NS_ERROR_OUT_OF_MEMORY;
00178     NS_ADDREF(nssCert);
00179     *_cert = NS_STATIC_CAST(nsIX509Cert*, nssCert);
00180   }
00181   return NS_OK;
00182 }
00183 
00184 NS_IMETHODIMP 
00185 nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken, 
00186                                      PRUint32      aType,
00187                                      PRUint32     *_count,
00188                                      PRUnichar  ***_certNames)
00189 {
00190   nsNSSShutDownPreventionLock locker;
00191   nsresult rv = NS_ERROR_FAILURE;
00192   /*
00193    * obtain the cert list from NSS
00194    */
00195   CERTCertList *certList = NULL;
00196   PK11CertListType pk11type;
00197 #if 0
00198   // this would seem right, but it didn't work...
00199   // oh, I know why - bonks out on internal slot certs
00200   if (aType == nsIX509Cert::USER_CERT)
00201     pk11type = PK11CertListUser;
00202   else 
00203 #endif
00204     pk11type = PK11CertListUnique;
00205   certList = PK11_ListCerts(pk11type, NULL);
00206   if (!certList)
00207     goto cleanup;
00208   /*
00209    * get list of cert names from list of certs
00210    * XXX also cull the list (NSS only distinguishes based on user/non-user
00211    */
00212   getCertNames(certList, aType, _count, _certNames);
00213   rv = NS_OK;
00214   /*
00215    * finish up
00216    */
00217 cleanup:
00218   if (certList)
00219     CERT_DestroyCertList(certList);
00220   return rv;
00221 }
00222 
00223 SECStatus PR_CALLBACK
00224 collect_certs(void *arg, SECItem **certs, int numcerts)
00225 {
00226   CERTDERCerts *collectArgs;
00227   SECItem *cert;
00228   SECStatus rv;
00229 
00230   collectArgs = (CERTDERCerts *)arg;
00231 
00232   collectArgs->numcerts = numcerts;
00233   collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
00234                                            sizeof(SECItem) * numcerts);
00235   if ( collectArgs->rawCerts == NULL )
00236     return(SECFailure);
00237 
00238   cert = collectArgs->rawCerts;
00239 
00240   while ( numcerts-- ) {
00241     rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
00242     if ( rv == SECFailure )
00243       return(SECFailure);
00244     cert++;
00245     certs++;
00246   }
00247 
00248   return (SECSuccess);
00249 }
00250 
00251 CERTDERCerts*
00252 nsNSSCertificateDB::getCertsFromPackage(PRArenaPool *arena, PRUint8 *data, 
00253                                         PRUint32 length)
00254 {
00255   nsNSSShutDownPreventionLock locker;
00256   CERTDERCerts *collectArgs = 
00257                (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
00258   if ( collectArgs == nsnull ) 
00259     return nsnull;
00260 
00261   collectArgs->arena = arena;
00262   SECStatus sec_rv = CERT_DecodeCertPackage(NS_REINTERPRET_CAST(char *, data), 
00263                                             length, collect_certs, 
00264                                             (void *)collectArgs);
00265   if (sec_rv != SECSuccess)
00266     return nsnull;
00267 
00268   return collectArgs;
00269 }
00270 
00271 nsresult
00272 nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs,
00273                                          nsIInterfaceRequestor *ctx)
00274 {
00275   // First thing we have to do is figure out which certificate we're 
00276   // gonna present to the user.  The CA may have sent down a list of 
00277   // certs which may or may not be a chained list of certs.  Until
00278   // the day we can design some solid UI for the general case, we'll
00279   // code to the > 90% case.  That case is where a CA sends down a
00280   // list that is a hierarchy whose root is either the first or 
00281   // the last cert.  What we're gonna do is compare the first 
00282   // 2 entries, if the second was signed by the first, we assume
00283   // the root cert is the first cert and display it.  Otherwise,
00284   // we compare the last 2 entries, if the second to last cert was
00285   // signed by the last cert, then we assume the last cert is the
00286   // root and display it.
00287 
00288   nsNSSShutDownPreventionLock locker;
00289 
00290   PRUint32 numCerts;
00291 
00292   x509Certs->GetLength(&numCerts);
00293   NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
00294   if (numCerts == 0)
00295     return NS_OK; // Nothing to import, so nothing to do.
00296 
00297   nsCOMPtr<nsIX509Cert> certToShow;
00298   nsCOMPtr<nsISupports> isupports;
00299   PRUint32 selCertIndex;
00300   if (numCerts == 1) {
00301     // There's only one cert, so let's show it.
00302     selCertIndex = 0;
00303     certToShow = do_QueryElementAt(x509Certs, selCertIndex);
00304   } else {
00305     nsCOMPtr<nsIX509Cert> cert0;    // first cert
00306     nsCOMPtr<nsIX509Cert> cert1;    // second cert
00307     nsCOMPtr<nsIX509Cert> certn_2;  // second to last cert
00308     nsCOMPtr<nsIX509Cert> certn_1;  // last cert
00309 
00310     cert0 = do_QueryElementAt(x509Certs, 0);
00311     cert1 = do_QueryElementAt(x509Certs, 1);
00312     certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
00313     certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
00314 
00315     nsXPIDLString cert0SubjectName;
00316     nsXPIDLString cert1IssuerName;
00317     nsXPIDLString certn_2IssuerName;
00318     nsXPIDLString certn_1SubjectName;
00319 
00320     cert0->GetSubjectName(cert0SubjectName);
00321     cert1->GetIssuerName(cert1IssuerName);
00322     certn_2->GetIssuerName(certn_2IssuerName);
00323     certn_1->GetSubjectName(certn_1SubjectName);
00324 
00325     if (cert1IssuerName.Equals(cert0SubjectName)) {
00326       // In this case, the first cert in the list signed the second,
00327       // so the first cert is the root.  Let's display it. 
00328       selCertIndex = 0;
00329       certToShow = cert0;
00330     } else 
00331     if (certn_2IssuerName.Equals(certn_1SubjectName)) { 
00332       // In this case the last cert has signed the second to last cert.
00333       // The last cert is the root, so let's display it.
00334       selCertIndex = numCerts-1;
00335       certToShow = certn_1;
00336     } else {
00337       // It's not a chain, so let's just show the first one in the 
00338       // downloaded list.
00339       selCertIndex = 0;
00340       certToShow = cert0;
00341     }
00342   }
00343 
00344   if (!certToShow)
00345     return NS_ERROR_FAILURE;
00346 
00347   nsCOMPtr<nsICertificateDialogs> dialogs;
00348   nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), 
00349                                 NS_GET_IID(nsICertificateDialogs),
00350                                 NS_CERTIFICATEDIALOGS_CONTRACTID);
00351                        
00352   if (NS_FAILED(rv))
00353     return rv;
00354  
00355   SECItem der;
00356   rv=certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data);
00357 
00358   if (NS_FAILED(rv))
00359     return rv;
00360 
00361   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
00362   CERTCertificate *tmpCert;
00363   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
00364   tmpCert = CERT_FindCertByDERCert(certdb, &der);
00365   if (!tmpCert) {
00366     tmpCert = CERT_NewTempCertificate(certdb, &der,
00367                                       nsnull, PR_FALSE, PR_TRUE);
00368   }
00369   nsMemory::Free(der.data);
00370   der.data = nsnull;
00371   der.len = 0;
00372   
00373   if (!tmpCert) {
00374     NS_ERROR("Couldn't create cert from DER blob\n");
00375     return NS_ERROR_FAILURE;
00376   }
00377 
00378   CERTCertificateCleaner tmpCertCleaner(tmpCert);
00379 
00380   if (!CERT_IsCACert(tmpCert, NULL)) {
00381     DisplayCertificateAlert(ctx, "NotACACert", certToShow);
00382     return NS_ERROR_FAILURE;
00383   }
00384 
00385   if (tmpCert->isperm) {
00386     DisplayCertificateAlert(ctx, "CaCertExists", certToShow);
00387     return NS_ERROR_FAILURE;
00388   }
00389 
00390   PRUint32 trustBits;
00391   PRBool allows;
00392   rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
00393   if (NS_FAILED(rv))
00394     return rv;
00395 
00396   if (!allows)
00397     return NS_ERROR_NOT_AVAILABLE;
00398 
00399   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));
00400   nsXPIDLCString nickname;
00401   nickname.Adopt(CERT_MakeCANickname(tmpCert));
00402 
00403   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
00404 
00405   nsNSSCertTrust trust;
00406   trust.SetValidCA();
00407   trust.AddCATrust(trustBits & nsIX509CertDB::TRUSTED_SSL,
00408                    trustBits & nsIX509CertDB::TRUSTED_EMAIL,
00409                    trustBits & nsIX509CertDB::TRUSTED_OBJSIGN);
00410 
00411   SECStatus srv = CERT_AddTempCertToPerm(tmpCert, 
00412                                          NS_CONST_CAST(char*,nickname.get()), 
00413                                          trust.GetTrust()); 
00414 
00415   if (srv != SECSuccess)
00416     return NS_ERROR_FAILURE;
00417 
00418   // Import additional delivered certificates that can be verified.
00419 
00420   // build a CertList for filtering
00421   CERTCertList *certList = CERT_NewCertList();
00422   if (certList == NULL) {
00423     return NS_ERROR_FAILURE;
00424   }
00425 
00426   CERTCertListCleaner listCleaner(certList);
00427 
00428   // get all remaining certs into temp store
00429 
00430   for (PRUint32 i=0; i<numCerts; i++) {
00431     if (i == selCertIndex) {
00432       // we already processed that one
00433       continue;
00434     }
00435 
00436     certToShow = do_QueryElementAt(x509Certs, i);
00437     certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data);
00438 
00439     CERTCertificate *tmpCert2 = 
00440       CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE);
00441 
00442     nsMemory::Free(der.data);
00443     der.data = nsnull;
00444     der.len = 0;
00445 
00446     if (!tmpCert2) {
00447       NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n");
00448       continue;  // Let's try to import the rest of 'em
00449     }
00450     
00451     CERT_AddCertToListTail(certList, tmpCert2);
00452   }
00453 
00454   return ImportValidCACertsInList(certList, ctx);
00455 }
00456 
00457 /*
00458  *  [noscript] void importCertificates(in charPtr data, in unsigned long length,
00459  *                                     in unsigned long type, 
00460  *                                     in nsIInterfaceRequestor ctx);
00461  */
00462 NS_IMETHODIMP 
00463 nsNSSCertificateDB::ImportCertificates(PRUint8 * data, PRUint32 length, 
00464                                        PRUint32 type, 
00465                                        nsIInterfaceRequestor *ctx)
00466 
00467 {
00468   nsNSSShutDownPreventionLock locker;
00469   nsresult nsrv;
00470 
00471   PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00472   if (!arena)
00473     return NS_ERROR_OUT_OF_MEMORY;
00474 
00475   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
00476   if (!certCollection) {
00477     PORT_FreeArena(arena, PR_FALSE);
00478     return NS_ERROR_FAILURE;
00479   }
00480   nsCOMPtr<nsIMutableArray> array;
00481   nsresult rv = NS_NewArray(getter_AddRefs(array));
00482   if (NS_FAILED(rv)) {
00483     PORT_FreeArena(arena, PR_FALSE);
00484     return rv;
00485   }
00486 
00487   // Now let's create some certs to work with
00488   nsCOMPtr<nsIX509Cert> x509Cert;
00489   nsNSSCertificate *nssCert;
00490   SECItem *currItem;
00491   for (int i=0; i<certCollection->numcerts; i++) {
00492      currItem = &certCollection->rawCerts[i];
00493      nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
00494      if (!nssCert)
00495        return NS_ERROR_FAILURE;
00496      x509Cert = do_QueryInterface((nsIX509Cert*)nssCert);
00497      array->AppendElement(x509Cert, PR_FALSE);
00498   }
00499   switch (type) {
00500   case nsIX509Cert::CA_CERT:
00501     nsrv = handleCACertDownload(array, ctx);
00502     break;
00503   default:
00504     // We only deal with import CA certs in this method currently.
00505      nsrv = NS_ERROR_FAILURE;
00506      break;
00507   }  
00508   PORT_FreeArena(arena, PR_FALSE);
00509   return nsrv;
00510 }
00511 
00512 
00513 /*
00514  *  [noscript] void importEmailCertificates(in charPtr data, in unsigned long length,
00515  *                                     in nsIInterfaceRequestor ctx);
00516  */
00517 NS_IMETHODIMP
00518 nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length, 
00519                                        nsIInterfaceRequestor *ctx)
00520 
00521 {
00522   nsNSSShutDownPreventionLock locker;
00523   SECStatus srv = SECFailure;
00524   nsresult nsrv = NS_OK;
00525   CERTCertDBHandle *certdb;
00526   CERTCertificate **certArray = NULL;
00527   CERTCertList *certList = NULL;
00528   CERTCertListNode *node;
00529   PRTime now;
00530   SECCertUsage certusage;
00531   SECItem **rawArray;
00532   int numcerts;
00533   int i;
00534  
00535   PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00536   if (!arena)
00537     return NS_ERROR_OUT_OF_MEMORY;
00538 
00539   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
00540   if (!certCollection) {
00541     PORT_FreeArena(arena, PR_FALSE);
00542     return NS_ERROR_FAILURE;
00543   }
00544 
00545   certdb = CERT_GetDefaultCertDB();
00546   certusage = certUsageEmailRecipient;
00547 
00548   numcerts = certCollection->numcerts;
00549 
00550   rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
00551   if ( !rawArray ) {
00552     nsrv = NS_ERROR_FAILURE;
00553     goto loser;
00554   }
00555 
00556   for (i=0; i < numcerts; i++) {
00557     rawArray[i] = &certCollection->rawCerts[i];
00558   }
00559 
00560   srv = CERT_ImportCerts(certdb, certusage, numcerts, rawArray, 
00561                          &certArray, PR_FALSE, PR_FALSE, NULL);
00562 
00563   PORT_Free(rawArray);
00564   rawArray = NULL;
00565 
00566   if (srv != SECSuccess) {
00567     nsrv = NS_ERROR_FAILURE;
00568     goto loser;
00569   }
00570 
00571   // build a CertList for filtering
00572   certList = CERT_NewCertList();
00573   if (certList == NULL) {
00574     nsrv = NS_ERROR_FAILURE;
00575     goto loser;
00576   }
00577   for (i=0; i < numcerts; i++) {
00578     CERTCertificate *cert = certArray[i];
00579     if (cert)
00580       cert = CERT_DupCertificate(cert);
00581     if (cert)
00582       CERT_AddCertToListTail(certList, cert);
00583   }
00584 
00585   /* go down the remaining list of certs and verify that they have
00586    * valid chains, then import them.
00587    */
00588   now = PR_Now();
00589   for (node = CERT_LIST_HEAD(certList);
00590        !CERT_LIST_END(node,certList);
00591        node = CERT_LIST_NEXT(node)) {
00592 
00593     bool alert_and_skip = false;
00594 
00595     if (!node->cert) {
00596       continue;
00597     }
00598 
00599     if (CERT_VerifyCert(certdb, node->cert, 
00600         PR_TRUE, certusage, now, ctx, NULL) != SECSuccess) {
00601       alert_and_skip = true;
00602     }
00603 
00604     CERTCertificateList *certChain = nsnull;
00605     CERTCertificateListCleaner chainCleaner(certChain);
00606 
00607     if (!alert_and_skip) {
00608       certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE);
00609       if (!certChain) {
00610         alert_and_skip = true;
00611       }
00612     }
00613 
00614     if (alert_and_skip) {    
00615       nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert);
00616       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow);
00617       continue;
00618     }
00619 
00620     /*
00621      * CertChain returns an array of SECItems, import expects an array of
00622      * SECItem pointers. Create the SECItem Pointers from the array of
00623      * SECItems.
00624      */
00625     rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *));
00626     if (!rawArray) {
00627       continue;
00628     }
00629     for (i=0; i < certChain->len; i++) {
00630       rawArray[i] = &certChain->certs[i];
00631     }
00632     CERT_ImportCerts(certdb, certusage, certChain->len, 
00633                             rawArray,  NULL, PR_TRUE, PR_FALSE, NULL);
00634 
00635     CERT_SaveSMimeProfile(node->cert, NULL, NULL);
00636 
00637     PORT_Free(rawArray);
00638   }
00639 
00640 loser:
00641   if (certArray) {
00642     CERT_DestroyCertArray(certArray, numcerts);
00643   }
00644   if (certList) {
00645     CERT_DestroyCertList(certList);
00646   }
00647   if (arena) 
00648     PORT_FreeArena(arena, PR_TRUE);
00649   return nsrv;
00650 }
00651 
00652 NS_IMETHODIMP
00653 nsNSSCertificateDB::ImportServerCertificate(PRUint8 * data, PRUint32 length, 
00654                                             nsIInterfaceRequestor *ctx)
00655 
00656 {
00657   nsNSSShutDownPreventionLock locker;
00658   SECStatus srv = SECFailure;
00659   nsresult nsrv = NS_OK;
00660   CERTCertificate * cert;
00661   SECItem **rawCerts = nsnull;
00662   int numcerts;
00663   int i;
00664   nsNSSCertTrust trust;
00665   char *serverNickname = nsnull;
00666  
00667   PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00668   if (!arena)
00669     return NS_ERROR_OUT_OF_MEMORY;
00670 
00671   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
00672   if (!certCollection) {
00673     PORT_FreeArena(arena, PR_FALSE);
00674     return NS_ERROR_FAILURE;
00675   }
00676   cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
00677                           (char *)NULL, PR_FALSE, PR_TRUE);
00678   if (!cert) {
00679     nsrv = NS_ERROR_FAILURE;
00680     goto loser;
00681   }
00682   numcerts = certCollection->numcerts;
00683   rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
00684   if ( !rawCerts ) {
00685     nsrv = NS_ERROR_FAILURE;
00686     goto loser;
00687   }
00688 
00689   for ( i = 0; i < numcerts; i++ ) {
00690     rawCerts[i] = &certCollection->rawCerts[i];
00691   }
00692 
00693   serverNickname = nsNSSCertificate::defaultServerNickname(cert);
00694   srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer,
00695              numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
00696              serverNickname);
00697   PR_FREEIF(serverNickname);
00698   if ( srv != SECSuccess ) {
00699     nsrv = NS_ERROR_FAILURE;
00700     goto loser;
00701   }
00702 
00703   trust.SetValidServerPeer();
00704   srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, trust.GetTrust());
00705   if ( srv != SECSuccess ) {
00706     nsrv = NS_ERROR_FAILURE;
00707     goto loser;
00708   }
00709 loser:
00710   PORT_Free(rawCerts);
00711   if (cert)
00712     CERT_DestroyCertificate(cert);
00713   if (arena) 
00714     PORT_FreeArena(arena, PR_TRUE);
00715   return nsrv;
00716 }
00717 
00718 nsresult
00719 nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx)
00720 {
00721   CERTCertList *certList = NULL;
00722   SECItem **rawArray;
00723 
00724   // build a CertList for filtering
00725   certList = CERT_NewCertList();
00726   if (certList == NULL) {
00727     return NS_ERROR_FAILURE;
00728   }
00729 
00730   CERTCertListCleaner listCleaner(certList);
00731 
00732   // get all certs into temp store
00733   SECStatus srv = SECFailure;
00734   CERTCertificate **certArray = NULL;
00735 
00736   rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts);
00737   if ( !rawArray ) {
00738     return NS_ERROR_FAILURE;
00739   }
00740 
00741   for (int i=0; i < numCACerts; i++) {
00742     rawArray[i] = &CACerts[i];
00743   }
00744 
00745   srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray, 
00746                          &certArray, PR_FALSE, PR_TRUE, NULL);
00747 
00748   PORT_Free(rawArray);
00749   rawArray = NULL;
00750 
00751   if (srv != SECSuccess) {
00752     return NS_ERROR_FAILURE;
00753   }
00754 
00755   for (int i2=0; i2 < numCACerts; i2++) {
00756     CERTCertificate *cacert = certArray[i2];
00757     if (cacert)
00758       cacert = CERT_DupCertificate(cacert);
00759     if (cacert)
00760       CERT_AddCertToListTail(certList, cacert);
00761   }
00762 
00763   CERT_DestroyCertArray(certArray, numCACerts);
00764 
00765   return ImportValidCACertsInList(certList, ctx);
00766 }
00767 
00768 nsresult
00769 nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx)
00770 {
00771   SECItem **rawArray;
00772 
00773   /* filter out the certs we don't want */
00774   SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, PR_TRUE);
00775   if (srv != SECSuccess) {
00776     return NS_ERROR_FAILURE;
00777   }
00778 
00779   /* go down the remaining list of certs and verify that they have
00780    * valid chains, if yes, then import.
00781    */
00782   PRTime now = PR_Now();
00783   CERTCertListNode *node;
00784   for (node = CERT_LIST_HEAD(certList);
00785        !CERT_LIST_END(node,certList);
00786        node = CERT_LIST_NEXT(node)) {
00787 
00788     bool alert_and_skip = false;
00789 
00790     if (CERT_VerifyCert(CERT_GetDefaultCertDB(), node->cert, 
00791         PR_TRUE, certUsageVerifyCA, now, ctx, NULL) != SECSuccess) {
00792       alert_and_skip = true;
00793     }
00794 
00795     CERTCertificateList *certChain = nsnull;
00796     CERTCertificateListCleaner chainCleaner(certChain);
00797 
00798     if (!alert_and_skip) {    
00799       certChain = CERT_CertChainFromCert(node->cert, certUsageAnyCA, PR_FALSE);
00800       if (!certChain) {
00801         alert_and_skip = true;
00802       }
00803     }
00804 
00805     if (alert_and_skip) {    
00806       nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert);
00807       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow);
00808       continue;
00809     }
00810 
00811     /*
00812      * CertChain returns an array of SECItems, import expects an array of
00813      * SECItem pointers. Create the SECItem Pointers from the array of
00814      * SECItems.
00815      */
00816     rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *));
00817     if (!rawArray) {
00818       continue;
00819     }
00820     for (int i=0; i < certChain->len; i++) {
00821       rawArray[i] = &certChain->certs[i];
00822     }
00823     CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, certChain->len, 
00824                             rawArray,  NULL, PR_TRUE, PR_TRUE, NULL);
00825 
00826     PORT_Free(rawArray);
00827   }
00828   
00829   return NS_OK;
00830 }
00831 
00832 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx, 
00833                                                  const char *stringID, 
00834                                                  nsIX509Cert *certToShow)
00835 {
00836   nsPSMUITracker tracker;
00837   if (!tracker.isUIForbidden()) {
00838 
00839     nsCOMPtr<nsIInterfaceRequestor> my_cxt = ctx;
00840     if (!my_cxt)
00841       my_cxt = new PipUIContext();
00842 
00843     // This shall be replaced by embedding ovverridable prompts
00844     // as discussed in bug 310446, and should make use of certToShow.
00845 
00846     nsresult rv;
00847     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00848     if (NS_SUCCEEDED(rv)) {
00849       nsAutoString tmpMessage;
00850       nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
00851 
00852       // The interface requestor object may not be safe, so proxy the call to get
00853       // the nsIPrompt.
00854 
00855       nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
00856       NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
00857                            NS_GET_IID(nsIInterfaceRequestor),
00858                            my_cxt,
00859                            PROXY_SYNC,
00860                            getter_AddRefs(proxiedCallbacks));
00861     
00862       nsCOMPtr<nsIPrompt> prompt (do_GetInterface(proxiedCallbacks));
00863       if (!prompt)
00864         return;
00865     
00866       // Finally, get a proxy for the nsIPrompt
00867     
00868       nsCOMPtr<nsIPrompt> proxyPrompt;
00869       NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
00870                            NS_GET_IID(nsIPrompt),
00871                            prompt,
00872                            PROXY_SYNC,
00873                            getter_AddRefs(proxyPrompt));
00874     
00875       proxyPrompt->Alert(nsnull, tmpMessage.get());
00876     }
00877   }
00878 }
00879 
00880 
00881 NS_IMETHODIMP 
00882 nsNSSCertificateDB::ImportUserCertificate(PRUint8 *data, PRUint32 length, nsIInterfaceRequestor *ctx)
00883 {
00884   nsNSSShutDownPreventionLock locker;
00885   PK11SlotInfo *slot;
00886   char * nickname = NULL;
00887   nsresult rv = NS_ERROR_FAILURE;
00888   int numCACerts;
00889   SECItem *CACerts;
00890   CERTDERCerts * collectArgs;
00891   PRArenaPool *arena;
00892   CERTCertificate * cert=NULL;
00893 
00894   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00895   if ( arena == NULL ) {
00896     goto loser;
00897   }
00898 
00899   collectArgs = getCertsFromPackage(arena, data, length);
00900   if (!collectArgs) {
00901     goto loser;
00902   }
00903 
00904   cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
00905                             (char *)NULL, PR_FALSE, PR_TRUE);
00906   if (!cert) {
00907     goto loser;
00908   }
00909 
00910   slot = PK11_KeyForCertExists(cert, NULL, ctx);
00911   if ( slot == NULL ) {
00912     nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert);
00913     DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow);
00914     goto loser;
00915   }
00916   PK11_FreeSlot(slot);
00917 
00918   /* pick a nickname for the cert */
00919   if (cert->nickname) {
00920        /* sigh, we need a call to look up other certs with this subject and
00921         * identify nicknames from them. We can no longer walk down internal
00922         * database structures  rjr */
00923        nickname = cert->nickname;
00924   }
00925   else {
00926     nickname = default_nickname(cert, ctx);
00927   }
00928 
00929   /* user wants to import the cert */
00930   slot = PK11_ImportCertForKey(cert, nickname, ctx);
00931   if (!slot) {
00932     goto loser;
00933   }
00934   PK11_FreeSlot(slot);
00935 
00936   {
00937     nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert);
00938     DisplayCertificateAlert(ctx, "UserCertImported", certToShow);
00939   }
00940   rv = NS_OK;
00941 
00942   numCACerts = collectArgs->numcerts - 1;
00943   if (numCACerts) {
00944     CACerts = collectArgs->rawCerts+1;
00945     rv = ImportValidCACerts(numCACerts, CACerts, ctx);
00946   }
00947   
00948 loser:
00949   if (arena) {
00950     PORT_FreeArena(arena, PR_FALSE);
00951   }
00952   if ( cert ) {
00953     CERT_DestroyCertificate(cert);
00954   }
00955   return rv;
00956 }
00957 
00958 /*
00959  * void deleteCertificate(in nsIX509Cert aCert);
00960  */
00961 NS_IMETHODIMP 
00962 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
00963 {
00964   nsNSSShutDownPreventionLock locker;
00965   nsNSSCertificate *nssCert = NS_STATIC_CAST(nsNSSCertificate*, aCert);
00966   CERTCertificate *cert = nssCert->GetCert();
00967   if (!cert) return NS_ERROR_FAILURE;
00968   CERTCertificateCleaner certCleaner(cert);
00969   SECStatus srv = SECSuccess;
00970 
00971   PRUint32 certType = getCertType(cert);
00972   nssCert->SetCertType(certType);
00973   if (NS_FAILED(nssCert->MarkForPermDeletion()))
00974   {
00975     return NS_ERROR_FAILURE;
00976   }
00977 
00978   if (cert->slot && certType != nsIX509Cert::USER_CERT) {
00979     // To delete a cert of a slot (builtin, most likely), mark it as
00980     // completely untrusted.  This way we keep a copy cached in the
00981     // local database, and next time we try to load it off of the 
00982     // external token/slot, we'll know not to trust it.  We don't 
00983     // want to do that with user certs, because a user may  re-store
00984     // the cert onto the card again at which point we *will* want to 
00985     // trust that cert if it chains up properly.
00986     nsNSSCertTrust trust(0, 0, 0);
00987     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
00988                                cert, trust.GetTrust());
00989   }
00990   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
00991   return (srv) ? NS_ERROR_FAILURE : NS_OK;
00992 }
00993 
00994 /*
00995  * void setCertTrust(in nsIX509Cert cert,
00996  *                   in unsigned long type,
00997  *                   in unsigned long trust);
00998  */
00999 NS_IMETHODIMP 
01000 nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert, 
01001                                  PRUint32 type,
01002                                  PRUint32 trusted)
01003 {
01004   nsNSSShutDownPreventionLock locker;
01005   SECStatus srv;
01006   nsNSSCertTrust trust;
01007   nsNSSCertificate *pipCert = NS_STATIC_CAST(nsNSSCertificate *, cert);
01008   if (!pipCert)
01009     return NS_ERROR_FAILURE;
01010   CERTCertificate *nsscert = pipCert->GetCert();
01011   CERTCertificateCleaner certCleaner(nsscert);
01012   if (type == nsIX509Cert::CA_CERT) {
01013     // always start with untrusted and move up
01014     trust.SetValidCA();
01015     trust.AddCATrust(trusted & nsIX509CertDB::TRUSTED_SSL,
01016                      trusted & nsIX509CertDB::TRUSTED_EMAIL,
01017                      trusted & nsIX509CertDB::TRUSTED_OBJSIGN);
01018     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
01019                                nsscert,
01020                                trust.GetTrust());
01021   } else if (type == nsIX509Cert::SERVER_CERT) {
01022     // always start with untrusted and move up
01023     trust.SetValidPeer();
01024     trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
01025     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
01026                                nsscert,
01027                                trust.GetTrust());
01028   } else if (type == nsIX509Cert::EMAIL_CERT) {
01029     // always start with untrusted and move up
01030     trust.SetValidPeer();
01031     trust.AddPeerTrust(0, trusted & nsIX509CertDB::TRUSTED_EMAIL, 0);
01032     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
01033                                nsscert,
01034                                trust.GetTrust());
01035   } else {
01036     // ignore user certs
01037     return NS_OK;
01038   }
01039   return (srv) ? NS_ERROR_FAILURE : NS_OK;
01040 }
01041 
01042 NS_IMETHODIMP 
01043 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert, 
01044                                   PRUint32 certType,
01045                                   PRUint32 trustType,
01046                                   PRBool *_isTrusted)
01047 {
01048   NS_ENSURE_ARG_POINTER(_isTrusted);
01049   *_isTrusted = PR_FALSE;
01050 
01051   nsNSSShutDownPreventionLock locker;
01052   SECStatus srv;
01053   nsNSSCertificate *pipCert = NS_STATIC_CAST(nsNSSCertificate *, cert);
01054   CERTCertificate *nsscert = pipCert->GetCert();
01055   CERTCertTrust nsstrust;
01056   srv = CERT_GetCertTrust(nsscert, &nsstrust);
01057   if (srv != SECSuccess)
01058     return NS_ERROR_FAILURE;
01059 
01060   nsNSSCertTrust trust(&nsstrust);
01061   CERT_DestroyCertificate(nsscert);
01062   if (certType == nsIX509Cert::CA_CERT) {
01063     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
01064       *_isTrusted = trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE);
01065     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
01066       *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE);
01067     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
01068       *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE);
01069     } else {
01070       return NS_ERROR_FAILURE;
01071     }
01072   } else if (certType == nsIX509Cert::SERVER_CERT) {
01073     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
01074       *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE);
01075     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
01076       *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE);
01077     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
01078       *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE);
01079     } else {
01080       return NS_ERROR_FAILURE;
01081     }
01082   } else if (certType == nsIX509Cert::EMAIL_CERT) {
01083     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
01084       *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE);
01085     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
01086       *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE);
01087     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
01088       *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE);
01089     } else {
01090       return NS_ERROR_FAILURE;
01091     }
01092   } /* user: ignore */
01093   return NS_OK;
01094 }
01095 
01096 
01097 NS_IMETHODIMP 
01098 nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken, 
01099                                         nsILocalFile *aFile,
01100                                         PRUint32 aType)
01101 {
01102   NS_ENSURE_ARG(aFile);
01103   switch (aType) {
01104     case nsIX509Cert::CA_CERT:
01105     case nsIX509Cert::EMAIL_CERT:
01106     case nsIX509Cert::SERVER_CERT:
01107       // good
01108       break;
01109     
01110     default:
01111       // not supported (yet)
01112       return NS_ERROR_FAILURE;
01113   }
01114 
01115   nsresult rv;
01116   PRFileDesc *fd = nsnull;
01117 
01118   rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
01119 
01120   if (NS_FAILED(rv))
01121     return rv;
01122 
01123   if (!fd)
01124     return NS_ERROR_FAILURE;
01125 
01126   PRFileInfo file_info;
01127   if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info))
01128     return NS_ERROR_FAILURE;
01129   
01130   unsigned char *buf = new unsigned char[file_info.size];
01131   if (!buf)
01132     return NS_ERROR_OUT_OF_MEMORY;
01133   
01134   PRInt32 bytes_obtained = PR_Read(fd, buf, file_info.size);
01135   PR_Close(fd);
01136   
01137   if (bytes_obtained != file_info.size)
01138     rv = NS_ERROR_FAILURE;
01139   else {
01140          nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
01141 
01142     switch (aType) {
01143       case nsIX509Cert::CA_CERT:
01144         rv = ImportCertificates(buf, bytes_obtained, aType, cxt);
01145         break;
01146         
01147       case nsIX509Cert::SERVER_CERT:
01148         rv = ImportServerCertificate(buf, bytes_obtained, cxt);
01149         break;
01150 
01151       case nsIX509Cert::EMAIL_CERT:
01152         rv = ImportEmailCertificate(buf, bytes_obtained, cxt);
01153         break;
01154       
01155       default:
01156         break;
01157     }
01158   }
01159 
01160   delete [] buf;
01161   return rv;  
01162 }
01163 
01164 NS_IMETHODIMP 
01165 nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken, 
01166                                      nsILocalFile *aFile)
01167 {
01168   NS_ENSURE_ARG(aFile);
01169   nsPKCS12Blob blob;
01170   nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
01171   if (token) {
01172     blob.SetToken(token);
01173   }
01174   return blob.ImportFromFile(aFile);
01175 }
01176 
01177 NS_IMETHODIMP 
01178 nsNSSCertificateDB::ExportPKCS12File(nsISupports     *aToken, 
01179                                      nsILocalFile     *aFile,
01180                                      PRUint32          count,
01181                                      nsIX509Cert     **certs)
01182                                      //const PRUnichar **aCertNames)
01183 {
01184   nsNSSShutDownPreventionLock locker;
01185   NS_ENSURE_ARG(aFile);
01186   nsPKCS12Blob blob;
01187   if (count == 0) return NS_OK;
01188   nsCOMPtr<nsIPK11Token> localRef;
01189   if (!aToken) {
01190     PK11SlotInfo *keySlot = PK11_GetInternalKeySlot();
01191     NS_ASSERTION(keySlot,"Failed to get the internal key slot");
01192     localRef = new nsPK11Token(keySlot);
01193     PK11_FreeSlot(keySlot);
01194   }
01195   else {
01196     localRef = do_QueryInterface(aToken);
01197   }
01198   blob.SetToken(localRef);
01199   //blob.LoadCerts(aCertNames, count);
01200   //return blob.ExportToFile(aFile);
01201   return blob.ExportToFile(aFile, certs, count);
01202 }
01203 
01204 
01205 static SECStatus PR_CALLBACK 
01206 GetOCSPResponders (CERTCertificate *aCert,
01207                    SECItem         *aDBKey,
01208                    void            *aArg)
01209 {
01210   nsIMutableArray *array = NS_STATIC_CAST(nsIMutableArray*, aArg);
01211   PRUnichar* nn = nsnull;
01212   PRUnichar* url = nsnull;
01213   char *serviceURL = nsnull;
01214   char *nickname = nsnull;
01215   PRUint32 i, count;
01216   nsresult rv;
01217 
01218   // Are we interested in this cert //
01219   if (!nsOCSPResponder::IncludeCert(aCert)) {
01220     return SECSuccess;
01221   }
01222 
01223   // Get the AIA and nickname //
01224   serviceURL = CERT_GetOCSPAuthorityInfoAccessLocation(aCert);
01225   if (serviceURL) {
01226     url = ToNewUnicode(NS_ConvertUTF8toUCS2(serviceURL));
01227     PORT_Free(serviceURL);
01228   }
01229 
01230   nickname = aCert->nickname;
01231   nn = ToNewUnicode(NS_ConvertUTF8toUCS2(nickname));
01232 
01233   nsCOMPtr<nsIOCSPResponder> new_entry = new nsOCSPResponder(nn, url);
01234   nsMemory::Free(nn);
01235   nsMemory::Free(url);
01236 
01237   // Sort the items according to nickname //
01238   rv = array->GetLength(&count);
01239   for (i=0; i < count; ++i) {
01240     nsCOMPtr<nsIOCSPResponder> entry = do_QueryElementAt(array, i);
01241     if (nsOCSPResponder::CompareEntries(new_entry, entry) < 0) {
01242       array->InsertElementAt(new_entry, i, PR_FALSE);
01243       break;
01244     }
01245   }
01246   if (i == count) {
01247     array->AppendElement(new_entry, PR_FALSE);
01248   }
01249   return SECSuccess;
01250 }
01251 
01252 
01253 
01254 /*
01255  * getOCSPResponders
01256  *
01257  * Export a set of certs and keys from the database to a PKCS#12 file.
01258 */
01259 NS_IMETHODIMP 
01260 nsNSSCertificateDB::GetOCSPResponders(nsIArray ** aResponders)
01261 {
01262   nsNSSShutDownPreventionLock locker;
01263   SECStatus sec_rv;
01264   nsCOMPtr<nsIMutableArray> respondersArray;
01265   nsresult rv = NS_NewArray(getter_AddRefs(respondersArray));
01266   if (NS_FAILED(rv)) {
01267     return rv;
01268   }
01269 
01270   sec_rv = PK11_TraverseSlotCerts(::GetOCSPResponders,
01271                                   respondersArray,
01272                                   nsnull);
01273   if (sec_rv != SECSuccess) {
01274     goto loser;
01275   }
01276 
01277   *aResponders = respondersArray;
01278   NS_IF_ADDREF(*aResponders);
01279   return NS_OK;
01280 loser:
01281   return NS_ERROR_FAILURE;
01282 }
01283 
01284 /*
01285  * NSS Helper Routines (private to nsNSSCertificateDB)
01286  */
01287 
01288 #define DELIM '\001'
01289 
01290 /*
01291  * GetSortedNameList
01292  *
01293  * Converts a CERTCertList to a list of certificate names
01294  */
01295 void
01296 nsNSSCertificateDB::getCertNames(CERTCertList *certList,
01297                                  PRUint32      type, 
01298                                  PRUint32     *_count,
01299                                  PRUnichar  ***_certNames)
01300 {
01301   nsNSSShutDownPreventionLock locker;
01302   nsresult rv;
01303   CERTCertListNode *node;
01304   PRUint32 numcerts = 0, i=0;
01305   PRUnichar **tmpArray = NULL;
01306   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type));
01307   for (node = CERT_LIST_HEAD(certList);
01308        !CERT_LIST_END(node, certList);
01309        node = CERT_LIST_NEXT(node)) {
01310     if (getCertType(node->cert) == type) {
01311       numcerts++;
01312     }
01313   }
01314   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts));
01315   int nc = (numcerts == 0) ? 1 : numcerts;
01316   tmpArray = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nc);
01317   if (numcerts == 0) goto finish;
01318   for (node = CERT_LIST_HEAD(certList);
01319        !CERT_LIST_END(node, certList);
01320        node = CERT_LIST_NEXT(node)) {
01321     if (getCertType(node->cert) == type) {
01322       nsNSSCertificate pipCert(node->cert);
01323       char *dbkey = NULL;
01324       char *namestr = NULL;
01325       nsAutoString certstr;
01326       rv = pipCert.GetDbKey(&dbkey);
01327       nsAutoString keystr = NS_ConvertASCIItoUCS2(dbkey);
01328       PR_FREEIF(dbkey);
01329       if (type == nsIX509Cert::EMAIL_CERT) {
01330         namestr = node->cert->emailAddr;
01331       } else {
01332         namestr = node->cert->nickname;
01333         if (namestr) {
01334           char *sc = strchr(namestr, ':');
01335           if (sc) *sc = DELIM;
01336         }
01337       }
01338       if (!namestr) namestr = "";
01339       nsAutoString certname = NS_ConvertASCIItoUCS2(namestr);
01340       certstr.Append(PRUnichar(DELIM));
01341       certstr += certname;
01342       certstr.Append(PRUnichar(DELIM));
01343       certstr += keystr;
01344       tmpArray[i++] = ToNewUnicode(certstr);
01345     }
01346   }
01347 finish:
01348   *_count = numcerts;
01349   *_certNames = tmpArray;
01350 }
01351 
01352 /* somewhat follows logic of cert_list_include_cert from PSM 1.x */
01353 
01354 
01355 NS_IMETHODIMP 
01356 nsNSSCertificateDB::GetIsOcspOn(PRBool *aOcspOn)
01357 {
01358   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
01359 
01360   PRInt32 ocspEnabled;
01361   pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
01362   *aOcspOn = ( ocspEnabled == 0 ) ? PR_FALSE : PR_TRUE; 
01363   return NS_OK;
01364 }
01365 
01366 /* nsIX509Cert getDefaultEmailEncryptionCert (); */
01367 NS_IMETHODIMP
01368 nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
01369 {
01370   if (!_retval)
01371     return NS_ERROR_FAILURE;
01372 
01373   *_retval = 0;
01374 
01375   if (aNickname.IsEmpty())
01376     return NS_OK;
01377 
01378   nsNSSShutDownPreventionLock locker;
01379   nsresult rv = NS_OK;
01380   CERTCertificate *cert = 0;
01381   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
01382   nsNSSCertificate *nssCert = nsnull;
01383   char *asciiname = NULL;
01384   NS_ConvertUCS2toUTF8 aUtf8Nickname(aNickname);
01385   asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
01386 
01387   /* Find a good cert in the user's database */
01388   cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 
01389            certUsageEmailRecipient, PR_TRUE, ctx);
01390 
01391   if (!cert) { goto loser; }  
01392 
01393   nssCert = new nsNSSCertificate(cert);
01394   if (nssCert == nsnull) {
01395     rv = NS_ERROR_OUT_OF_MEMORY;
01396   }
01397   NS_ADDREF(nssCert);
01398 
01399   *_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
01400 
01401 loser:
01402   if (cert) CERT_DestroyCertificate(cert);
01403   return rv;
01404 }
01405 
01406 /* nsIX509Cert getDefaultEmailSigningCert (); */
01407 NS_IMETHODIMP
01408 nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
01409 {
01410   if (!_retval)
01411     return NS_ERROR_FAILURE;
01412 
01413   *_retval = 0;
01414 
01415   if (aNickname.IsEmpty())
01416     return NS_OK;
01417 
01418   nsNSSShutDownPreventionLock locker;
01419   nsresult rv = NS_OK;
01420   CERTCertificate *cert = 0;
01421   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
01422   nsNSSCertificate *nssCert = nsnull;
01423   char *asciiname = NULL;
01424   NS_ConvertUCS2toUTF8 aUtf8Nickname(aNickname);
01425   asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
01426 
01427   /* Find a good cert in the user's database */
01428   cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 
01429            certUsageEmailSigner, PR_TRUE, ctx);
01430 
01431   if (!cert) { goto loser; }  
01432 
01433   nssCert = new nsNSSCertificate(cert);
01434   if (nssCert == nsnull) {
01435     rv = NS_ERROR_OUT_OF_MEMORY;
01436   }
01437   NS_ADDREF(nssCert);
01438 
01439   *_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
01440 
01441 loser:
01442   if (cert) CERT_DestroyCertificate(cert);
01443   return rv;
01444 }
01445 
01446 NS_IMETHODIMP
01447 nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval)
01448 {
01449   nsNSSShutDownPreventionLock locker;
01450   CERTCertificate *any_cert = CERT_FindCertByNicknameOrEmailAddr(CERT_GetDefaultCertDB(), (char*)aEmailAddress);
01451   if (!any_cert)
01452     return NS_ERROR_FAILURE;
01453 
01454   CERTCertificateCleaner certCleaner(any_cert);
01455     
01456   // any_cert now contains a cert with the right subject, but it might not have the correct usage
01457   CERTCertList *certlist = CERT_CreateSubjectCertList(
01458     nsnull, CERT_GetDefaultCertDB(), &any_cert->derSubject, PR_Now(), PR_TRUE);
01459   if (!certlist)
01460     return NS_ERROR_FAILURE;  
01461 
01462   CERTCertListCleaner listCleaner(certlist);
01463 
01464   if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE))
01465     return NS_ERROR_FAILURE;
01466   
01467   if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
01468     return NS_ERROR_FAILURE;
01469   
01470   nsNSSCertificate *nssCert = new nsNSSCertificate(CERT_LIST_HEAD(certlist)->cert);
01471   if (!nssCert)
01472     return NS_ERROR_OUT_OF_MEMORY;
01473 
01474   NS_ADDREF(nssCert);
01475   *_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
01476   return NS_OK;
01477 }
01478 
01479 /* nsIX509Cert constructX509FromBase64 (in string base64); */
01480 NS_IMETHODIMP
01481 nsNSSCertificateDB::ConstructX509FromBase64(const char * base64, nsIX509Cert **_retval)
01482 {
01483   if (!_retval) {
01484     return NS_ERROR_FAILURE;
01485   }
01486 
01487   nsNSSShutDownPreventionLock locker;
01488   PRUint32 len = PL_strlen(base64);
01489   int adjust = 0;
01490 
01491   /* Compute length adjustment */
01492   if (base64[len-1] == '=') {
01493     adjust++;
01494     if (base64[len-2] == '=') adjust++;
01495   }
01496 
01497   nsresult rv = NS_OK;
01498   char *certDER = 0;
01499   PRInt32 lengthDER = 0;
01500 
01501   certDER = PL_Base64Decode(base64, len, NULL);
01502   if (!certDER || !*certDER) {
01503     rv = NS_ERROR_ILLEGAL_VALUE;
01504   }
01505   else {
01506     lengthDER = (len*3)/4 - adjust;
01507 
01508     SECItem secitem_cert;
01509     secitem_cert.type = siDERCertBuffer;
01510     secitem_cert.data = (unsigned char*)certDER;
01511     secitem_cert.len = lengthDER;
01512 
01513     CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, nsnull, PR_FALSE, PR_TRUE);
01514 
01515     if (!cert) {
01516       rv = NS_ERROR_FAILURE;
01517     }
01518     else {
01519       nsNSSCertificate *nsNSS = new nsNSSCertificate(cert);
01520       if (!nsNSS) {
01521         rv = NS_ERROR_OUT_OF_MEMORY;
01522       }
01523       else {
01524         nsresult rv = nsNSS->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)_retval);
01525 
01526         if (NS_SUCCEEDED(rv) && *_retval) {
01527           NS_ADDREF(*_retval);
01528         }
01529         
01530         NS_RELEASE(nsNSS);
01531       }
01532       CERT_DestroyCertificate(cert);
01533     }
01534   }
01535   
01536   if (certDER) {
01537     nsCRT::free(certDER);
01538   }
01539   return rv;
01540 }
01541 
01542 
01543 
01544 char *
01545 nsNSSCertificateDB::default_nickname(CERTCertificate *cert, nsIInterfaceRequestor* ctx)
01546 {   
01547   nsNSSShutDownPreventionLock locker;
01548   nsresult rv;
01549   char *username = NULL;
01550   char *caname = NULL;
01551   char *nickname = NULL;
01552   char *tmp = NULL;
01553   int count;
01554   char *nickFmt=NULL, *nickFmtWithNum = NULL;
01555   CERTCertificate *dummycert;
01556   PK11SlotInfo *slot=NULL;
01557   CK_OBJECT_HANDLE keyHandle;
01558   nsAutoString tmpNickFmt;
01559   nsAutoString tmpNickFmtWithNum;
01560 
01561   CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
01562   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
01563   if (NS_FAILED(rv)) goto loser; 
01564 
01565   username = CERT_GetCommonName(&cert->subject);
01566   if ( username == NULL ) 
01567     username = PL_strdup("");
01568 
01569   if ( username == NULL ) 
01570     goto loser;
01571     
01572   caname = CERT_GetOrgName(&cert->issuer);
01573   if ( caname == NULL ) 
01574     caname = PL_strdup("");
01575   
01576   if ( caname == NULL ) 
01577     goto loser;
01578   
01579   count = 1;
01580   nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
01581   nickFmt = ToNewUTF8String(tmpNickFmt);
01582 
01583   nssComponent->GetPIPNSSBundleString("nick_template_with_num", tmpNickFmtWithNum);
01584   nickFmtWithNum = ToNewUTF8String(tmpNickFmtWithNum);
01585 
01586 
01587   nickname = PR_smprintf(nickFmt, username, caname);
01588   /*
01589    * We need to see if the private key exists on a token, if it does
01590    * then we need to check for nicknames that already exist on the smart
01591    * card.
01592    */
01593   slot = PK11_KeyForCertExists(cert, &keyHandle, ctx);
01594   if (slot == NULL) {
01595     goto loser;
01596   }
01597   if (!PK11_IsInternal(slot)) {
01598     tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), nickname);
01599     PR_Free(nickname);
01600     nickname = tmp;
01601     tmp = NULL;
01602   }
01603   tmp = nickname;
01604   while ( 1 ) {      
01605     if ( count > 1 ) {
01606       nickname = PR_smprintf("%s #%d", tmp, count);
01607     }
01608   
01609     if ( nickname == NULL ) 
01610       goto loser;
01611  
01612     if (PK11_IsInternal(slot)) {
01613       /* look up the nickname to make sure it isn't in use already */
01614       dummycert = CERT_FindCertByNickname(defaultcertdb, nickname);
01615       
01616     } else {
01617       /*
01618        * Check the cert against others that already live on the smart 
01619        * card.
01620        */
01621       dummycert = PK11_FindCertFromNickname(nickname, ctx);
01622       if (dummycert != NULL) {
01623        /*
01624         * Make sure the subject names are different.
01625         */ 
01626        if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
01627        {
01628          /*
01629           * There is another certificate with the same nickname and
01630           * the same subject name on the smart card, so let's use this
01631           * nickname.
01632           */
01633          CERT_DestroyCertificate(dummycert);
01634          dummycert = NULL;
01635        }
01636       }
01637     }
01638     if ( dummycert == NULL ) 
01639       goto done;
01640     
01641     /* found a cert, destroy it and loop */
01642     CERT_DestroyCertificate(dummycert);
01643     if (tmp != nickname) PR_Free(nickname);
01644     count++;
01645   } /* end of while(1) */
01646     
01647 loser:
01648   if ( nickname ) {
01649     PR_Free(nickname);
01650   }
01651   nickname = NULL;
01652 done:
01653   if ( caname ) {
01654     PR_Free(caname);
01655   }
01656   if ( username )  {
01657     PR_Free(username);
01658   }
01659   if (slot != NULL) {
01660       PK11_FreeSlot(slot);
01661       if (nickname != NULL) {
01662              tmp = nickname;
01663              nickname = strchr(tmp, ':');
01664              if (nickname != NULL) {
01665                nickname++;
01666                nickname = PL_strdup(nickname);
01667                PR_Free(tmp);
01668              tmp = nsnull;
01669              } else {
01670                nickname = tmp;
01671                tmp = NULL;
01672              }
01673       }
01674     }
01675     PR_FREEIF(tmp);
01676     return(nickname);
01677 }
01678 
01679 NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName)
01680 {
01681   NS_ENSURE_ARG_POINTER(aBase64);
01682   nsCOMPtr <nsIX509Cert> newCert;
01683 
01684   nsNSSCertTrust trust;
01685 
01686   // need to calculate the trust bits from the aTrust string.
01687   nsresult rv = CERT_DecodeTrustString(trust.GetTrust(), /* this is const, but not declared that way */(char *) aTrust);
01688   NS_ENSURE_SUCCESS(rv, rv); // if bad trust passed in, return error.
01689 
01690 
01691   rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
01692   NS_ENSURE_SUCCESS(rv, rv);
01693 
01694   SECItem der;
01695   rv = newCert->GetRawDER(&der.len, (PRUint8 **)&der.data);
01696   NS_ENSURE_SUCCESS(rv, rv);
01697 
01698   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
01699   CERTCertificate *tmpCert;
01700   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
01701   tmpCert = CERT_FindCertByDERCert(certdb, &der);
01702   if (!tmpCert) 
01703     tmpCert = CERT_NewTempCertificate(certdb, &der,
01704                                       nsnull, PR_FALSE, PR_TRUE);
01705   nsMemory::Free(der.data);
01706   der.data = nsnull;
01707   der.len = 0;
01708 
01709   if (!tmpCert) {
01710     NS_ASSERTION(0,"Couldn't create cert from DER blob\n");
01711     return NS_ERROR_FAILURE;
01712   }
01713 
01714   if (tmpCert->isperm) {
01715     CERT_DestroyCertificate(tmpCert);
01716     return NS_OK;
01717   }
01718 
01719   CERTCertificateCleaner tmpCertCleaner(tmpCert);
01720 
01721   nsXPIDLCString nickname;
01722   nickname.Adopt(CERT_MakeCANickname(tmpCert));
01723 
01724   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
01725 
01726   SECStatus srv = CERT_AddTempCertToPerm(tmpCert, 
01727                                          NS_CONST_CAST(char*,nickname.get()), 
01728                                          trust.GetTrust()); 
01729 
01730 
01731   return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
01732 }