NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName) { NS_ENSURE_ARG_POINTER(aBase64); nsCOMPtr <nsIX509Cert> newCert; nsNSSCertTrust trust; // need to calculate the trust bits from the aTrust string. nsresult rv = CERT_DecodeTrustString(trust.GetTrust(), /* this is const, but not declared that way */(char *) aTrust); NS_ENSURE_SUCCESS(rv, rv); // if bad trust passed in, return error. rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert)); NS_ENSURE_SUCCESS(rv, rv); SECItem der; rv = newCert->GetRawDER(&der.len, (PRUint8 **)&der.data); NS_ENSURE_SUCCESS(rv, rv); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); CERTCertificate *tmpCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); tmpCert = CERT_FindCertByDERCert(certdb, &der); if (!tmpCert) tmpCert = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert) { NS_ASSERTION(0,"Couldn't create cert from DER blob\n"); return NS_ERROR_FAILURE; } if (tmpCert->isperm) { CERT_DestroyCertificate(tmpCert); return NS_OK; } CERTCertificateCleaner tmpCertCleaner(tmpCert); nsXPIDLCString nickname; nickname.Adopt(CERT_MakeCANickname(tmpCert)); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); SECStatus srv = CERT_AddTempCertToPerm(tmpCert, const_cast<char*>(nickname.get()), trust.GetTrust()); return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; }
/* From certdb.c */ static SECStatus cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) { SECStatus rv; SECItem *derCert; CERTCertificate *cert = NULL; CERTCertificate *newcert = NULL; CERTCertDBHandle *handle; CERTCertTrust trust; PRBool isca; char *nickname; unsigned int certtype; handle = CERT_GetDefaultCertDB(); while (numcerts--) { derCert = certs; certs++; /* decode my certificate */ /* This use is ok -- only looks at decoded parts, calls NewTemp later */ newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); if ( newcert == NULL ) { goto loser; } if (!trusted) { /* make sure that cert is valid */ rv = CERT_CertTimesValid(newcert); if ( rv == SECFailure ) { goto endloop; } } /* does it have the CA extension */ /* * Make sure that if this is an intermediate CA in the chain that * it was given permission by its signer to be a CA. */ isca = CERT_IsCACert(newcert, &certtype); if ( !isca ) { if (!trusted) { goto endloop; } trust.sslFlags = CERTDB_VALID_CA; trust.emailFlags = CERTDB_VALID_CA; trust.objectSigningFlags = CERTDB_VALID_CA; } else { /* SSL ca's must have the ssl bit set */ if ( ( certUsage == certUsageSSLCA ) && (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { goto endloop; } /* it passed all of the tests, so lets add it to the database */ /* mark it as a CA */ PORT_Memset((void *)&trust, 0, sizeof(trust)); switch ( certUsage ) { case certUsageSSLCA: trust.sslFlags = CERTDB_VALID_CA; break; case certUsageUserCertImport: if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { trust.sslFlags = CERTDB_VALID_CA; } if ((certtype & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA ) { trust.emailFlags = CERTDB_VALID_CA; } if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == NS_CERT_TYPE_OBJECT_SIGNING_CA ) { trust.objectSigningFlags = CERTDB_VALID_CA; } break; default: PORT_Assert(0); break; } } cert = CERT_NewTempCertificate(handle, derCert, NULL, PR_FALSE, PR_FALSE); if ( cert == NULL ) { goto loser; } /* if the cert is temp, make it perm; otherwise we're done */ if (cert->istemp) { /* get a default nickname for it */ nickname = CERT_MakeCANickname(cert); rv = CERT_AddTempCertToPerm(cert, nickname, &trust); /* free the nickname */ if ( nickname ) { PORT_Free(nickname); } } else { rv = SECSuccess; } CERT_DestroyCertificate(cert); cert = NULL; if ( rv != SECSuccess ) { goto loser; } endloop: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } } rv = SECSuccess; goto done; loser: rv = SECFailure; done: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } if ( cert ) { CERT_DestroyCertificate(cert); cert = NULL; } return(rv); }
nsresult nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs, nsIInterfaceRequestor *ctx) { // First thing we have to do is figure out which certificate we're // gonna present to the user. The CA may have sent down a list of // certs which may or may not be a chained list of certs. Until // the day we can design some solid UI for the general case, we'll // code to the > 90% case. That case is where a CA sends down a // list that is a hierarchy whose root is either the first or // the last cert. What we're gonna do is compare the first // 2 entries, if the second was signed by the first, we assume // the root cert is the first cert and display it. Otherwise, // we compare the last 2 entries, if the second to last cert was // signed by the last cert, then we assume the last cert is the // root and display it. nsNSSShutDownPreventionLock locker; PRUint32 numCerts; x509Certs->GetLength(&numCerts); NS_ASSERTION(numCerts > 0, "Didn't get any certs to import."); if (numCerts == 0) return NS_OK; // Nothing to import, so nothing to do. nsCOMPtr<nsIX509Cert> certToShow; nsCOMPtr<nsISupports> isupports; PRUint32 selCertIndex; if (numCerts == 1) { // There's only one cert, so let's show it. selCertIndex = 0; certToShow = do_QueryElementAt(x509Certs, selCertIndex); } else { nsCOMPtr<nsIX509Cert> cert0; // first cert nsCOMPtr<nsIX509Cert> cert1; // second cert nsCOMPtr<nsIX509Cert> certn_2; // second to last cert nsCOMPtr<nsIX509Cert> certn_1; // last cert cert0 = do_QueryElementAt(x509Certs, 0); cert1 = do_QueryElementAt(x509Certs, 1); certn_2 = do_QueryElementAt(x509Certs, numCerts-2); certn_1 = do_QueryElementAt(x509Certs, numCerts-1); nsXPIDLString cert0SubjectName; nsXPIDLString cert1IssuerName; nsXPIDLString certn_2IssuerName; nsXPIDLString certn_1SubjectName; cert0->GetSubjectName(cert0SubjectName); cert1->GetIssuerName(cert1IssuerName); certn_2->GetIssuerName(certn_2IssuerName); certn_1->GetSubjectName(certn_1SubjectName); if (cert1IssuerName.Equals(cert0SubjectName)) { // In this case, the first cert in the list signed the second, // so the first cert is the root. Let's display it. selCertIndex = 0; certToShow = cert0; } else if (certn_2IssuerName.Equals(certn_1SubjectName)) { // In this case the last cert has signed the second to last cert. // The last cert is the root, so let's display it. selCertIndex = numCerts-1; certToShow = certn_1; } else { // It's not a chain, so let's just show the first one in the // downloaded list. selCertIndex = 0; certToShow = cert0; } } if (!certToShow) return NS_ERROR_FAILURE; nsCOMPtr<nsICertificateDialogs> dialogs; nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID); if (NS_FAILED(rv)) return rv; SECItem der; rv=certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); if (NS_FAILED(rv)) return rv; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); CERTCertificate *tmpCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); tmpCert = CERT_FindCertByDERCert(certdb, &der); if (!tmpCert) { tmpCert = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); } nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert) { NS_ERROR("Couldn't create cert from DER blob\n"); return NS_ERROR_FAILURE; } CERTCertificateCleaner tmpCertCleaner(tmpCert); if (!CERT_IsCACert(tmpCert, NULL)) { DisplayCertificateAlert(ctx, "NotACACert", certToShow); return NS_ERROR_FAILURE; } if (tmpCert->isperm) { DisplayCertificateAlert(ctx, "CaCertExists", certToShow); return NS_ERROR_FAILURE; } PRUint32 trustBits; PRBool allows; rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); if (NS_FAILED(rv)) return rv; if (!allows) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits)); nsXPIDLCString nickname; nickname.Adopt(CERT_MakeCANickname(tmpCert)); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); nsNSSCertTrust trust; trust.SetValidCA(); trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); SECStatus srv = CERT_AddTempCertToPerm(tmpCert, const_cast<char*>(nickname.get()), trust.GetTrust()); if (srv != SECSuccess) return NS_ERROR_FAILURE; // Import additional delivered certificates that can be verified. // build a CertList for filtering CERTCertList *certList = CERT_NewCertList(); if (certList == NULL) { return NS_ERROR_FAILURE; } CERTCertListCleaner listCleaner(certList); // get all remaining certs into temp store for (PRUint32 i=0; i<numCerts; i++) { if (i == selCertIndex) { // we already processed that one continue; } certToShow = do_QueryElementAt(x509Certs, i); certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); CERTCertificate *tmpCert2 = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert2) { NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n"); continue; // Let's try to import the rest of 'em } CERT_AddCertToListTail(certList, tmpCert2); } return ImportValidCACertsInList(certList, ctx); }