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);
194 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
196 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
200 // NSS ignores the first argument to CERT_ChangeCertTrust
201 SECStatus srv
= CERT_ChangeCertTrust(nullptr, cert
.get(), &trust
);
202 if (srv
!= SECSuccess
&& PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN
) {
205 if (srv
== SECSuccess
) {
206 certVerifier
->ClearTrustCache();
210 // CERT_ChangeCertTrust failed with SEC_ERROR_TOKEN_NOT_LOGGED_IN, so
211 // authenticate and try again.
213 // If this certificate is on an external PKCS#11 token, we have to
214 // authenticate to that token.
215 srv
= PK11_Authenticate(cert
->slot
, PR_TRUE
, ctx
);
217 // Otherwise, the certificate is on the internal module.
218 UniquePK11SlotInfo
internalSlot(PK11_GetInternalKeySlot());
219 srv
= PK11_Authenticate(internalSlot
.get(), PR_TRUE
, ctx
);
221 if (srv
!= SECSuccess
) {
224 srv
= CERT_ChangeCertTrust(nullptr, cert
.get(), &trust
);
225 if (srv
!= SECSuccess
) {
229 certVerifier
->ClearTrustCache();
233 static nsresult
ImportCertsIntoPermanentStorage(
234 const UniqueCERTCertList
& certChain
) {
235 bool encounteredFailure
= false;
236 PRErrorCode savedErrorCode
= 0;
237 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
238 for (CERTCertListNode
* chainNode
= CERT_LIST_HEAD(certChain
);
239 !CERT_LIST_END(chainNode
, certChain
);
240 chainNode
= CERT_LIST_NEXT(chainNode
)) {
241 UniquePORTString
nickname(CERT_MakeCANickname(chainNode
->cert
));
242 SECStatus srv
= PK11_ImportCert(slot
.get(), chainNode
->cert
,
243 CK_INVALID_HANDLE
, nickname
.get(),
244 false); // this parameter is ignored by NSS
245 if (srv
!= SECSuccess
) {
246 encounteredFailure
= true;
247 savedErrorCode
= PR_GetError();
251 if (encounteredFailure
) {
252 return GetXPCOMFromNSSError(savedErrorCode
);
258 nsresult
nsNSSCertificateDB::handleCACertDownload(NotNull
<nsIArray
*> x509Certs
,
259 nsIInterfaceRequestor
* ctx
) {
260 // First thing we have to do is figure out which certificate we're
261 // gonna present to the user. The CA may have sent down a list of
262 // certs which may or may not be a chained list of certs. Until
263 // the day we can design some solid UI for the general case, we'll
264 // code to the > 90% case. That case is where a CA sends down a
265 // list that is a hierarchy whose root is either the first or
266 // the last cert. What we're gonna do is compare the first
267 // 2 entries, if the second was signed by the first, we assume
268 // the root cert is the first cert and display it. Otherwise,
269 // we compare the last 2 entries, if the second to last cert was
270 // signed by the last cert, then we assume the last cert is the
271 // root and display it.
275 x509Certs
->GetLength(&numCerts
);
277 if (numCerts
== 0) return NS_OK
; // Nothing to import, so nothing to do.
279 nsCOMPtr
<nsIX509Cert
> certToShow
;
280 uint32_t selCertIndex
;
282 // There's only one cert, so let's show it.
284 certToShow
= do_QueryElementAt(x509Certs
, selCertIndex
);
286 nsCOMPtr
<nsIX509Cert
> cert0
; // first cert
287 nsCOMPtr
<nsIX509Cert
> cert1
; // second cert
288 nsCOMPtr
<nsIX509Cert
> certn_2
; // second to last cert
289 nsCOMPtr
<nsIX509Cert
> certn_1
; // last cert
291 cert0
= do_QueryElementAt(x509Certs
, 0);
292 cert1
= do_QueryElementAt(x509Certs
, 1);
293 certn_2
= do_QueryElementAt(x509Certs
, numCerts
- 2);
294 certn_1
= do_QueryElementAt(x509Certs
, numCerts
- 1);
296 nsAutoString cert0SubjectName
;
297 nsAutoString cert1IssuerName
;
298 nsAutoString certn_2IssuerName
;
299 nsAutoString certn_1SubjectName
;
301 cert0
->GetSubjectName(cert0SubjectName
);
302 cert1
->GetIssuerName(cert1IssuerName
);
303 certn_2
->GetIssuerName(certn_2IssuerName
);
304 certn_1
->GetSubjectName(certn_1SubjectName
);
306 if (cert1IssuerName
.Equals(cert0SubjectName
)) {
307 // In this case, the first cert in the list signed the second,
308 // so the first cert is the root. Let's display it.
311 } else if (certn_2IssuerName
.Equals(certn_1SubjectName
)) {
312 // In this case the last cert has signed the second to last cert.
313 // The last cert is the root, so let's display it.
314 selCertIndex
= numCerts
- 1;
315 certToShow
= certn_1
;
317 // It's not a chain, so let's just show the first one in the
324 if (!certToShow
) return NS_ERROR_FAILURE
;
326 nsCOMPtr
<nsICertificateDialogs
> dialogs
;
327 nsresult rv
= ::getNSSDialogs(getter_AddRefs(dialogs
),
328 NS_GET_IID(nsICertificateDialogs
),
329 NS_CERTIFICATEDIALOGS_CONTRACTID
);
334 UniqueCERTCertificate
tmpCert(certToShow
->GetCert());
336 return NS_ERROR_FAILURE
;
339 if (!CERT_IsCACert(tmpCert
.get(), nullptr)) {
340 DisplayCertificateAlert(ctx
, "NotACACert", certToShow
);
341 return NS_ERROR_FAILURE
;
344 if (tmpCert
->isperm
) {
345 DisplayCertificateAlert(ctx
, "CaCertExists", certToShow
);
346 return NS_ERROR_FAILURE
;
351 rv
= dialogs
->ConfirmDownloadCACert(ctx
, certToShow
, &trustBits
, &allows
);
352 if (NS_FAILED(rv
)) return rv
;
354 if (!allows
) return NS_ERROR_NOT_AVAILABLE
;
356 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("trust is %d\n", trustBits
));
357 UniquePORTString
nickname(CERT_MakeCANickname(tmpCert
.get()));
359 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
360 ("Created nick \"%s\"\n", nickname
.get()));
362 nsNSSCertTrust trust
;
364 trust
.AddCATrust(!!(trustBits
& nsIX509CertDB::TRUSTED_SSL
),
365 !!(trustBits
& nsIX509CertDB::TRUSTED_EMAIL
));
367 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
368 SECStatus srv
= PK11_ImportCert(slot
.get(), tmpCert
.get(), CK_INVALID_HANDLE
,
370 false); // this parameter is ignored by NSS
371 if (srv
!= SECSuccess
) {
372 return MapSECStatus(srv
);
375 ChangeCertTrustWithPossibleAuthentication(tmpCert
, trust
.GetTrust(), ctx
);
376 if (srv
!= SECSuccess
) {
377 return MapSECStatus(srv
);
380 // Import additional delivered certificates that can be verified.
382 // build a CertList for filtering
383 UniqueCERTCertList
certList(CERT_NewCertList());
385 return NS_ERROR_FAILURE
;
388 // get all remaining certs into temp store
390 for (uint32_t i
= 0; i
< numCerts
; i
++) {
391 if (i
== selCertIndex
) {
392 // we already processed that one
396 nsCOMPtr
<nsIX509Cert
> remainingCert
= do_QueryElementAt(x509Certs
, i
);
397 if (!remainingCert
) {
401 UniqueCERTCertificate
tmpCert2(remainingCert
->GetCert());
403 continue; // Let's try to import the rest of 'em
406 if (CERT_AddCertToListTail(certList
.get(), tmpCert2
.get()) != SECSuccess
) {
410 Unused
<< tmpCert2
.release();
413 return ImportCertsIntoPermanentStorage(certList
);
416 nsresult
nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(
417 const UniqueCERTCertList
& aCertListIn
,
418 nsTArray
<RefPtr
<nsIX509Cert
>>& aCertListOut
) {
419 if (!aCertListIn
.get()) {
420 return NS_ERROR_INVALID_ARG
;
423 for (CERTCertListNode
* node
= CERT_LIST_HEAD(aCertListIn
.get());
424 !CERT_LIST_END(node
, aCertListIn
.get()); node
= CERT_LIST_NEXT(node
)) {
425 RefPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(node
->cert
);
426 aCertListOut
.AppendElement(cert
);
432 nsNSSCertificateDB::ImportCertificates(uint8_t* data
, uint32_t length
,
434 nsIInterfaceRequestor
* ctx
) {
435 // We currently only handle CA certificates.
436 if (type
!= nsIX509Cert::CA_CERT
) {
437 return NS_ERROR_FAILURE
;
440 nsTArray
<nsTArray
<uint8_t>> certsArray
;
441 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
446 nsCOMPtr
<nsIMutableArray
> array
= nsArrayBase::Create();
448 return NS_ERROR_FAILURE
;
451 // Now let's create some certs to work with
452 for (nsTArray
<uint8_t>& certDER
: certsArray
) {
453 nsCOMPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(std::move(certDER
));
454 nsresult rv
= array
->AppendElement(cert
);
460 return handleCACertDownload(WrapNotNull(array
), ctx
);
464 * Decodes a given array of DER-encoded certificates into temporary storage.
467 * Array in which the decoded certificates are stored as arrays of
469 * @param temporaryCerts
470 * List of decoded certificates.
472 static nsresult
ImportCertsIntoTempStorage(
473 nsTArray
<nsTArray
<uint8_t>>& certs
,
474 /*out*/ const UniqueCERTCertList
& temporaryCerts
) {
475 NS_ENSURE_ARG_POINTER(temporaryCerts
);
477 for (nsTArray
<uint8_t>& certDER
: certs
) {
478 CERTCertificate
* certificate
;
480 certItem
.len
= certDER
.Length();
481 certItem
.data
= certDER
.Elements();
482 certificate
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certItem
,
483 nullptr, false, true);
485 UniqueCERTCertificate
cert(certificate
);
490 if (CERT_AddCertToListTail(temporaryCerts
.get(), cert
.get()) ==
492 Unused
<< cert
.release();
500 nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data
, uint32_t length
,
501 nsIInterfaceRequestor
* ctx
) {
502 nsTArray
<nsTArray
<uint8_t>> certsArray
;
504 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
509 UniqueCERTCertList
temporaryCerts(CERT_NewCertList());
510 if (!temporaryCerts
) {
511 return NS_ERROR_FAILURE
;
514 rv
= ImportCertsIntoTempStorage(certsArray
, temporaryCerts
);
519 return ImportCertsIntoPermanentStorage(temporaryCerts
);
522 nsresult
nsNSSCertificateDB::ImportCACerts(nsTArray
<nsTArray
<uint8_t>>& caCerts
,
523 nsIInterfaceRequestor
* ctx
) {
524 UniqueCERTCertList
temporaryCerts(CERT_NewCertList());
525 if (!temporaryCerts
) {
526 return NS_ERROR_FAILURE
;
529 nsresult rv
= ImportCertsIntoTempStorage(caCerts
, temporaryCerts
);
534 return ImportCertsIntoPermanentStorage(temporaryCerts
);
537 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor
* ctx
,
538 const char* stringID
,
539 nsIX509Cert
* certToShow
) {
540 if (!NS_IsMainThread()) {
542 "nsNSSCertificateDB::DisplayCertificateAlert called off the main "
547 nsCOMPtr
<nsIInterfaceRequestor
> my_ctx
= ctx
;
549 my_ctx
= new PipUIContext();
552 // This shall be replaced by embedding ovverridable prompts
553 // as discussed in bug 310446, and should make use of certToShow.
555 nsAutoString tmpMessage
;
556 GetPIPNSSBundleString(stringID
, tmpMessage
);
557 nsCOMPtr
<nsIPrompt
> prompt(do_GetInterface(my_ctx
));
562 prompt
->Alert(nullptr, tmpMessage
.get());
566 nsNSSCertificateDB::ImportUserCertificate(uint8_t* data
, uint32_t length
,
567 nsIInterfaceRequestor
* ctx
) {
568 if (!NS_IsMainThread()) {
570 "nsNSSCertificateDB::ImportUserCertificate called off the main thread");
571 return NS_ERROR_NOT_SAME_THREAD
;
574 nsTArray
<nsTArray
<uint8_t>> certsArray
;
576 nsresult rv
= getCertsFromPackage(certsArray
, data
, length
);
583 if (certsArray
.IsEmpty()) {
587 certItem
.len
= certsArray
.ElementAt(0).Length();
588 certItem
.data
= certsArray
.ElementAt(0).Elements();
590 UniqueCERTCertificate
cert(CERT_NewTempCertificate(
591 CERT_GetDefaultCertDB(), &certItem
, nullptr, false, true));
593 return NS_ERROR_FAILURE
;
596 UniquePK11SlotInfo
slot(PK11_KeyForCertExists(cert
.get(), nullptr, ctx
));
598 nsCOMPtr
<nsIX509Cert
> certToShow
= new nsNSSCertificate(cert
.get());
599 DisplayCertificateAlert(ctx
, "UserCertIgnoredNoPrivateKey", certToShow
);
600 return NS_ERROR_FAILURE
;
604 /* pick a nickname for the cert */
605 nsAutoCString nickname
;
606 if (cert
->nickname
) {
607 nickname
= cert
->nickname
;
609 get_default_nickname(cert
.get(), ctx
, nickname
);
612 /* user wants to import the cert */
613 slot
.reset(PK11_ImportCertForKey(cert
.get(), nickname
.get(), ctx
));
615 return NS_ERROR_FAILURE
;
620 nsCOMPtr
<nsIX509Cert
> certToShow
= new nsNSSCertificate(cert
.get());
621 DisplayCertificateAlert(ctx
, "UserCertImported", certToShow
);
625 if (!certsArray
.IsEmpty()) {
626 certsArray
.RemoveElementAt(0);
627 rv
= ImportCACerts(certsArray
, ctx
);
630 nsCOMPtr
<nsIObserverService
> observerService
=
631 mozilla::services::GetObserverService();
632 if (observerService
) {
633 observerService
->NotifyObservers(nullptr, "psm:user-certificate-added",
641 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert
* aCert
) {
642 NS_ENSURE_ARG_POINTER(aCert
);
643 UniqueCERTCertificate
cert(aCert
->GetCert());
645 return NS_ERROR_FAILURE
;
648 // Temporary certificates aren't on a slot and will go away when the
649 // nsIX509Cert is destructed.
652 nsresult rv
= aCert
->GetCertType(&certType
);
653 if (NS_WARN_IF(NS_FAILED(rv
))) {
656 if (certType
== nsIX509Cert::USER_CERT
) {
657 SECStatus srv
= PK11_Authenticate(cert
->slot
, true, nullptr);
658 if (srv
!= SECSuccess
) {
659 return NS_ERROR_FAILURE
;
661 srv
= PK11_DeleteTokenCertAndKey(cert
.get(), nullptr);
662 if (srv
!= SECSuccess
) {
663 return NS_ERROR_FAILURE
;
666 // For certificates that can't be deleted (e.g. built-in roots), un-set
668 nsNSSCertTrust
trust(0, 0);
669 SECStatus srv
= ChangeCertTrustWithPossibleAuthentication(
670 cert
, trust
.GetTrust(), nullptr);
671 if (srv
!= SECSuccess
) {
672 return NS_ERROR_FAILURE
;
674 if (!PK11_IsReadOnly(cert
->slot
)) {
675 srv
= SEC_DeletePermCertificate(cert
.get());
676 if (srv
!= SECSuccess
) {
677 return NS_ERROR_FAILURE
;
683 nsCOMPtr
<nsIObserverService
> observerService
=
684 mozilla::services::GetObserverService();
685 if (observerService
) {
686 observerService
->NotifyObservers(nullptr, "psm:user-certificate-deleted",
694 nsNSSCertificateDB::SetCertTrust(nsIX509Cert
* cert
, uint32_t type
,
696 NS_ENSURE_ARG_POINTER(cert
);
697 nsNSSCertTrust trust
;
699 case nsIX509Cert::CA_CERT
:
701 trust
.AddCATrust(!!(trusted
& nsIX509CertDB::TRUSTED_SSL
),
702 !!(trusted
& nsIX509CertDB::TRUSTED_EMAIL
));
704 case nsIX509Cert::SERVER_CERT
:
705 trust
.SetValidPeer();
706 trust
.AddPeerTrust(trusted
& nsIX509CertDB::TRUSTED_SSL
, false);
708 case nsIX509Cert::EMAIL_CERT
:
709 trust
.SetValidPeer();
710 trust
.AddPeerTrust(false, !!(trusted
& nsIX509CertDB::TRUSTED_EMAIL
));
713 // Ignore any other type of certificate (including invalid types).
717 UniqueCERTCertificate
nsscert(cert
->GetCert());
718 SECStatus srv
= ChangeCertTrustWithPossibleAuthentication(
719 nsscert
, trust
.GetTrust(), nullptr);
720 return MapSECStatus(srv
);
724 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert
* cert
, uint32_t certType
,
725 uint32_t trustType
, bool* _isTrusted
) {
726 NS_ENSURE_ARG_POINTER(_isTrusted
);
729 nsresult rv
= BlockUntilLoadableCertsLoaded();
735 UniqueCERTCertificate
nsscert(cert
->GetCert());
736 CERTCertTrust nsstrust
;
737 srv
= CERT_GetCertTrust(nsscert
.get(), &nsstrust
);
738 if (srv
!= SECSuccess
) {
739 // CERT_GetCertTrust returns SECFailure if given a temporary cert that
740 // doesn't have any trust information yet. This isn't an error.
744 nsNSSCertTrust
trust(&nsstrust
);
745 if (certType
== nsIX509Cert::CA_CERT
) {
746 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
747 *_isTrusted
= trust
.HasTrustedCA(true, false);
748 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
749 *_isTrusted
= trust
.HasTrustedCA(false, true);
751 return NS_ERROR_FAILURE
;
753 } else if (certType
== nsIX509Cert::SERVER_CERT
) {
754 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
755 *_isTrusted
= trust
.HasTrustedPeer(true, false);
756 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
757 *_isTrusted
= trust
.HasTrustedPeer(false, true);
759 return NS_ERROR_FAILURE
;
761 } else if (certType
== nsIX509Cert::EMAIL_CERT
) {
762 if (trustType
& nsIX509CertDB::TRUSTED_SSL
) {
763 *_isTrusted
= trust
.HasTrustedPeer(true, false);
764 } else if (trustType
& nsIX509CertDB::TRUSTED_EMAIL
) {
765 *_isTrusted
= trust
.HasTrustedPeer(false, true);
767 return NS_ERROR_FAILURE
;
774 nsNSSCertificateDB::ImportCertsFromFile(nsIFile
* aFile
, uint32_t aType
) {
775 NS_ENSURE_ARG(aFile
);
777 case nsIX509Cert::CA_CERT
:
778 case nsIX509Cert::EMAIL_CERT
:
783 // not supported (yet)
784 return NS_ERROR_FAILURE
;
787 PRFileDesc
* fd
= nullptr;
788 nsresult rv
= aFile
->OpenNSPRFileDesc(PR_RDONLY
, 0, &fd
);
793 return NS_ERROR_FAILURE
;
797 if (PR_GetOpenFileInfo(fd
, &fileInfo
) != PR_SUCCESS
) {
798 return NS_ERROR_FAILURE
;
801 auto buf
= MakeUnique
<unsigned char[]>(fileInfo
.size
);
802 int32_t bytesObtained
= PR_Read(fd
, buf
.get(), fileInfo
.size
);
805 if (bytesObtained
!= fileInfo
.size
) {
806 return NS_ERROR_FAILURE
;
809 nsCOMPtr
<nsIInterfaceRequestor
> cxt
= new PipUIContext();
812 case nsIX509Cert::CA_CERT
:
813 return ImportCertificates(buf
.get(), bytesObtained
, aType
, cxt
);
814 case nsIX509Cert::EMAIL_CERT
:
815 return ImportEmailCertificate(buf
.get(), bytesObtained
, cxt
);
817 MOZ_ASSERT(false, "Unsupported type should have been filtered out");
821 return NS_ERROR_FAILURE
;
825 nsNSSCertificateDB::ImportPKCS12File(nsIFile
* aFile
, const nsAString
& aPassword
,
827 if (!NS_IsMainThread()) {
828 return NS_ERROR_NOT_SAME_THREAD
;
830 nsresult rv
= BlockUntilLoadableCertsLoaded();
835 NS_ENSURE_ARG(aFile
);
837 rv
= blob
.ImportFromFile(aFile
, aPassword
, *aError
);
838 nsCOMPtr
<nsIObserverService
> observerService
=
839 mozilla::services::GetObserverService();
840 if (NS_SUCCEEDED(rv
) && observerService
) {
841 observerService
->NotifyObservers(nullptr, "psm:user-certificate-added",
849 nsNSSCertificateDB::ExportPKCS12File(
850 nsIFile
* aFile
, const nsTArray
<RefPtr
<nsIX509Cert
>>& aCerts
,
851 const nsAString
& aPassword
, uint32_t* aError
) {
852 if (!NS_IsMainThread()) {
853 return NS_ERROR_NOT_SAME_THREAD
;
855 nsresult rv
= BlockUntilLoadableCertsLoaded();
860 NS_ENSURE_ARG(aFile
);
861 if (aCerts
.IsEmpty()) {
865 return blob
.ExportToFile(aFile
, aCerts
, aPassword
, *aError
);
869 nsNSSCertificateDB::ConstructX509FromBase64(const nsACString
& base64
,
870 /*out*/ nsIX509Cert
** _retval
) {
872 return NS_ERROR_INVALID_POINTER
;
875 // Base64Decode() doesn't consider a zero length input as an error, and just
876 // returns the empty string. We don't want this behavior, so the below check
877 // catches this case.
878 if (base64
.Length() < 1) {
879 return NS_ERROR_ILLEGAL_VALUE
;
882 nsAutoCString certDER
;
883 nsresult rv
= Base64Decode(base64
, certDER
);
888 return ConstructX509FromSpan(AsBytes(Span(certDER
)), _retval
);
892 nsNSSCertificateDB::ConstructX509(const nsTArray
<uint8_t>& certDER
,
893 nsIX509Cert
** _retval
) {
894 return ConstructX509FromSpan(Span(certDER
.Elements(), certDER
.Length()),
898 nsresult
nsNSSCertificateDB::ConstructX509FromSpan(
899 Span
<const uint8_t> aInputSpan
, nsIX509Cert
** _retval
) {
900 if (NS_WARN_IF(!_retval
)) {
901 return NS_ERROR_INVALID_POINTER
;
904 if (aInputSpan
.Length() > std::numeric_limits
<unsigned int>::max()) {
905 return NS_ERROR_ILLEGAL_VALUE
;
909 certData
.type
= siDERCertBuffer
;
910 certData
.data
= const_cast<unsigned char*>(
911 reinterpret_cast<const unsigned char*>(aInputSpan
.Elements()));
912 certData
.len
= aInputSpan
.Length();
914 UniqueCERTCertificate
cert(CERT_NewTempCertificate(
915 CERT_GetDefaultCertDB(), &certData
, nullptr, false, true));
917 return (PORT_GetError() == SEC_ERROR_NO_MEMORY
) ? NS_ERROR_OUT_OF_MEMORY
920 nsCOMPtr
<nsIX509Cert
> nssCert
= new nsNSSCertificate(cert
.get());
921 nssCert
.forget(_retval
);
925 void nsNSSCertificateDB::get_default_nickname(CERTCertificate
* cert
,
926 nsIInterfaceRequestor
* ctx
,
927 nsCString
& nickname
) {
930 CK_OBJECT_HANDLE keyHandle
;
932 if (NS_FAILED(BlockUntilLoadableCertsLoaded())) {
936 CERTCertDBHandle
* defaultcertdb
= CERT_GetDefaultCertDB();
937 nsAutoCString username
;
938 UniquePORTString
tempCN(CERT_GetCommonName(&cert
->subject
));
940 username
= tempCN
.get();
943 nsAutoCString caname
;
944 UniquePORTString
tempIssuerOrg(CERT_GetOrgName(&cert
->issuer
));
946 caname
= tempIssuerOrg
.get();
949 nsAutoString tmpNickFmt
;
950 GetPIPNSSBundleString("nick_template", tmpNickFmt
);
951 NS_ConvertUTF16toUTF8
nickFmt(tmpNickFmt
);
953 nsAutoCString baseName
;
954 baseName
.AppendPrintf(nickFmt
.get(), username
.get(), caname
.get());
955 if (baseName
.IsEmpty()) {
962 * We need to see if the private key exists on a token, if it does
963 * then we need to check for nicknames that already exist on the smart
966 UniquePK11SlotInfo
slot(PK11_KeyForCertExists(cert
, &keyHandle
, ctx
));
969 if (!PK11_IsInternal(slot
.get())) {
971 tmp
.AppendPrintf("%s:%s", PK11_GetTokenName(slot
.get()), baseName
.get());
984 tmp
.AppendPrintf("%s #%d", baseName
.get(), count
);
992 UniqueCERTCertificate dummycert
;
994 if (PK11_IsInternal(slot
.get())) {
995 /* look up the nickname to make sure it isn't in use already */
996 dummycert
.reset(CERT_FindCertByNickname(defaultcertdb
, nickname
.get()));
998 // Check the cert against others that already live on the smart card.
999 dummycert
.reset(PK11_FindCertFromNickname(nickname
.get(), ctx
));
1001 // Make sure the subject names are different.
1002 if (CERT_CompareName(&cert
->subject
, &dummycert
->subject
) == SECEqual
) {
1004 * There is another certificate with the same nickname and
1005 * the same subject name on the smart card, so let's use this
1008 dummycert
= nullptr;
1020 nsNSSCertificateDB::AddCertFromBase64(const nsACString
& aBase64
,
1021 const nsACString
& aTrust
,
1022 nsIX509Cert
** addedCertificate
) {
1023 // Base64Decode() doesn't consider a zero length input as an error, and just
1024 // returns the empty string. We don't want this behavior, so the below check
1025 // catches this case.
1026 if (aBase64
.Length() < 1) {
1027 return NS_ERROR_ILLEGAL_VALUE
;
1030 nsAutoCString aCertDER
;
1031 nsresult rv
= Base64Decode(aBase64
, aCertDER
);
1032 if (NS_FAILED(rv
)) {
1035 return AddCert(aCertDER
, aTrust
, addedCertificate
);
1039 nsNSSCertificateDB::AddCert(const nsACString
& aCertDER
,
1040 const nsACString
& aTrust
,
1041 nsIX509Cert
** addedCertificate
) {
1042 MOZ_ASSERT(addedCertificate
);
1043 if (!addedCertificate
) {
1044 return NS_ERROR_INVALID_ARG
;
1046 *addedCertificate
= nullptr;
1048 nsNSSCertTrust trust
;
1049 if (CERT_DecodeTrustString(&trust
.GetTrust(),
1050 PromiseFlatCString(aTrust
).get()) != SECSuccess
) {
1051 return NS_ERROR_FAILURE
;
1054 nsCOMPtr
<nsIX509Cert
> newCert
;
1056 ConstructX509FromSpan(AsBytes(Span(aCertDER
)), getter_AddRefs(newCert
));
1057 if (NS_FAILED(rv
)) {
1061 UniqueCERTCertificate
tmpCert(newCert
->GetCert());
1063 return NS_ERROR_FAILURE
;
1066 // If there's already a certificate that matches this one in the database, we
1067 // still want to set its trust to the given value.
1068 if (tmpCert
->isperm
) {
1069 rv
= SetCertTrustFromString(newCert
, aTrust
);
1070 if (NS_FAILED(rv
)) {
1073 newCert
.forget(addedCertificate
);
1077 UniquePORTString
nickname(CERT_MakeCANickname(tmpCert
.get()));
1079 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1080 ("Created nick \"%s\"\n", nickname
.get()));
1082 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
1083 SECStatus srv
= PK11_ImportCert(slot
.get(), tmpCert
.get(), CK_INVALID_HANDLE
,
1085 false); // this parameter is ignored by NSS
1086 if (srv
!= SECSuccess
) {
1087 return MapSECStatus(srv
);
1089 srv
= ChangeCertTrustWithPossibleAuthentication(tmpCert
, trust
.GetTrust(),
1091 if (srv
!= SECSuccess
) {
1092 return MapSECStatus(srv
);
1094 newCert
.forget(addedCertificate
);
1099 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert
* cert
,
1100 const nsACString
& trustString
) {
1101 NS_ENSURE_ARG(cert
);
1103 CERTCertTrust trust
;
1105 CERT_DecodeTrustString(&trust
, PromiseFlatCString(trustString
).get());
1106 if (srv
!= SECSuccess
) {
1107 return MapSECStatus(srv
);
1109 UniqueCERTCertificate
nssCert(cert
->GetCert());
1111 srv
= ChangeCertTrustWithPossibleAuthentication(nssCert
, trust
, nullptr);
1112 return MapSECStatus(srv
);
1115 NS_IMETHODIMP
nsNSSCertificateDB::AsPKCS7Blob(
1116 const nsTArray
<RefPtr
<nsIX509Cert
>>& certList
, nsACString
& _retval
) {
1117 if (certList
.IsEmpty()) {
1118 return NS_ERROR_INVALID_ARG
;
1121 UniqueNSSCMSMessage
cmsg(NSS_CMSMessage_Create(nullptr));
1123 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1124 ("nsNSSCertificateDB::AsPKCS7Blob - can't create CMS message"));
1125 return NS_ERROR_OUT_OF_MEMORY
;
1128 UniqueNSSCMSSignedData
sigd(nullptr);
1129 for (const auto& cert
: certList
) {
1130 // We need an owning handle when calling nsIX509Cert::GetCert().
1131 UniqueCERTCertificate
nssCert(cert
->GetCert());
1134 NSS_CMSSignedData_CreateCertsOnly(cmsg
.get(), nssCert
.get(), false));
1136 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1137 ("nsNSSCertificateDB::AsPKCS7Blob - can't create SignedData"));
1138 return NS_ERROR_FAILURE
;
1140 } else if (NSS_CMSSignedData_AddCertificate(sigd
.get(), nssCert
.get()) !=
1142 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1143 ("nsNSSCertificateDB::AsPKCS7Blob - can't add cert"));
1144 return NS_ERROR_FAILURE
;
1148 NSSCMSContentInfo
* cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
.get());
1149 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg
.get(), cinfo
, sigd
.get()) !=
1151 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1152 ("nsNSSCertificateDB::AsPKCS7Blob - can't attach SignedData"));
1153 return NS_ERROR_FAILURE
;
1155 // cmsg owns sigd now.
1156 Unused
<< sigd
.release();
1158 UniquePLArenaPool
arena(PORT_NewArena(1024));
1160 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1161 ("nsNSSCertificateDB::AsPKCS7Blob - out of memory"));
1162 return NS_ERROR_OUT_OF_MEMORY
;
1165 SECItem certP7
= {siBuffer
, nullptr, 0};
1166 NSSCMSEncoderContext
* ecx
= NSS_CMSEncoder_Start(
1167 cmsg
.get(), nullptr, nullptr, &certP7
, arena
.get(), nullptr, nullptr,
1168 nullptr, nullptr, nullptr, nullptr);
1170 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1171 ("nsNSSCertificateDB::AsPKCS7Blob - can't create encoder"));
1172 return NS_ERROR_FAILURE
;
1175 if (NSS_CMSEncoder_Finish(ecx
) != SECSuccess
) {
1176 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1177 ("nsNSSCertificateDB::AsPKCS7Blob - failed to add encoded data"));
1178 return NS_ERROR_FAILURE
;
1181 _retval
.Assign(nsDependentCSubstring(
1182 reinterpret_cast<const char*>(certP7
.data
), certP7
.len
));
1187 nsNSSCertificateDB::GetCerts(nsTArray
<RefPtr
<nsIX509Cert
>>& _retval
) {
1188 nsresult rv
= BlockUntilLoadableCertsLoaded();
1189 if (NS_FAILED(rv
)) {
1193 rv
= CheckForSmartCardChanges();
1194 if (NS_FAILED(rv
)) {
1198 nsCOMPtr
<nsIInterfaceRequestor
> ctx
= new PipUIContext();
1199 UniqueCERTCertList
certList(PK11_ListCerts(PK11CertListUnique
, ctx
));
1201 return NS_ERROR_FAILURE
;
1203 return nsNSSCertificateDB::ConstructCertArrayFromUniqueCertList(certList
,
1207 nsresult
IsCertBuiltInRoot(const RefPtr
<nsIX509Cert
>& cert
,
1208 bool& isBuiltInRoot
) {
1209 nsTArray
<uint8_t> der
;
1210 nsresult rv
= cert
->GetRawDER(der
);
1211 if (NS_FAILED(rv
)) {
1214 pkix::Input certInput
;
1215 pkix::Result result
= certInput
.Init(der
.Elements(), der
.Length());
1216 if (result
!= pkix::Result::Success
) {
1217 return NS_ERROR_FAILURE
;
1219 result
= IsCertBuiltInRoot(certInput
, isBuiltInRoot
);
1220 if (result
!= pkix::Result::Success
) {
1221 return NS_ERROR_FAILURE
;
1227 nsNSSCertificateDB::AsyncHasThirdPartyRoots(nsIAsyncBoolCallback
* aCallback
) {
1228 NS_ENSURE_ARG_POINTER(aCallback
);
1229 nsMainThreadPtrHandle
<nsIAsyncBoolCallback
> callback(
1230 new nsMainThreadPtrHolder
<nsIAsyncBoolCallback
>("AsyncHasThirdPartyRoots",
1233 return NS_DispatchBackgroundTask(
1234 NS_NewRunnableFunction(
1235 "nsNSSCertificateDB::AsyncHasThirdPartyRoots",
1236 [cb
= std::move(callback
), self
= RefPtr
{this}] {
1237 bool hasThirdPartyRoots
= [self
]() -> bool {
1238 nsTArray
<RefPtr
<nsIX509Cert
>> certs
;
1239 nsresult rv
= self
->GetCerts(certs
);
1240 if (NS_FAILED(rv
)) {
1244 for (const auto& cert
: certs
) {
1245 bool isTrusted
= false;
1247 self
->IsCertTrusted(cert
, nsIX509Cert::CA_CERT
,
1248 nsIX509CertDB::TRUSTED_SSL
, &isTrusted
);
1249 if (NS_FAILED(rv
)) {
1257 bool isBuiltInRoot
= false;
1258 rv
= IsCertBuiltInRoot(cert
, isBuiltInRoot
);
1259 if (NS_FAILED(rv
)) {
1263 if (!isBuiltInRoot
) {
1271 NS_DispatchToMainThread(NS_NewRunnableFunction(
1272 "nsNSSCertificateDB::AsyncHasThirdPartyRoots callback",
1273 [cb
, hasThirdPartyRoots
]() {
1274 cb
->OnResult(hasThirdPartyRoots
);
1277 NS_DISPATCH_EVENT_MAY_BLOCK
);
1280 nsresult
VerifyCertAtTime(nsIX509Cert
* aCert
,
1281 int64_t /*SECCertificateUsage*/ aUsage
,
1282 uint32_t aFlags
, const nsACString
& aHostname
,
1283 mozilla::pkix::Time aTime
,
1284 nsTArray
<RefPtr
<nsIX509Cert
>>& aVerifiedChain
,
1286 int32_t* /*PRErrorCode*/ _retval
) {
1287 NS_ENSURE_ARG_POINTER(aCert
);
1288 NS_ENSURE_ARG_POINTER(aHasEVPolicy
);
1289 NS_ENSURE_ARG_POINTER(_retval
);
1291 if (!aVerifiedChain
.IsEmpty()) {
1292 return NS_ERROR_INVALID_ARG
;
1295 *aHasEVPolicy
= false;
1296 *_retval
= PR_UNKNOWN_ERROR
;
1298 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
1299 NS_ENSURE_TRUE(certVerifier
, NS_ERROR_FAILURE
);
1301 nsTArray
<nsTArray
<uint8_t>> resultChain
;
1303 mozilla::pkix::Result result
;
1305 nsTArray
<uint8_t> certBytes
;
1306 nsresult nsrv
= aCert
->GetRawDER(certBytes
);
1307 if (NS_FAILED(nsrv
)) {
1311 if (!aHostname
.IsVoid() && aUsage
== certificateUsageSSLServer
) {
1313 certVerifier
->VerifySSLServerCert(certBytes
, aTime
,
1314 nullptr, // Assume no context
1315 aHostname
, resultChain
, aFlags
,
1316 Nothing(), // extraCertificates
1317 Nothing(), // stapledOCSPResponse
1318 Nothing(), // sctsFromTLSExtension
1319 Nothing(), // dcInfo
1320 OriginAttributes(), &evStatus
);
1322 const nsCString
& flatHostname
= PromiseFlatCString(aHostname
);
1323 result
= certVerifier
->VerifyCert(
1324 certBytes
, aUsage
, aTime
,
1325 nullptr, // Assume no context
1326 aHostname
.IsVoid() ? nullptr : flatHostname
.get(), resultChain
, aFlags
,
1327 Nothing(), // extraCertificates
1328 Nothing(), // stapledOCSPResponse
1329 Nothing(), // sctsFromTLSExtension
1330 OriginAttributes(), &evStatus
);
1333 if (result
== mozilla::pkix::Success
) {
1334 for (auto& certDER
: resultChain
) {
1335 RefPtr
<nsIX509Cert
> cert
= new nsNSSCertificate(std::move(certDER
));
1336 aVerifiedChain
.AppendElement(cert
);
1339 if (evStatus
== EVStatus::EV
) {
1340 *aHasEVPolicy
= true;
1344 *_retval
= mozilla::pkix::MapResultToPRErrorCode(result
);
1349 class VerifyCertAtTimeTask final
: public CryptoTask
{
1351 VerifyCertAtTimeTask(nsIX509Cert
* aCert
, int64_t aUsage
, uint32_t aFlags
,
1352 const nsACString
& aHostname
, uint64_t aTime
,
1353 nsICertVerificationCallback
* aCallback
)
1357 mHostname(aHostname
),
1359 mCallback(new nsMainThreadPtrHolder
<nsICertVerificationCallback
>(
1360 "nsICertVerificationCallback", aCallback
)),
1361 mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE
),
1362 mHasEVPolicy(false) {}
1365 virtual nsresult
CalculateResult() override
{
1366 nsCOMPtr
<nsIX509CertDB
> certDB
= do_GetService(NS_X509CERTDB_CONTRACTID
);
1368 return NS_ERROR_FAILURE
;
1370 return VerifyCertAtTime(mCert
, mUsage
, mFlags
, mHostname
,
1371 mozilla::pkix::TimeFromEpochInSeconds(mTime
),
1372 mVerifiedCertList
, &mHasEVPolicy
, &mPRErrorCode
);
1375 virtual void CallCallback(nsresult rv
) override
{
1376 if (NS_FAILED(rv
)) {
1377 nsTArray
<RefPtr
<nsIX509Cert
>> tmp
;
1378 Unused
<< mCallback
->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE
, tmp
,
1381 Unused
<< mCallback
->VerifyCertFinished(mPRErrorCode
, mVerifiedCertList
,
1386 nsCOMPtr
<nsIX509Cert
> mCert
;
1389 nsCString mHostname
;
1391 nsMainThreadPtrHandle
<nsICertVerificationCallback
> mCallback
;
1392 int32_t mPRErrorCode
;
1393 nsTArray
<RefPtr
<nsIX509Cert
>> mVerifiedCertList
;
1398 nsNSSCertificateDB::AsyncVerifyCertAtTime(
1399 nsIX509Cert
* aCert
, int64_t /*SECCertificateUsage*/ aUsage
, uint32_t aFlags
,
1400 const nsACString
& aHostname
, uint64_t aTime
,
1401 nsICertVerificationCallback
* aCallback
) {
1402 RefPtr
<VerifyCertAtTimeTask
> task(new VerifyCertAtTimeTask(
1403 aCert
, aUsage
, aFlags
, aHostname
, aTime
, aCallback
));
1404 return task
->Dispatch();
1408 nsNSSCertificateDB::ClearOCSPCache() {
1409 RefPtr
<SharedCertVerifier
> certVerifier(GetDefaultCertVerifier());
1410 NS_ENSURE_TRUE(certVerifier
, NS_ERROR_FAILURE
);
1411 certVerifier
->ClearOCSPCache();