1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsNSSCertificateDB.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1829 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// XXX: This must be done prior to including cert.h (directly or indirectly). 1.9 +// CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm, but it is 1.10 +// only exported so PSM can use it for this specific purpose. 1.11 +#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm 1.12 + 1.13 +#include "nsNSSComponent.h" 1.14 +#include "nsNSSCertificateDB.h" 1.15 + 1.16 +#include "CertVerifier.h" 1.17 +#include "ExtendedValidation.h" 1.18 +#include "NSSCertDBTrustDomain.h" 1.19 +#include "pkix/pkixtypes.h" 1.20 +#include "nsNSSComponent.h" 1.21 +#include "mozilla/Base64.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nsNSSCertificate.h" 1.24 +#include "nsNSSHelper.h" 1.25 +#include "nsNSSCertHelper.h" 1.26 +#include "nsNSSCertCache.h" 1.27 +#include "nsCRT.h" 1.28 +#include "nsICertificateDialogs.h" 1.29 +#include "nsNSSCertTrust.h" 1.30 +#include "nsIFile.h" 1.31 +#include "nsPKCS12Blob.h" 1.32 +#include "nsPK11TokenDB.h" 1.33 +#include "nsReadableUtils.h" 1.34 +#include "nsIMutableArray.h" 1.35 +#include "nsArrayUtils.h" 1.36 +#include "nsNSSShutDown.h" 1.37 +#include "nsIPrefService.h" 1.38 +#include "nsIPrefBranch.h" 1.39 +#include "nsComponentManagerUtils.h" 1.40 +#include "nsIPrompt.h" 1.41 +#include "nsThreadUtils.h" 1.42 +#include "nsIObserverService.h" 1.43 +#include "nsRecentBadCerts.h" 1.44 +#include "SharedSSLState.h" 1.45 + 1.46 +#include "nspr.h" 1.47 +#include "certdb.h" 1.48 +#include "secerr.h" 1.49 +#include "nssb64.h" 1.50 +#include "secasn1.h" 1.51 +#include "secder.h" 1.52 +#include "ssl.h" 1.53 +#include "ocsp.h" 1.54 +#include "plbase64.h" 1.55 + 1.56 +using namespace mozilla; 1.57 +using namespace mozilla::psm; 1.58 +using mozilla::psm::SharedSSLState; 1.59 + 1.60 +#ifdef PR_LOGGING 1.61 +extern PRLogModuleInfo* gPIPNSSLog; 1.62 +#endif 1.63 + 1.64 +static nsresult 1.65 +attemptToLogInWithDefaultPassword() 1.66 +{ 1.67 +#ifdef NSS_DISABLE_DBM 1.68 + // The SQL NSS DB requires the user to be authenticated to set certificate 1.69 + // trust settings, even if the user's password is empty. To maintain 1.70 + // compatibility with the DBM-based database, try to log in with the 1.71 + // default empty password. This will allow, at least, tests that need to 1.72 + // change certificate trust to pass on all platforms. TODO(bug 978120): Do 1.73 + // proper testing and/or implement a better solution so that we are confident 1.74 + // that this does the correct thing outside of xpcshell tests too. 1.75 + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); 1.76 + if (!slot) { 1.77 + return MapSECStatus(SECFailure); 1.78 + } 1.79 + if (PK11_NeedUserInit(slot)) { 1.80 + // Ignore the return value. Presumably PK11_InitPin will fail if the user 1.81 + // has a non-default password. 1.82 + (void) PK11_InitPin(slot, nullptr, nullptr); 1.83 + } 1.84 +#endif 1.85 + 1.86 + return NS_OK; 1.87 +} 1.88 + 1.89 +NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2) 1.90 + 1.91 +nsNSSCertificateDB::nsNSSCertificateDB() 1.92 +: mBadCertsLock("nsNSSCertificateDB::mBadCertsLock") 1.93 +{ 1.94 + SharedSSLState::NoteCertDBServiceInstantiated(); 1.95 +} 1.96 + 1.97 +nsNSSCertificateDB::~nsNSSCertificateDB() 1.98 +{ 1.99 + nsNSSShutDownPreventionLock locker; 1.100 + if (isAlreadyShutDown()) { 1.101 + return; 1.102 + } 1.103 + 1.104 + shutdown(calledFromObject); 1.105 +} 1.106 + 1.107 +NS_IMETHODIMP 1.108 +nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken, 1.109 + const nsAString &nickname, 1.110 + nsIX509Cert **_rvCert) 1.111 +{ 1.112 + NS_ENSURE_ARG_POINTER(_rvCert); 1.113 + *_rvCert = nullptr; 1.114 + 1.115 + nsNSSShutDownPreventionLock locker; 1.116 + if (isAlreadyShutDown()) { 1.117 + return NS_ERROR_NOT_AVAILABLE; 1.118 + } 1.119 + mozilla::pkix::ScopedCERTCertificate cert; 1.120 + char *asciiname = nullptr; 1.121 + NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname); 1.122 + asciiname = const_cast<char*>(aUtf8Nickname.get()); 1.123 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname)); 1.124 + cert = PK11_FindCertFromNickname(asciiname, nullptr); 1.125 + if (!cert) { 1.126 + cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname); 1.127 + } 1.128 + if (cert) { 1.129 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n")); 1.130 + nsCOMPtr<nsIX509Cert> pCert = nsNSSCertificate::Create(cert.get()); 1.131 + if (pCert) { 1.132 + pCert.forget(_rvCert); 1.133 + return NS_OK; 1.134 + } 1.135 + } 1.136 + return NS_ERROR_FAILURE; 1.137 +} 1.138 + 1.139 +NS_IMETHODIMP 1.140 +nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken, 1.141 + nsIX509Cert **_cert) 1.142 +{ 1.143 + NS_ENSURE_ARG_POINTER(aDBkey); 1.144 + NS_ENSURE_ARG(aDBkey[0]); 1.145 + NS_ENSURE_ARG_POINTER(_cert); 1.146 + *_cert = nullptr; 1.147 + 1.148 + nsNSSShutDownPreventionLock locker; 1.149 + if (isAlreadyShutDown()) { 1.150 + return NS_ERROR_NOT_AVAILABLE; 1.151 + } 1.152 + 1.153 + SECItem keyItem = {siBuffer, nullptr, 0}; 1.154 + SECItem *dummy; 1.155 + CERTIssuerAndSN issuerSN; 1.156 + //unsigned long moduleID,slotID; 1.157 + 1.158 + dummy = NSSBase64_DecodeBuffer(nullptr, &keyItem, aDBkey, 1.159 + (uint32_t)strlen(aDBkey)); 1.160 + if (!dummy || keyItem.len < NS_NSS_LONG*4) { 1.161 + PR_FREEIF(keyItem.data); 1.162 + return NS_ERROR_INVALID_ARG; 1.163 + } 1.164 + 1.165 + mozilla::pkix::ScopedCERTCertificate cert; 1.166 + // someday maybe we can speed up the search using the moduleID and slotID 1.167 + // moduleID = NS_NSS_GET_LONG(keyItem.data); 1.168 + // slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]); 1.169 + 1.170 + // build the issuer/SN structure 1.171 + issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]); 1.172 + issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]); 1.173 + if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0 1.174 + || issuerSN.serialNumber.len + issuerSN.derIssuer.len 1.175 + != keyItem.len - NS_NSS_LONG*4) { 1.176 + PR_FREEIF(keyItem.data); 1.177 + return NS_ERROR_INVALID_ARG; 1.178 + } 1.179 + issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4]; 1.180 + issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+ 1.181 + issuerSN.serialNumber.len]; 1.182 + 1.183 + cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN); 1.184 + PR_FREEIF(keyItem.data); 1.185 + if (cert) { 1.186 + nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get()); 1.187 + if (!nssCert) 1.188 + return NS_ERROR_OUT_OF_MEMORY; 1.189 + nssCert.forget(_cert); 1.190 + } 1.191 + return NS_OK; 1.192 +} 1.193 + 1.194 +NS_IMETHODIMP 1.195 +nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken, 1.196 + uint32_t aType, 1.197 + uint32_t *_count, 1.198 + char16_t ***_certNames) 1.199 +{ 1.200 + nsNSSShutDownPreventionLock locker; 1.201 + if (isAlreadyShutDown()) { 1.202 + return NS_ERROR_NOT_AVAILABLE; 1.203 + } 1.204 + 1.205 + nsresult rv = NS_ERROR_FAILURE; 1.206 + /* 1.207 + * obtain the cert list from NSS 1.208 + */ 1.209 + mozilla::pkix::ScopedCERTCertList certList; 1.210 + certList = PK11_ListCerts(PK11CertListUnique, nullptr); 1.211 + if (!certList) 1.212 + goto cleanup; 1.213 + /* 1.214 + * get list of cert names from list of certs 1.215 + * XXX also cull the list (NSS only distinguishes based on user/non-user 1.216 + */ 1.217 + getCertNames(certList.get(), aType, _count, _certNames, locker); 1.218 + rv = NS_OK; 1.219 + /* 1.220 + * finish up 1.221 + */ 1.222 +cleanup: 1.223 + return rv; 1.224 +} 1.225 + 1.226 +SECStatus 1.227 +collect_certs(void *arg, SECItem **certs, int numcerts) 1.228 +{ 1.229 + CERTDERCerts *collectArgs; 1.230 + SECItem *cert; 1.231 + SECStatus rv; 1.232 + 1.233 + collectArgs = (CERTDERCerts *)arg; 1.234 + 1.235 + collectArgs->numcerts = numcerts; 1.236 + collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena, 1.237 + sizeof(SECItem) * numcerts); 1.238 + if (!collectArgs->rawCerts) 1.239 + return(SECFailure); 1.240 + 1.241 + cert = collectArgs->rawCerts; 1.242 + 1.243 + while ( numcerts-- ) { 1.244 + rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs); 1.245 + if ( rv == SECFailure ) 1.246 + return(SECFailure); 1.247 + cert++; 1.248 + certs++; 1.249 + } 1.250 + 1.251 + return (SECSuccess); 1.252 +} 1.253 + 1.254 +CERTDERCerts* 1.255 +nsNSSCertificateDB::getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 1.256 + uint32_t length, 1.257 + const nsNSSShutDownPreventionLock &/*proofOfLock*/) 1.258 +{ 1.259 + CERTDERCerts *collectArgs = 1.260 + (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts)); 1.261 + if (!collectArgs) 1.262 + return nullptr; 1.263 + 1.264 + collectArgs->arena = arena; 1.265 + SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast<char *>(data), 1.266 + length, collect_certs, 1.267 + (void *)collectArgs); 1.268 + if (sec_rv != SECSuccess) 1.269 + return nullptr; 1.270 + 1.271 + return collectArgs; 1.272 +} 1.273 + 1.274 +nsresult 1.275 +nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs, 1.276 + nsIInterfaceRequestor *ctx, 1.277 + const nsNSSShutDownPreventionLock &proofOfLock) 1.278 +{ 1.279 + // First thing we have to do is figure out which certificate we're 1.280 + // gonna present to the user. The CA may have sent down a list of 1.281 + // certs which may or may not be a chained list of certs. Until 1.282 + // the day we can design some solid UI for the general case, we'll 1.283 + // code to the > 90% case. That case is where a CA sends down a 1.284 + // list that is a hierarchy whose root is either the first or 1.285 + // the last cert. What we're gonna do is compare the first 1.286 + // 2 entries, if the second was signed by the first, we assume 1.287 + // the root cert is the first cert and display it. Otherwise, 1.288 + // we compare the last 2 entries, if the second to last cert was 1.289 + // signed by the last cert, then we assume the last cert is the 1.290 + // root and display it. 1.291 + 1.292 + uint32_t numCerts; 1.293 + 1.294 + x509Certs->GetLength(&numCerts); 1.295 + NS_ASSERTION(numCerts > 0, "Didn't get any certs to import."); 1.296 + if (numCerts == 0) 1.297 + return NS_OK; // Nothing to import, so nothing to do. 1.298 + 1.299 + nsCOMPtr<nsIX509Cert> certToShow; 1.300 + nsCOMPtr<nsISupports> isupports; 1.301 + uint32_t selCertIndex; 1.302 + if (numCerts == 1) { 1.303 + // There's only one cert, so let's show it. 1.304 + selCertIndex = 0; 1.305 + certToShow = do_QueryElementAt(x509Certs, selCertIndex); 1.306 + } else { 1.307 + nsCOMPtr<nsIX509Cert> cert0; // first cert 1.308 + nsCOMPtr<nsIX509Cert> cert1; // second cert 1.309 + nsCOMPtr<nsIX509Cert> certn_2; // second to last cert 1.310 + nsCOMPtr<nsIX509Cert> certn_1; // last cert 1.311 + 1.312 + cert0 = do_QueryElementAt(x509Certs, 0); 1.313 + cert1 = do_QueryElementAt(x509Certs, 1); 1.314 + certn_2 = do_QueryElementAt(x509Certs, numCerts-2); 1.315 + certn_1 = do_QueryElementAt(x509Certs, numCerts-1); 1.316 + 1.317 + nsXPIDLString cert0SubjectName; 1.318 + nsXPIDLString cert1IssuerName; 1.319 + nsXPIDLString certn_2IssuerName; 1.320 + nsXPIDLString certn_1SubjectName; 1.321 + 1.322 + cert0->GetSubjectName(cert0SubjectName); 1.323 + cert1->GetIssuerName(cert1IssuerName); 1.324 + certn_2->GetIssuerName(certn_2IssuerName); 1.325 + certn_1->GetSubjectName(certn_1SubjectName); 1.326 + 1.327 + if (cert1IssuerName.Equals(cert0SubjectName)) { 1.328 + // In this case, the first cert in the list signed the second, 1.329 + // so the first cert is the root. Let's display it. 1.330 + selCertIndex = 0; 1.331 + certToShow = cert0; 1.332 + } else 1.333 + if (certn_2IssuerName.Equals(certn_1SubjectName)) { 1.334 + // In this case the last cert has signed the second to last cert. 1.335 + // The last cert is the root, so let's display it. 1.336 + selCertIndex = numCerts-1; 1.337 + certToShow = certn_1; 1.338 + } else { 1.339 + // It's not a chain, so let's just show the first one in the 1.340 + // downloaded list. 1.341 + selCertIndex = 0; 1.342 + certToShow = cert0; 1.343 + } 1.344 + } 1.345 + 1.346 + if (!certToShow) 1.347 + return NS_ERROR_FAILURE; 1.348 + 1.349 + nsCOMPtr<nsICertificateDialogs> dialogs; 1.350 + nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), 1.351 + NS_GET_IID(nsICertificateDialogs), 1.352 + NS_CERTIFICATEDIALOGS_CONTRACTID); 1.353 + 1.354 + if (NS_FAILED(rv)) 1.355 + return rv; 1.356 + 1.357 + SECItem der; 1.358 + rv=certToShow->GetRawDER(&der.len, (uint8_t **)&der.data); 1.359 + 1.360 + if (NS_FAILED(rv)) 1.361 + return rv; 1.362 + 1.363 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); 1.364 + mozilla::pkix::ScopedCERTCertificate tmpCert; 1.365 + CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); 1.366 + tmpCert = CERT_FindCertByDERCert(certdb, &der); 1.367 + if (!tmpCert) { 1.368 + tmpCert = CERT_NewTempCertificate(certdb, &der, 1.369 + nullptr, false, true); 1.370 + } 1.371 + nsMemory::Free(der.data); 1.372 + der.data = nullptr; 1.373 + der.len = 0; 1.374 + 1.375 + if (!tmpCert) { 1.376 + NS_ERROR("Couldn't create cert from DER blob"); 1.377 + return NS_ERROR_FAILURE; 1.378 + } 1.379 + 1.380 + if (!CERT_IsCACert(tmpCert.get(), nullptr)) { 1.381 + DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock); 1.382 + return NS_ERROR_FAILURE; 1.383 + } 1.384 + 1.385 + if (tmpCert->isperm) { 1.386 + DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock); 1.387 + return NS_ERROR_FAILURE; 1.388 + } 1.389 + 1.390 + uint32_t trustBits; 1.391 + bool allows; 1.392 + rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); 1.393 + if (NS_FAILED(rv)) 1.394 + return rv; 1.395 + 1.396 + if (!allows) 1.397 + return NS_ERROR_NOT_AVAILABLE; 1.398 + 1.399 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits)); 1.400 + nsXPIDLCString nickname; 1.401 + nickname.Adopt(CERT_MakeCANickname(tmpCert.get())); 1.402 + 1.403 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); 1.404 + 1.405 + nsNSSCertTrust trust; 1.406 + trust.SetValidCA(); 1.407 + trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), 1.408 + !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), 1.409 + !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); 1.410 + 1.411 + SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(), 1.412 + const_cast<char*>(nickname.get()), 1.413 + trust.GetTrust()); 1.414 + 1.415 + if (srv != SECSuccess) 1.416 + return NS_ERROR_FAILURE; 1.417 + 1.418 + // Import additional delivered certificates that can be verified. 1.419 + 1.420 + // build a CertList for filtering 1.421 + mozilla::pkix::ScopedCERTCertList certList(CERT_NewCertList()); 1.422 + if (!certList) { 1.423 + return NS_ERROR_FAILURE; 1.424 + } 1.425 + 1.426 + // get all remaining certs into temp store 1.427 + 1.428 + for (uint32_t i=0; i<numCerts; i++) { 1.429 + if (i == selCertIndex) { 1.430 + // we already processed that one 1.431 + continue; 1.432 + } 1.433 + 1.434 + certToShow = do_QueryElementAt(x509Certs, i); 1.435 + certToShow->GetRawDER(&der.len, (uint8_t **)&der.data); 1.436 + 1.437 + CERTCertificate *tmpCert2 = 1.438 + CERT_NewTempCertificate(certdb, &der, nullptr, false, true); 1.439 + 1.440 + nsMemory::Free(der.data); 1.441 + der.data = nullptr; 1.442 + der.len = 0; 1.443 + 1.444 + if (!tmpCert2) { 1.445 + NS_ERROR("Couldn't create temp cert from DER blob"); 1.446 + continue; // Let's try to import the rest of 'em 1.447 + } 1.448 + 1.449 + CERT_AddCertToListTail(certList.get(), tmpCert2); 1.450 + } 1.451 + 1.452 + return ImportValidCACertsInList(certList.get(), ctx, proofOfLock); 1.453 +} 1.454 + 1.455 +/* 1.456 + * [noscript] void importCertificates(in charPtr data, in unsigned long length, 1.457 + * in unsigned long type, 1.458 + * in nsIInterfaceRequestor ctx); 1.459 + */ 1.460 +NS_IMETHODIMP 1.461 +nsNSSCertificateDB::ImportCertificates(uint8_t * data, uint32_t length, 1.462 + uint32_t type, 1.463 + nsIInterfaceRequestor *ctx) 1.464 + 1.465 +{ 1.466 + nsNSSShutDownPreventionLock locker; 1.467 + if (isAlreadyShutDown()) { 1.468 + return NS_ERROR_NOT_AVAILABLE; 1.469 + } 1.470 + 1.471 + nsresult nsrv; 1.472 + 1.473 + PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.474 + if (!arena) 1.475 + return NS_ERROR_OUT_OF_MEMORY; 1.476 + 1.477 + CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); 1.478 + if (!certCollection) { 1.479 + PORT_FreeArena(arena, false); 1.480 + return NS_ERROR_FAILURE; 1.481 + } 1.482 + nsCOMPtr<nsIMutableArray> array = 1.483 + do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv); 1.484 + if (NS_FAILED(nsrv)) { 1.485 + PORT_FreeArena(arena, false); 1.486 + return nsrv; 1.487 + } 1.488 + 1.489 + // Now let's create some certs to work with 1.490 + nsCOMPtr<nsIX509Cert> x509Cert; 1.491 + nsNSSCertificate *nssCert; 1.492 + SECItem *currItem; 1.493 + for (int i=0; i<certCollection->numcerts; i++) { 1.494 + currItem = &certCollection->rawCerts[i]; 1.495 + nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len); 1.496 + if (!nssCert) 1.497 + return NS_ERROR_FAILURE; 1.498 + x509Cert = do_QueryInterface((nsIX509Cert*)nssCert); 1.499 + array->AppendElement(x509Cert, false); 1.500 + } 1.501 + switch (type) { 1.502 + case nsIX509Cert::CA_CERT: 1.503 + nsrv = handleCACertDownload(array, ctx, locker); 1.504 + break; 1.505 + default: 1.506 + // We only deal with import CA certs in this method currently. 1.507 + nsrv = NS_ERROR_FAILURE; 1.508 + break; 1.509 + } 1.510 + PORT_FreeArena(arena, false); 1.511 + return nsrv; 1.512 +} 1.513 + 1.514 +static 1.515 +SECStatus 1.516 +ImportCertsIntoPermanentStorage( 1.517 + const mozilla::pkix::ScopedCERTCertList& certChain, 1.518 + const SECCertUsage usage, const PRBool caOnly) 1.519 +{ 1.520 + CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); 1.521 + 1.522 + int chainLen = 0; 1.523 + for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); 1.524 + !CERT_LIST_END(chainNode, certChain); 1.525 + chainNode = CERT_LIST_NEXT(chainNode)) { 1.526 + chainLen++; 1.527 + } 1.528 + 1.529 + SECItem **rawArray; 1.530 + rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *)); 1.531 + if (!rawArray) { 1.532 + return SECFailure; 1.533 + } 1.534 + 1.535 + int i = 0; 1.536 + for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); 1.537 + !CERT_LIST_END(chainNode, certChain); 1.538 + chainNode = CERT_LIST_NEXT(chainNode), i++) { 1.539 + rawArray[i] = &chainNode->cert->derCert; 1.540 + } 1.541 + SECStatus srv = CERT_ImportCerts(certdb, usage, chainLen, rawArray, 1.542 + nullptr, true, caOnly, nullptr); 1.543 + 1.544 + PORT_Free(rawArray); 1.545 + return srv; 1.546 +} 1.547 + 1.548 + 1.549 +/* 1.550 + * [noscript] void importEmailCertificates(in charPtr data, in unsigned long length, 1.551 + * in nsIInterfaceRequestor ctx); 1.552 + */ 1.553 +NS_IMETHODIMP 1.554 +nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length, 1.555 + nsIInterfaceRequestor *ctx) 1.556 + 1.557 +{ 1.558 + nsNSSShutDownPreventionLock locker; 1.559 + if (isAlreadyShutDown()) { 1.560 + return NS_ERROR_NOT_AVAILABLE; 1.561 + } 1.562 + 1.563 + SECStatus srv = SECFailure; 1.564 + nsresult nsrv = NS_OK; 1.565 + CERTCertDBHandle *certdb; 1.566 + CERTCertificate **certArray = nullptr; 1.567 + mozilla::pkix::ScopedCERTCertList certList; 1.568 + CERTCertListNode *node; 1.569 + SECItem **rawArray; 1.570 + int numcerts; 1.571 + int i; 1.572 + 1.573 + PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.574 + if (!arena) 1.575 + return NS_ERROR_OUT_OF_MEMORY; 1.576 + 1.577 + CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); 1.578 + if (!certCollection) { 1.579 + PORT_FreeArena(arena, false); 1.580 + return NS_ERROR_FAILURE; 1.581 + } 1.582 + 1.583 + RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1.584 + NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); 1.585 + 1.586 + certdb = CERT_GetDefaultCertDB(); 1.587 + const PRTime now = PR_Now(); 1.588 + 1.589 + numcerts = certCollection->numcerts; 1.590 + 1.591 + rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); 1.592 + if ( !rawArray ) { 1.593 + nsrv = NS_ERROR_FAILURE; 1.594 + goto loser; 1.595 + } 1.596 + 1.597 + for (i=0; i < numcerts; i++) { 1.598 + rawArray[i] = &certCollection->rawCerts[i]; 1.599 + } 1.600 + 1.601 + srv = CERT_ImportCerts(certdb, certUsageEmailRecipient, numcerts, rawArray, 1.602 + &certArray, false, false, nullptr); 1.603 + 1.604 + PORT_Free(rawArray); 1.605 + rawArray = nullptr; 1.606 + 1.607 + if (srv != SECSuccess) { 1.608 + nsrv = NS_ERROR_FAILURE; 1.609 + goto loser; 1.610 + } 1.611 + 1.612 + // build a CertList for filtering 1.613 + certList = CERT_NewCertList(); 1.614 + if (!certList) { 1.615 + nsrv = NS_ERROR_FAILURE; 1.616 + goto loser; 1.617 + } 1.618 + for (i=0; i < numcerts; i++) { 1.619 + CERTCertificate *cert = certArray[i]; 1.620 + if (cert) 1.621 + cert = CERT_DupCertificate(cert); 1.622 + if (cert) 1.623 + CERT_AddCertToListTail(certList.get(), cert); 1.624 + } 1.625 + 1.626 + /* go down the remaining list of certs and verify that they have 1.627 + * valid chains, then import them. 1.628 + */ 1.629 + 1.630 + for (node = CERT_LIST_HEAD(certList); 1.631 + !CERT_LIST_END(node,certList); 1.632 + node = CERT_LIST_NEXT(node)) { 1.633 + 1.634 + if (!node->cert) { 1.635 + continue; 1.636 + } 1.637 + 1.638 + mozilla::pkix::ScopedCERTCertList certChain; 1.639 + 1.640 + SECStatus rv = certVerifier->VerifyCert(node->cert, 1.641 + certificateUsageEmailRecipient, 1.642 + now, ctx, nullptr, 0, 1.643 + nullptr, &certChain); 1.644 + 1.645 + if (rv != SECSuccess) { 1.646 + nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert); 1.647 + DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker); 1.648 + continue; 1.649 + } 1.650 + rv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient, 1.651 + false); 1.652 + if (rv != SECSuccess) { 1.653 + goto loser; 1.654 + } 1.655 + CERT_SaveSMimeProfile(node->cert, nullptr, nullptr); 1.656 + 1.657 + } 1.658 + 1.659 +loser: 1.660 + if (certArray) { 1.661 + CERT_DestroyCertArray(certArray, numcerts); 1.662 + } 1.663 + if (arena) 1.664 + PORT_FreeArena(arena, true); 1.665 + return nsrv; 1.666 +} 1.667 + 1.668 +NS_IMETHODIMP 1.669 +nsNSSCertificateDB::ImportServerCertificate(uint8_t * data, uint32_t length, 1.670 + nsIInterfaceRequestor *ctx) 1.671 + 1.672 +{ 1.673 + nsNSSShutDownPreventionLock locker; 1.674 + if (isAlreadyShutDown()) { 1.675 + return NS_ERROR_NOT_AVAILABLE; 1.676 + } 1.677 + 1.678 + SECStatus srv = SECFailure; 1.679 + nsresult nsrv = NS_OK; 1.680 + mozilla::pkix::ScopedCERTCertificate cert; 1.681 + SECItem **rawCerts = nullptr; 1.682 + int numcerts; 1.683 + int i; 1.684 + nsNSSCertTrust trust; 1.685 + char *serverNickname = nullptr; 1.686 + 1.687 + PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.688 + if (!arena) 1.689 + return NS_ERROR_OUT_OF_MEMORY; 1.690 + 1.691 + CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); 1.692 + if (!certCollection) { 1.693 + PORT_FreeArena(arena, false); 1.694 + return NS_ERROR_FAILURE; 1.695 + } 1.696 + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts, 1.697 + nullptr, false, true); 1.698 + if (!cert) { 1.699 + nsrv = NS_ERROR_FAILURE; 1.700 + goto loser; 1.701 + } 1.702 + numcerts = certCollection->numcerts; 1.703 + rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); 1.704 + if ( !rawCerts ) { 1.705 + nsrv = NS_ERROR_FAILURE; 1.706 + goto loser; 1.707 + } 1.708 + 1.709 + for ( i = 0; i < numcerts; i++ ) { 1.710 + rawCerts[i] = &certCollection->rawCerts[i]; 1.711 + } 1.712 + 1.713 + serverNickname = DefaultServerNicknameForCert(cert.get()); 1.714 + srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer, 1.715 + numcerts, rawCerts, nullptr, true, false, 1.716 + serverNickname); 1.717 + PR_FREEIF(serverNickname); 1.718 + if ( srv != SECSuccess ) { 1.719 + nsrv = NS_ERROR_FAILURE; 1.720 + goto loser; 1.721 + } 1.722 + 1.723 + trust.SetValidServerPeer(); 1.724 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert.get(), 1.725 + trust.GetTrust()); 1.726 + if ( srv != SECSuccess ) { 1.727 + nsrv = NS_ERROR_FAILURE; 1.728 + goto loser; 1.729 + } 1.730 +loser: 1.731 + PORT_Free(rawCerts); 1.732 + if (arena) 1.733 + PORT_FreeArena(arena, true); 1.734 + return nsrv; 1.735 +} 1.736 + 1.737 +nsresult 1.738 +nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx, const nsNSSShutDownPreventionLock &proofOfLock) 1.739 +{ 1.740 + ScopedCERTCertList certList; 1.741 + SECItem **rawArray; 1.742 + 1.743 + // build a CertList for filtering 1.744 + certList = CERT_NewCertList(); 1.745 + if (!certList) { 1.746 + return NS_ERROR_FAILURE; 1.747 + } 1.748 + 1.749 + // get all certs into temp store 1.750 + SECStatus srv = SECFailure; 1.751 + CERTCertificate **certArray = nullptr; 1.752 + 1.753 + rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts); 1.754 + if ( !rawArray ) { 1.755 + return NS_ERROR_FAILURE; 1.756 + } 1.757 + 1.758 + for (int i=0; i < numCACerts; i++) { 1.759 + rawArray[i] = &CACerts[i]; 1.760 + } 1.761 + 1.762 + srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray, 1.763 + &certArray, false, true, nullptr); 1.764 + 1.765 + PORT_Free(rawArray); 1.766 + rawArray = nullptr; 1.767 + 1.768 + if (srv != SECSuccess) { 1.769 + return NS_ERROR_FAILURE; 1.770 + } 1.771 + 1.772 + for (int i2=0; i2 < numCACerts; i2++) { 1.773 + CERTCertificate *cacert = certArray[i2]; 1.774 + if (cacert) 1.775 + cacert = CERT_DupCertificate(cacert); 1.776 + if (cacert) 1.777 + CERT_AddCertToListTail(certList, cacert); 1.778 + } 1.779 + 1.780 + CERT_DestroyCertArray(certArray, numCACerts); 1.781 + 1.782 + return ImportValidCACertsInList(certList, ctx, proofOfLock); 1.783 +} 1.784 + 1.785 +nsresult 1.786 +nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx, 1.787 + const nsNSSShutDownPreventionLock &proofOfLock) 1.788 +{ 1.789 + RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1.790 + if (!certVerifier) 1.791 + return NS_ERROR_UNEXPECTED; 1.792 + 1.793 + /* filter out the certs we don't want */ 1.794 + SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, true); 1.795 + if (srv != SECSuccess) { 1.796 + return NS_ERROR_FAILURE; 1.797 + } 1.798 + 1.799 + /* go down the remaining list of certs and verify that they have 1.800 + * valid chains, if yes, then import. 1.801 + */ 1.802 + CERTCertListNode *node; 1.803 + 1.804 + for (node = CERT_LIST_HEAD(certList); 1.805 + !CERT_LIST_END(node,certList); 1.806 + node = CERT_LIST_NEXT(node)) { 1.807 + mozilla::pkix::ScopedCERTCertList certChain; 1.808 + SECStatus rv = certVerifier->VerifyCert(node->cert, 1.809 + certificateUsageVerifyCA, 1.810 + PR_Now(), ctx, nullptr, 0, nullptr, 1.811 + &certChain); 1.812 + if (rv != SECSuccess) { 1.813 + nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert); 1.814 + DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock); 1.815 + continue; 1.816 + } 1.817 + 1.818 + rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true); 1.819 + if (rv != SECSuccess) { 1.820 + return NS_ERROR_FAILURE; 1.821 + } 1.822 + } 1.823 + 1.824 + return NS_OK; 1.825 +} 1.826 + 1.827 +void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx, 1.828 + const char *stringID, 1.829 + nsIX509Cert *certToShow, 1.830 + const nsNSSShutDownPreventionLock &/*proofOfLock*/) 1.831 +{ 1.832 + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.833 + 1.834 + if (!NS_IsMainThread()) { 1.835 + NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread"); 1.836 + return; 1.837 + } 1.838 + 1.839 + nsPSMUITracker tracker; 1.840 + if (!tracker.isUIForbidden()) { 1.841 + 1.842 + nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx; 1.843 + if (!my_ctx) 1.844 + my_ctx = new PipUIContext(); 1.845 + 1.846 + // This shall be replaced by embedding ovverridable prompts 1.847 + // as discussed in bug 310446, and should make use of certToShow. 1.848 + 1.849 + nsresult rv; 1.850 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.851 + if (NS_SUCCEEDED(rv)) { 1.852 + nsAutoString tmpMessage; 1.853 + nssComponent->GetPIPNSSBundleString(stringID, tmpMessage); 1.854 + 1.855 + nsCOMPtr<nsIPrompt> prompt (do_GetInterface(my_ctx)); 1.856 + if (!prompt) 1.857 + return; 1.858 + 1.859 + prompt->Alert(nullptr, tmpMessage.get()); 1.860 + } 1.861 + } 1.862 +} 1.863 + 1.864 + 1.865 +NS_IMETHODIMP 1.866 +nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx) 1.867 +{ 1.868 + if (!NS_IsMainThread()) { 1.869 + NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread"); 1.870 + return NS_ERROR_NOT_SAME_THREAD; 1.871 + } 1.872 + 1.873 + nsNSSShutDownPreventionLock locker; 1.874 + if (isAlreadyShutDown()) { 1.875 + return NS_ERROR_NOT_AVAILABLE; 1.876 + } 1.877 + 1.878 + ScopedPK11SlotInfo slot; 1.879 + nsAutoCString nickname; 1.880 + nsresult rv = NS_ERROR_FAILURE; 1.881 + int numCACerts; 1.882 + SECItem *CACerts; 1.883 + CERTDERCerts * collectArgs; 1.884 + PLArenaPool *arena; 1.885 + mozilla::pkix::ScopedCERTCertificate cert; 1.886 + 1.887 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.888 + if (!arena) { 1.889 + goto loser; 1.890 + } 1.891 + 1.892 + collectArgs = getCertsFromPackage(arena, data, length, locker); 1.893 + if (!collectArgs) { 1.894 + goto loser; 1.895 + } 1.896 + 1.897 + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts, 1.898 + nullptr, false, true); 1.899 + if (!cert) { 1.900 + goto loser; 1.901 + } 1.902 + 1.903 + slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx); 1.904 + if (!slot) { 1.905 + nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get()); 1.906 + DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker); 1.907 + goto loser; 1.908 + } 1.909 + slot = nullptr; 1.910 + 1.911 + /* pick a nickname for the cert */ 1.912 + if (cert->nickname) { 1.913 + /* sigh, we need a call to look up other certs with this subject and 1.914 + * identify nicknames from them. We can no longer walk down internal 1.915 + * database structures rjr */ 1.916 + nickname = cert->nickname; 1.917 + } 1.918 + else { 1.919 + get_default_nickname(cert.get(), ctx, nickname, locker); 1.920 + } 1.921 + 1.922 + /* user wants to import the cert */ 1.923 + { 1.924 + char *cast_const_away = const_cast<char*>(nickname.get()); 1.925 + slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx); 1.926 + } 1.927 + if (!slot) { 1.928 + goto loser; 1.929 + } 1.930 + slot = nullptr; 1.931 + 1.932 + { 1.933 + nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get()); 1.934 + DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker); 1.935 + } 1.936 + rv = NS_OK; 1.937 + 1.938 + numCACerts = collectArgs->numcerts - 1; 1.939 + if (numCACerts) { 1.940 + CACerts = collectArgs->rawCerts+1; 1.941 + rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker); 1.942 + } 1.943 + 1.944 +loser: 1.945 + if (arena) { 1.946 + PORT_FreeArena(arena, false); 1.947 + } 1.948 + return rv; 1.949 +} 1.950 + 1.951 +/* 1.952 + * void deleteCertificate(in nsIX509Cert aCert); 1.953 + */ 1.954 +NS_IMETHODIMP 1.955 +nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert) 1.956 +{ 1.957 + nsNSSShutDownPreventionLock locker; 1.958 + if (isAlreadyShutDown()) { 1.959 + return NS_ERROR_NOT_AVAILABLE; 1.960 + } 1.961 + nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); 1.962 + mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert()); 1.963 + if (!cert) return NS_ERROR_FAILURE; 1.964 + SECStatus srv = SECSuccess; 1.965 + 1.966 + uint32_t certType; 1.967 + nssCert->GetCertType(&certType); 1.968 + if (NS_FAILED(nssCert->MarkForPermDeletion())) 1.969 + { 1.970 + return NS_ERROR_FAILURE; 1.971 + } 1.972 + 1.973 + if (cert->slot && certType != nsIX509Cert::USER_CERT) { 1.974 + // To delete a cert of a slot (builtin, most likely), mark it as 1.975 + // completely untrusted. This way we keep a copy cached in the 1.976 + // local database, and next time we try to load it off of the 1.977 + // external token/slot, we'll know not to trust it. We don't 1.978 + // want to do that with user certs, because a user may re-store 1.979 + // the cert onto the card again at which point we *will* want to 1.980 + // trust that cert if it chains up properly. 1.981 + nsNSSCertTrust trust(0, 0, 0); 1.982 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 1.983 + cert.get(), trust.GetTrust()); 1.984 + } 1.985 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv)); 1.986 + return (srv) ? NS_ERROR_FAILURE : NS_OK; 1.987 +} 1.988 + 1.989 +/* 1.990 + * void setCertTrust(in nsIX509Cert cert, 1.991 + * in unsigned long type, 1.992 + * in unsigned long trust); 1.993 + */ 1.994 +NS_IMETHODIMP 1.995 +nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert, 1.996 + uint32_t type, 1.997 + uint32_t trusted) 1.998 +{ 1.999 + nsNSSShutDownPreventionLock locker; 1.1000 + if (isAlreadyShutDown()) { 1.1001 + return NS_ERROR_NOT_AVAILABLE; 1.1002 + } 1.1003 + nsNSSCertTrust trust; 1.1004 + nsresult rv; 1.1005 + nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv); 1.1006 + if (!pipCert) { 1.1007 + return rv; 1.1008 + } 1.1009 + mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert()); 1.1010 + 1.1011 + rv = attemptToLogInWithDefaultPassword(); 1.1012 + if (NS_WARN_IF(rv != NS_OK)) { 1.1013 + return rv; 1.1014 + } 1.1015 + 1.1016 + SECStatus srv; 1.1017 + if (type == nsIX509Cert::CA_CERT) { 1.1018 + // always start with untrusted and move up 1.1019 + trust.SetValidCA(); 1.1020 + trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL), 1.1021 + !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 1.1022 + !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN)); 1.1023 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 1.1024 + nsscert.get(), 1.1025 + trust.GetTrust()); 1.1026 + } else if (type == nsIX509Cert::SERVER_CERT) { 1.1027 + // always start with untrusted and move up 1.1028 + trust.SetValidPeer(); 1.1029 + trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0); 1.1030 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 1.1031 + nsscert.get(), 1.1032 + trust.GetTrust()); 1.1033 + } else if (type == nsIX509Cert::EMAIL_CERT) { 1.1034 + // always start with untrusted and move up 1.1035 + trust.SetValidPeer(); 1.1036 + trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0); 1.1037 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 1.1038 + nsscert.get(), 1.1039 + trust.GetTrust()); 1.1040 + } else { 1.1041 + // ignore user certs 1.1042 + return NS_OK; 1.1043 + } 1.1044 + return MapSECStatus(srv); 1.1045 +} 1.1046 + 1.1047 +NS_IMETHODIMP 1.1048 +nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert, 1.1049 + uint32_t certType, 1.1050 + uint32_t trustType, 1.1051 + bool *_isTrusted) 1.1052 +{ 1.1053 + NS_ENSURE_ARG_POINTER(_isTrusted); 1.1054 + *_isTrusted = false; 1.1055 + 1.1056 + nsNSSShutDownPreventionLock locker; 1.1057 + if (isAlreadyShutDown()) { 1.1058 + return NS_ERROR_NOT_AVAILABLE; 1.1059 + } 1.1060 + SECStatus srv; 1.1061 + nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert); 1.1062 + mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert()); 1.1063 + CERTCertTrust nsstrust; 1.1064 + srv = CERT_GetCertTrust(nsscert.get(), &nsstrust); 1.1065 + if (srv != SECSuccess) 1.1066 + return NS_ERROR_FAILURE; 1.1067 + 1.1068 + nsNSSCertTrust trust(&nsstrust); 1.1069 + if (certType == nsIX509Cert::CA_CERT) { 1.1070 + if (trustType & nsIX509CertDB::TRUSTED_SSL) { 1.1071 + *_isTrusted = trust.HasTrustedCA(true, false, false); 1.1072 + } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 1.1073 + *_isTrusted = trust.HasTrustedCA(false, true, false); 1.1074 + } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { 1.1075 + *_isTrusted = trust.HasTrustedCA(false, false, true); 1.1076 + } else { 1.1077 + return NS_ERROR_FAILURE; 1.1078 + } 1.1079 + } else if (certType == nsIX509Cert::SERVER_CERT) { 1.1080 + if (trustType & nsIX509CertDB::TRUSTED_SSL) { 1.1081 + *_isTrusted = trust.HasTrustedPeer(true, false, false); 1.1082 + } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 1.1083 + *_isTrusted = trust.HasTrustedPeer(false, true, false); 1.1084 + } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { 1.1085 + *_isTrusted = trust.HasTrustedPeer(false, false, true); 1.1086 + } else { 1.1087 + return NS_ERROR_FAILURE; 1.1088 + } 1.1089 + } else if (certType == nsIX509Cert::EMAIL_CERT) { 1.1090 + if (trustType & nsIX509CertDB::TRUSTED_SSL) { 1.1091 + *_isTrusted = trust.HasTrustedPeer(true, false, false); 1.1092 + } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 1.1093 + *_isTrusted = trust.HasTrustedPeer(false, true, false); 1.1094 + } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { 1.1095 + *_isTrusted = trust.HasTrustedPeer(false, false, true); 1.1096 + } else { 1.1097 + return NS_ERROR_FAILURE; 1.1098 + } 1.1099 + } /* user: ignore */ 1.1100 + return NS_OK; 1.1101 +} 1.1102 + 1.1103 + 1.1104 +NS_IMETHODIMP 1.1105 +nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken, 1.1106 + nsIFile *aFile, 1.1107 + uint32_t aType) 1.1108 +{ 1.1109 + nsNSSShutDownPreventionLock locker; 1.1110 + if (isAlreadyShutDown()) { 1.1111 + return NS_ERROR_NOT_AVAILABLE; 1.1112 + } 1.1113 + 1.1114 + NS_ENSURE_ARG(aFile); 1.1115 + switch (aType) { 1.1116 + case nsIX509Cert::CA_CERT: 1.1117 + case nsIX509Cert::EMAIL_CERT: 1.1118 + case nsIX509Cert::SERVER_CERT: 1.1119 + // good 1.1120 + break; 1.1121 + 1.1122 + default: 1.1123 + // not supported (yet) 1.1124 + return NS_ERROR_FAILURE; 1.1125 + } 1.1126 + 1.1127 + nsresult rv; 1.1128 + PRFileDesc *fd = nullptr; 1.1129 + 1.1130 + rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); 1.1131 + 1.1132 + if (NS_FAILED(rv)) 1.1133 + return rv; 1.1134 + 1.1135 + if (!fd) 1.1136 + return NS_ERROR_FAILURE; 1.1137 + 1.1138 + PRFileInfo file_info; 1.1139 + if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info)) 1.1140 + return NS_ERROR_FAILURE; 1.1141 + 1.1142 + unsigned char *buf = new unsigned char[file_info.size]; 1.1143 + 1.1144 + int32_t bytes_obtained = PR_Read(fd, buf, file_info.size); 1.1145 + PR_Close(fd); 1.1146 + 1.1147 + if (bytes_obtained != file_info.size) 1.1148 + rv = NS_ERROR_FAILURE; 1.1149 + else { 1.1150 + nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext(); 1.1151 + 1.1152 + switch (aType) { 1.1153 + case nsIX509Cert::CA_CERT: 1.1154 + rv = ImportCertificates(buf, bytes_obtained, aType, cxt); 1.1155 + break; 1.1156 + 1.1157 + case nsIX509Cert::SERVER_CERT: 1.1158 + rv = ImportServerCertificate(buf, bytes_obtained, cxt); 1.1159 + break; 1.1160 + 1.1161 + case nsIX509Cert::EMAIL_CERT: 1.1162 + rv = ImportEmailCertificate(buf, bytes_obtained, cxt); 1.1163 + break; 1.1164 + 1.1165 + default: 1.1166 + break; 1.1167 + } 1.1168 + } 1.1169 + 1.1170 + delete [] buf; 1.1171 + return rv; 1.1172 +} 1.1173 + 1.1174 +NS_IMETHODIMP 1.1175 +nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken, 1.1176 + nsIFile *aFile) 1.1177 +{ 1.1178 + nsNSSShutDownPreventionLock locker; 1.1179 + if (isAlreadyShutDown()) { 1.1180 + return NS_ERROR_NOT_AVAILABLE; 1.1181 + } 1.1182 + 1.1183 + NS_ENSURE_ARG(aFile); 1.1184 + nsPKCS12Blob blob; 1.1185 + nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken); 1.1186 + if (token) { 1.1187 + blob.SetToken(token); 1.1188 + } 1.1189 + return blob.ImportFromFile(aFile); 1.1190 +} 1.1191 + 1.1192 +NS_IMETHODIMP 1.1193 +nsNSSCertificateDB::ExportPKCS12File(nsISupports *aToken, 1.1194 + nsIFile *aFile, 1.1195 + uint32_t count, 1.1196 + nsIX509Cert **certs) 1.1197 + //const char16_t **aCertNames) 1.1198 +{ 1.1199 + nsNSSShutDownPreventionLock locker; 1.1200 + if (isAlreadyShutDown()) { 1.1201 + return NS_ERROR_NOT_AVAILABLE; 1.1202 + } 1.1203 + 1.1204 + NS_ENSURE_ARG(aFile); 1.1205 + nsPKCS12Blob blob; 1.1206 + if (count == 0) return NS_OK; 1.1207 + nsCOMPtr<nsIPK11Token> localRef; 1.1208 + if (!aToken) { 1.1209 + ScopedPK11SlotInfo keySlot(PK11_GetInternalKeySlot()); 1.1210 + NS_ASSERTION(keySlot,"Failed to get the internal key slot"); 1.1211 + localRef = new nsPK11Token(keySlot); 1.1212 + } 1.1213 + else { 1.1214 + localRef = do_QueryInterface(aToken); 1.1215 + } 1.1216 + blob.SetToken(localRef); 1.1217 + //blob.LoadCerts(aCertNames, count); 1.1218 + //return blob.ExportToFile(aFile); 1.1219 + return blob.ExportToFile(aFile, certs, count); 1.1220 +} 1.1221 + 1.1222 +/* 1.1223 + * NSS Helper Routines (private to nsNSSCertificateDB) 1.1224 + */ 1.1225 + 1.1226 +#define DELIM '\001' 1.1227 + 1.1228 +/* 1.1229 + * GetSortedNameList 1.1230 + * 1.1231 + * Converts a CERTCertList to a list of certificate names 1.1232 + */ 1.1233 +void 1.1234 +nsNSSCertificateDB::getCertNames(CERTCertList *certList, 1.1235 + uint32_t type, 1.1236 + uint32_t *_count, 1.1237 + char16_t ***_certNames, 1.1238 + const nsNSSShutDownPreventionLock &/*proofOfLock*/) 1.1239 +{ 1.1240 + CERTCertListNode *node; 1.1241 + uint32_t numcerts = 0, i=0; 1.1242 + char16_t **tmpArray = nullptr; 1.1243 + 1.1244 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type)); 1.1245 + for (node = CERT_LIST_HEAD(certList); 1.1246 + !CERT_LIST_END(node, certList); 1.1247 + node = CERT_LIST_NEXT(node)) { 1.1248 + if (getCertType(node->cert) == type) { 1.1249 + numcerts++; 1.1250 + } 1.1251 + } 1.1252 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts)); 1.1253 + int nc = (numcerts == 0) ? 1 : numcerts; 1.1254 + tmpArray = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nc); 1.1255 + if (numcerts == 0) goto finish; 1.1256 + for (node = CERT_LIST_HEAD(certList); 1.1257 + !CERT_LIST_END(node, certList); 1.1258 + node = CERT_LIST_NEXT(node)) { 1.1259 + if (getCertType(node->cert) == type) { 1.1260 + nsNSSCertificate pipCert(node->cert); 1.1261 + char *dbkey = nullptr; 1.1262 + char *namestr = nullptr; 1.1263 + nsAutoString certstr; 1.1264 + pipCert.GetDbKey(&dbkey); 1.1265 + nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey); 1.1266 + PR_FREEIF(dbkey); 1.1267 + if (type == nsIX509Cert::EMAIL_CERT) { 1.1268 + namestr = node->cert->emailAddr; 1.1269 + } else { 1.1270 + namestr = node->cert->nickname; 1.1271 + if (namestr) { 1.1272 + char *sc = strchr(namestr, ':'); 1.1273 + if (sc) *sc = DELIM; 1.1274 + } 1.1275 + } 1.1276 + nsAutoString certname = NS_ConvertASCIItoUTF16(namestr ? namestr : ""); 1.1277 + certstr.Append(char16_t(DELIM)); 1.1278 + certstr += certname; 1.1279 + certstr.Append(char16_t(DELIM)); 1.1280 + certstr += keystr; 1.1281 + tmpArray[i++] = ToNewUnicode(certstr); 1.1282 + } 1.1283 + } 1.1284 +finish: 1.1285 + *_count = numcerts; 1.1286 + *_certNames = tmpArray; 1.1287 +} 1.1288 + 1.1289 +/* nsIX509Cert getDefaultEmailEncryptionCert (); */ 1.1290 +NS_IMETHODIMP 1.1291 +nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval) 1.1292 +{ 1.1293 + NS_ENSURE_ARG_POINTER(_retval); 1.1294 + *_retval = nullptr; 1.1295 + 1.1296 + if (aNickname.IsEmpty()) 1.1297 + return NS_OK; 1.1298 + 1.1299 + nsNSSShutDownPreventionLock locker; 1.1300 + if (isAlreadyShutDown()) { 1.1301 + return NS_ERROR_NOT_AVAILABLE; 1.1302 + } 1.1303 + 1.1304 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.1305 + char *asciiname = nullptr; 1.1306 + NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname); 1.1307 + asciiname = const_cast<char*>(aUtf8Nickname.get()); 1.1308 + 1.1309 + /* Find a good cert in the user's database */ 1.1310 + mozilla::pkix::ScopedCERTCertificate cert; 1.1311 + cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 1.1312 + certUsageEmailRecipient, true, ctx); 1.1313 + if (!cert) { 1.1314 + return NS_OK; 1.1315 + } 1.1316 + 1.1317 + nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get()); 1.1318 + if (!nssCert) { 1.1319 + return NS_ERROR_OUT_OF_MEMORY; 1.1320 + } 1.1321 + nssCert.forget(_retval); 1.1322 + return NS_OK; 1.1323 +} 1.1324 + 1.1325 +/* nsIX509Cert getDefaultEmailSigningCert (); */ 1.1326 +NS_IMETHODIMP 1.1327 +nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval) 1.1328 +{ 1.1329 + NS_ENSURE_ARG_POINTER(_retval); 1.1330 + *_retval = nullptr; 1.1331 + 1.1332 + if (aNickname.IsEmpty()) 1.1333 + return NS_OK; 1.1334 + 1.1335 + nsNSSShutDownPreventionLock locker; 1.1336 + if (isAlreadyShutDown()) { 1.1337 + return NS_ERROR_NOT_AVAILABLE; 1.1338 + } 1.1339 + 1.1340 + mozilla::pkix::ScopedCERTCertificate cert; 1.1341 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.1342 + char *asciiname = nullptr; 1.1343 + NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname); 1.1344 + asciiname = const_cast<char*>(aUtf8Nickname.get()); 1.1345 + 1.1346 + /* Find a good cert in the user's database */ 1.1347 + cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 1.1348 + certUsageEmailSigner, true, ctx); 1.1349 + if (!cert) { 1.1350 + return NS_OK; 1.1351 + } 1.1352 + 1.1353 + nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get()); 1.1354 + if (!nssCert) { 1.1355 + return NS_ERROR_OUT_OF_MEMORY; 1.1356 + } 1.1357 + nssCert.forget(_retval); 1.1358 + return NS_OK; 1.1359 +} 1.1360 + 1.1361 +NS_IMETHODIMP 1.1362 +nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval) 1.1363 +{ 1.1364 + nsNSSShutDownPreventionLock locker; 1.1365 + if (isAlreadyShutDown()) { 1.1366 + return NS_ERROR_NOT_AVAILABLE; 1.1367 + } 1.1368 + 1.1369 + RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1.1370 + NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); 1.1371 + 1.1372 + ScopedCERTCertList certlist( 1.1373 + PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr)); 1.1374 + if (!certlist) 1.1375 + return NS_ERROR_FAILURE; 1.1376 + 1.1377 + // certlist now contains certificates with the right email address, 1.1378 + // but they might not have the correct usage or might even be invalid 1.1379 + 1.1380 + if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) 1.1381 + return NS_ERROR_FAILURE; // no certs found 1.1382 + 1.1383 + CERTCertListNode *node; 1.1384 + // search for a valid certificate 1.1385 + for (node = CERT_LIST_HEAD(certlist); 1.1386 + !CERT_LIST_END(node, certlist); 1.1387 + node = CERT_LIST_NEXT(node)) { 1.1388 + 1.1389 + SECStatus srv = certVerifier->VerifyCert(node->cert, 1.1390 + certificateUsageEmailRecipient, 1.1391 + PR_Now(), nullptr /*XXX pinarg*/, 1.1392 + nullptr /*hostname*/); 1.1393 + if (srv == SECSuccess) { 1.1394 + break; 1.1395 + } 1.1396 + } 1.1397 + 1.1398 + if (CERT_LIST_END(node, certlist)) { 1.1399 + // no valid cert found 1.1400 + return NS_ERROR_FAILURE; 1.1401 + } 1.1402 + 1.1403 + // node now contains the first valid certificate with correct usage 1.1404 + nsNSSCertificate *nssCert = nsNSSCertificate::Create(node->cert); 1.1405 + if (!nssCert) 1.1406 + return NS_ERROR_OUT_OF_MEMORY; 1.1407 + 1.1408 + NS_ADDREF(nssCert); 1.1409 + *_retval = static_cast<nsIX509Cert*>(nssCert); 1.1410 + return NS_OK; 1.1411 +} 1.1412 + 1.1413 +/* nsIX509Cert constructX509FromBase64 (in string base64); */ 1.1414 +NS_IMETHODIMP 1.1415 +nsNSSCertificateDB::ConstructX509FromBase64(const char *base64, 1.1416 + nsIX509Cert **_retval) 1.1417 +{ 1.1418 + nsNSSShutDownPreventionLock locker; 1.1419 + if (isAlreadyShutDown()) { 1.1420 + return NS_ERROR_NOT_AVAILABLE; 1.1421 + } 1.1422 + if (NS_WARN_IF(!_retval)) { 1.1423 + return NS_ERROR_INVALID_POINTER; 1.1424 + } 1.1425 + 1.1426 + // sure would be nice to have a smart pointer class for PL_ allocations 1.1427 + // unfortunately, we cannot distinguish out-of-memory from bad-input here 1.1428 + uint32_t len = base64 ? strlen(base64) : 0; 1.1429 + char *certDER = PL_Base64Decode(base64, len, nullptr); 1.1430 + if (!certDER) 1.1431 + return NS_ERROR_ILLEGAL_VALUE; 1.1432 + if (!*certDER) { 1.1433 + PL_strfree(certDER); 1.1434 + return NS_ERROR_ILLEGAL_VALUE; 1.1435 + } 1.1436 + 1.1437 + // If we get to this point, we know we had well-formed base64 input; 1.1438 + // therefore the input string cannot have been less than two 1.1439 + // characters long. Compute the unpadded length of the decoded data. 1.1440 + uint32_t lengthDER = (len * 3) / 4; 1.1441 + if (base64[len-1] == '=') { 1.1442 + lengthDER--; 1.1443 + if (base64[len-2] == '=') 1.1444 + lengthDER--; 1.1445 + } 1.1446 + 1.1447 + nsresult rv = ConstructX509(certDER, lengthDER, _retval); 1.1448 + PL_strfree(certDER); 1.1449 + return rv; 1.1450 +} 1.1451 + 1.1452 +/* nsIX509Cert constructX509 (in string certDER, unsigned long len); */ 1.1453 +NS_IMETHODIMP 1.1454 +nsNSSCertificateDB::ConstructX509(const char* certDER, 1.1455 + uint32_t lengthDER, 1.1456 + nsIX509Cert** _retval) 1.1457 +{ 1.1458 + nsNSSShutDownPreventionLock locker; 1.1459 + if (isAlreadyShutDown()) { 1.1460 + return NS_ERROR_NOT_AVAILABLE; 1.1461 + } 1.1462 + if (NS_WARN_IF(!_retval)) { 1.1463 + return NS_ERROR_INVALID_POINTER; 1.1464 + } 1.1465 + 1.1466 + SECItem secitem_cert; 1.1467 + secitem_cert.type = siDERCertBuffer; 1.1468 + secitem_cert.data = (unsigned char*)certDER; 1.1469 + secitem_cert.len = lengthDER; 1.1470 + 1.1471 + mozilla::pkix::ScopedCERTCertificate cert; 1.1472 + cert = 1.1473 + CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, 1.1474 + nullptr, false, true); 1.1475 + if (!cert) 1.1476 + return (PORT_GetError() == SEC_ERROR_NO_MEMORY) 1.1477 + ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE; 1.1478 + 1.1479 + nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get()); 1.1480 + if (!nssCert) { 1.1481 + return NS_ERROR_OUT_OF_MEMORY; 1.1482 + } 1.1483 + nssCert.forget(_retval); 1.1484 + return NS_OK; 1.1485 +} 1.1486 + 1.1487 +void 1.1488 +nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, 1.1489 + nsIInterfaceRequestor* ctx, 1.1490 + nsCString &nickname, 1.1491 + const nsNSSShutDownPreventionLock &/*proofOfLock*/) 1.1492 +{ 1.1493 + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.1494 + 1.1495 + nickname.Truncate(); 1.1496 + 1.1497 + nsresult rv; 1.1498 + CK_OBJECT_HANDLE keyHandle; 1.1499 + 1.1500 + CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB(); 1.1501 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.1502 + if (NS_FAILED(rv)) 1.1503 + return; 1.1504 + 1.1505 + nsAutoCString username; 1.1506 + char *temp_un = CERT_GetCommonName(&cert->subject); 1.1507 + if (temp_un) { 1.1508 + username = temp_un; 1.1509 + PORT_Free(temp_un); 1.1510 + temp_un = nullptr; 1.1511 + } 1.1512 + 1.1513 + nsAutoCString caname; 1.1514 + char *temp_ca = CERT_GetOrgName(&cert->issuer); 1.1515 + if (temp_ca) { 1.1516 + caname = temp_ca; 1.1517 + PORT_Free(temp_ca); 1.1518 + temp_ca = nullptr; 1.1519 + } 1.1520 + 1.1521 + nsAutoString tmpNickFmt; 1.1522 + nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt); 1.1523 + NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); 1.1524 + 1.1525 + nsAutoCString baseName; 1.1526 + char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get()); 1.1527 + if (!temp_nn) { 1.1528 + return; 1.1529 + } else { 1.1530 + baseName = temp_nn; 1.1531 + PR_smprintf_free(temp_nn); 1.1532 + temp_nn = nullptr; 1.1533 + } 1.1534 + 1.1535 + nickname = baseName; 1.1536 + 1.1537 + /* 1.1538 + * We need to see if the private key exists on a token, if it does 1.1539 + * then we need to check for nicknames that already exist on the smart 1.1540 + * card. 1.1541 + */ 1.1542 + ScopedPK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx)); 1.1543 + if (!slot) 1.1544 + return; 1.1545 + 1.1546 + if (!PK11_IsInternal(slot)) { 1.1547 + char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get()); 1.1548 + if (!tmp) { 1.1549 + nickname.Truncate(); 1.1550 + return; 1.1551 + } 1.1552 + baseName = tmp; 1.1553 + PR_smprintf_free(tmp); 1.1554 + 1.1555 + nickname = baseName; 1.1556 + } 1.1557 + 1.1558 + int count = 1; 1.1559 + while (true) { 1.1560 + if ( count > 1 ) { 1.1561 + char *tmp = PR_smprintf("%s #%d", baseName.get(), count); 1.1562 + if (!tmp) { 1.1563 + nickname.Truncate(); 1.1564 + return; 1.1565 + } 1.1566 + nickname = tmp; 1.1567 + PR_smprintf_free(tmp); 1.1568 + } 1.1569 + 1.1570 + mozilla::pkix::ScopedCERTCertificate dummycert; 1.1571 + 1.1572 + if (PK11_IsInternal(slot)) { 1.1573 + /* look up the nickname to make sure it isn't in use already */ 1.1574 + dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get()); 1.1575 + 1.1576 + } else { 1.1577 + /* 1.1578 + * Check the cert against others that already live on the smart 1.1579 + * card. 1.1580 + */ 1.1581 + dummycert = PK11_FindCertFromNickname(nickname.get(), ctx); 1.1582 + if (dummycert) { 1.1583 + /* 1.1584 + * Make sure the subject names are different. 1.1585 + */ 1.1586 + if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) 1.1587 + { 1.1588 + /* 1.1589 + * There is another certificate with the same nickname and 1.1590 + * the same subject name on the smart card, so let's use this 1.1591 + * nickname. 1.1592 + */ 1.1593 + dummycert = nullptr; 1.1594 + } 1.1595 + } 1.1596 + } 1.1597 + if (!dummycert) 1.1598 + break; 1.1599 + 1.1600 + count++; 1.1601 + } 1.1602 +} 1.1603 + 1.1604 +NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName) 1.1605 +{ 1.1606 + NS_ENSURE_ARG_POINTER(aBase64); 1.1607 + nsCOMPtr <nsIX509Cert> newCert; 1.1608 + 1.1609 + nsNSSShutDownPreventionLock locker; 1.1610 + if (isAlreadyShutDown()) { 1.1611 + return NS_ERROR_NOT_AVAILABLE; 1.1612 + } 1.1613 + 1.1614 + nsNSSCertTrust trust; 1.1615 + 1.1616 + // need to calculate the trust bits from the aTrust string. 1.1617 + SECStatus stat = CERT_DecodeTrustString(trust.GetTrust(), 1.1618 + /* this is const, but not declared that way */(char *) aTrust); 1.1619 + NS_ENSURE_STATE(stat == SECSuccess); // if bad trust passed in, return error. 1.1620 + 1.1621 + 1.1622 + nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert)); 1.1623 + NS_ENSURE_SUCCESS(rv, rv); 1.1624 + 1.1625 + SECItem der; 1.1626 + rv = newCert->GetRawDER(&der.len, (uint8_t **)&der.data); 1.1627 + NS_ENSURE_SUCCESS(rv, rv); 1.1628 + 1.1629 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); 1.1630 + CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); 1.1631 + mozilla::pkix::ScopedCERTCertificate tmpCert(CERT_FindCertByDERCert(certdb, &der)); 1.1632 + if (!tmpCert) 1.1633 + tmpCert = CERT_NewTempCertificate(certdb, &der, 1.1634 + nullptr, false, true); 1.1635 + nsMemory::Free(der.data); 1.1636 + der.data = nullptr; 1.1637 + der.len = 0; 1.1638 + 1.1639 + if (!tmpCert) { 1.1640 + NS_ERROR("Couldn't create cert from DER blob"); 1.1641 + return MapSECStatus(SECFailure); 1.1642 + } 1.1643 + 1.1644 + if (tmpCert->isperm) { 1.1645 + return NS_OK; 1.1646 + } 1.1647 + 1.1648 + nsXPIDLCString nickname; 1.1649 + nickname.Adopt(CERT_MakeCANickname(tmpCert.get())); 1.1650 + 1.1651 + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); 1.1652 + 1.1653 + rv = attemptToLogInWithDefaultPassword(); 1.1654 + if (NS_WARN_IF(rv != NS_OK)) { 1.1655 + return rv; 1.1656 + } 1.1657 + 1.1658 + SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(), 1.1659 + const_cast<char*>(nickname.get()), 1.1660 + trust.GetTrust()); 1.1661 + return MapSECStatus(srv); 1.1662 +} 1.1663 + 1.1664 +NS_IMETHODIMP 1.1665 +nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust, 1.1666 + const char *aName) 1.1667 +{ 1.1668 + nsCString base64; 1.1669 + nsresult rv = Base64Encode(aCertDER, base64); 1.1670 + NS_ENSURE_SUCCESS(rv, rv); 1.1671 + return AddCertFromBase64(base64.get(), aTrust, aName); 1.1672 +} 1.1673 + 1.1674 +NS_IMETHODIMP 1.1675 +nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert, 1.1676 + const char* trustString) 1.1677 +{ 1.1678 + CERTCertTrust trust; 1.1679 + 1.1680 + // need to calculate the trust bits from the aTrust string. 1.1681 + SECStatus srv = CERT_DecodeTrustString(&trust, 1.1682 + const_cast<char *>(trustString)); 1.1683 + if (srv != SECSuccess) { 1.1684 + return MapSECStatus(SECFailure); 1.1685 + } 1.1686 + mozilla::pkix::ScopedCERTCertificate nssCert(cert->GetCert()); 1.1687 + 1.1688 + nsresult rv = attemptToLogInWithDefaultPassword(); 1.1689 + if (NS_WARN_IF(rv != NS_OK)) { 1.1690 + return rv; 1.1691 + } 1.1692 + 1.1693 + srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust); 1.1694 + return MapSECStatus(srv); 1.1695 +} 1.1696 + 1.1697 +NS_IMETHODIMP 1.1698 +nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval) 1.1699 +{ 1.1700 + nsNSSShutDownPreventionLock locker; 1.1701 + if (isAlreadyShutDown()) { 1.1702 + return NS_ERROR_NOT_AVAILABLE; 1.1703 + } 1.1704 + 1.1705 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.1706 + nsCOMPtr<nsIX509CertList> nssCertList; 1.1707 + mozilla::pkix::ScopedCERTCertList certList( 1.1708 + PK11_ListCerts(PK11CertListUnique, ctx)); 1.1709 + 1.1710 + // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine. 1.1711 + // (returns an empty list) 1.1712 + nssCertList = new nsNSSCertList(certList, locker); 1.1713 + 1.1714 + *_retval = nssCertList; 1.1715 + NS_ADDREF(*_retval); 1.1716 + return NS_OK; 1.1717 +} 1.1718 + 1.1719 +NS_IMETHODIMP 1.1720 +nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result) 1.1721 +{ 1.1722 + nsNSSShutDownPreventionLock locker; 1.1723 + if (isAlreadyShutDown()) { 1.1724 + return NS_ERROR_NOT_AVAILABLE; 1.1725 + } 1.1726 + 1.1727 + MutexAutoLock lock(mBadCertsLock); 1.1728 + if (isPrivate) { 1.1729 + if (!mPrivateRecentBadCerts) { 1.1730 + mPrivateRecentBadCerts = new nsRecentBadCerts; 1.1731 + } 1.1732 + NS_ADDREF(*result = mPrivateRecentBadCerts); 1.1733 + } else { 1.1734 + if (!mPublicRecentBadCerts) { 1.1735 + mPublicRecentBadCerts = new nsRecentBadCerts; 1.1736 + } 1.1737 + NS_ADDREF(*result = mPublicRecentBadCerts); 1.1738 + } 1.1739 + return NS_OK; 1.1740 +} 1.1741 + 1.1742 +NS_IMETHODIMP 1.1743 +nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert, 1.1744 + int64_t /*SECCertificateUsage*/ aUsage, 1.1745 + uint32_t aFlags, 1.1746 + nsIX509CertList** verifiedChain, 1.1747 + bool* aHasEVPolicy, 1.1748 + int32_t* /*PRErrorCode*/ _retval ) 1.1749 +{ 1.1750 + NS_ENSURE_ARG_POINTER(aCert); 1.1751 + NS_ENSURE_ARG_POINTER(aHasEVPolicy); 1.1752 + NS_ENSURE_ARG_POINTER(verifiedChain); 1.1753 + NS_ENSURE_ARG_POINTER(_retval); 1.1754 + 1.1755 + *verifiedChain = nullptr; 1.1756 + *aHasEVPolicy = false; 1.1757 + *_retval = PR_UNKNOWN_ERROR; 1.1758 + 1.1759 + nsNSSShutDownPreventionLock locker; 1.1760 + if (isAlreadyShutDown()) { 1.1761 + return NS_ERROR_NOT_AVAILABLE; 1.1762 + } 1.1763 + 1.1764 +#ifndef MOZ_NO_EV_CERTS 1.1765 + EnsureIdentityInfoLoaded(); 1.1766 +#endif 1.1767 + 1.1768 + nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert); 1.1769 + if (!x509Cert) { 1.1770 + return NS_ERROR_INVALID_ARG; 1.1771 + } 1.1772 + ScopedCERTCertificate nssCert(x509Cert->GetCert()); 1.1773 + 1.1774 + RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1.1775 + NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); 1.1776 + 1.1777 + mozilla::pkix::ScopedCERTCertList resultChain; 1.1778 + SECOidTag evOidPolicy; 1.1779 + SECStatus srv; 1.1780 + 1.1781 + srv = certVerifier->VerifyCert(nssCert, 1.1782 + aUsage, PR_Now(), 1.1783 + nullptr, // Assume no context 1.1784 + nullptr, // hostname 1.1785 + aFlags, 1.1786 + nullptr, // stapledOCSPResponse 1.1787 + &resultChain, 1.1788 + &evOidPolicy); 1.1789 + 1.1790 + PRErrorCode error = PR_GetError(); 1.1791 + 1.1792 + nsCOMPtr<nsIX509CertList> nssCertList; 1.1793 + // This adopts the list 1.1794 + nssCertList = new nsNSSCertList(resultChain, locker); 1.1795 + NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE); 1.1796 + 1.1797 + if (srv == SECSuccess) { 1.1798 + if (evOidPolicy != SEC_OID_UNKNOWN) { 1.1799 + *aHasEVPolicy = true; 1.1800 + } 1.1801 + *_retval = 0; 1.1802 + } else { 1.1803 + NS_ENSURE_TRUE(evOidPolicy == SEC_OID_UNKNOWN, NS_ERROR_FAILURE); 1.1804 + NS_ENSURE_TRUE(error != 0, NS_ERROR_FAILURE); 1.1805 + *_retval = error; 1.1806 + } 1.1807 + nssCertList.forget(verifiedChain); 1.1808 + 1.1809 + return NS_OK; 1.1810 +} 1.1811 + 1.1812 +NS_IMETHODIMP 1.1813 +nsNSSCertificateDB::ClearOCSPCache() 1.1814 +{ 1.1815 + nsNSSShutDownPreventionLock locker; 1.1816 + if (isAlreadyShutDown()) { 1.1817 + return NS_ERROR_NOT_AVAILABLE; 1.1818 + } 1.1819 + 1.1820 + RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1.1821 + NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); 1.1822 + if (certVerifier->mImplementation == CertVerifier::mozillapkix) { 1.1823 + certVerifier->ClearOCSPCache(); 1.1824 + } else { 1.1825 + SECStatus srv = CERT_ClearOCSPCache(); 1.1826 + if (srv != SECSuccess) { 1.1827 + return MapSECStatus(srv); 1.1828 + } 1.1829 + } 1.1830 + 1.1831 + return NS_OK; 1.1832 +}