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"
12 #include "mozilla/glean/GleanMetrics.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"
23 #include "nsArrayUtils.h"
25 #include "nsComponentManagerUtils.h"
26 #include "nsICertificateDialogs.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"
48 # include <winsock.h> // for ntohl
51 using namespace mozilla
;
52 using namespace mozilla::psm
;
54 extern LazyLogModule gPIPNSSLog
;
56 NS_IMPL_ISUPPORTS(nsNSSCertificateDB
, nsIX509CertDB
)
59 nsNSSCertificateDB::CountTrustObjects(uint32_t* aCount
) {
60 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
61 PK11GenericObject
* objects
=
62 PK11_FindGenericObjects(slot
.get(), CKO_NSS_TRUST
);
64 for (PK11GenericObject
* cursor
= objects
; cursor
;
65 cursor
= PK11_GetNextGenericObject(cursor
)) {
68 PK11_DestroyGenericObjects(objects
);
70 mozilla::glean::cert_verifier::trust_obj_count
.Set(count
);
77 nsNSSCertificateDB::FindCertByDBKey(const nsACString
& aDBKey
,
78 /*out*/ nsIX509Cert
** _cert
) {
79 NS_ENSURE_ARG_POINTER(_cert
);
82 if (aDBKey
.IsEmpty()) {
83 return NS_ERROR_INVALID_ARG
;
86 nsresult rv
= BlockUntilLoadableCertsLoaded();
91 UniqueCERTCertificate cert
;
92 rv
= FindCertByDBKey(aDBKey
, cert
);
96 // If we can't find the certificate, that's not an error. Just return null.
100 nsCOMPtr
<nsIX509Cert
> nssCert
= new nsNSSCertificate(cert
.get());
101 nssCert
.forget(_cert
);
105 nsresult
nsNSSCertificateDB::FindCertByDBKey(const nsACString
& aDBKey
,
106 UniqueCERTCertificate
& cert
) {
107 static_assert(sizeof(uint64_t) == 8, "type size sanity check");
108 static_assert(sizeof(uint32_t) == 4, "type size sanity check");
109 // (From nsNSSCertificate::GetDbKey)
110 // The format of the key is the base64 encoding of the following:
111 // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
112 // never implemented)
113 // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
114 // never implemented)
115 // 4 bytes: <serial number length in big-endian order>
116 // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
117 // n bytes: <bytes of serial number>
118 // m bytes: <DER-encoded issuer distinguished name>
119 nsAutoCString decoded
;
120 nsAutoCString
tmpDBKey(aDBKey
);
121 // Filter out any whitespace for backwards compatibility.
122 tmpDBKey
.StripWhitespace();
123 nsresult rv
= Base64Decode(tmpDBKey
, decoded
);
127 if (decoded
.Length() < 16) {
128 return NS_ERROR_ILLEGAL_INPUT
;
130 const char* reader
= decoded
.BeginReading();
131 uint64_t zeroes
= *BitwiseCast
<const uint64_t*, const char*>(reader
);
133 return NS_ERROR_ILLEGAL_INPUT
;
135 reader
+= sizeof(uint64_t);
136 // Note: We surround the ntohl() argument with parentheses to stop the macro
137 // from thinking two arguments were passed.
138 uint32_t serialNumberLen
=
139 ntohl((*BitwiseCast
<const uint32_t*, const char*>(reader
)));
140 reader
+= sizeof(uint32_t);
142 ntohl((*BitwiseCast
<const uint32_t*, const char*>(reader
)));
143 reader
+= sizeof(uint32_t);
144 if (decoded
.Length() != 16ULL + serialNumberLen
+ issuerLen
) {
145 return NS_ERROR_ILLEGAL_INPUT
;
147 CERTIssuerAndSN issuerSN
;
148 issuerSN
.serialNumber
.len
= serialNumberLen
;
149 issuerSN
.serialNumber
.data
= BitwiseCast
<unsigned char*, const char*>(reader
);
150 reader
+= serialNumberLen
;
151 issuerSN
.derIssuer
.len
= issuerLen
;
152 issuerSN
.derIssuer
.data
= BitwiseCast
<unsigned char*, const char*>(reader
);
154 MOZ_ASSERT(reader
== decoded
.EndReading());
156 cert
.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN
));
160 SECStatus
collect_certs(void* arg
, SECItem
** certs
, int numcerts
) {
161 nsTArray
<nsTArray
<uint8_t>>* certsArray
=
162 reinterpret_cast<nsTArray
<nsTArray
<uint8_t>>*>(arg
);
165 nsTArray
<uint8_t> certArray
;
166 SECItem
* cert
= *certs
;
167 certArray
.AppendElements(cert
->data
, cert
->len
);
168 certsArray
->AppendElement(std::move(certArray
));
174 nsresult
nsNSSCertificateDB::getCertsFromPackage(
175 nsTArray
<nsTArray
<uint8_t>>& collectArgs
, uint8_t* data
, uint32_t length
) {
176 if (CERT_DecodeCertPackage(BitwiseCast
<char*, uint8_t*>(data
), length
,
177 collect_certs
, &collectArgs
) != SECSuccess
) {
178 return NS_ERROR_FAILURE
;
183 // When using the sql-backed softoken, trust settings are authenticated using a
184 // key in the secret database. Thus, if the user has a password, we need to
185 // authenticate to the token in order to be able to change trust settings.
186 SECStatus
ChangeCertTrustWithPossibleAuthentication(
187 const UniqueCERTCertificate
& cert
, CERTCertTrust
& trust
, void* ctx
) {
188 MOZ_ASSERT(cert
, "cert must be non-null");
190 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
193 // NSS ignores the first argument to CERT_ChangeCertTrust
194 SECStatus srv
= CERT_ChangeCertTrust(nullptr, cert
.get(), &trust
);
195 if (srv
== SECSuccess
|| PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN
) {
199 // If this certificate is on an external PKCS#11 token, we have to
200 // authenticate to that token.
201 srv
= PK11_Authenticate(cert
->slot
, PR_TRUE
, ctx
);
203 // Otherwise, the certificate is on the internal module.
204 UniquePK11SlotInfo
internalSlot(PK11_GetInternalKeySlot());
205 srv
= PK11_Authenticate(internalSlot
.get(), PR_TRUE
, ctx
);
207 if (srv
!= SECSuccess
) {
210 return CERT_ChangeCertTrust(nullptr, cert
.get(), &trust
);
213 static nsresult
ImportCertsIntoPermanentStorage(
214 const UniqueCERTCertList
& certChain
) {
215 bool encounteredFailure
= false;
216 PRErrorCode savedErrorCode
= 0;
217 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
218 for (CERTCertListNode
* chainNode
= CERT_LIST_HEAD(certChain
);
219 !CERT_LIST_END(chainNode
, certChain
);
220 chainNode
= CERT_LIST_NEXT(chainNode
)) {
221 UniquePORTString
nickname(CERT_MakeCANickname(chainNode
->cert
));
222 SECStatus srv
= PK11_ImportCert(slot
.get(), chainNode
->cert
,
223 CK_INVALID_HANDLE
, nickname
.get(),
224 false); // this parameter is ignored by NSS
225 if (srv
!= SECSuccess
) {
226 encounteredFailure
= true;
227 savedErrorCode
= PR_GetError();
231 if (encounteredFailure
) {
232 return GetXPCOMFromNSSError(savedErrorCode
);
238 nsresult
nsNSSCertificateDB::handleCACertDownload(NotNull
<nsIArray
*> x509Certs
,
239 nsIInterfaceRequestor
* ctx
) {
240 // First thing we have to do is figure out which certificate we're
241 // gonna present to the user. The CA may have sent down a list of
242 // certs which may or may not be a chained list of certs. Until
243 // the day we can design some solid UI for the general case, we'll
244 // code to the > 90% case. That case is where a CA sends down a
245 // list that is a hierarchy whose root is either the first or
246 // the last cert. What we're gonna do is compare the first
247 // 2 entries, if the second was signed by the first, we assume
248 // the root cert is the first cert and display it. Otherwise,
249 // we compare the last 2 entries, if the second to last cert was
250 // signed by the last cert, then we assume the last cert is the
251 // root and display it.
255 x509Certs
->GetLength(&numCerts
);
257 if (numCerts
== 0) return NS_OK
; // Nothing to import, so nothing to do.
259 nsCOMPtr
<nsIX509Cert
> certToShow
;
260 uint32_t selCertIndex
;
262 // There's only one cert, so let's show it.
264 certToShow
= do_QueryElementAt(x509Certs
, selCertIndex
);
266 nsCOMPtr
<nsIX509Cert
> cert0
; // first cert
267 nsCOMPtr
<nsIX509Cert
> cert1
; // second cert
268 nsCOMPtr
<nsIX509Cert
> certn_2
; // second to last cert
269 nsCOMPtr
<nsIX509Cert
> certn_1
; // last cert
271 cert0
= do_QueryElementAt(x509Certs
, 0);
272 cert1
= do_QueryElementAt(x509Certs
, 1);
273 certn_2
= do_QueryElementAt(x509Certs
, numCerts
- 2);
274 certn_1
= do_QueryElementAt(x509Certs
, numCerts
- 1);
276 nsAutoString cert0SubjectName
;
277 nsAutoString cert1IssuerName
;
278 nsAutoString certn_2IssuerName
;
279 nsAutoString certn_1SubjectName
;
281 cert0
->GetSubjectName(cert0SubjectName
);
282 cert1
->GetIssuerName(cert1IssuerName
);
283 certn_2
->GetIssuerName(certn_2IssuerName
);
284 certn_1
->GetSubjectName(certn_1SubjectName
);
286 if (cert1IssuerName
.Equals(cert0SubjectName
)) {
287 // In this case, the first cert in the list signed the second,
288 // so the first cert is the root. Let's display it.
291 } else if (certn_2IssuerName
.Equals(certn_1SubjectName
)) {
292 // In this case the last cert has signed the second to last cert.
293 // The last cert is the root, so let's display it.
294 selCertIndex
= numCerts
- 1;
295 certToShow
= certn_1
;
297 // It's not a chain, so let's just show the first one in the
304 if (!certToShow
) return NS_ERROR_FAILURE
;
306 nsCOMPtr
<nsICertificateDialogs
> dialogs
;
307 nsresult rv
= ::getNSSDialogs(getter_AddRefs(dialogs
),
308 NS_GET_IID(nsICertificateDialogs
),
309 NS_CERTIFICATEDIALOGS_CONTRACTID
);
314 UniqueCERTCertificate
tmpCert(certToShow
->GetCert());
316 return NS_ERROR_FAILURE
;
319 if (!CERT_IsCACert(tmpCert
.get(), nullptr)) {
320 DisplayCertificateAlert(ctx
, "NotACACert", certToShow
);
321 return NS_ERROR_FAILURE
;
324 if (tmpCert
->isperm
) {
325 DisplayCertificateAlert(ctx
, "CaCertExists", certToShow
);
326 return NS_ERROR_FAILURE
;
331 rv
= dialogs
->ConfirmDownloadCACert(ctx
, certToShow
, &trustBits
, &allows
);
332 if (NS_FAILED(rv
)) return rv
;
334 if (!allows
) return NS_ERROR_NOT_AVAILABLE
;
336 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("trust is %d\n", trustBits
));
337 UniquePORTString
nickname(CERT_MakeCANickname(tmpCert
.get()));
339 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
340 ("Created nick \"%s\"\n", nickname
.get()));
342 nsNSSCertTrust trust
;
344 trust
.AddCATrust(!!(trustBits
& nsIX509CertDB::TRUSTED_SSL
),
345 !!(trustBits
& nsIX509CertDB::TRUSTED_EMAIL
));
347 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
348 SECStatus srv
= PK11_ImportCert(slot
.get(), tmpCert
.get(), CK_INVALID_HANDLE
,
350 false); // this parameter is ignored by NSS
351 if (srv
!= SECSuccess
) {
352 return MapSECStatus(srv
);
355 ChangeCertTrustWithPossibleAuthentication(tmpCert
, trust
.GetTrust(), ctx
);
356 if (srv
!= SECSuccess
) {
357 return MapSECStatus(srv
);
360 // Import additional delivered certificates that can be verified.
362 // build a CertList for filtering
363 UniqueCERTCertList
certList(CERT_NewCertList());
365 return NS_ERROR_FAILURE
;
368 // get all remaining certs into temp store
370 for (uint32_t i
= 0; i
< numCerts
; i
++) {
371 if (i
== selCertIndex
) {
372 // we already processed that one
376 nsCOMPtr
<nsIX509Cert
> remainingCert
= do_QueryElementAt(x509Certs
, i
);
377 if (!remainingCert
) {
381 UniqueCERTCertificate
tmpCert2(remainingCert
->GetCert());
383 continue; // Let's try to import the rest of 'em
386 if (CERT_AddCertToListTail(certList
.get(), tmpCert2
.get()) != SECSuccess
) {
390 Unused
<< tmpCert2
.release();
393 return ImportCertsIntoPermanentStorage(certList
);
396 nsresult
nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(
397 const UniqueCERTCertList
& aCertListIn
,
398 nsTArray
<RefPtr
<nsIX509Cert
>>& aCertListOut
) {
399 if (!aCertListIn
.get()) {
400 return NS_ERROR_INVALID_ARG
;
403 for (CERTCertListNode
* node
= CERT_LIST_HEAD(aCertListIn
.get());
404 !CERT_LIST_END(node
, aCertListIn
.get()); node
= CERT_LIST_NEXT(node
)) {
405 RefPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(node
->cert
);
406 aCertListOut
.AppendElement(cert
);
412 nsNSSCertificateDB::ImportCertificates(uint8_t* data
, uint32_t length
,
414 nsIInterfaceRequestor
* ctx
) {
415 // We currently only handle CA certificates.
416 if (type
!= nsIX509Cert::CA_CERT
) {
417 return NS_ERROR_FAILURE
;
420 nsTArray
<nsTArray
<uint8_t>> certsArray
;
421 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
426 nsCOMPtr
<nsIMutableArray
> array
= nsArrayBase::Create();
428 return NS_ERROR_FAILURE
;
431 // Now let's create some certs to work with
432 for (nsTArray
<uint8_t>& certDER
: certsArray
) {
433 nsCOMPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(std::move(certDER
));
434 nsresult rv
= array
->AppendElement(cert
);
440 return handleCACertDownload(WrapNotNull(array
), ctx
);
444 * Decodes a given array of DER-encoded certificates into temporary storage.
447 * Array in which the decoded certificates are stored as arrays of
449 * @param temporaryCerts
450 * List of decoded certificates.
452 static nsresult
ImportCertsIntoTempStorage(
453 nsTArray
<nsTArray
<uint8_t>>& certs
,
454 /*out*/ const UniqueCERTCertList
& temporaryCerts
) {
455 NS_ENSURE_ARG_POINTER(temporaryCerts
);
457 for (nsTArray
<uint8_t>& certDER
: certs
) {
458 CERTCertificate
* certificate
;
460 certItem
.len
= certDER
.Length();
461 certItem
.data
= certDER
.Elements();
462 certificate
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certItem
,
463 nullptr, false, true);
465 UniqueCERTCertificate
cert(certificate
);
470 if (CERT_AddCertToListTail(temporaryCerts
.get(), cert
.get()) ==
472 Unused
<< cert
.release();
480 nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data
, uint32_t length
,
481 nsIInterfaceRequestor
* ctx
) {
482 nsTArray
<nsTArray
<uint8_t>> certsArray
;
484 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
489 UniqueCERTCertList
temporaryCerts(CERT_NewCertList());
490 if (!temporaryCerts
) {
491 return NS_ERROR_FAILURE
;
494 rv
= ImportCertsIntoTempStorage(certsArray
, temporaryCerts
);
499 return ImportCertsIntoPermanentStorage(temporaryCerts
);
502 nsresult
nsNSSCertificateDB::ImportCACerts(nsTArray
<nsTArray
<uint8_t>>& caCerts
,
503 nsIInterfaceRequestor
* ctx
) {
504 UniqueCERTCertList
temporaryCerts(CERT_NewCertList());
505 if (!temporaryCerts
) {
506 return NS_ERROR_FAILURE
;
509 nsresult rv
= ImportCertsIntoTempStorage(caCerts
, temporaryCerts
);
514 return ImportCertsIntoPermanentStorage(temporaryCerts
);
517 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor
* ctx
,
518 const char* stringID
,
519 nsIX509Cert
* certToShow
) {
520 if (!NS_IsMainThread()) {
522 "nsNSSCertificateDB::DisplayCertificateAlert called off the main "
527 nsCOMPtr
<nsIInterfaceRequestor
> my_ctx
= ctx
;
529 my_ctx
= new PipUIContext();
532 // This shall be replaced by embedding ovverridable prompts
533 // as discussed in bug 310446, and should make use of certToShow.
535 nsAutoString tmpMessage
;
536 GetPIPNSSBundleString(stringID
, tmpMessage
);
537 nsCOMPtr
<nsIPrompt
> prompt(do_GetInterface(my_ctx
));
542 prompt
->Alert(nullptr, tmpMessage
.get());
546 nsNSSCertificateDB::ImportUserCertificate(uint8_t* data
, uint32_t length
,
547 nsIInterfaceRequestor
* ctx
) {
548 if (!NS_IsMainThread()) {
550 "nsNSSCertificateDB::ImportUserCertificate called off the main thread");
551 return NS_ERROR_NOT_SAME_THREAD
;
554 nsTArray
<nsTArray
<uint8_t>> certsArray
;
556 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
563 if (certsArray
.IsEmpty()) {
567 certItem
.len
= certsArray
.ElementAt(0).Length();
568 certItem
.data
= certsArray
.ElementAt(0).Elements();
570 UniqueCERTCertificate
cert(CERT_NewTempCertificate(
571 CERT_GetDefaultCertDB(), &certItem
, nullptr, false, true));
573 return NS_ERROR_FAILURE
;
576 UniquePK11SlotInfo
slot(PK11_KeyForCertExists(cert
.get(), nullptr, ctx
));
578 nsCOMPtr
<nsIX509Cert
> certToShow
= new nsNSSCertificate(cert
.get());
579 DisplayCertificateAlert(ctx
, "UserCertIgnoredNoPrivateKey", certToShow
);
580 return NS_ERROR_FAILURE
;
584 /* pick a nickname for the cert */
585 nsAutoCString nickname
;
586 if (cert
->nickname
) {
587 nickname
= cert
->nickname
;
589 get_default_nickname(cert
.get(), ctx
, nickname
);
592 /* user wants to import the cert */
593 slot
.reset(PK11_ImportCertForKey(cert
.get(), nickname
.get(), ctx
));
595 return NS_ERROR_FAILURE
;
600 nsCOMPtr
<nsIX509Cert
> certToShow
= new nsNSSCertificate(cert
.get());
601 DisplayCertificateAlert(ctx
, "UserCertImported", certToShow
);
605 if (!certsArray
.IsEmpty()) {
606 certsArray
.RemoveElementAt(0);
607 rv
= ImportCACerts(certsArray
, ctx
);
610 nsCOMPtr
<nsIObserverService
> observerService
=
611 mozilla::services::GetObserverService();
612 if (observerService
) {
613 observerService
->NotifyObservers(nullptr, "psm:user-certificate-added",
621 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert
* aCert
) {
622 NS_ENSURE_ARG_POINTER(aCert
);
623 UniqueCERTCertificate
cert(aCert
->GetCert());
625 return NS_ERROR_FAILURE
;
628 // Temporary certificates aren't on a slot and will go away when the
629 // nsIX509Cert is destructed.
632 nsresult rv
= aCert
->GetCertType(&certType
);
633 if (NS_WARN_IF(NS_FAILED(rv
))) {
636 if (certType
== nsIX509Cert::USER_CERT
) {
637 SECStatus srv
= PK11_Authenticate(cert
->slot
, true, nullptr);
638 if (srv
!= SECSuccess
) {
639 return NS_ERROR_FAILURE
;
641 srv
= PK11_DeleteTokenCertAndKey(cert
.get(), nullptr);
642 if (srv
!= SECSuccess
) {
643 return NS_ERROR_FAILURE
;
646 // For certificates that can't be deleted (e.g. built-in roots), un-set
648 nsNSSCertTrust
trust(0, 0);
649 SECStatus srv
= ChangeCertTrustWithPossibleAuthentication(
650 cert
, trust
.GetTrust(), nullptr);
651 if (srv
!= SECSuccess
) {
652 return NS_ERROR_FAILURE
;
654 if (!PK11_IsReadOnly(cert
->slot
)) {
655 srv
= SEC_DeletePermCertificate(cert
.get());
656 if (srv
!= SECSuccess
) {
657 return NS_ERROR_FAILURE
;
663 nsCOMPtr
<nsIObserverService
> observerService
=
664 mozilla::services::GetObserverService();
665 if (observerService
) {
666 observerService
->NotifyObservers(nullptr, "psm:user-certificate-deleted",
674 nsNSSCertificateDB::SetCertTrust(nsIX509Cert
* cert
, uint32_t type
,
676 NS_ENSURE_ARG_POINTER(cert
);
677 nsNSSCertTrust trust
;
679 case nsIX509Cert::CA_CERT
:
681 trust
.AddCATrust(!!(trusted
& nsIX509CertDB::TRUSTED_SSL
),
682 !!(trusted
& nsIX509CertDB::TRUSTED_EMAIL
));
684 case nsIX509Cert::SERVER_CERT
:
685 trust
.SetValidPeer();
686 trust
.AddPeerTrust(trusted
& nsIX509CertDB::TRUSTED_SSL
, false);
688 case nsIX509Cert::EMAIL_CERT
:
689 trust
.SetValidPeer();
690 trust
.AddPeerTrust(false, !!(trusted
& nsIX509CertDB::TRUSTED_EMAIL
));
693 // Ignore any other type of certificate (including invalid types).
697 UniqueCERTCertificate
nsscert(cert
->GetCert());
698 SECStatus srv
= ChangeCertTrustWithPossibleAuthentication(
699 nsscert
, trust
.GetTrust(), nullptr);
700 return MapSECStatus(srv
);
704 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert
* cert
, uint32_t certType
,
705 uint32_t trustType
, bool* _isTrusted
) {
706 NS_ENSURE_ARG_POINTER(_isTrusted
);
709 nsresult rv
= BlockUntilLoadableCertsLoaded();
715 UniqueCERTCertificate
nsscert(cert
->GetCert());
716 CERTCertTrust nsstrust
;
717 srv
= CERT_GetCertTrust(nsscert
.get(), &nsstrust
);
718 if (srv
!= SECSuccess
) {
719 // CERT_GetCertTrust returns SECFailure if given a temporary cert that
720 // doesn't have any trust information yet. This isn't an error.
724 nsNSSCertTrust
trust(&nsstrust
);
725 if (certType
== nsIX509Cert::CA_CERT
) {
726 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
727 *_isTrusted
= trust
.HasTrustedCA(true, false);
728 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
729 *_isTrusted
= trust
.HasTrustedCA(false, true);
731 return NS_ERROR_FAILURE
;
733 } else if (certType
== nsIX509Cert::SERVER_CERT
) {
734 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
735 *_isTrusted
= trust
.HasTrustedPeer(true, false);
736 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
737 *_isTrusted
= trust
.HasTrustedPeer(false, true);
739 return NS_ERROR_FAILURE
;
741 } else if (certType
== nsIX509Cert::EMAIL_CERT
) {
742 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
743 *_isTrusted
= trust
.HasTrustedPeer(true, false);
744 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
745 *_isTrusted
= trust
.HasTrustedPeer(false, true);
747 return NS_ERROR_FAILURE
;
754 nsNSSCertificateDB::ImportCertsFromFile(nsIFile
* aFile
, uint32_t aType
) {
755 NS_ENSURE_ARG(aFile
);
757 case nsIX509Cert::CA_CERT
:
758 case nsIX509Cert::EMAIL_CERT
:
763 // not supported (yet)
764 return NS_ERROR_FAILURE
;
767 PRFileDesc
* fd
= nullptr;
768 nsresult rv
= aFile
->OpenNSPRFileDesc(PR_RDONLY
, 0, &fd
);
773 return NS_ERROR_FAILURE
;
777 if (PR_GetOpenFileInfo(fd
, &fileInfo
) != PR_SUCCESS
) {
778 return NS_ERROR_FAILURE
;
781 auto buf
= MakeUnique
<unsigned char[]>(fileInfo
.size
);
782 int32_t bytesObtained
= PR_Read(fd
, buf
.get(), fileInfo
.size
);
785 if (bytesObtained
!= fileInfo
.size
) {
786 return NS_ERROR_FAILURE
;
789 nsCOMPtr
<nsIInterfaceRequestor
> cxt
= new PipUIContext();
792 case nsIX509Cert::CA_CERT
:
793 return ImportCertificates(buf
.get(), bytesObtained
, aType
, cxt
);
794 case nsIX509Cert::EMAIL_CERT
:
795 return ImportEmailCertificate(buf
.get(), bytesObtained
, cxt
);
797 MOZ_ASSERT(false, "Unsupported type should have been filtered out");
801 return NS_ERROR_FAILURE
;
805 nsNSSCertificateDB::ImportPKCS12File(nsIFile
* aFile
, const nsAString
& aPassword
,
807 if (!NS_IsMainThread()) {
808 return NS_ERROR_NOT_SAME_THREAD
;
810 nsresult rv
= BlockUntilLoadableCertsLoaded();
815 NS_ENSURE_ARG(aFile
);
817 rv
= blob
.ImportFromFile(aFile
, aPassword
, *aError
);
818 nsCOMPtr
<nsIObserverService
> observerService
=
819 mozilla::services::GetObserverService();
820 if (NS_SUCCEEDED(rv
) && observerService
) {
821 observerService
->NotifyObservers(nullptr, "psm:user-certificate-added",
829 nsNSSCertificateDB::ExportPKCS12File(
830 nsIFile
* aFile
, const nsTArray
<RefPtr
<nsIX509Cert
>>& aCerts
,
831 const nsAString
& aPassword
, uint32_t* aError
) {
832 if (!NS_IsMainThread()) {
833 return NS_ERROR_NOT_SAME_THREAD
;
835 nsresult rv
= BlockUntilLoadableCertsLoaded();
840 NS_ENSURE_ARG(aFile
);
841 if (aCerts
.IsEmpty()) {
845 return blob
.ExportToFile(aFile
, aCerts
, aPassword
, *aError
);
849 nsNSSCertificateDB::ConstructX509FromBase64(const nsACString
& base64
,
850 /*out*/ nsIX509Cert
** _retval
) {
852 return NS_ERROR_INVALID_POINTER
;
855 // Base64Decode() doesn't consider a zero length input as an error, and just
856 // returns the empty string. We don't want this behavior, so the below check
857 // catches this case.
858 if (base64
.Length() < 1) {
859 return NS_ERROR_ILLEGAL_VALUE
;
862 nsAutoCString certDER
;
863 nsresult rv
= Base64Decode(base64
, certDER
);
868 return ConstructX509FromSpan(AsBytes(Span(certDER
)), _retval
);
872 nsNSSCertificateDB::ConstructX509(const nsTArray
<uint8_t>& certDER
,
873 nsIX509Cert
** _retval
) {
874 return ConstructX509FromSpan(Span(certDER
.Elements(), certDER
.Length()),
878 nsresult
nsNSSCertificateDB::ConstructX509FromSpan(
879 Span
<const uint8_t> aInputSpan
, nsIX509Cert
** _retval
) {
880 if (NS_WARN_IF(!_retval
)) {
881 return NS_ERROR_INVALID_POINTER
;
884 if (aInputSpan
.Length() > std::numeric_limits
<unsigned int>::max()) {
885 return NS_ERROR_ILLEGAL_VALUE
;
889 certData
.type
= siDERCertBuffer
;
890 certData
.data
= const_cast<unsigned char*>(
891 reinterpret_cast<const unsigned char*>(aInputSpan
.Elements()));
892 certData
.len
= aInputSpan
.Length();
894 UniqueCERTCertificate
cert(CERT_NewTempCertificate(
895 CERT_GetDefaultCertDB(), &certData
, nullptr, false, true));
897 return (PORT_GetError() == SEC_ERROR_NO_MEMORY
) ? NS_ERROR_OUT_OF_MEMORY
900 nsCOMPtr
<nsIX509Cert
> nssCert
= new nsNSSCertificate(cert
.get());
901 nssCert
.forget(_retval
);
905 void nsNSSCertificateDB::get_default_nickname(CERTCertificate
* cert
,
906 nsIInterfaceRequestor
* ctx
,
907 nsCString
& nickname
) {
910 CK_OBJECT_HANDLE keyHandle
;
912 if (NS_FAILED(BlockUntilLoadableCertsLoaded())) {
916 CERTCertDBHandle
* defaultcertdb
= CERT_GetDefaultCertDB();
917 nsAutoCString username
;
918 UniquePORTString
tempCN(CERT_GetCommonName(&cert
->subject
));
920 username
= tempCN
.get();
923 nsAutoCString caname
;
924 UniquePORTString
tempIssuerOrg(CERT_GetOrgName(&cert
->issuer
));
926 caname
= tempIssuerOrg
.get();
929 nsAutoString tmpNickFmt
;
930 GetPIPNSSBundleString("nick_template", tmpNickFmt
);
931 NS_ConvertUTF16toUTF8
nickFmt(tmpNickFmt
);
933 nsAutoCString baseName
;
934 baseName
.AppendPrintf(nickFmt
.get(), username
.get(), caname
.get());
935 if (baseName
.IsEmpty()) {
942 * We need to see if the private key exists on a token, if it does
943 * then we need to check for nicknames that already exist on the smart
946 UniquePK11SlotInfo
slot(PK11_KeyForCertExists(cert
, &keyHandle
, ctx
));
949 if (!PK11_IsInternal(slot
.get())) {
951 tmp
.AppendPrintf("%s:%s", PK11_GetTokenName(slot
.get()), baseName
.get());
964 tmp
.AppendPrintf("%s #%d", baseName
.get(), count
);
972 UniqueCERTCertificate dummycert
;
974 if (PK11_IsInternal(slot
.get())) {
975 /* look up the nickname to make sure it isn't in use already */
976 dummycert
.reset(CERT_FindCertByNickname(defaultcertdb
, nickname
.get()));
978 // Check the cert against others that already live on the smart card.
979 dummycert
.reset(PK11_FindCertFromNickname(nickname
.get(), ctx
));
981 // Make sure the subject names are different.
982 if (CERT_CompareName(&cert
->subject
, &dummycert
->subject
) == SECEqual
) {
984 * There is another certificate with the same nickname and
985 * the same subject name on the smart card, so let's use this
1000 nsNSSCertificateDB::AddCertFromBase64(const nsACString
& aBase64
,
1001 const nsACString
& aTrust
,
1002 nsIX509Cert
** addedCertificate
) {
1003 // Base64Decode() doesn't consider a zero length input as an error, and just
1004 // returns the empty string. We don't want this behavior, so the below check
1005 // catches this case.
1006 if (aBase64
.Length() < 1) {
1007 return NS_ERROR_ILLEGAL_VALUE
;
1010 nsAutoCString aCertDER
;
1011 nsresult rv
= Base64Decode(aBase64
, aCertDER
);
1012 if (NS_FAILED(rv
)) {
1015 return AddCert(aCertDER
, aTrust
, addedCertificate
);
1019 nsNSSCertificateDB::AddCert(const nsACString
& aCertDER
,
1020 const nsACString
& aTrust
,
1021 nsIX509Cert
** addedCertificate
) {
1022 MOZ_ASSERT(addedCertificate
);
1023 if (!addedCertificate
) {
1024 return NS_ERROR_INVALID_ARG
;
1026 *addedCertificate
= nullptr;
1028 nsNSSCertTrust trust
;
1029 if (CERT_DecodeTrustString(&trust
.GetTrust(),
1030 PromiseFlatCString(aTrust
).get()) != SECSuccess
) {
1031 return NS_ERROR_FAILURE
;
1034 nsCOMPtr
<nsIX509Cert
> newCert
;
1036 ConstructX509FromSpan(AsBytes(Span(aCertDER
)), getter_AddRefs(newCert
));
1037 if (NS_FAILED(rv
)) {
1041 UniqueCERTCertificate
tmpCert(newCert
->GetCert());
1043 return NS_ERROR_FAILURE
;
1046 // If there's already a certificate that matches this one in the database, we
1047 // still want to set its trust to the given value.
1048 if (tmpCert
->isperm
) {
1049 rv
= SetCertTrustFromString(newCert
, aTrust
);
1050 if (NS_FAILED(rv
)) {
1053 newCert
.forget(addedCertificate
);
1057 UniquePORTString
nickname(CERT_MakeCANickname(tmpCert
.get()));
1059 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1060 ("Created nick \"%s\"\n", nickname
.get()));
1062 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
1063 SECStatus srv
= PK11_ImportCert(slot
.get(), tmpCert
.get(), CK_INVALID_HANDLE
,
1065 false); // this parameter is ignored by NSS
1066 if (srv
!= SECSuccess
) {
1067 return MapSECStatus(srv
);
1069 srv
= ChangeCertTrustWithPossibleAuthentication(tmpCert
, trust
.GetTrust(),
1071 if (srv
!= SECSuccess
) {
1072 return MapSECStatus(srv
);
1074 newCert
.forget(addedCertificate
);
1079 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert
* cert
,
1080 const nsACString
& trustString
) {
1081 NS_ENSURE_ARG(cert
);
1083 CERTCertTrust trust
;
1085 CERT_DecodeTrustString(&trust
, PromiseFlatCString(trustString
).get());
1086 if (srv
!= SECSuccess
) {
1087 return MapSECStatus(srv
);
1089 UniqueCERTCertificate
nssCert(cert
->GetCert());
1091 srv
= ChangeCertTrustWithPossibleAuthentication(nssCert
, trust
, nullptr);
1092 return MapSECStatus(srv
);
1095 NS_IMETHODIMP
nsNSSCertificateDB::AsPKCS7Blob(
1096 const nsTArray
<RefPtr
<nsIX509Cert
>>& certList
, nsACString
& _retval
) {
1097 if (certList
.IsEmpty()) {
1098 return NS_ERROR_INVALID_ARG
;
1101 UniqueNSSCMSMessage
cmsg(NSS_CMSMessage_Create(nullptr));
1103 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1104 ("nsNSSCertificateDB::AsPKCS7Blob - can't create CMS message"));
1105 return NS_ERROR_OUT_OF_MEMORY
;
1108 UniqueNSSCMSSignedData
sigd(nullptr);
1109 for (const auto& cert
: certList
) {
1110 // We need an owning handle when calling nsIX509Cert::GetCert().
1111 UniqueCERTCertificate
nssCert(cert
->GetCert());
1114 NSS_CMSSignedData_CreateCertsOnly(cmsg
.get(), nssCert
.get(), false));
1116 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1117 ("nsNSSCertificateDB::AsPKCS7Blob - can't create SignedData"));
1118 return NS_ERROR_FAILURE
;
1120 } else if (NSS_CMSSignedData_AddCertificate(sigd
.get(), nssCert
.get()) !=
1122 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1123 ("nsNSSCertificateDB::AsPKCS7Blob - can't add cert"));
1124 return NS_ERROR_FAILURE
;
1128 NSSCMSContentInfo
* cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
.get());
1129 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg
.get(), cinfo
, sigd
.get()) !=
1131 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1132 ("nsNSSCertificateDB::AsPKCS7Blob - can't attach SignedData"));
1133 return NS_ERROR_FAILURE
;
1135 // cmsg owns sigd now.
1136 Unused
<< sigd
.release();
1138 UniquePLArenaPool
arena(PORT_NewArena(1024));
1140 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1141 ("nsNSSCertificateDB::AsPKCS7Blob - out of memory"));
1142 return NS_ERROR_OUT_OF_MEMORY
;
1145 SECItem certP7
= {siBuffer
, nullptr, 0};
1146 NSSCMSEncoderContext
* ecx
= NSS_CMSEncoder_Start(
1147 cmsg
.get(), nullptr, nullptr, &certP7
, arena
.get(), nullptr, nullptr,
1148 nullptr, nullptr, nullptr, nullptr);
1150 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1151 ("nsNSSCertificateDB::AsPKCS7Blob - can't create encoder"));
1152 return NS_ERROR_FAILURE
;
1155 if (NSS_CMSEncoder_Finish(ecx
) != SECSuccess
) {
1156 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1157 ("nsNSSCertificateDB::AsPKCS7Blob - failed to add encoded data"));
1158 return NS_ERROR_FAILURE
;
1161 _retval
.Assign(nsDependentCSubstring(
1162 reinterpret_cast<const char*>(certP7
.data
), certP7
.len
));
1167 nsNSSCertificateDB::GetCerts(nsTArray
<RefPtr
<nsIX509Cert
>>& _retval
) {
1168 nsresult rv
= BlockUntilLoadableCertsLoaded();
1169 if (NS_FAILED(rv
)) {
1173 rv
= CheckForSmartCardChanges();
1174 if (NS_FAILED(rv
)) {
1178 nsCOMPtr
<nsIInterfaceRequestor
> ctx
= new PipUIContext();
1179 UniqueCERTCertList
certList(PK11_ListCerts(PK11CertListUnique
, ctx
));
1181 return NS_ERROR_FAILURE
;
1183 return nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(certList
,
1187 nsresult
IsCertBuiltInRoot(const RefPtr
<nsIX509Cert
>& cert
,
1188 bool& isBuiltInRoot
) {
1189 nsTArray
<uint8_t> der
;
1190 nsresult rv
= cert
->GetRawDER(der
);
1191 if (NS_FAILED(rv
)) {
1194 pkix::Input certInput
;
1195 pkix::Result result
= certInput
.Init(der
.Elements(), der
.Length());
1196 if (result
!= pkix::Result::Success
) {
1197 return NS_ERROR_FAILURE
;
1199 result
= IsCertBuiltInRoot(certInput
, isBuiltInRoot
);
1200 if (result
!= pkix::Result::Success
) {
1201 return NS_ERROR_FAILURE
;
1207 nsNSSCertificateDB::AsyncHasThirdPartyRoots(nsIAsyncBoolCallback
* aCallback
) {
1208 NS_ENSURE_ARG_POINTER(aCallback
);
1209 nsMainThreadPtrHandle
<nsIAsyncBoolCallback
> callback(
1210 new nsMainThreadPtrHolder
<nsIAsyncBoolCallback
>("AsyncHasThirdPartyRoots",
1213 return NS_DispatchBackgroundTask(
1214 NS_NewRunnableFunction(
1215 "nsNSSCertificateDB::AsyncHasThirdPartyRoots",
1216 [cb
= std::move(callback
), self
= RefPtr
{this}] {
1217 bool hasThirdPartyRoots
= [self
]() -> bool {
1218 nsTArray
<RefPtr
<nsIX509Cert
>> certs
;
1219 nsresult rv
= self
->GetCerts(certs
);
1220 if (NS_FAILED(rv
)) {
1224 for (const auto& cert
: certs
) {
1225 bool isTrusted
= false;
1227 self
->IsCertTrusted(cert
, nsIX509Cert::CA_CERT
,
1228 nsIX509CertDB::TRUSTED_SSL
, &isTrusted
);
1229 if (NS_FAILED(rv
)) {
1237 bool isBuiltInRoot
= false;
1238 rv
= IsCertBuiltInRoot(cert
, isBuiltInRoot
);
1239 if (NS_FAILED(rv
)) {
1243 if (!isBuiltInRoot
) {
1251 NS_DispatchToMainThread(NS_NewRunnableFunction(
1252 "nsNSSCertificateDB::AsyncHasThirdPartyRoots callback",
1253 [cb
, hasThirdPartyRoots
]() {
1254 cb
->OnResult(hasThirdPartyRoots
);
1257 NS_DISPATCH_EVENT_MAY_BLOCK
);
1260 nsresult
VerifyCertAtTime(nsIX509Cert
* aCert
,
1261 int64_t /*SECCertificateUsage*/ aUsage
,
1262 uint32_t aFlags
, const nsACString
& aHostname
,
1263 mozilla::pkix::Time aTime
,
1264 nsTArray
<RefPtr
<nsIX509Cert
>>& aVerifiedChain
,
1266 int32_t* /*PRErrorCode*/ _retval
) {
1267 NS_ENSURE_ARG_POINTER(aCert
);
1268 NS_ENSURE_ARG_POINTER(aHasEVPolicy
);
1269 NS_ENSURE_ARG_POINTER(_retval
);
1271 if (!aVerifiedChain
.IsEmpty()) {
1272 return NS_ERROR_INVALID_ARG
;
1275 *aHasEVPolicy
= false;
1276 *_retval
= PR_UNKNOWN_ERROR
;
1278 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
1279 NS_ENSURE_TRUE(certVerifier
, NS_ERROR_FAILURE
);
1281 nsTArray
<nsTArray
<uint8_t>> resultChain
;
1283 mozilla::pkix::Result result
;
1285 nsTArray
<uint8_t> certBytes
;
1286 nsresult nsrv
= aCert
->GetRawDER(certBytes
);
1287 if (NS_FAILED(nsrv
)) {
1291 if (!aHostname
.IsVoid() && aUsage
== certificateUsageSSLServer
) {
1293 certVerifier
->VerifySSLServerCert(certBytes
, aTime
,
1294 nullptr, // Assume no context
1295 aHostname
, resultChain
, aFlags
,
1296 Nothing(), // extraCertificates
1297 Nothing(), // stapledOCSPResponse
1298 Nothing(), // sctsFromTLSExtension
1299 Nothing(), // dcInfo
1300 OriginAttributes(), &evStatus
);
1302 const nsCString
& flatHostname
= PromiseFlatCString(aHostname
);
1303 result
= certVerifier
->VerifyCert(
1304 certBytes
, aUsage
, aTime
,
1305 nullptr, // Assume no context
1306 aHostname
.IsVoid() ? nullptr : flatHostname
.get(), resultChain
, aFlags
,
1307 Nothing(), // extraCertificates
1308 Nothing(), // stapledOCSPResponse
1309 Nothing(), // sctsFromTLSExtension
1310 OriginAttributes(), &evStatus
);
1313 if (result
== mozilla::pkix::Success
) {
1314 for (auto& certDER
: resultChain
) {
1315 RefPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(std::move(certDER
));
1316 aVerifiedChain
.AppendElement(cert
);
1319 if (evStatus
== EVStatus::EV
) {
1320 *aHasEVPolicy
= true;
1324 *_retval
= mozilla::pkix::MapResultToPRErrorCode(result
);
1329 class VerifyCertAtTimeTask final
: public CryptoTask
{
1331 VerifyCertAtTimeTask(nsIX509Cert
* aCert
, int64_t aUsage
, uint32_t aFlags
,
1332 const nsACString
& aHostname
, uint64_t aTime
,
1333 nsICertVerificationCallback
* aCallback
)
1337 mHostname(aHostname
),
1339 mCallback(new nsMainThreadPtrHolder
<nsICertVerificationCallback
>(
1340 "nsICertVerificationCallback", aCallback
)),
1341 mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE
),
1342 mHasEVPolicy(false) {}
1345 virtual nsresult
CalculateResult() override
{
1346 nsCOMPtr
<nsIX509CertDB
> certDB
= do_GetService(NS_X509CERTDB_CONTRACTID
);
1348 return NS_ERROR_FAILURE
;
1350 return VerifyCertAtTime(mCert
, mUsage
, mFlags
, mHostname
,
1351 mozilla::pkix::TimeFromEpochInSeconds(mTime
),
1352 mVerifiedCertList
, &mHasEVPolicy
, &mPRErrorCode
);
1355 virtual void CallCallback(nsresult rv
) override
{
1356 if (NS_FAILED(rv
)) {
1357 nsTArray
<RefPtr
<nsIX509Cert
>> tmp
;
1358 Unused
<< mCallback
->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE
, tmp
,
1361 Unused
<< mCallback
->VerifyCertFinished(mPRErrorCode
, mVerifiedCertList
,
1366 nsCOMPtr
<nsIX509Cert
> mCert
;
1369 nsCString mHostname
;
1371 nsMainThreadPtrHandle
<nsICertVerificationCallback
> mCallback
;
1372 int32_t mPRErrorCode
;
1373 nsTArray
<RefPtr
<nsIX509Cert
>> mVerifiedCertList
;
1378 nsNSSCertificateDB::AsyncVerifyCertAtTime(
1379 nsIX509Cert
* aCert
, int64_t /*SECCertificateUsage*/ aUsage
, uint32_t aFlags
,
1380 const nsACString
& aHostname
, uint64_t aTime
,
1381 nsICertVerificationCallback
* aCallback
) {
1382 RefPtr
<VerifyCertAtTimeTask
> task(new VerifyCertAtTimeTask(
1383 aCert
, aUsage
, aFlags
, aHostname
, aTime
, aCallback
));
1384 return task
->Dispatch();
1388 nsNSSCertificateDB::ClearOCSPCache() {
1389 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
1390 NS_ENSURE_TRUE(certVerifier
, NS_ERROR_FAILURE
);
1391 certVerifier
->ClearOCSPCache();