nsNSSCertificateDB.cpp (43543B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "nsNSSCertificateDB.h" 6 7 #include "CertVerifier.h" 8 #include "CryptoTask.h" 9 #include "ExtendedValidation.h" 10 #include "NSSCertDBTrustDomain.h" 11 #include "certdb.h" 12 #include "mozilla/Assertions.h" 13 #include "mozilla/Base64.h" 14 #include "mozilla/Casting.h" 15 #include "mozilla/Logging.h" 16 #include "mozilla/Services.h" 17 #include "mozpkix/Time.h" 18 #include "mozpkix/pkixnss.h" 19 #include "mozpkix/pkixtypes.h" 20 #include "nsArray.h" 21 #include "nsArrayUtils.h" 22 #include "nsCOMPtr.h" 23 #include "nsComponentManagerUtils.h" 24 #include "nsICertificateDialogs.h" 25 #include "nsIFile.h" 26 #include "nsIMutableArray.h" 27 #include "nsIObserverService.h" 28 #include "nsIPrompt.h" 29 #include "nsNSSCertHelper.h" 30 #include "nsNSSCertTrust.h" 31 #include "nsNSSCertificate.h" 32 #include "nsNSSComponent.h" 33 #include "nsNSSHelper.h" 34 #include "nsPKCS12Blob.h" 35 #include "nsPromiseFlatString.h" 36 #include "nsProxyRelease.h" 37 #include "nsReadableUtils.h" 38 #include "nsThreadUtils.h" 39 #include "nspr.h" 40 #include "secasn1.h" 41 #include "secder.h" 42 #include "secerr.h" 43 #include "ssl.h" 44 45 #ifdef MOZ_WIDGET_ANDROID 46 # include "mozilla/java/ClientAuthCertificateManagerWrappers.h" 47 #endif 48 49 #ifdef XP_WIN 50 # include <winsock.h> // for ntohl 51 #endif 52 53 using namespace mozilla; 54 using namespace mozilla::psm; 55 56 extern LazyLogModule gPIPNSSLog; 57 58 NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB) 59 60 NS_IMETHODIMP 61 nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey, 62 /*out*/ nsIX509Cert** _cert) { 63 NS_ENSURE_ARG_POINTER(_cert); 64 *_cert = nullptr; 65 66 if (aDBKey.IsEmpty()) { 67 return NS_ERROR_INVALID_ARG; 68 } 69 70 nsresult rv = BlockUntilLoadableCertsLoaded(); 71 if (NS_FAILED(rv)) { 72 return rv; 73 } 74 75 UniqueCERTCertificate cert; 76 rv = FindCertByDBKey(aDBKey, cert); 77 if (NS_FAILED(rv)) { 78 return rv; 79 } 80 // If we can't find the certificate, that's not an error. Just return null. 81 if (!cert) { 82 return NS_OK; 83 } 84 nsCOMPtr<nsIX509Cert> nssCert = new nsNSSCertificate(cert.get()); 85 nssCert.forget(_cert); 86 return NS_OK; 87 } 88 89 nsresult nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey, 90 UniqueCERTCertificate& cert) { 91 static_assert(sizeof(uint64_t) == 8, "type size sanity check"); 92 static_assert(sizeof(uint32_t) == 4, "type size sanity check"); 93 // (From nsNSSCertificate::GetDbKey) 94 // The format of the key is the base64 encoding of the following: 95 // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was 96 // never implemented) 97 // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was 98 // never implemented) 99 // 4 bytes: <serial number length in big-endian order> 100 // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order> 101 // n bytes: <bytes of serial number> 102 // m bytes: <DER-encoded issuer distinguished name> 103 nsAutoCString decoded; 104 nsAutoCString tmpDBKey(aDBKey); 105 // Filter out any whitespace for backwards compatibility. 106 tmpDBKey.StripWhitespace(); 107 nsresult rv = Base64Decode(tmpDBKey, decoded); 108 if (NS_FAILED(rv)) { 109 return rv; 110 } 111 if (decoded.Length() < 16) { 112 return NS_ERROR_ILLEGAL_INPUT; 113 } 114 const char* reader = decoded.BeginReading(); 115 uint64_t zeroes = *BitwiseCast<const uint64_t*, const char*>(reader); 116 if (zeroes != 0) { 117 return NS_ERROR_ILLEGAL_INPUT; 118 } 119 reader += sizeof(uint64_t); 120 // Note: We surround the ntohl() argument with parentheses to stop the macro 121 // from thinking two arguments were passed. 122 uint32_t serialNumberLen = 123 ntohl((*BitwiseCast<const uint32_t*, const char*>(reader))); 124 reader += sizeof(uint32_t); 125 uint32_t issuerLen = 126 ntohl((*BitwiseCast<const uint32_t*, const char*>(reader))); 127 reader += sizeof(uint32_t); 128 if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) { 129 return NS_ERROR_ILLEGAL_INPUT; 130 } 131 CERTIssuerAndSN issuerSN; 132 issuerSN.serialNumber.len = serialNumberLen; 133 issuerSN.serialNumber.data = BitwiseCast<unsigned char*, const char*>(reader); 134 reader += serialNumberLen; 135 issuerSN.derIssuer.len = issuerLen; 136 issuerSN.derIssuer.data = BitwiseCast<unsigned char*, const char*>(reader); 137 reader += issuerLen; 138 MOZ_ASSERT(reader == decoded.EndReading()); 139 140 AutoSearchingForClientAuthCertificates _; 141 cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN)); 142 return NS_OK; 143 } 144 145 SECStatus collect_certs(void* arg, SECItem** certs, int numcerts) { 146 nsTArray<nsTArray<uint8_t>>* certsArray = 147 reinterpret_cast<nsTArray<nsTArray<uint8_t>>*>(arg); 148 149 while (numcerts--) { 150 nsTArray<uint8_t> certArray; 151 SECItem* cert = *certs; 152 certArray.AppendElements(cert->data, cert->len); 153 certsArray->AppendElement(std::move(certArray)); 154 certs++; 155 } 156 return (SECSuccess); 157 } 158 159 nsresult nsNSSCertificateDB::getCertsFromPackage( 160 nsTArray<nsTArray<uint8_t>>& collectArgs, uint8_t* data, uint32_t length) { 161 if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length, 162 collect_certs, &collectArgs) != SECSuccess) { 163 return NS_ERROR_FAILURE; 164 } 165 return NS_OK; 166 } 167 168 // When using the sql-backed softoken, trust settings are authenticated using a 169 // key in the secret database. Thus, if the user has a password, we need to 170 // authenticate to the token in order to be able to change trust settings. 171 SECStatus ChangeCertTrustWithPossibleAuthentication( 172 const UniqueCERTCertificate& cert, CERTCertTrust& trust, void* ctx) { 173 MOZ_ASSERT(cert, "cert must be non-null"); 174 if (!cert) { 175 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 176 return SECFailure; 177 } 178 179 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 180 if (!certVerifier) { 181 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 182 return SECFailure; 183 } 184 185 // NSS ignores the first argument to CERT_ChangeCertTrust 186 SECStatus srv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust); 187 if (srv != SECSuccess && PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) { 188 return SECFailure; 189 } 190 if (srv == SECSuccess) { 191 certVerifier->ClearTrustCache(); 192 return SECSuccess; 193 } 194 195 // CERT_ChangeCertTrust failed with SEC_ERROR_TOKEN_NOT_LOGGED_IN, so 196 // authenticate and try again. 197 if (cert->slot) { 198 // If this certificate is on an external PKCS#11 token, we have to 199 // authenticate to that token. 200 srv = PK11_Authenticate(cert->slot, PR_TRUE, ctx); 201 } else { 202 // Otherwise, the certificate is on the internal module. 203 UniquePK11SlotInfo internalSlot(PK11_GetInternalKeySlot()); 204 srv = PK11_Authenticate(internalSlot.get(), PR_TRUE, ctx); 205 } 206 if (srv != SECSuccess) { 207 return srv; 208 } 209 srv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust); 210 if (srv != SECSuccess) { 211 return srv; 212 } 213 214 certVerifier->ClearTrustCache(); 215 return SECSuccess; 216 } 217 218 static nsresult ImportCertsIntoPermanentStorage( 219 const UniqueCERTCertList& certChain) { 220 bool encounteredFailure = false; 221 PRErrorCode savedErrorCode = 0; 222 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 223 for (CERTCertListNode* chainNode = CERT_LIST_HEAD(certChain); 224 !CERT_LIST_END(chainNode, certChain); 225 chainNode = CERT_LIST_NEXT(chainNode)) { 226 UniquePORTString nickname(CERT_MakeCANickname(chainNode->cert)); 227 SECStatus srv = PK11_ImportCert(slot.get(), chainNode->cert, 228 CK_INVALID_HANDLE, nickname.get(), 229 false); // this parameter is ignored by NSS 230 if (srv != SECSuccess) { 231 encounteredFailure = true; 232 savedErrorCode = PR_GetError(); 233 } 234 } 235 236 if (encounteredFailure) { 237 return GetXPCOMFromNSSError(savedErrorCode); 238 } 239 240 return NS_OK; 241 } 242 243 nsresult nsNSSCertificateDB::handleCACertDownload(NotNull<nsIArray*> x509Certs, 244 nsIInterfaceRequestor* ctx) { 245 // First thing we have to do is figure out which certificate we're 246 // gonna present to the user. The CA may have sent down a list of 247 // certs which may or may not be a chained list of certs. Until 248 // the day we can design some solid UI for the general case, we'll 249 // code to the > 90% case. That case is where a CA sends down a 250 // list that is a hierarchy whose root is either the first or 251 // the last cert. What we're gonna do is compare the first 252 // 2 entries, if the second was signed by the first, we assume 253 // the root cert is the first cert and display it. Otherwise, 254 // we compare the last 2 entries, if the second to last cert was 255 // signed by the last cert, then we assume the last cert is the 256 // root and display it. 257 258 uint32_t numCerts; 259 260 x509Certs->GetLength(&numCerts); 261 262 if (numCerts == 0) return NS_OK; // Nothing to import, so nothing to do. 263 264 nsCOMPtr<nsIX509Cert> certToShow; 265 uint32_t selCertIndex; 266 if (numCerts == 1) { 267 // There's only one cert, so let's show it. 268 selCertIndex = 0; 269 certToShow = do_QueryElementAt(x509Certs, selCertIndex); 270 } else { 271 nsCOMPtr<nsIX509Cert> cert0; // first cert 272 nsCOMPtr<nsIX509Cert> cert1; // second cert 273 nsCOMPtr<nsIX509Cert> certn_2; // second to last cert 274 nsCOMPtr<nsIX509Cert> certn_1; // last cert 275 276 cert0 = do_QueryElementAt(x509Certs, 0); 277 cert1 = do_QueryElementAt(x509Certs, 1); 278 certn_2 = do_QueryElementAt(x509Certs, numCerts - 2); 279 certn_1 = do_QueryElementAt(x509Certs, numCerts - 1); 280 281 nsAutoString cert0SubjectName; 282 nsAutoString cert1IssuerName; 283 nsAutoString certn_2IssuerName; 284 nsAutoString certn_1SubjectName; 285 286 cert0->GetSubjectName(cert0SubjectName); 287 cert1->GetIssuerName(cert1IssuerName); 288 certn_2->GetIssuerName(certn_2IssuerName); 289 certn_1->GetSubjectName(certn_1SubjectName); 290 291 if (cert1IssuerName.Equals(cert0SubjectName)) { 292 // In this case, the first cert in the list signed the second, 293 // so the first cert is the root. Let's display it. 294 selCertIndex = 0; 295 certToShow = cert0; 296 } else if (certn_2IssuerName.Equals(certn_1SubjectName)) { 297 // In this case the last cert has signed the second to last cert. 298 // The last cert is the root, so let's display it. 299 selCertIndex = numCerts - 1; 300 certToShow = certn_1; 301 } else { 302 // It's not a chain, so let's just show the first one in the 303 // downloaded list. 304 selCertIndex = 0; 305 certToShow = cert0; 306 } 307 } 308 309 if (!certToShow) return NS_ERROR_FAILURE; 310 311 nsCOMPtr<nsICertificateDialogs> dialogs; 312 nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), 313 NS_GET_IID(nsICertificateDialogs), 314 NS_CERTIFICATEDIALOGS_CONTRACTID); 315 if (NS_FAILED(rv)) { 316 return rv; 317 } 318 319 UniqueCERTCertificate tmpCert(certToShow->GetCert()); 320 if (!tmpCert) { 321 return NS_ERROR_FAILURE; 322 } 323 324 if (!CERT_IsCACert(tmpCert.get(), nullptr)) { 325 DisplayCertificateAlert(ctx, "NotACACert", certToShow); 326 return NS_ERROR_FAILURE; 327 } 328 329 if (tmpCert->isperm) { 330 DisplayCertificateAlert(ctx, "CaCertExists", certToShow); 331 return NS_ERROR_FAILURE; 332 } 333 334 uint32_t trustBits; 335 bool allows; 336 rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); 337 if (NS_FAILED(rv)) return rv; 338 339 if (!allows) return NS_ERROR_NOT_AVAILABLE; 340 341 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trust is %d\n", trustBits)); 342 UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get())); 343 344 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 345 ("Created nick \"%s\"\n", nickname.get())); 346 347 nsNSSCertTrust trust; 348 trust.SetValidCA(); 349 trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), 350 !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL)); 351 352 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 353 SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE, 354 nickname.get(), 355 false); // this parameter is ignored by NSS 356 if (srv != SECSuccess) { 357 return MapSECStatus(srv); 358 } 359 srv = 360 ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(), ctx); 361 if (srv != SECSuccess) { 362 return MapSECStatus(srv); 363 } 364 365 // Import additional delivered certificates that can be verified. 366 367 // build a CertList for filtering 368 UniqueCERTCertList certList(CERT_NewCertList()); 369 if (!certList) { 370 return NS_ERROR_FAILURE; 371 } 372 373 // get all remaining certs into temp store 374 375 for (uint32_t i = 0; i < numCerts; i++) { 376 if (i == selCertIndex) { 377 // we already processed that one 378 continue; 379 } 380 381 nsCOMPtr<nsIX509Cert> remainingCert = do_QueryElementAt(x509Certs, i); 382 if (!remainingCert) { 383 continue; 384 } 385 386 UniqueCERTCertificate tmpCert2(remainingCert->GetCert()); 387 if (!tmpCert2) { 388 continue; // Let's try to import the rest of 'em 389 } 390 391 if (CERT_AddCertToListTail(certList.get(), tmpCert2.get()) != SECSuccess) { 392 continue; 393 } 394 395 (void)tmpCert2.release(); 396 } 397 398 return ImportCertsIntoPermanentStorage(certList); 399 } 400 401 nsresult nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList( 402 const UniqueCERTCertList& aCertListIn, 403 nsTArray<RefPtr<nsIX509Cert>>& aCertListOut) { 404 if (!aCertListIn.get()) { 405 return NS_ERROR_INVALID_ARG; 406 } 407 408 for (CERTCertListNode* node = CERT_LIST_HEAD(aCertListIn.get()); 409 !CERT_LIST_END(node, aCertListIn.get()); node = CERT_LIST_NEXT(node)) { 410 RefPtr<nsIX509Cert> cert = new nsNSSCertificate(node->cert); 411 aCertListOut.AppendElement(cert); 412 } 413 return NS_OK; 414 } 415 416 NS_IMETHODIMP 417 nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length, 418 uint32_t type, 419 nsIInterfaceRequestor* ctx) { 420 // We currently only handle CA certificates. 421 if (type != nsIX509Cert::CA_CERT) { 422 return NS_ERROR_FAILURE; 423 } 424 425 nsTArray<nsTArray<uint8_t>> certsArray; 426 nsresult rv = getCertsFromPackage(certsArray, data, length); 427 if (NS_FAILED(rv)) { 428 return rv; 429 } 430 431 nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create(); 432 if (!array) { 433 return NS_ERROR_FAILURE; 434 } 435 436 // Now let's create some certs to work with 437 for (nsTArray<uint8_t>& certDER : certsArray) { 438 nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(std::move(certDER)); 439 nsresult rv = array->AppendElement(cert); 440 if (NS_FAILED(rv)) { 441 return rv; 442 } 443 } 444 445 return handleCACertDownload(WrapNotNull(array), ctx); 446 } 447 448 /** 449 * Decodes a given array of DER-encoded certificates into temporary storage. 450 * 451 * @param certs 452 * Array in which the decoded certificates are stored as arrays of 453 * unsigned chars. 454 * @param temporaryCerts 455 * List of decoded certificates. 456 */ 457 static nsresult ImportCertsIntoTempStorage( 458 nsTArray<nsTArray<uint8_t>>& certs, 459 /*out*/ const UniqueCERTCertList& temporaryCerts) { 460 NS_ENSURE_ARG_POINTER(temporaryCerts); 461 462 for (nsTArray<uint8_t>& certDER : certs) { 463 CERTCertificate* certificate; 464 SECItem certItem; 465 certItem.len = certDER.Length(); 466 certItem.data = certDER.Elements(); 467 certificate = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certItem, 468 nullptr, false, true); 469 470 UniqueCERTCertificate cert(certificate); 471 if (!cert) { 472 continue; 473 } 474 475 if (CERT_AddCertToListTail(temporaryCerts.get(), cert.get()) == 476 SECSuccess) { 477 (void)cert.release(); 478 } 479 } 480 481 return NS_OK; 482 } 483 484 NS_IMETHODIMP 485 nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length, 486 nsIInterfaceRequestor* ctx) { 487 nsTArray<nsTArray<uint8_t>> certsArray; 488 489 nsresult rv = getCertsFromPackage(certsArray, data, length); 490 if (NS_FAILED(rv)) { 491 return rv; 492 } 493 494 UniqueCERTCertList temporaryCerts(CERT_NewCertList()); 495 if (!temporaryCerts) { 496 return NS_ERROR_FAILURE; 497 } 498 499 rv = ImportCertsIntoTempStorage(certsArray, temporaryCerts); 500 if (NS_FAILED(rv)) { 501 return rv; 502 } 503 504 return ImportCertsIntoPermanentStorage(temporaryCerts); 505 } 506 507 nsresult nsNSSCertificateDB::ImportCACerts(nsTArray<nsTArray<uint8_t>>& caCerts, 508 nsIInterfaceRequestor* ctx) { 509 UniqueCERTCertList temporaryCerts(CERT_NewCertList()); 510 if (!temporaryCerts) { 511 return NS_ERROR_FAILURE; 512 } 513 514 nsresult rv = ImportCertsIntoTempStorage(caCerts, temporaryCerts); 515 if (NS_FAILED(rv)) { 516 return rv; 517 } 518 519 return ImportCertsIntoPermanentStorage(temporaryCerts); 520 } 521 522 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor* ctx, 523 const char* stringID, 524 nsIX509Cert* certToShow) { 525 if (!NS_IsMainThread()) { 526 NS_ERROR( 527 "nsNSSCertificateDB::DisplayCertificateAlert called off the main " 528 "thread"); 529 return; 530 } 531 532 nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx; 533 if (!my_ctx) { 534 my_ctx = new PipUIContext(); 535 } 536 537 // This shall be replaced by embedding ovverridable prompts 538 // as discussed in bug 310446, and should make use of certToShow. 539 540 nsAutoString tmpMessage; 541 GetPIPNSSBundleString(stringID, tmpMessage); 542 nsCOMPtr<nsIPrompt> prompt(do_GetInterface(my_ctx)); 543 if (!prompt) { 544 return; 545 } 546 547 prompt->Alert(nullptr, tmpMessage.get()); 548 } 549 550 NS_IMETHODIMP 551 nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length, 552 nsIInterfaceRequestor* ctx) { 553 if (!NS_IsMainThread()) { 554 NS_ERROR( 555 "nsNSSCertificateDB::ImportUserCertificate called off the main thread"); 556 return NS_ERROR_NOT_SAME_THREAD; 557 } 558 559 nsTArray<nsTArray<uint8_t>> certsArray; 560 561 nsresult rv = getCertsFromPackage(certsArray, data, length); 562 if (NS_FAILED(rv)) { 563 return rv; 564 } 565 566 SECItem certItem; 567 568 if (certsArray.IsEmpty()) { 569 return NS_OK; 570 } 571 572 certItem.len = certsArray.ElementAt(0).Length(); 573 certItem.data = certsArray.ElementAt(0).Elements(); 574 575 UniqueCERTCertificate cert(CERT_NewTempCertificate( 576 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true)); 577 if (!cert) { 578 return NS_ERROR_FAILURE; 579 } 580 581 UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx)); 582 if (!slot) { 583 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert.get()); 584 DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow); 585 return NS_ERROR_FAILURE; 586 } 587 slot = nullptr; 588 589 /* pick a nickname for the cert */ 590 nsAutoCString nickname; 591 if (cert->nickname) { 592 nickname = cert->nickname; 593 } else { 594 get_default_nickname(cert.get(), ctx, nickname); 595 } 596 597 /* user wants to import the cert */ 598 slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx)); 599 if (!slot) { 600 return NS_ERROR_FAILURE; 601 } 602 slot = nullptr; 603 604 { 605 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert.get()); 606 DisplayCertificateAlert(ctx, "UserCertImported", certToShow); 607 } 608 609 rv = NS_OK; 610 if (!certsArray.IsEmpty()) { 611 certsArray.RemoveElementAt(0); 612 rv = ImportCACerts(certsArray, ctx); 613 } 614 615 nsCOMPtr<nsIObserverService> observerService = 616 mozilla::services::GetObserverService(); 617 if (observerService) { 618 observerService->NotifyObservers(nullptr, "psm:user-certificate-added", 619 nullptr); 620 } 621 622 return rv; 623 } 624 625 NS_IMETHODIMP 626 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert* aCert) { 627 NS_ENSURE_ARG_POINTER(aCert); 628 UniqueCERTCertificate cert(aCert->GetCert()); 629 if (!cert) { 630 return NS_ERROR_FAILURE; 631 } 632 633 // Temporary certificates aren't on a slot and will go away when the 634 // nsIX509Cert is destructed. 635 if (cert->slot) { 636 uint32_t certType; 637 nsresult rv = aCert->GetCertType(&certType); 638 if (NS_WARN_IF(NS_FAILED(rv))) { 639 return rv; 640 } 641 if (certType == nsIX509Cert::USER_CERT) { 642 SECStatus srv = PK11_Authenticate(cert->slot, true, nullptr); 643 if (srv != SECSuccess) { 644 return NS_ERROR_FAILURE; 645 } 646 srv = PK11_DeleteTokenCertAndKey(cert.get(), nullptr); 647 if (srv != SECSuccess) { 648 return NS_ERROR_FAILURE; 649 } 650 } else { 651 // For certificates that can't be deleted (e.g. built-in roots), un-set 652 // all trust bits. 653 nsNSSCertTrust trust(0, 0); 654 SECStatus srv = ChangeCertTrustWithPossibleAuthentication( 655 cert, trust.GetTrust(), nullptr); 656 if (srv != SECSuccess) { 657 return NS_ERROR_FAILURE; 658 } 659 if (!PK11_IsReadOnly(cert->slot)) { 660 srv = SEC_DeletePermCertificate(cert.get()); 661 if (srv != SECSuccess) { 662 return NS_ERROR_FAILURE; 663 } 664 } 665 } 666 } 667 668 nsCOMPtr<nsIObserverService> observerService = 669 mozilla::services::GetObserverService(); 670 if (observerService) { 671 observerService->NotifyObservers(nullptr, "psm:user-certificate-deleted", 672 nullptr); 673 } 674 675 return NS_OK; 676 } 677 678 NS_IMETHODIMP 679 nsNSSCertificateDB::SetCertTrust(nsIX509Cert* cert, uint32_t type, 680 uint32_t trusted) { 681 NS_ENSURE_ARG_POINTER(cert); 682 nsNSSCertTrust trust; 683 switch (type) { 684 case nsIX509Cert::CA_CERT: 685 trust.SetValidCA(); 686 trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL), 687 !!(trusted & nsIX509CertDB::TRUSTED_EMAIL)); 688 break; 689 case nsIX509Cert::SERVER_CERT: 690 trust.SetValidPeer(); 691 trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, false); 692 break; 693 case nsIX509Cert::EMAIL_CERT: 694 trust.SetValidPeer(); 695 trust.AddPeerTrust(false, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL)); 696 break; 697 default: 698 // Ignore any other type of certificate (including invalid types). 699 return NS_OK; 700 } 701 702 UniqueCERTCertificate nsscert(cert->GetCert()); 703 SECStatus srv = ChangeCertTrustWithPossibleAuthentication( 704 nsscert, trust.GetTrust(), nullptr); 705 return MapSECStatus(srv); 706 } 707 708 NS_IMETHODIMP 709 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert* cert, uint32_t certType, 710 uint32_t trustType, bool* _isTrusted) { 711 NS_ENSURE_ARG_POINTER(_isTrusted); 712 *_isTrusted = false; 713 714 nsresult rv = BlockUntilLoadableCertsLoaded(); 715 if (NS_FAILED(rv)) { 716 return rv; 717 } 718 719 SECStatus srv; 720 UniqueCERTCertificate nsscert(cert->GetCert()); 721 CERTCertTrust nsstrust; 722 srv = CERT_GetCertTrust(nsscert.get(), &nsstrust); 723 if (srv != SECSuccess) { 724 // CERT_GetCertTrust returns SECFailure if given a temporary cert that 725 // doesn't have any trust information yet. This isn't an error. 726 return NS_OK; 727 } 728 729 nsNSSCertTrust trust(&nsstrust); 730 if (certType == nsIX509Cert::CA_CERT) { 731 if (trustType & nsIX509CertDB::TRUSTED_SSL) { 732 *_isTrusted = trust.HasTrustedCA(true, false); 733 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 734 *_isTrusted = trust.HasTrustedCA(false, true); 735 } else { 736 return NS_ERROR_FAILURE; 737 } 738 } else if (certType == nsIX509Cert::SERVER_CERT) { 739 if (trustType & nsIX509CertDB::TRUSTED_SSL) { 740 *_isTrusted = trust.HasTrustedPeer(true, false); 741 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 742 *_isTrusted = trust.HasTrustedPeer(false, true); 743 } else { 744 return NS_ERROR_FAILURE; 745 } 746 } else if (certType == nsIX509Cert::EMAIL_CERT) { 747 if (trustType & nsIX509CertDB::TRUSTED_SSL) { 748 *_isTrusted = trust.HasTrustedPeer(true, false); 749 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { 750 *_isTrusted = trust.HasTrustedPeer(false, true); 751 } else { 752 return NS_ERROR_FAILURE; 753 } 754 } /* user: ignore */ 755 return NS_OK; 756 } 757 758 NS_IMETHODIMP 759 nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType) { 760 NS_ENSURE_ARG(aFile); 761 switch (aType) { 762 case nsIX509Cert::CA_CERT: 763 case nsIX509Cert::EMAIL_CERT: 764 // good 765 break; 766 767 default: 768 // not supported (yet) 769 return NS_ERROR_FAILURE; 770 } 771 772 PRFileDesc* fd = nullptr; 773 nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); 774 if (NS_FAILED(rv)) { 775 return rv; 776 } 777 if (!fd) { 778 return NS_ERROR_FAILURE; 779 } 780 781 PRFileInfo fileInfo; 782 if (PR_GetOpenFileInfo(fd, &fileInfo) != PR_SUCCESS) { 783 return NS_ERROR_FAILURE; 784 } 785 786 auto buf = MakeUnique<unsigned char[]>(fileInfo.size); 787 int32_t bytesObtained = PR_Read(fd, buf.get(), fileInfo.size); 788 PR_Close(fd); 789 790 if (bytesObtained != fileInfo.size) { 791 return NS_ERROR_FAILURE; 792 } 793 794 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext(); 795 796 switch (aType) { 797 case nsIX509Cert::CA_CERT: 798 return ImportCertificates(buf.get(), bytesObtained, aType, cxt); 799 case nsIX509Cert::EMAIL_CERT: 800 return ImportEmailCertificate(buf.get(), bytesObtained, cxt); 801 default: 802 MOZ_ASSERT(false, "Unsupported type should have been filtered out"); 803 break; 804 } 805 806 return NS_ERROR_FAILURE; 807 } 808 809 NS_IMETHODIMP 810 nsNSSCertificateDB::ImportPKCS12File(nsIFile* aFile, const nsAString& aPassword, 811 uint32_t* aError) { 812 if (!NS_IsMainThread()) { 813 return NS_ERROR_NOT_SAME_THREAD; 814 } 815 nsresult rv = BlockUntilLoadableCertsLoaded(); 816 if (NS_FAILED(rv)) { 817 return rv; 818 } 819 820 NS_ENSURE_ARG(aFile); 821 nsPKCS12Blob blob; 822 rv = blob.ImportFromFile(aFile, aPassword, *aError); 823 nsCOMPtr<nsIObserverService> observerService = 824 mozilla::services::GetObserverService(); 825 if (NS_SUCCEEDED(rv) && observerService) { 826 observerService->NotifyObservers(nullptr, "psm:user-certificate-added", 827 nullptr); 828 } 829 830 return rv; 831 } 832 833 NS_IMETHODIMP 834 nsNSSCertificateDB::ExportPKCS12File( 835 nsIFile* aFile, const nsTArray<RefPtr<nsIX509Cert>>& aCerts, 836 const nsAString& aPassword, uint32_t* aError) { 837 if (!NS_IsMainThread()) { 838 return NS_ERROR_NOT_SAME_THREAD; 839 } 840 nsresult rv = BlockUntilLoadableCertsLoaded(); 841 if (NS_FAILED(rv)) { 842 return rv; 843 } 844 845 NS_ENSURE_ARG(aFile); 846 if (aCerts.IsEmpty()) { 847 return NS_OK; 848 } 849 nsPKCS12Blob blob; 850 return blob.ExportToFile(aFile, aCerts, aPassword, *aError); 851 } 852 853 NS_IMETHODIMP 854 nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64, 855 /*out*/ nsIX509Cert** _retval) { 856 if (!_retval) { 857 return NS_ERROR_INVALID_POINTER; 858 } 859 860 // Base64Decode() doesn't consider a zero length input as an error, and just 861 // returns the empty string. We don't want this behavior, so the below check 862 // catches this case. 863 if (base64.Length() < 1) { 864 return NS_ERROR_ILLEGAL_VALUE; 865 } 866 867 nsAutoCString certDER; 868 nsresult rv = Base64Decode(base64, certDER); 869 if (NS_FAILED(rv)) { 870 return rv; 871 } 872 873 return ConstructX509FromSpan(AsBytes(Span(certDER)), _retval); 874 } 875 876 NS_IMETHODIMP 877 nsNSSCertificateDB::ConstructX509(const nsTArray<uint8_t>& certDER, 878 nsIX509Cert** _retval) { 879 return ConstructX509FromSpan(Span(certDER.Elements(), certDER.Length()), 880 _retval); 881 } 882 883 nsresult nsNSSCertificateDB::ConstructX509FromSpan( 884 Span<const uint8_t> aInputSpan, nsIX509Cert** _retval) { 885 if (NS_WARN_IF(!_retval)) { 886 return NS_ERROR_INVALID_POINTER; 887 } 888 889 if (aInputSpan.Length() > std::numeric_limits<unsigned int>::max()) { 890 return NS_ERROR_ILLEGAL_VALUE; 891 } 892 893 SECItem certData; 894 certData.type = siDERCertBuffer; 895 certData.data = const_cast<unsigned char*>( 896 reinterpret_cast<const unsigned char*>(aInputSpan.Elements())); 897 certData.len = aInputSpan.Length(); 898 899 UniqueCERTCertificate cert(CERT_NewTempCertificate( 900 CERT_GetDefaultCertDB(), &certData, nullptr, false, true)); 901 if (!cert) 902 return (PORT_GetError() == SEC_ERROR_NO_MEMORY) ? NS_ERROR_OUT_OF_MEMORY 903 : NS_ERROR_FAILURE; 904 905 nsCOMPtr<nsIX509Cert> nssCert = new nsNSSCertificate(cert.get()); 906 nssCert.forget(_retval); 907 return NS_OK; 908 } 909 910 void nsNSSCertificateDB::get_default_nickname(CERTCertificate* cert, 911 nsIInterfaceRequestor* ctx, 912 nsCString& nickname) { 913 nickname.Truncate(); 914 915 CK_OBJECT_HANDLE keyHandle; 916 917 if (NS_FAILED(BlockUntilLoadableCertsLoaded())) { 918 return; 919 } 920 921 CERTCertDBHandle* defaultcertdb = CERT_GetDefaultCertDB(); 922 nsAutoCString username; 923 UniquePORTString tempCN(CERT_GetCommonName(&cert->subject)); 924 if (tempCN) { 925 username = tempCN.get(); 926 } 927 928 nsAutoCString caname; 929 UniquePORTString tempIssuerOrg(CERT_GetOrgName(&cert->issuer)); 930 if (tempIssuerOrg) { 931 caname = tempIssuerOrg.get(); 932 } 933 934 nsAutoString tmpNickFmt; 935 GetPIPNSSBundleString("nick_template", tmpNickFmt); 936 NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); 937 938 nsAutoCString baseName; 939 baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get()); 940 if (baseName.IsEmpty()) { 941 return; 942 } 943 944 nickname = baseName; 945 946 /* 947 * We need to see if the private key exists on a token, if it does 948 * then we need to check for nicknames that already exist on the smart 949 * card. 950 */ 951 UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx)); 952 if (!slot) return; 953 954 if (!PK11_IsInternal(slot.get())) { 955 nsAutoCString tmp; 956 tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get()); 957 if (tmp.IsEmpty()) { 958 nickname.Truncate(); 959 return; 960 } 961 baseName = tmp; 962 nickname = baseName; 963 } 964 965 int count = 1; 966 while (true) { 967 if (count > 1) { 968 nsAutoCString tmp; 969 tmp.AppendPrintf("%s #%d", baseName.get(), count); 970 if (tmp.IsEmpty()) { 971 nickname.Truncate(); 972 return; 973 } 974 nickname = tmp; 975 } 976 977 UniqueCERTCertificate dummycert; 978 979 if (PK11_IsInternal(slot.get())) { 980 /* look up the nickname to make sure it isn't in use already */ 981 dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get())); 982 } else { 983 // Check the cert against others that already live on the smart card. 984 dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx)); 985 if (dummycert) { 986 // Make sure the subject names are different. 987 if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) { 988 /* 989 * There is another certificate with the same nickname and 990 * the same subject name on the smart card, so let's use this 991 * nickname. 992 */ 993 dummycert = nullptr; 994 } 995 } 996 } 997 if (!dummycert) { 998 break; 999 } 1000 count++; 1001 } 1002 } 1003 1004 NS_IMETHODIMP 1005 nsNSSCertificateDB::AddCertFromBase64(const nsACString& aBase64, 1006 const nsACString& aTrust, 1007 nsIX509Cert** addedCertificate) { 1008 // Base64Decode() doesn't consider a zero length input as an error, and just 1009 // returns the empty string. We don't want this behavior, so the below check 1010 // catches this case. 1011 if (aBase64.Length() < 1) { 1012 return NS_ERROR_ILLEGAL_VALUE; 1013 } 1014 1015 nsAutoCString aCertDER; 1016 nsresult rv = Base64Decode(aBase64, aCertDER); 1017 if (NS_FAILED(rv)) { 1018 return rv; 1019 } 1020 return AddCert(aCertDER, aTrust, addedCertificate); 1021 } 1022 1023 NS_IMETHODIMP 1024 nsNSSCertificateDB::AddCert(const nsACString& aCertDER, 1025 const nsACString& aTrust, 1026 nsIX509Cert** addedCertificate) { 1027 MOZ_ASSERT(addedCertificate); 1028 if (!addedCertificate) { 1029 return NS_ERROR_INVALID_ARG; 1030 } 1031 *addedCertificate = nullptr; 1032 1033 nsNSSCertTrust trust; 1034 if (CERT_DecodeTrustString(&trust.GetTrust(), 1035 PromiseFlatCString(aTrust).get()) != SECSuccess) { 1036 return NS_ERROR_FAILURE; 1037 } 1038 1039 nsCOMPtr<nsIX509Cert> newCert; 1040 nsresult rv = 1041 ConstructX509FromSpan(AsBytes(Span(aCertDER)), getter_AddRefs(newCert)); 1042 if (NS_FAILED(rv)) { 1043 return rv; 1044 } 1045 1046 UniqueCERTCertificate tmpCert(newCert->GetCert()); 1047 if (!tmpCert) { 1048 return NS_ERROR_FAILURE; 1049 } 1050 1051 // If there's already a certificate that matches this one in the database, we 1052 // still want to set its trust to the given value. 1053 if (tmpCert->isperm) { 1054 rv = SetCertTrustFromString(newCert, aTrust); 1055 if (NS_FAILED(rv)) { 1056 return rv; 1057 } 1058 newCert.forget(addedCertificate); 1059 return NS_OK; 1060 } 1061 1062 UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get())); 1063 1064 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1065 ("Created nick \"%s\"\n", nickname.get())); 1066 1067 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 1068 SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE, 1069 nickname.get(), 1070 false); // this parameter is ignored by NSS 1071 if (srv != SECSuccess) { 1072 return MapSECStatus(srv); 1073 } 1074 srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(), 1075 nullptr); 1076 if (srv != SECSuccess) { 1077 return MapSECStatus(srv); 1078 } 1079 newCert.forget(addedCertificate); 1080 return NS_OK; 1081 } 1082 1083 NS_IMETHODIMP 1084 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert, 1085 const nsACString& trustString) { 1086 NS_ENSURE_ARG(cert); 1087 1088 CERTCertTrust trust; 1089 SECStatus srv = 1090 CERT_DecodeTrustString(&trust, PromiseFlatCString(trustString).get()); 1091 if (srv != SECSuccess) { 1092 return MapSECStatus(srv); 1093 } 1094 UniqueCERTCertificate nssCert(cert->GetCert()); 1095 1096 srv = ChangeCertTrustWithPossibleAuthentication(nssCert, trust, nullptr); 1097 return MapSECStatus(srv); 1098 } 1099 1100 NS_IMETHODIMP nsNSSCertificateDB::AsPKCS7Blob( 1101 const nsTArray<RefPtr<nsIX509Cert>>& certList, nsACString& _retval) { 1102 if (certList.IsEmpty()) { 1103 return NS_ERROR_INVALID_ARG; 1104 } 1105 1106 UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr)); 1107 if (!cmsg) { 1108 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1109 ("nsNSSCertificateDB::AsPKCS7Blob - can't create CMS message")); 1110 return NS_ERROR_OUT_OF_MEMORY; 1111 } 1112 1113 UniqueNSSCMSSignedData sigd(nullptr); 1114 for (const auto& cert : certList) { 1115 // We need an owning handle when calling nsIX509Cert::GetCert(). 1116 UniqueCERTCertificate nssCert(cert->GetCert()); 1117 if (!sigd) { 1118 sigd.reset( 1119 NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), nssCert.get(), false)); 1120 if (!sigd) { 1121 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1122 ("nsNSSCertificateDB::AsPKCS7Blob - can't create SignedData")); 1123 return NS_ERROR_FAILURE; 1124 } 1125 } else if (NSS_CMSSignedData_AddCertificate(sigd.get(), nssCert.get()) != 1126 SECSuccess) { 1127 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1128 ("nsNSSCertificateDB::AsPKCS7Blob - can't add cert")); 1129 return NS_ERROR_FAILURE; 1130 } 1131 } 1132 1133 NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get()); 1134 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get()) != 1135 SECSuccess) { 1136 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1137 ("nsNSSCertificateDB::AsPKCS7Blob - can't attach SignedData")); 1138 return NS_ERROR_FAILURE; 1139 } 1140 // cmsg owns sigd now. 1141 (void)sigd.release(); 1142 1143 UniquePLArenaPool arena(PORT_NewArena(1024)); 1144 if (!arena) { 1145 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1146 ("nsNSSCertificateDB::AsPKCS7Blob - out of memory")); 1147 return NS_ERROR_OUT_OF_MEMORY; 1148 } 1149 1150 SECItem certP7 = {siBuffer, nullptr, 0}; 1151 NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start( 1152 cmsg.get(), nullptr, nullptr, &certP7, arena.get(), nullptr, nullptr, 1153 nullptr, nullptr, nullptr, nullptr); 1154 if (!ecx) { 1155 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1156 ("nsNSSCertificateDB::AsPKCS7Blob - can't create encoder")); 1157 return NS_ERROR_FAILURE; 1158 } 1159 1160 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) { 1161 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1162 ("nsNSSCertificateDB::AsPKCS7Blob - failed to add encoded data")); 1163 return NS_ERROR_FAILURE; 1164 } 1165 1166 _retval.Assign(nsDependentCSubstring( 1167 reinterpret_cast<const char*>(certP7.data), certP7.len)); 1168 return NS_OK; 1169 } 1170 1171 NS_IMETHODIMP 1172 nsNSSCertificateDB::GetCerts(nsTArray<RefPtr<nsIX509Cert>>& _retval) { 1173 nsresult rv = BlockUntilLoadableCertsLoaded(); 1174 if (NS_FAILED(rv)) { 1175 return rv; 1176 } 1177 1178 rv = CheckForSmartCardChanges(); 1179 if (NS_FAILED(rv)) { 1180 return rv; 1181 } 1182 1183 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1184 AutoSearchingForClientAuthCertificates _; 1185 UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx)); 1186 if (!certList) { 1187 return NS_ERROR_FAILURE; 1188 } 1189 return nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(certList, 1190 _retval); 1191 } 1192 1193 static mozilla::Result<VerifyUsage, nsresult> MapX509UsageToVerifierUsage( 1194 nsIX509CertDB::VerifyUsage usage) { 1195 switch (usage) { 1196 case nsIX509CertDB::verifyUsageTLSServer: 1197 return VerifyUsage::TLSServer; 1198 case nsIX509CertDB::verifyUsageTLSServerCA: 1199 return VerifyUsage::TLSServerCA; 1200 case nsIX509CertDB::verifyUsageTLSClient: 1201 return VerifyUsage::TLSClient; 1202 case nsIX509CertDB::verifyUsageTLSClientCA: 1203 return VerifyUsage::TLSClientCA; 1204 case nsIX509CertDB::verifyUsageEmailSigner: 1205 return VerifyUsage::EmailSigner; 1206 case nsIX509CertDB::verifyUsageEmailRecipient: 1207 return VerifyUsage::EmailRecipient; 1208 case nsIX509CertDB::verifyUsageEmailCA: 1209 return VerifyUsage::EmailCA; 1210 } 1211 return Err(NS_ERROR_INVALID_ARG); 1212 } 1213 1214 nsresult VerifyCertAtTime(nsIX509Cert* aCert, nsIX509CertDB::VerifyUsage aUsage, 1215 uint32_t aFlags, const nsACString& aHostname, 1216 mozilla::pkix::Time aTime, 1217 const Maybe<nsTArray<uint8_t>>& aSctsFromTls, 1218 nsTArray<RefPtr<nsIX509Cert>>& aVerifiedChain, 1219 bool* aHasEVPolicy, 1220 int32_t* /*PRErrorCode*/ _retval) { 1221 NS_ENSURE_ARG_POINTER(aCert); 1222 NS_ENSURE_ARG_POINTER(aHasEVPolicy); 1223 NS_ENSURE_ARG_POINTER(_retval); 1224 1225 if (!aVerifiedChain.IsEmpty()) { 1226 return NS_ERROR_INVALID_ARG; 1227 } 1228 1229 *aHasEVPolicy = false; 1230 *_retval = PR_UNKNOWN_ERROR; 1231 1232 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1233 NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); 1234 1235 nsTArray<nsTArray<uint8_t>> resultChain; 1236 EVStatus evStatus; 1237 mozilla::pkix::Result result; 1238 1239 nsTArray<uint8_t> certBytes; 1240 nsresult nsrv = aCert->GetRawDER(certBytes); 1241 if (NS_FAILED(nsrv)) { 1242 return nsrv; 1243 } 1244 1245 if (!aHostname.IsVoid() && aUsage == nsIX509CertDB::verifyUsageTLSServer) { 1246 result = 1247 certVerifier->VerifySSLServerCert(certBytes, aTime, 1248 nullptr, // Assume no context 1249 aHostname, resultChain, aFlags, 1250 Nothing(), // extraCertificates 1251 Nothing(), // stapledOCSPResponse 1252 aSctsFromTls, // sctsFromTLSExtension 1253 Nothing(), // dcInfo 1254 OriginAttributes(), &evStatus); 1255 } else { 1256 const nsCString& flatHostname = PromiseFlatCString(aHostname); 1257 VerifyUsage vu = MOZ_TRY(MapX509UsageToVerifierUsage(aUsage)); 1258 result = certVerifier->VerifyCert( 1259 certBytes, vu, aTime, 1260 nullptr, // Assume no context 1261 aHostname.IsVoid() ? nullptr : flatHostname.get(), resultChain, aFlags, 1262 Nothing(), // extraCertificates 1263 Nothing(), // stapledOCSPResponse 1264 aSctsFromTls, // sctsFromTLSExtension 1265 OriginAttributes(), &evStatus); 1266 } 1267 1268 if (result == mozilla::pkix::Success) { 1269 for (auto& certDER : resultChain) { 1270 RefPtr<nsIX509Cert> cert = new nsNSSCertificate(std::move(certDER)); 1271 aVerifiedChain.AppendElement(cert); 1272 } 1273 1274 if (evStatus == EVStatus::EV) { 1275 *aHasEVPolicy = true; 1276 } 1277 } 1278 1279 *_retval = mozilla::pkix::MapResultToPRErrorCode(result); 1280 1281 return NS_OK; 1282 } 1283 1284 class VerifyCertAtTimeTask final : public CryptoTask { 1285 public: 1286 VerifyCertAtTimeTask(nsIX509Cert* aCert, nsIX509CertDB::VerifyUsage aUsage, 1287 uint32_t aFlags, const nsACString& aHostname, 1288 uint64_t aTime, const nsTArray<uint8_t>& aSctsFromTls, 1289 nsICertVerificationCallback* aCallback) 1290 : mCert(aCert), 1291 mUsage(aUsage), 1292 mFlags(aFlags), 1293 mHostname(aHostname), 1294 mTime(aTime), 1295 mCallback(new nsMainThreadPtrHolder<nsICertVerificationCallback>( 1296 "nsICertVerificationCallback", aCallback)), 1297 mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE), 1298 mHasEVPolicy(false) { 1299 if (aSctsFromTls.Length() > 0) { 1300 mSctsFromTls.emplace(aSctsFromTls.Clone()); 1301 } 1302 } 1303 1304 private: 1305 virtual nsresult CalculateResult() override { 1306 nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID); 1307 if (!certDB) { 1308 return NS_ERROR_FAILURE; 1309 } 1310 return VerifyCertAtTime(mCert, mUsage, mFlags, mHostname, 1311 mozilla::pkix::TimeFromEpochInSeconds(mTime), 1312 mSctsFromTls, mVerifiedCertList, &mHasEVPolicy, 1313 &mPRErrorCode); 1314 } 1315 1316 virtual void CallCallback(nsresult rv) override { 1317 if (NS_FAILED(rv)) { 1318 nsTArray<RefPtr<nsIX509Cert>> tmp; 1319 (void)mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE, tmp, 1320 false); 1321 } else { 1322 (void)mCallback->VerifyCertFinished(mPRErrorCode, mVerifiedCertList, 1323 mHasEVPolicy); 1324 } 1325 } 1326 1327 nsCOMPtr<nsIX509Cert> mCert; 1328 nsIX509CertDB::VerifyUsage mUsage; 1329 uint32_t mFlags; 1330 nsCString mHostname; 1331 uint64_t mTime; 1332 nsMainThreadPtrHandle<nsICertVerificationCallback> mCallback; 1333 int32_t mPRErrorCode; 1334 nsTArray<RefPtr<nsIX509Cert>> mVerifiedCertList; 1335 bool mHasEVPolicy; 1336 Maybe<nsTArray<uint8_t>> mSctsFromTls; 1337 }; 1338 1339 NS_IMETHODIMP 1340 nsNSSCertificateDB::AsyncVerifyCertAtTime( 1341 nsIX509Cert* aCert, nsIX509CertDB::VerifyUsage aUsage, uint32_t aFlags, 1342 const nsACString& aHostname, uint64_t aTime, 1343 const nsTArray<uint8_t>& aSctsFromTls, 1344 nsICertVerificationCallback* aCallback) { 1345 RefPtr<VerifyCertAtTimeTask> task(new VerifyCertAtTimeTask( 1346 aCert, aUsage, aFlags, aHostname, aTime, aSctsFromTls, aCallback)); 1347 return task->Dispatch(); 1348 } 1349 1350 NS_IMETHODIMP 1351 nsNSSCertificateDB::ClearOCSPCache() { 1352 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 1353 NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); 1354 certVerifier->ClearOCSPCache(); 1355 return NS_OK; 1356 } 1357 1358 NS_IMETHODIMP 1359 nsNSSCertificateDB::GetAndroidCertificateFromAlias( 1360 const nsAString& aAlias, /*out*/ nsIX509Cert** aResult) { 1361 *aResult = nullptr; 1362 #ifndef MOZ_WIDGET_ANDROID 1363 return NS_ERROR_NOT_AVAILABLE; 1364 #else 1365 if (!jni::IsAvailable()) { 1366 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("JNI not available")); 1367 return NS_ERROR_NOT_AVAILABLE; 1368 } 1369 1370 jni::String::LocalRef alias = jni::StringParam(aAlias); 1371 jni::ByteArray::LocalRef certificateBytes = 1372 java::ClientAuthCertificateManager::GetCertificateFromAlias(alias); 1373 if (!certificateBytes) { 1374 return NS_ERROR_NOT_AVAILABLE; 1375 } 1376 nsTArray<uint8_t> certificateByteArray( 1377 certificateBytes->GetElements().Elements(), certificateBytes->Length()); 1378 nsCOMPtr<nsIX509Cert> certificate( 1379 new nsNSSCertificate(std::move(certificateByteArray))); 1380 certificate.forget(aResult); 1381 return NS_OK; 1382 #endif // MOZ_WIDGET_ANDROID 1383 }