Bug 1839316: part 5) Guard the "fetchpriority" attribute behind a pref. r=kershaw...
[gecko.git] / security / manager / ssl / nsNSSCertificateDB.cpp
blob3a760734b304145b1d7101fab30ffa5ebd526810
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/. */
5 #include "nsNSSCertificateDB.h"
7 #include "CertVerifier.h"
8 #include "CryptoTask.h"
9 #include "ExtendedValidation.h"
10 #include "NSSCertDBTrustDomain.h"
11 #include "SharedSSLState.h"
12 #include "certdb.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Base64.h"
15 #include "mozilla/Casting.h"
16 #include "mozilla/Logging.h"
17 #include "mozilla/Services.h"
18 #include "mozilla/Unused.h"
19 #include "mozpkix/Time.h"
20 #include "mozpkix/pkixnss.h"
21 #include "mozpkix/pkixtypes.h"
22 #include "nsArray.h"
23 #include "nsArrayUtils.h"
24 #include "nsCOMPtr.h"
25 #include "nsComponentManagerUtils.h"
26 #include "nsICertificateDialogs.h"
27 #include "nsIFile.h"
28 #include "nsIMutableArray.h"
29 #include "nsIObserverService.h"
30 #include "nsIPrompt.h"
31 #include "nsNSSCertHelper.h"
32 #include "nsNSSCertTrust.h"
33 #include "nsNSSCertificate.h"
34 #include "nsNSSComponent.h"
35 #include "nsNSSHelper.h"
36 #include "nsPKCS12Blob.h"
37 #include "nsPromiseFlatString.h"
38 #include "nsProxyRelease.h"
39 #include "nsReadableUtils.h"
40 #include "nsThreadUtils.h"
41 #include "nspr.h"
42 #include "secasn1.h"
43 #include "secder.h"
44 #include "secerr.h"
45 #include "ssl.h"
47 #ifdef XP_WIN
48 # include <winsock.h> // for ntohl
49 #endif
51 using namespace mozilla;
52 using namespace mozilla::psm;
54 extern LazyLogModule gPIPNSSLog;
56 NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
58 NS_IMETHODIMP
59 nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
60 /*out*/ nsIX509Cert** _cert) {
61 NS_ENSURE_ARG_POINTER(_cert);
62 *_cert = nullptr;
64 if (aDBKey.IsEmpty()) {
65 return NS_ERROR_INVALID_ARG;
68 nsresult rv = BlockUntilLoadableCertsLoaded();
69 if (NS_FAILED(rv)) {
70 return rv;
73 UniqueCERTCertificate cert;
74 rv = FindCertByDBKey(aDBKey, cert);
75 if (NS_FAILED(rv)) {
76 return rv;
78 // If we can't find the certificate, that's not an error. Just return null.
79 if (!cert) {
80 return NS_OK;
82 nsCOMPtr<nsIX509Cert> nssCert = new nsNSSCertificate(cert.get());
83 nssCert.forget(_cert);
84 return NS_OK;
87 nsresult nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
88 UniqueCERTCertificate& cert) {
89 static_assert(sizeof(uint64_t) == 8, "type size sanity check");
90 static_assert(sizeof(uint32_t) == 4, "type size sanity check");
91 // (From nsNSSCertificate::GetDbKey)
92 // The format of the key is the base64 encoding of the following:
93 // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
94 // never implemented)
95 // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
96 // never implemented)
97 // 4 bytes: <serial number length in big-endian order>
98 // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
99 // n bytes: <bytes of serial number>
100 // m bytes: <DER-encoded issuer distinguished name>
101 nsAutoCString decoded;
102 nsAutoCString tmpDBKey(aDBKey);
103 // Filter out any whitespace for backwards compatibility.
104 tmpDBKey.StripWhitespace();
105 nsresult rv = Base64Decode(tmpDBKey, decoded);
106 if (NS_FAILED(rv)) {
107 return rv;
109 if (decoded.Length() < 16) {
110 return NS_ERROR_ILLEGAL_INPUT;
112 const char* reader = decoded.BeginReading();
113 uint64_t zeroes = *BitwiseCast<const uint64_t*, const char*>(reader);
114 if (zeroes != 0) {
115 return NS_ERROR_ILLEGAL_INPUT;
117 reader += sizeof(uint64_t);
118 // Note: We surround the ntohl() argument with parentheses to stop the macro
119 // from thinking two arguments were passed.
120 uint32_t serialNumberLen =
121 ntohl((*BitwiseCast<const uint32_t*, const char*>(reader)));
122 reader += sizeof(uint32_t);
123 uint32_t issuerLen =
124 ntohl((*BitwiseCast<const uint32_t*, const char*>(reader)));
125 reader += sizeof(uint32_t);
126 if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) {
127 return NS_ERROR_ILLEGAL_INPUT;
129 CERTIssuerAndSN issuerSN;
130 issuerSN.serialNumber.len = serialNumberLen;
131 issuerSN.serialNumber.data = BitwiseCast<unsigned char*, const char*>(reader);
132 reader += serialNumberLen;
133 issuerSN.derIssuer.len = issuerLen;
134 issuerSN.derIssuer.data = BitwiseCast<unsigned char*, const char*>(reader);
135 reader += issuerLen;
136 MOZ_ASSERT(reader == decoded.EndReading());
138 cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
139 return NS_OK;
142 SECStatus collect_certs(void* arg, SECItem** certs, int numcerts) {
143 nsTArray<nsTArray<uint8_t>>* certsArray =
144 reinterpret_cast<nsTArray<nsTArray<uint8_t>>*>(arg);
146 while (numcerts--) {
147 nsTArray<uint8_t> certArray;
148 SECItem* cert = *certs;
149 certArray.AppendElements(cert->data, cert->len);
150 certsArray->AppendElement(std::move(certArray));
151 certs++;
153 return (SECSuccess);
156 nsresult nsNSSCertificateDB::getCertsFromPackage(
157 nsTArray<nsTArray<uint8_t>>& collectArgs, uint8_t* data, uint32_t length) {
158 if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length,
159 collect_certs, &collectArgs) != SECSuccess) {
160 return NS_ERROR_FAILURE;
162 return NS_OK;
165 // When using the sql-backed softoken, trust settings are authenticated using a
166 // key in the secret database. Thus, if the user has a password, we need to
167 // authenticate to the token in order to be able to change trust settings.
168 SECStatus ChangeCertTrustWithPossibleAuthentication(
169 const UniqueCERTCertificate& cert, CERTCertTrust& trust, void* ctx) {
170 MOZ_ASSERT(cert, "cert must be non-null");
171 if (!cert) {
172 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
173 return SECFailure;
175 // NSS ignores the first argument to CERT_ChangeCertTrust
176 SECStatus srv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
177 if (srv == SECSuccess || PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
178 return srv;
180 if (cert->slot) {
181 // If this certificate is on an external PKCS#11 token, we have to
182 // authenticate to that token.
183 srv = PK11_Authenticate(cert->slot, PR_TRUE, ctx);
184 } else {
185 // Otherwise, the certificate is on the internal module.
186 UniquePK11SlotInfo internalSlot(PK11_GetInternalKeySlot());
187 srv = PK11_Authenticate(internalSlot.get(), PR_TRUE, ctx);
189 if (srv != SECSuccess) {
190 return srv;
192 return CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
195 static nsresult ImportCertsIntoPermanentStorage(
196 const UniqueCERTCertList& certChain) {
197 bool encounteredFailure = false;
198 PRErrorCode savedErrorCode = 0;
199 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
200 for (CERTCertListNode* chainNode = CERT_LIST_HEAD(certChain);
201 !CERT_LIST_END(chainNode, certChain);
202 chainNode = CERT_LIST_NEXT(chainNode)) {
203 UniquePORTString nickname(CERT_MakeCANickname(chainNode->cert));
204 SECStatus srv = PK11_ImportCert(slot.get(), chainNode->cert,
205 CK_INVALID_HANDLE, nickname.get(),
206 false); // this parameter is ignored by NSS
207 if (srv != SECSuccess) {
208 encounteredFailure = true;
209 savedErrorCode = PR_GetError();
213 if (encounteredFailure) {
214 return GetXPCOMFromNSSError(savedErrorCode);
217 return NS_OK;
220 nsresult nsNSSCertificateDB::handleCACertDownload(NotNull<nsIArray*> x509Certs,
221 nsIInterfaceRequestor* ctx) {
222 // First thing we have to do is figure out which certificate we're
223 // gonna present to the user. The CA may have sent down a list of
224 // certs which may or may not be a chained list of certs. Until
225 // the day we can design some solid UI for the general case, we'll
226 // code to the > 90% case. That case is where a CA sends down a
227 // list that is a hierarchy whose root is either the first or
228 // the last cert. What we're gonna do is compare the first
229 // 2 entries, if the second was signed by the first, we assume
230 // the root cert is the first cert and display it. Otherwise,
231 // we compare the last 2 entries, if the second to last cert was
232 // signed by the last cert, then we assume the last cert is the
233 // root and display it.
235 uint32_t numCerts;
237 x509Certs->GetLength(&numCerts);
239 if (numCerts == 0) return NS_OK; // Nothing to import, so nothing to do.
241 nsCOMPtr<nsIX509Cert> certToShow;
242 uint32_t selCertIndex;
243 if (numCerts == 1) {
244 // There's only one cert, so let's show it.
245 selCertIndex = 0;
246 certToShow = do_QueryElementAt(x509Certs, selCertIndex);
247 } else {
248 nsCOMPtr<nsIX509Cert> cert0; // first cert
249 nsCOMPtr<nsIX509Cert> cert1; // second cert
250 nsCOMPtr<nsIX509Cert> certn_2; // second to last cert
251 nsCOMPtr<nsIX509Cert> certn_1; // last cert
253 cert0 = do_QueryElementAt(x509Certs, 0);
254 cert1 = do_QueryElementAt(x509Certs, 1);
255 certn_2 = do_QueryElementAt(x509Certs, numCerts - 2);
256 certn_1 = do_QueryElementAt(x509Certs, numCerts - 1);
258 nsAutoString cert0SubjectName;
259 nsAutoString cert1IssuerName;
260 nsAutoString certn_2IssuerName;
261 nsAutoString certn_1SubjectName;
263 cert0->GetSubjectName(cert0SubjectName);
264 cert1->GetIssuerName(cert1IssuerName);
265 certn_2->GetIssuerName(certn_2IssuerName);
266 certn_1->GetSubjectName(certn_1SubjectName);
268 if (cert1IssuerName.Equals(cert0SubjectName)) {
269 // In this case, the first cert in the list signed the second,
270 // so the first cert is the root. Let's display it.
271 selCertIndex = 0;
272 certToShow = cert0;
273 } else if (certn_2IssuerName.Equals(certn_1SubjectName)) {
274 // In this case the last cert has signed the second to last cert.
275 // The last cert is the root, so let's display it.
276 selCertIndex = numCerts - 1;
277 certToShow = certn_1;
278 } else {
279 // It's not a chain, so let's just show the first one in the
280 // downloaded list.
281 selCertIndex = 0;
282 certToShow = cert0;
286 if (!certToShow) return NS_ERROR_FAILURE;
288 nsCOMPtr<nsICertificateDialogs> dialogs;
289 nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
290 NS_GET_IID(nsICertificateDialogs),
291 NS_CERTIFICATEDIALOGS_CONTRACTID);
292 if (NS_FAILED(rv)) {
293 return rv;
296 UniqueCERTCertificate tmpCert(certToShow->GetCert());
297 if (!tmpCert) {
298 return NS_ERROR_FAILURE;
301 if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
302 DisplayCertificateAlert(ctx, "NotACACert", certToShow);
303 return NS_ERROR_FAILURE;
306 if (tmpCert->isperm) {
307 DisplayCertificateAlert(ctx, "CaCertExists", certToShow);
308 return NS_ERROR_FAILURE;
311 uint32_t trustBits;
312 bool allows;
313 rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
314 if (NS_FAILED(rv)) return rv;
316 if (!allows) return NS_ERROR_NOT_AVAILABLE;
318 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trust is %d\n", trustBits));
319 UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
321 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
322 ("Created nick \"%s\"\n", nickname.get()));
324 nsNSSCertTrust trust;
325 trust.SetValidCA();
326 trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
327 !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL));
329 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
330 SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
331 nickname.get(),
332 false); // this parameter is ignored by NSS
333 if (srv != SECSuccess) {
334 return MapSECStatus(srv);
336 srv =
337 ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(), ctx);
338 if (srv != SECSuccess) {
339 return MapSECStatus(srv);
342 // Import additional delivered certificates that can be verified.
344 // build a CertList for filtering
345 UniqueCERTCertList certList(CERT_NewCertList());
346 if (!certList) {
347 return NS_ERROR_FAILURE;
350 // get all remaining certs into temp store
352 for (uint32_t i = 0; i < numCerts; i++) {
353 if (i == selCertIndex) {
354 // we already processed that one
355 continue;
358 nsCOMPtr<nsIX509Cert> remainingCert = do_QueryElementAt(x509Certs, i);
359 if (!remainingCert) {
360 continue;
363 UniqueCERTCertificate tmpCert2(remainingCert->GetCert());
364 if (!tmpCert2) {
365 continue; // Let's try to import the rest of 'em
368 if (CERT_AddCertToListTail(certList.get(), tmpCert2.get()) != SECSuccess) {
369 continue;
372 Unused << tmpCert2.release();
375 return ImportCertsIntoPermanentStorage(certList);
378 nsresult nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(
379 const UniqueCERTCertList& aCertListIn,
380 nsTArray<RefPtr<nsIX509Cert>>& aCertListOut) {
381 if (!aCertListIn.get()) {
382 return NS_ERROR_INVALID_ARG;
385 for (CERTCertListNode* node = CERT_LIST_HEAD(aCertListIn.get());
386 !CERT_LIST_END(node, aCertListIn.get()); node = CERT_LIST_NEXT(node)) {
387 RefPtr<nsIX509Cert> cert = new nsNSSCertificate(node->cert);
388 aCertListOut.AppendElement(cert);
390 return NS_OK;
393 NS_IMETHODIMP
394 nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length,
395 uint32_t type,
396 nsIInterfaceRequestor* ctx) {
397 // We currently only handle CA certificates.
398 if (type != nsIX509Cert::CA_CERT) {
399 return NS_ERROR_FAILURE;
402 nsTArray<nsTArray<uint8_t>> certsArray;
403 nsresult rv = getCertsFromPackage(certsArray, data, length);
404 if (NS_FAILED(rv)) {
405 return rv;
408 nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
409 if (!array) {
410 return NS_ERROR_FAILURE;
413 // Now let's create some certs to work with
414 for (nsTArray<uint8_t>& certDER : certsArray) {
415 nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(std::move(certDER));
416 nsresult rv = array->AppendElement(cert);
417 if (NS_FAILED(rv)) {
418 return rv;
422 return handleCACertDownload(WrapNotNull(array), ctx);
426 * Decodes a given array of DER-encoded certificates into temporary storage.
428 * @param certs
429 * Array in which the decoded certificates are stored as arrays of
430 * unsigned chars.
431 * @param temporaryCerts
432 * List of decoded certificates.
434 static nsresult ImportCertsIntoTempStorage(
435 nsTArray<nsTArray<uint8_t>>& certs,
436 /*out*/ const UniqueCERTCertList& temporaryCerts) {
437 NS_ENSURE_ARG_POINTER(temporaryCerts);
439 for (nsTArray<uint8_t>& certDER : certs) {
440 CERTCertificate* certificate;
441 SECItem certItem;
442 certItem.len = certDER.Length();
443 certItem.data = certDER.Elements();
444 certificate = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certItem,
445 nullptr, false, true);
447 UniqueCERTCertificate cert(certificate);
448 if (!cert) {
449 continue;
452 if (CERT_AddCertToListTail(temporaryCerts.get(), cert.get()) ==
453 SECSuccess) {
454 Unused << cert.release();
458 return NS_OK;
461 NS_IMETHODIMP
462 nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
463 nsIInterfaceRequestor* ctx) {
464 nsTArray<nsTArray<uint8_t>> certsArray;
466 nsresult rv = getCertsFromPackage(certsArray, data, length);
467 if (NS_FAILED(rv)) {
468 return rv;
471 UniqueCERTCertList temporaryCerts(CERT_NewCertList());
472 if (!temporaryCerts) {
473 return NS_ERROR_FAILURE;
476 rv = ImportCertsIntoTempStorage(certsArray, temporaryCerts);
477 if (NS_FAILED(rv)) {
478 return rv;
481 return ImportCertsIntoPermanentStorage(temporaryCerts);
484 nsresult nsNSSCertificateDB::ImportCACerts(nsTArray<nsTArray<uint8_t>>& caCerts,
485 nsIInterfaceRequestor* ctx) {
486 UniqueCERTCertList temporaryCerts(CERT_NewCertList());
487 if (!temporaryCerts) {
488 return NS_ERROR_FAILURE;
491 nsresult rv = ImportCertsIntoTempStorage(caCerts, temporaryCerts);
492 if (NS_FAILED(rv)) {
493 return rv;
496 return ImportCertsIntoPermanentStorage(temporaryCerts);
499 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor* ctx,
500 const char* stringID,
501 nsIX509Cert* certToShow) {
502 if (!NS_IsMainThread()) {
503 NS_ERROR(
504 "nsNSSCertificateDB::DisplayCertificateAlert called off the main "
505 "thread");
506 return;
509 nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
510 if (!my_ctx) {
511 my_ctx = new PipUIContext();
514 // This shall be replaced by embedding ovverridable prompts
515 // as discussed in bug 310446, and should make use of certToShow.
517 nsAutoString tmpMessage;
518 GetPIPNSSBundleString(stringID, tmpMessage);
519 nsCOMPtr<nsIPrompt> prompt(do_GetInterface(my_ctx));
520 if (!prompt) {
521 return;
524 prompt->Alert(nullptr, tmpMessage.get());
527 NS_IMETHODIMP
528 nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length,
529 nsIInterfaceRequestor* ctx) {
530 if (!NS_IsMainThread()) {
531 NS_ERROR(
532 "nsNSSCertificateDB::ImportUserCertificate called off the main thread");
533 return NS_ERROR_NOT_SAME_THREAD;
536 nsTArray<nsTArray<uint8_t>> certsArray;
538 nsresult rv = getCertsFromPackage(certsArray, data, length);
539 if (NS_FAILED(rv)) {
540 return rv;
543 SECItem certItem;
545 if (certsArray.IsEmpty()) {
546 return NS_OK;
549 certItem.len = certsArray.ElementAt(0).Length();
550 certItem.data = certsArray.ElementAt(0).Elements();
552 UniqueCERTCertificate cert(CERT_NewTempCertificate(
553 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
554 if (!cert) {
555 return NS_ERROR_FAILURE;
558 UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx));
559 if (!slot) {
560 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert.get());
561 DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow);
562 return NS_ERROR_FAILURE;
564 slot = nullptr;
566 /* pick a nickname for the cert */
567 nsAutoCString nickname;
568 if (cert->nickname) {
569 nickname = cert->nickname;
570 } else {
571 get_default_nickname(cert.get(), ctx, nickname);
574 /* user wants to import the cert */
575 slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx));
576 if (!slot) {
577 return NS_ERROR_FAILURE;
579 slot = nullptr;
582 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert.get());
583 DisplayCertificateAlert(ctx, "UserCertImported", certToShow);
586 rv = NS_OK;
587 if (!certsArray.IsEmpty()) {
588 certsArray.RemoveElementAt(0);
589 rv = ImportCACerts(certsArray, ctx);
592 nsCOMPtr<nsIObserverService> observerService =
593 mozilla::services::GetObserverService();
594 if (observerService) {
595 observerService->NotifyObservers(nullptr, "psm:user-certificate-added",
596 nullptr);
599 return rv;
602 NS_IMETHODIMP
603 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert* aCert) {
604 NS_ENSURE_ARG_POINTER(aCert);
605 UniqueCERTCertificate cert(aCert->GetCert());
606 if (!cert) {
607 return NS_ERROR_FAILURE;
610 // Temporary certificates aren't on a slot and will go away when the
611 // nsIX509Cert is destructed.
612 if (cert->slot) {
613 uint32_t certType;
614 nsresult rv = aCert->GetCertType(&certType);
615 if (NS_WARN_IF(NS_FAILED(rv))) {
616 return rv;
618 if (certType == nsIX509Cert::USER_CERT) {
619 SECStatus srv = PK11_Authenticate(cert->slot, true, nullptr);
620 if (srv != SECSuccess) {
621 return NS_ERROR_FAILURE;
623 srv = PK11_DeleteTokenCertAndKey(cert.get(), nullptr);
624 if (srv != SECSuccess) {
625 return NS_ERROR_FAILURE;
627 } else {
628 // For certificates that can't be deleted (e.g. built-in roots), un-set
629 // all trust bits.
630 nsNSSCertTrust trust(0, 0);
631 SECStatus srv = ChangeCertTrustWithPossibleAuthentication(
632 cert, trust.GetTrust(), nullptr);
633 if (srv != SECSuccess) {
634 return NS_ERROR_FAILURE;
636 if (!PK11_IsReadOnly(cert->slot)) {
637 srv = SEC_DeletePermCertificate(cert.get());
638 if (srv != SECSuccess) {
639 return NS_ERROR_FAILURE;
645 nsCOMPtr<nsIObserverService> observerService =
646 mozilla::services::GetObserverService();
647 if (observerService) {
648 observerService->NotifyObservers(nullptr, "psm:user-certificate-deleted",
649 nullptr);
652 return NS_OK;
655 NS_IMETHODIMP
656 nsNSSCertificateDB::SetCertTrust(nsIX509Cert* cert, uint32_t type,
657 uint32_t trusted) {
658 NS_ENSURE_ARG_POINTER(cert);
659 nsNSSCertTrust trust;
660 switch (type) {
661 case nsIX509Cert::CA_CERT:
662 trust.SetValidCA();
663 trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
664 !!(trusted & nsIX509CertDB::TRUSTED_EMAIL));
665 break;
666 case nsIX509Cert::SERVER_CERT:
667 trust.SetValidPeer();
668 trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, false);
669 break;
670 case nsIX509Cert::EMAIL_CERT:
671 trust.SetValidPeer();
672 trust.AddPeerTrust(false, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL));
673 break;
674 default:
675 // Ignore any other type of certificate (including invalid types).
676 return NS_OK;
679 UniqueCERTCertificate nsscert(cert->GetCert());
680 SECStatus srv = ChangeCertTrustWithPossibleAuthentication(
681 nsscert, trust.GetTrust(), nullptr);
682 return MapSECStatus(srv);
685 NS_IMETHODIMP
686 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert* cert, uint32_t certType,
687 uint32_t trustType, bool* _isTrusted) {
688 NS_ENSURE_ARG_POINTER(_isTrusted);
689 *_isTrusted = false;
691 nsresult rv = BlockUntilLoadableCertsLoaded();
692 if (NS_FAILED(rv)) {
693 return rv;
696 SECStatus srv;
697 UniqueCERTCertificate nsscert(cert->GetCert());
698 CERTCertTrust nsstrust;
699 srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
700 if (srv != SECSuccess) {
701 // CERT_GetCertTrust returns SECFailure if given a temporary cert that
702 // doesn't have any trust information yet. This isn't an error.
703 return NS_OK;
706 nsNSSCertTrust trust(&nsstrust);
707 if (certType == nsIX509Cert::CA_CERT) {
708 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
709 *_isTrusted = trust.HasTrustedCA(true, false);
710 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
711 *_isTrusted = trust.HasTrustedCA(false, true);
712 } else {
713 return NS_ERROR_FAILURE;
715 } else if (certType == nsIX509Cert::SERVER_CERT) {
716 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
717 *_isTrusted = trust.HasTrustedPeer(true, false);
718 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
719 *_isTrusted = trust.HasTrustedPeer(false, true);
720 } else {
721 return NS_ERROR_FAILURE;
723 } else if (certType == nsIX509Cert::EMAIL_CERT) {
724 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
725 *_isTrusted = trust.HasTrustedPeer(true, false);
726 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
727 *_isTrusted = trust.HasTrustedPeer(false, true);
728 } else {
729 return NS_ERROR_FAILURE;
731 } /* user: ignore */
732 return NS_OK;
735 NS_IMETHODIMP
736 nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType) {
737 NS_ENSURE_ARG(aFile);
738 switch (aType) {
739 case nsIX509Cert::CA_CERT:
740 case nsIX509Cert::EMAIL_CERT:
741 // good
742 break;
744 default:
745 // not supported (yet)
746 return NS_ERROR_FAILURE;
749 PRFileDesc* fd = nullptr;
750 nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
751 if (NS_FAILED(rv)) {
752 return rv;
754 if (!fd) {
755 return NS_ERROR_FAILURE;
758 PRFileInfo fileInfo;
759 if (PR_GetOpenFileInfo(fd, &fileInfo) != PR_SUCCESS) {
760 return NS_ERROR_FAILURE;
763 auto buf = MakeUnique<unsigned char[]>(fileInfo.size);
764 int32_t bytesObtained = PR_Read(fd, buf.get(), fileInfo.size);
765 PR_Close(fd);
767 if (bytesObtained != fileInfo.size) {
768 return NS_ERROR_FAILURE;
771 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
773 switch (aType) {
774 case nsIX509Cert::CA_CERT:
775 return ImportCertificates(buf.get(), bytesObtained, aType, cxt);
776 case nsIX509Cert::EMAIL_CERT:
777 return ImportEmailCertificate(buf.get(), bytesObtained, cxt);
778 default:
779 MOZ_ASSERT(false, "Unsupported type should have been filtered out");
780 break;
783 return NS_ERROR_FAILURE;
786 NS_IMETHODIMP
787 nsNSSCertificateDB::ImportPKCS12File(nsIFile* aFile, const nsAString& aPassword,
788 uint32_t* aError) {
789 if (!NS_IsMainThread()) {
790 return NS_ERROR_NOT_SAME_THREAD;
792 nsresult rv = BlockUntilLoadableCertsLoaded();
793 if (NS_FAILED(rv)) {
794 return rv;
797 NS_ENSURE_ARG(aFile);
798 nsPKCS12Blob blob;
799 rv = blob.ImportFromFile(aFile, aPassword, *aError);
800 nsCOMPtr<nsIObserverService> observerService =
801 mozilla::services::GetObserverService();
802 if (NS_SUCCEEDED(rv) && observerService) {
803 observerService->NotifyObservers(nullptr, "psm:user-certificate-added",
804 nullptr);
807 return rv;
810 NS_IMETHODIMP
811 nsNSSCertificateDB::ExportPKCS12File(
812 nsIFile* aFile, const nsTArray<RefPtr<nsIX509Cert>>& aCerts,
813 const nsAString& aPassword, uint32_t* aError) {
814 if (!NS_IsMainThread()) {
815 return NS_ERROR_NOT_SAME_THREAD;
817 nsresult rv = BlockUntilLoadableCertsLoaded();
818 if (NS_FAILED(rv)) {
819 return rv;
822 NS_ENSURE_ARG(aFile);
823 if (aCerts.IsEmpty()) {
824 return NS_OK;
826 nsPKCS12Blob blob;
827 return blob.ExportToFile(aFile, aCerts, aPassword, *aError);
830 NS_IMETHODIMP
831 nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64,
832 /*out*/ nsIX509Cert** _retval) {
833 if (!_retval) {
834 return NS_ERROR_INVALID_POINTER;
837 // Base64Decode() doesn't consider a zero length input as an error, and just
838 // returns the empty string. We don't want this behavior, so the below check
839 // catches this case.
840 if (base64.Length() < 1) {
841 return NS_ERROR_ILLEGAL_VALUE;
844 nsAutoCString certDER;
845 nsresult rv = Base64Decode(base64, certDER);
846 if (NS_FAILED(rv)) {
847 return rv;
850 return ConstructX509FromSpan(AsBytes(Span(certDER)), _retval);
853 NS_IMETHODIMP
854 nsNSSCertificateDB::ConstructX509(const nsTArray<uint8_t>& certDER,
855 nsIX509Cert** _retval) {
856 return ConstructX509FromSpan(Span(certDER.Elements(), certDER.Length()),
857 _retval);
860 nsresult nsNSSCertificateDB::ConstructX509FromSpan(
861 Span<const uint8_t> aInputSpan, nsIX509Cert** _retval) {
862 if (NS_WARN_IF(!_retval)) {
863 return NS_ERROR_INVALID_POINTER;
866 if (aInputSpan.Length() > std::numeric_limits<unsigned int>::max()) {
867 return NS_ERROR_ILLEGAL_VALUE;
870 SECItem certData;
871 certData.type = siDERCertBuffer;
872 certData.data = const_cast<unsigned char*>(
873 reinterpret_cast<const unsigned char*>(aInputSpan.Elements()));
874 certData.len = aInputSpan.Length();
876 UniqueCERTCertificate cert(CERT_NewTempCertificate(
877 CERT_GetDefaultCertDB(), &certData, nullptr, false, true));
878 if (!cert)
879 return (PORT_GetError() == SEC_ERROR_NO_MEMORY) ? NS_ERROR_OUT_OF_MEMORY
880 : NS_ERROR_FAILURE;
882 nsCOMPtr<nsIX509Cert> nssCert = new nsNSSCertificate(cert.get());
883 nssCert.forget(_retval);
884 return NS_OK;
887 void nsNSSCertificateDB::get_default_nickname(CERTCertificate* cert,
888 nsIInterfaceRequestor* ctx,
889 nsCString& nickname) {
890 nickname.Truncate();
892 CK_OBJECT_HANDLE keyHandle;
894 if (NS_FAILED(BlockUntilLoadableCertsLoaded())) {
895 return;
898 CERTCertDBHandle* defaultcertdb = CERT_GetDefaultCertDB();
899 nsAutoCString username;
900 UniquePORTString tempCN(CERT_GetCommonName(&cert->subject));
901 if (tempCN) {
902 username = tempCN.get();
905 nsAutoCString caname;
906 UniquePORTString tempIssuerOrg(CERT_GetOrgName(&cert->issuer));
907 if (tempIssuerOrg) {
908 caname = tempIssuerOrg.get();
911 nsAutoString tmpNickFmt;
912 GetPIPNSSBundleString("nick_template", tmpNickFmt);
913 NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
915 nsAutoCString baseName;
916 baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get());
917 if (baseName.IsEmpty()) {
918 return;
921 nickname = baseName;
924 * We need to see if the private key exists on a token, if it does
925 * then we need to check for nicknames that already exist on the smart
926 * card.
928 UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
929 if (!slot) return;
931 if (!PK11_IsInternal(slot.get())) {
932 nsAutoCString tmp;
933 tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get());
934 if (tmp.IsEmpty()) {
935 nickname.Truncate();
936 return;
938 baseName = tmp;
939 nickname = baseName;
942 int count = 1;
943 while (true) {
944 if (count > 1) {
945 nsAutoCString tmp;
946 tmp.AppendPrintf("%s #%d", baseName.get(), count);
947 if (tmp.IsEmpty()) {
948 nickname.Truncate();
949 return;
951 nickname = tmp;
954 UniqueCERTCertificate dummycert;
956 if (PK11_IsInternal(slot.get())) {
957 /* look up the nickname to make sure it isn't in use already */
958 dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get()));
959 } else {
960 // Check the cert against others that already live on the smart card.
961 dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx));
962 if (dummycert) {
963 // Make sure the subject names are different.
964 if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) {
966 * There is another certificate with the same nickname and
967 * the same subject name on the smart card, so let's use this
968 * nickname.
970 dummycert = nullptr;
974 if (!dummycert) {
975 break;
977 count++;
981 NS_IMETHODIMP
982 nsNSSCertificateDB::AddCertFromBase64(const nsACString& aBase64,
983 const nsACString& aTrust,
984 nsIX509Cert** addedCertificate) {
985 // Base64Decode() doesn't consider a zero length input as an error, and just
986 // returns the empty string. We don't want this behavior, so the below check
987 // catches this case.
988 if (aBase64.Length() < 1) {
989 return NS_ERROR_ILLEGAL_VALUE;
992 nsAutoCString aCertDER;
993 nsresult rv = Base64Decode(aBase64, aCertDER);
994 if (NS_FAILED(rv)) {
995 return rv;
997 return AddCert(aCertDER, aTrust, addedCertificate);
1000 NS_IMETHODIMP
1001 nsNSSCertificateDB::AddCert(const nsACString& aCertDER,
1002 const nsACString& aTrust,
1003 nsIX509Cert** addedCertificate) {
1004 MOZ_ASSERT(addedCertificate);
1005 if (!addedCertificate) {
1006 return NS_ERROR_INVALID_ARG;
1008 *addedCertificate = nullptr;
1010 nsNSSCertTrust trust;
1011 if (CERT_DecodeTrustString(&trust.GetTrust(),
1012 PromiseFlatCString(aTrust).get()) != SECSuccess) {
1013 return NS_ERROR_FAILURE;
1016 nsCOMPtr<nsIX509Cert> newCert;
1017 nsresult rv =
1018 ConstructX509FromSpan(AsBytes(Span(aCertDER)), getter_AddRefs(newCert));
1019 if (NS_FAILED(rv)) {
1020 return rv;
1023 UniqueCERTCertificate tmpCert(newCert->GetCert());
1024 if (!tmpCert) {
1025 return NS_ERROR_FAILURE;
1028 // If there's already a certificate that matches this one in the database, we
1029 // still want to set its trust to the given value.
1030 if (tmpCert->isperm) {
1031 rv = SetCertTrustFromString(newCert, aTrust);
1032 if (NS_FAILED(rv)) {
1033 return rv;
1035 newCert.forget(addedCertificate);
1036 return NS_OK;
1039 UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
1041 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1042 ("Created nick \"%s\"\n", nickname.get()));
1044 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
1045 SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
1046 nickname.get(),
1047 false); // this parameter is ignored by NSS
1048 if (srv != SECSuccess) {
1049 return MapSECStatus(srv);
1051 srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(),
1052 nullptr);
1053 if (srv != SECSuccess) {
1054 return MapSECStatus(srv);
1056 newCert.forget(addedCertificate);
1057 return NS_OK;
1060 NS_IMETHODIMP
1061 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
1062 const nsACString& trustString) {
1063 NS_ENSURE_ARG(cert);
1065 CERTCertTrust trust;
1066 SECStatus srv =
1067 CERT_DecodeTrustString(&trust, PromiseFlatCString(trustString).get());
1068 if (srv != SECSuccess) {
1069 return MapSECStatus(srv);
1071 UniqueCERTCertificate nssCert(cert->GetCert());
1073 srv = ChangeCertTrustWithPossibleAuthentication(nssCert, trust, nullptr);
1074 return MapSECStatus(srv);
1077 NS_IMETHODIMP nsNSSCertificateDB::AsPKCS7Blob(
1078 const nsTArray<RefPtr<nsIX509Cert>>& certList, nsACString& _retval) {
1079 if (certList.IsEmpty()) {
1080 return NS_ERROR_INVALID_ARG;
1083 UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
1084 if (!cmsg) {
1085 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1086 ("nsNSSCertificateDB::AsPKCS7Blob - can't create CMS message"));
1087 return NS_ERROR_OUT_OF_MEMORY;
1090 UniqueNSSCMSSignedData sigd(nullptr);
1091 for (const auto& cert : certList) {
1092 // We need an owning handle when calling nsIX509Cert::GetCert().
1093 UniqueCERTCertificate nssCert(cert->GetCert());
1094 if (!sigd) {
1095 sigd.reset(
1096 NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), nssCert.get(), false));
1097 if (!sigd) {
1098 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1099 ("nsNSSCertificateDB::AsPKCS7Blob - can't create SignedData"));
1100 return NS_ERROR_FAILURE;
1102 } else if (NSS_CMSSignedData_AddCertificate(sigd.get(), nssCert.get()) !=
1103 SECSuccess) {
1104 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1105 ("nsNSSCertificateDB::AsPKCS7Blob - can't add cert"));
1106 return NS_ERROR_FAILURE;
1110 NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
1111 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get()) !=
1112 SECSuccess) {
1113 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1114 ("nsNSSCertificateDB::AsPKCS7Blob - can't attach SignedData"));
1115 return NS_ERROR_FAILURE;
1117 // cmsg owns sigd now.
1118 Unused << sigd.release();
1120 UniquePLArenaPool arena(PORT_NewArena(1024));
1121 if (!arena) {
1122 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1123 ("nsNSSCertificateDB::AsPKCS7Blob - out of memory"));
1124 return NS_ERROR_OUT_OF_MEMORY;
1127 SECItem certP7 = {siBuffer, nullptr, 0};
1128 NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(
1129 cmsg.get(), nullptr, nullptr, &certP7, arena.get(), nullptr, nullptr,
1130 nullptr, nullptr, nullptr, nullptr);
1131 if (!ecx) {
1132 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1133 ("nsNSSCertificateDB::AsPKCS7Blob - can't create encoder"));
1134 return NS_ERROR_FAILURE;
1137 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
1138 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1139 ("nsNSSCertificateDB::AsPKCS7Blob - failed to add encoded data"));
1140 return NS_ERROR_FAILURE;
1143 _retval.Assign(nsDependentCSubstring(
1144 reinterpret_cast<const char*>(certP7.data), certP7.len));
1145 return NS_OK;
1148 NS_IMETHODIMP
1149 nsNSSCertificateDB::GetCerts(nsTArray<RefPtr<nsIX509Cert>>& _retval) {
1150 nsresult rv = BlockUntilLoadableCertsLoaded();
1151 if (NS_FAILED(rv)) {
1152 return rv;
1155 rv = CheckForSmartCardChanges();
1156 if (NS_FAILED(rv)) {
1157 return rv;
1160 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1161 UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx));
1162 if (!certList) {
1163 return NS_ERROR_FAILURE;
1165 return nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(certList,
1166 _retval);
1169 NS_IMETHODIMP
1170 nsNSSCertificateDB::AsyncHasThirdPartyRoots(nsIAsyncBoolCallback* aCallback) {
1171 NS_ENSURE_ARG_POINTER(aCallback);
1172 nsMainThreadPtrHandle<nsIAsyncBoolCallback> callback(
1173 new nsMainThreadPtrHolder<nsIAsyncBoolCallback>("AsyncHasThirdPartyRoots",
1174 aCallback));
1176 return NS_DispatchBackgroundTask(
1177 NS_NewRunnableFunction(
1178 "nsNSSCertificateDB::AsyncHasThirdPartyRoots",
1179 [cb = std::move(callback), self = RefPtr{this}] {
1180 bool hasThirdPartyRoots = [self]() -> bool {
1181 nsTArray<RefPtr<nsIX509Cert>> certs;
1182 nsresult rv = self->GetCerts(certs);
1183 if (NS_FAILED(rv)) {
1184 return false;
1187 for (const auto& cert : certs) {
1188 bool isTrusted = false;
1189 nsresult rv =
1190 self->IsCertTrusted(cert, nsIX509Cert::CA_CERT,
1191 nsIX509CertDB::TRUSTED_SSL, &isTrusted);
1192 if (NS_FAILED(rv)) {
1193 return false;
1196 if (!isTrusted) {
1197 continue;
1200 bool isBuiltInRoot = false;
1201 rv = cert->GetIsBuiltInRoot(&isBuiltInRoot);
1202 if (NS_FAILED(rv)) {
1203 return false;
1206 if (!isBuiltInRoot) {
1207 return true;
1211 return false;
1212 }();
1214 NS_DispatchToMainThread(NS_NewRunnableFunction(
1215 "nsNSSCertificateDB::AsyncHasThirdPartyRoots callback",
1216 [cb, hasThirdPartyRoots]() {
1217 cb->OnResult(hasThirdPartyRoots);
1218 }));
1220 NS_DISPATCH_EVENT_MAY_BLOCK);
1223 nsresult VerifyCertAtTime(nsIX509Cert* aCert,
1224 int64_t /*SECCertificateUsage*/ aUsage,
1225 uint32_t aFlags, const nsACString& aHostname,
1226 mozilla::pkix::Time aTime,
1227 nsTArray<RefPtr<nsIX509Cert>>& aVerifiedChain,
1228 bool* aHasEVPolicy,
1229 int32_t* /*PRErrorCode*/ _retval) {
1230 NS_ENSURE_ARG_POINTER(aCert);
1231 NS_ENSURE_ARG_POINTER(aHasEVPolicy);
1232 NS_ENSURE_ARG_POINTER(_retval);
1234 if (!aVerifiedChain.IsEmpty()) {
1235 return NS_ERROR_INVALID_ARG;
1238 *aHasEVPolicy = false;
1239 *_retval = PR_UNKNOWN_ERROR;
1241 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1242 NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
1244 nsTArray<nsTArray<uint8_t>> resultChain;
1245 EVStatus evStatus;
1246 mozilla::pkix::Result result;
1248 nsTArray<uint8_t> certBytes;
1249 nsresult nsrv = aCert->GetRawDER(certBytes);
1250 if (NS_FAILED(nsrv)) {
1251 return nsrv;
1254 if (!aHostname.IsVoid() && aUsage == certificateUsageSSLServer) {
1255 result =
1256 certVerifier->VerifySSLServerCert(certBytes, aTime,
1257 nullptr, // Assume no context
1258 aHostname, resultChain, aFlags,
1259 Nothing(), // extraCertificates
1260 Nothing(), // stapledOCSPResponse
1261 Nothing(), // sctsFromTLSExtension
1262 Nothing(), // dcInfo
1263 OriginAttributes(), &evStatus);
1264 } else {
1265 const nsCString& flatHostname = PromiseFlatCString(aHostname);
1266 result = certVerifier->VerifyCert(
1267 certBytes, aUsage, aTime,
1268 nullptr, // Assume no context
1269 aHostname.IsVoid() ? nullptr : flatHostname.get(), resultChain, aFlags,
1270 Nothing(), // extraCertificates
1271 Nothing(), // stapledOCSPResponse
1272 Nothing(), // sctsFromTLSExtension
1273 OriginAttributes(), &evStatus);
1276 if (result == mozilla::pkix::Success) {
1277 for (auto& certDER : resultChain) {
1278 RefPtr<nsIX509Cert> cert = new nsNSSCertificate(std::move(certDER));
1279 aVerifiedChain.AppendElement(cert);
1282 if (evStatus == EVStatus::EV) {
1283 *aHasEVPolicy = true;
1287 *_retval = mozilla::pkix::MapResultToPRErrorCode(result);
1289 return NS_OK;
1292 class VerifyCertAtTimeTask final : public CryptoTask {
1293 public:
1294 VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags,
1295 const nsACString& aHostname, uint64_t aTime,
1296 nsICertVerificationCallback* aCallback)
1297 : mCert(aCert),
1298 mUsage(aUsage),
1299 mFlags(aFlags),
1300 mHostname(aHostname),
1301 mTime(aTime),
1302 mCallback(new nsMainThreadPtrHolder<nsICertVerificationCallback>(
1303 "nsICertVerificationCallback", aCallback)),
1304 mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE),
1305 mHasEVPolicy(false) {}
1307 private:
1308 virtual nsresult CalculateResult() override {
1309 nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID);
1310 if (!certDB) {
1311 return NS_ERROR_FAILURE;
1313 return VerifyCertAtTime(mCert, mUsage, mFlags, mHostname,
1314 mozilla::pkix::TimeFromEpochInSeconds(mTime),
1315 mVerifiedCertList, &mHasEVPolicy, &mPRErrorCode);
1318 virtual void CallCallback(nsresult rv) override {
1319 if (NS_FAILED(rv)) {
1320 nsTArray<RefPtr<nsIX509Cert>> tmp;
1321 Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE, tmp,
1322 false);
1323 } else {
1324 Unused << mCallback->VerifyCertFinished(mPRErrorCode, mVerifiedCertList,
1325 mHasEVPolicy);
1329 nsCOMPtr<nsIX509Cert> mCert;
1330 int64_t mUsage;
1331 uint32_t mFlags;
1332 nsCString mHostname;
1333 uint64_t mTime;
1334 nsMainThreadPtrHandle<nsICertVerificationCallback> mCallback;
1335 int32_t mPRErrorCode;
1336 nsTArray<RefPtr<nsIX509Cert>> mVerifiedCertList;
1337 bool mHasEVPolicy;
1340 NS_IMETHODIMP
1341 nsNSSCertificateDB::AsyncVerifyCertAtTime(
1342 nsIX509Cert* aCert, int64_t /*SECCertificateUsage*/ aUsage, uint32_t aFlags,
1343 const nsACString& aHostname, uint64_t aTime,
1344 nsICertVerificationCallback* aCallback) {
1345 RefPtr<VerifyCertAtTimeTask> task(new VerifyCertAtTimeTask(
1346 aCert, aUsage, aFlags, aHostname, aTime, aCallback));
1347 return task->Dispatch();
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;