1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "NSSCertDBTrustDomain.h"
12 #include "CRLiteTimestamp.h"
13 #include "ExtendedValidation.h"
14 #include "MultiLogCTVerifier.h"
15 #include "NSSErrorsService.h"
16 #include "PublicKeyPinningService.h"
18 #include "cert_storage/src/cert_storage.h"
20 #include "mozilla/AppShutdown.h"
21 #include "mozilla/Assertions.h"
22 #include "mozilla/Casting.h"
23 #include "mozilla/ClearOnShutdown.h"
24 #include "mozilla/Logging.h"
25 #include "mozilla/PodOperations.h"
26 #include "mozilla/Services.h"
27 #include "mozilla/StaticPrefs_security.h"
28 #include "mozilla/SyncRunnable.h"
29 #include "mozilla/TimeStamp.h"
30 #include "mozilla/Unused.h"
31 #include "mozpkix/Result.h"
32 #include "mozpkix/pkix.h"
33 #include "mozpkix/pkixnss.h"
34 #include "mozpkix/pkixutil.h"
35 #include "nsCRTGlue.h"
36 #include "nsIObserverService.h"
38 #include "nsNSSCallbacks.h"
39 #include "nsNSSCertHelper.h"
40 #include "nsNSSCertificate.h"
41 #include "nsNSSCertificateDB.h"
42 #include "nsNSSIOLayer.h"
43 #include "nsPrintfCString.h"
44 #include "nsServiceManagerUtils.h"
45 #include "nsThreadUtils.h"
52 #include "TrustOverrideUtils.h"
53 #include "TrustOverride-AppleGoogleDigiCertData.inc"
54 #include "TrustOverride-SymantecData.inc"
56 using namespace mozilla
;
57 using namespace mozilla::ct
;
58 using namespace mozilla::pkix
;
60 extern LazyLogModule gCertVerifierLog
;
62 static const uint64_t ServerFailureDelaySeconds
= 5 * 60;
67 NSSCertDBTrustDomain::NSSCertDBTrustDomain(
68 SECTrustType certDBTrustType
, OCSPFetching ocspFetching
,
70 /*optional but shouldn't be*/ void* pinArg
, TimeDuration ocspTimeoutSoft
,
71 TimeDuration ocspTimeoutHard
, uint32_t certShortLifetimeInDays
,
72 unsigned int minRSABits
, ValidityCheckingMode validityCheckingMode
,
73 NetscapeStepUpPolicy netscapeStepUpPolicy
, CRLiteMode crliteMode
,
74 const OriginAttributes
& originAttributes
,
75 const nsTArray
<Input
>& thirdPartyRootInputs
,
76 const nsTArray
<Input
>& thirdPartyIntermediateInputs
,
77 const Maybe
<nsTArray
<nsTArray
<uint8_t>>>& extraCertificates
,
78 /*out*/ nsTArray
<nsTArray
<uint8_t>>& builtChain
,
79 /*optional*/ PinningTelemetryInfo
* pinningTelemetryInfo
,
80 /*optional*/ const char* hostname
)
81 : mCertDBTrustType(certDBTrustType
),
82 mOCSPFetching(ocspFetching
),
83 mOCSPCache(ocspCache
),
85 mOCSPTimeoutSoft(ocspTimeoutSoft
),
86 mOCSPTimeoutHard(ocspTimeoutHard
),
87 mCertShortLifetimeInDays(certShortLifetimeInDays
),
88 mMinRSABits(minRSABits
),
89 mValidityCheckingMode(validityCheckingMode
),
90 mNetscapeStepUpPolicy(netscapeStepUpPolicy
),
91 mCRLiteMode(crliteMode
),
92 mSawDistrustedCAByPolicyError(false),
93 mOriginAttributes(originAttributes
),
94 mThirdPartyRootInputs(thirdPartyRootInputs
),
95 mThirdPartyIntermediateInputs(thirdPartyIntermediateInputs
),
96 mExtraCertificates(extraCertificates
),
97 mBuiltChain(builtChain
),
98 mIsBuiltChainRootBuiltInRoot(false),
99 mPinningTelemetryInfo(pinningTelemetryInfo
),
101 mCertStorage(do_GetService(NS_CERT_STORAGE_CID
)),
102 mOCSPStaplingStatus(CertVerifier::OCSP_STAPLING_NEVER_CHECKED
),
103 mBuiltInRootsModule(SECMOD_FindModule(kRootModuleName
)),
104 mOCSPFetchStatus(OCSPFetchStatus::NotFetched
) {}
106 static void FindRootsWithSubject(UniqueSECMODModule
& rootsModule
,
108 /*out*/ nsTArray
<nsTArray
<uint8_t>>& roots
) {
109 MOZ_ASSERT(rootsModule
);
110 AutoSECMODListReadLock lock
;
111 for (int slotIndex
= 0; slotIndex
< rootsModule
->slotCount
; slotIndex
++) {
112 CERTCertificateList
* rawResults
= nullptr;
113 if (PK11_FindRawCertsWithSubject(rootsModule
->slots
[slotIndex
], &subject
,
114 &rawResults
) != SECSuccess
) {
117 // rawResults == nullptr means we didn't find any matching certificates
121 UniqueCERTCertificateList
results(rawResults
);
122 for (int certIndex
= 0; certIndex
< results
->len
; certIndex
++) {
123 nsTArray
<uint8_t> root
;
124 root
.AppendElements(results
->certs
[certIndex
].data
,
125 results
->certs
[certIndex
].len
);
126 roots
.AppendElement(std::move(root
));
131 // A self-signed issuer certificate should never be necessary in order to build
132 // a trusted certificate chain unless it is a trust anchor. This is because if
133 // it were necessary, there would exist another certificate with the same
134 // subject and public key that is also a valid issing certificate. Given this
135 // certificate, it is possible to build another chain using just it instead of
136 // it and the self-signed certificate. This is only true as long as the
137 // certificate extensions we support are restrictive rather than additive in
138 // terms of the rest of the chain (for example, we don't support policy mapping
139 // and we ignore any SCT information in intermediates).
140 bool NSSCertDBTrustDomain::ShouldSkipSelfSignedNonTrustAnchor(Input certDER
) {
141 BackCert
cert(certDER
, EndEntityOrCA::MustBeCA
, nullptr);
142 if (cert
.Init() != Success
) {
143 return false; // turn any failures into "don't skip trying this cert"
145 // If subject != issuer, this isn't a self-signed cert.
146 if (!InputsAreEqual(cert
.GetSubject(), cert
.GetIssuer())) {
150 if (GetCertTrust(EndEntityOrCA::MustBeCA
, CertPolicyId::anyPolicy
, certDER
,
154 // If the trust for this certificate is anything other than "inherit", we want
155 // to process it like normal.
156 if (trust
!= TrustLevel::InheritsTrust
) {
159 if (VerifySignedData(*this, cert
.GetSignedData(),
160 cert
.GetSubjectPublicKeyInfo()) != Success
) {
163 // This is a self-signed, non-trust-anchor certificate, so we shouldn't use it
164 // for path building. See bug 1056341.
168 Result
NSSCertDBTrustDomain::CheckCandidates(
169 IssuerChecker
& checker
, nsTArray
<IssuerCandidateWithSource
>& candidates
,
170 Input
* nameConstraintsInputPtr
, bool& keepGoing
) {
171 for (const auto& candidate
: candidates
) {
172 // Stop path building if the program is shutting down.
173 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
177 if (ShouldSkipSelfSignedNonTrustAnchor(candidate
.mDER
)) {
181 checker
.Check(candidate
.mDER
, nameConstraintsInputPtr
, keepGoing
);
186 mIssuerSources
+= candidate
.mIssuerSource
;
194 Result
NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName
,
195 IssuerChecker
& checker
, Time
) {
196 SECItem encodedIssuerNameItem
= UnsafeMapInputToSECItem(encodedIssuerName
);
197 // Handle imposed name constraints, if any.
198 ScopedAutoSECItem nameConstraints
;
199 Input nameConstraintsInput
;
200 Input
* nameConstraintsInputPtr
= nullptr;
202 CERT_GetImposedNameConstraints(&encodedIssuerNameItem
, &nameConstraints
);
203 if (srv
== SECSuccess
) {
204 if (nameConstraintsInput
.Init(nameConstraints
.data
, nameConstraints
.len
) !=
206 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
208 nameConstraintsInputPtr
= &nameConstraintsInput
;
209 } else if (PR_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND
) {
210 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
213 // First try all relevant certificates known to Gecko, which avoids calling
214 // CERT_CreateSubjectCertList, because that can be expensive.
215 nsTArray
<IssuerCandidateWithSource
> geckoRootCandidates
;
216 nsTArray
<IssuerCandidateWithSource
> geckoIntermediateCandidates
;
218 // We might not have this module if e.g. we're on a Linux distribution that
219 // does something unexpected.
220 nsTArray
<nsTArray
<uint8_t>> builtInRoots
;
221 if (mBuiltInRootsModule
) {
222 FindRootsWithSubject(mBuiltInRootsModule
, encodedIssuerNameItem
,
224 for (const auto& root
: builtInRoots
) {
226 Result rv
= rootInput
.Init(root
.Elements(), root
.Length());
228 continue; // probably too big
230 geckoRootCandidates
.AppendElement(IssuerCandidateWithSource
{
231 rootInput
, IssuerSource::BuiltInRootsModule
});
234 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
235 ("NSSCertDBTrustDomain::FindIssuer: no built-in roots module"));
238 if (mExtraCertificates
.isSome()) {
239 for (const auto& extraCert
: *mExtraCertificates
) {
241 Result rv
= certInput
.Init(extraCert
.Elements(), extraCert
.Length());
245 BackCert
cert(certInput
, EndEntityOrCA::MustBeCA
, nullptr);
250 // Filter out certificates that can't be issuers we're looking for because
251 // the subject distinguished name doesn't match. This prevents
252 // mozilla::pkix from accumulating spurious errors during path building.
253 if (!InputsAreEqual(encodedIssuerName
, cert
.GetSubject())) {
256 // We assume that extra certificates (presumably from the TLS handshake)
257 // are intermediates, since sending trust anchors would be superfluous.
258 geckoIntermediateCandidates
.AppendElement(
259 IssuerCandidateWithSource
{certInput
, IssuerSource::TLSHandshake
});
263 for (const auto& thirdPartyRootInput
: mThirdPartyRootInputs
) {
264 BackCert
root(thirdPartyRootInput
, EndEntityOrCA::MustBeCA
, nullptr);
265 Result rv
= root
.Init();
269 // Filter out 3rd party roots that can't be issuers we're looking for
270 // because the subject distinguished name doesn't match. This prevents
271 // mozilla::pkix from accumulating spurious errors during path building.
272 if (!InputsAreEqual(encodedIssuerName
, root
.GetSubject())) {
275 geckoRootCandidates
.AppendElement(IssuerCandidateWithSource
{
276 thirdPartyRootInput
, IssuerSource::ThirdPartyCertificates
});
279 for (const auto& thirdPartyIntermediateInput
:
280 mThirdPartyIntermediateInputs
) {
281 BackCert
intermediate(thirdPartyIntermediateInput
, EndEntityOrCA::MustBeCA
,
283 Result rv
= intermediate
.Init();
287 // Filter out 3rd party intermediates that can't be issuers we're looking
288 // for because the subject distinguished name doesn't match. This prevents
289 // mozilla::pkix from accumulating spurious errors during path building.
290 if (!InputsAreEqual(encodedIssuerName
, intermediate
.GetSubject())) {
293 geckoIntermediateCandidates
.AppendElement(IssuerCandidateWithSource
{
294 thirdPartyIntermediateInput
, IssuerSource::ThirdPartyCertificates
});
298 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
300 nsTArray
<uint8_t> subject
;
301 subject
.AppendElements(encodedIssuerName
.UnsafeGetData(),
302 encodedIssuerName
.GetLength());
303 nsTArray
<nsTArray
<uint8_t>> certs
;
304 nsresult rv
= mCertStorage
->FindCertsBySubject(subject
, certs
);
306 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
308 for (auto& cert
: certs
) {
310 Result rv
= certDER
.Init(cert
.Elements(), cert
.Length());
312 continue; // probably too big
314 // Currently we're only expecting intermediate certificates in cert storage.
315 geckoIntermediateCandidates
.AppendElement(IssuerCandidateWithSource
{
316 std::move(certDER
), IssuerSource::PreloadedIntermediates
});
319 // Try all root certs first and then all (presumably) intermediates.
320 geckoRootCandidates
.AppendElements(std::move(geckoIntermediateCandidates
));
322 bool keepGoing
= true;
323 Result result
= CheckCandidates(checker
, geckoRootCandidates
,
324 nameConstraintsInputPtr
, keepGoing
);
325 if (result
!= Success
) {
332 // Synchronously dispatch a task to the socket thread to find
333 // CERTCertificates with the given subject. This involves querying NSS
334 // structures and databases, so it should be done on the socket thread.
335 nsTArray
<nsTArray
<uint8_t>> nssRootCandidates
;
336 nsTArray
<nsTArray
<uint8_t>> nssIntermediateCandidates
;
337 RefPtr
<Runnable
> getCandidatesTask
=
338 NS_NewRunnableFunction("NSSCertDBTrustDomain::FindIssuer", [&]() {
339 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
342 // NSS seems not to differentiate between "no potential issuers found"
343 // and "there was an error trying to retrieve the potential issuers." We
344 // assume there was no error if CERT_CreateSubjectCertList returns
346 UniqueCERTCertList
candidates(
347 CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
348 &encodedIssuerNameItem
, 0, false));
350 for (CERTCertListNode
* n
= CERT_LIST_HEAD(candidates
);
351 !CERT_LIST_END(n
, candidates
); n
= CERT_LIST_NEXT(n
)) {
352 nsTArray
<uint8_t> candidate
;
353 candidate
.AppendElements(n
->cert
->derCert
.data
,
354 n
->cert
->derCert
.len
);
355 if (n
->cert
->isRoot
) {
356 nssRootCandidates
.AppendElement(std::move(candidate
));
358 nssIntermediateCandidates
.AppendElement(std::move(candidate
));
363 nsCOMPtr
<nsIEventTarget
> socketThread(
364 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
));
366 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
368 rv
= SyncRunnable::DispatchToThread(socketThread
, getCandidatesTask
);
370 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
373 nsTArray
<IssuerCandidateWithSource
> nssCandidates
;
374 for (const auto& rootCandidate
: nssRootCandidates
) {
376 Result rv
= certDER
.Init(rootCandidate
.Elements(), rootCandidate
.Length());
378 continue; // probably too big
380 nssCandidates
.AppendElement(
381 IssuerCandidateWithSource
{std::move(certDER
), IssuerSource::NSSCertDB
});
383 for (const auto& intermediateCandidate
: nssIntermediateCandidates
) {
385 Result rv
= certDER
.Init(intermediateCandidate
.Elements(),
386 intermediateCandidate
.Length());
388 continue; // probably too big
390 nssCandidates
.AppendElement(
391 IssuerCandidateWithSource
{std::move(certDER
), IssuerSource::NSSCertDB
});
394 return CheckCandidates(checker
, nssCandidates
, nameConstraintsInputPtr
,
398 Result
NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA
,
399 const CertPolicyId
& policy
,
400 Input candidateCertDER
,
401 /*out*/ TrustLevel
& trustLevel
) {
402 // Check the certificate against the OneCRL cert blocklist
404 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
407 // The certificate blocklist currently only applies to TLS server
409 if (mCertDBTrustType
== trustSSL
) {
410 int16_t revocationState
;
412 nsTArray
<uint8_t> issuerBytes
;
413 nsTArray
<uint8_t> serialBytes
;
414 nsTArray
<uint8_t> subjectBytes
;
415 nsTArray
<uint8_t> pubKeyBytes
;
418 BuildRevocationCheckArrays(candidateCertDER
, endEntityOrCA
, issuerBytes
,
419 serialBytes
, subjectBytes
, pubKeyBytes
);
420 if (result
!= Success
) {
424 nsresult nsrv
= mCertStorage
->GetRevocationState(
425 issuerBytes
, serialBytes
, subjectBytes
, pubKeyBytes
, &revocationState
);
426 if (NS_FAILED(nsrv
)) {
427 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
430 if (revocationState
== nsICertStorage::STATE_ENFORCE
) {
431 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
432 ("NSSCertDBTrustDomain: certificate is in blocklist"));
433 Telemetry::AccumulateCategorical(
434 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::OneCRL
);
435 return Result::ERROR_REVOKED_CERTIFICATE
;
439 // This may be a third-party root.
440 for (const auto& thirdPartyRootInput
: mThirdPartyRootInputs
) {
441 if (InputsAreEqual(candidateCertDER
, thirdPartyRootInput
)) {
442 trustLevel
= TrustLevel::TrustAnchor
;
447 // This may be a third-party intermediate.
448 for (const auto& thirdPartyIntermediateInput
:
449 mThirdPartyIntermediateInputs
) {
450 if (InputsAreEqual(candidateCertDER
, thirdPartyIntermediateInput
)) {
451 trustLevel
= TrustLevel::InheritsTrust
;
456 // Synchronously dispatch a task to the socket thread to construct a
457 // CERTCertificate and get its trust from NSS. This involves querying NSS
458 // structures and databases, so it should be done on the socket thread.
459 Result result
= Result::FATAL_ERROR_LIBRARY_FAILURE
;
460 RefPtr
<Runnable
> getTrustTask
=
461 NS_NewRunnableFunction("NSSCertDBTrustDomain::GetCertTrust", [&]() {
462 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
463 result
= Result::FATAL_ERROR_LIBRARY_FAILURE
;
466 // This would be cleaner and more efficient if we could get the trust
467 // information without constructing a CERTCertificate here, but NSS
468 // doesn't expose it in any other easy-to-use fashion. The use of
469 // CERT_NewTempCertificate to get a CERTCertificate shouldn't be a
470 // performance problem for certificates already known to NSS because NSS
471 // will just find the existing CERTCertificate in its in-memory cache
472 // and return it. For certificates not already in NSS (namely
473 // third-party roots and intermediates), we want to avoid calling
474 // CERT_NewTempCertificate repeatedly, so we've already checked if the
475 // candidate certificate is a third-party certificate, above.
476 SECItem candidateCertDERSECItem
=
477 UnsafeMapInputToSECItem(candidateCertDER
);
478 UniqueCERTCertificate
candidateCert(CERT_NewTempCertificate(
479 CERT_GetDefaultCertDB(), &candidateCertDERSECItem
, nullptr, false,
481 if (!candidateCert
) {
482 result
= MapPRErrorCodeToResult(PR_GetError());
485 // NB: CERT_GetCertTrust seems to be abusing SECStatus as a boolean,
486 // where SECSuccess means that there is a trust record and SECFailure
487 // means there is not a trust record. I looked at NSS's internal uses of
488 // CERT_GetCertTrust, and all that code uses the result as a boolean
489 // meaning "We have a trust record."
491 if (CERT_GetCertTrust(candidateCert
.get(), &trust
) == SECSuccess
) {
492 uint32_t flags
= SEC_GET_TRUST_FLAGS(&trust
, mCertDBTrustType
);
494 // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
495 // because we can have active distrust for either type of cert. Note
496 // that CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so
497 // if the relevant trust bit isn't set then that means the cert must
498 // be considered distrusted.
499 uint32_t relevantTrustBit
= endEntityOrCA
== EndEntityOrCA::MustBeCA
502 if (((flags
& (relevantTrustBit
| CERTDB_TERMINAL_RECORD
))) ==
503 CERTDB_TERMINAL_RECORD
) {
504 trustLevel
= TrustLevel::ActivelyDistrusted
;
509 // For TRUST, we use the CERTDB_TRUSTED_CA bit.
510 if (flags
& CERTDB_TRUSTED_CA
) {
511 if (policy
.IsAnyPolicy()) {
512 trustLevel
= TrustLevel::TrustAnchor
;
517 nsTArray
<uint8_t> certBytes(candidateCert
->derCert
.data
,
518 candidateCert
->derCert
.len
);
519 if (CertIsAuthoritativeForEVPolicy(certBytes
, policy
)) {
520 trustLevel
= TrustLevel::TrustAnchor
;
526 trustLevel
= TrustLevel::InheritsTrust
;
529 nsCOMPtr
<nsIEventTarget
> socketThread(
530 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
));
532 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
534 nsresult rv
= SyncRunnable::DispatchToThread(socketThread
, getTrustTask
);
536 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
541 Result
NSSCertDBTrustDomain::DigestBuf(Input item
, DigestAlgorithm digestAlg
,
542 /*out*/ uint8_t* digestBuf
,
543 size_t digestBufLen
) {
544 return DigestBufNSS(item
, digestAlg
, digestBuf
, digestBufLen
);
547 TimeDuration
NSSCertDBTrustDomain::GetOCSPTimeout() const {
548 switch (mOCSPFetching
) {
549 case NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
:
550 return mOCSPTimeoutSoft
;
551 case NSSCertDBTrustDomain::FetchOCSPForEV
:
552 case NSSCertDBTrustDomain::FetchOCSPForDVHardFail
:
553 return mOCSPTimeoutHard
;
554 // The rest of these are error cases. Assert in debug builds, but return
555 // the soft timeout value in release builds.
556 case NSSCertDBTrustDomain::NeverFetchOCSP
:
557 case NSSCertDBTrustDomain::LocalOnlyOCSPForEV
:
558 MOZ_ASSERT_UNREACHABLE("we should never see this OCSPFetching type here");
562 MOZ_ASSERT_UNREACHABLE("we're not handling every OCSPFetching type");
563 return mOCSPTimeoutSoft
;
566 // Copied and modified from CERT_GetOCSPAuthorityInfoAccessLocation and
567 // CERT_GetGeneralNameByType. Returns a non-Result::Success result on error,
568 // Success with result.IsVoid() == true when an OCSP URI was not found, and
569 // Success with result.IsVoid() == false when an OCSP URI was found.
570 static Result
GetOCSPAuthorityInfoAccessLocation(const UniquePLArenaPool
& arena
,
572 /*out*/ nsCString
& result
) {
573 MOZ_ASSERT(arena
.get());
575 return Result::FATAL_ERROR_INVALID_ARGS
;
578 result
.Assign(VoidCString());
579 SECItem aiaExtensionSECItem
= UnsafeMapInputToSECItem(aiaExtension
);
580 CERTAuthInfoAccess
** aia
=
581 CERT_DecodeAuthInfoAccessExtension(arena
.get(), &aiaExtensionSECItem
);
583 return Result::ERROR_CERT_BAD_ACCESS_LOCATION
;
585 for (size_t i
= 0; aia
[i
]; ++i
) {
586 if (SECOID_FindOIDTag(&aia
[i
]->method
) == SEC_OID_PKIX_OCSP
) {
587 // NSS chooses the **last** OCSP URL; we choose the **first**
588 CERTGeneralName
* current
= aia
[i
]->location
;
593 if (current
->type
== certURI
) {
594 const SECItem
& location
= current
->name
.other
;
595 // (location.len + 1) must be small enough to fit into a uint32_t,
596 // but we limit it to a smaller bound to reduce OOM risk.
597 if (location
.len
> 1024 || memchr(location
.data
, 0, location
.len
)) {
598 // Reject embedded nulls. (NSS doesn't do this)
599 return Result::ERROR_CERT_BAD_ACCESS_LOCATION
;
601 result
.Assign(nsDependentCSubstring(
602 reinterpret_cast<const char*>(location
.data
), location
.len
));
605 current
= CERT_GetNextGeneralName(current
);
606 } while (current
!= aia
[i
]->location
);
613 NS_IMPL_ISUPPORTS(CRLiteTimestamp
, nsICRLiteTimestamp
)
616 CRLiteTimestamp::GetLogID(nsTArray
<uint8_t>& aLogID
) {
618 aLogID
.AppendElements(mLogID
);
623 CRLiteTimestamp::GetTimestamp(uint64_t* aTimestamp
) {
624 *aTimestamp
= mTimestamp
;
628 Result
BuildCRLiteTimestampArray(
630 /*out*/ nsTArray
<RefPtr
<nsICRLiteTimestamp
>>& timestamps
) {
633 ExtractSignedCertificateTimestampListFromExtension(sctExtension
, sctList
);
637 std::vector
<SignedCertificateTimestamp
> decodedSCTs
;
638 size_t decodingErrors
;
639 DecodeSCTs(sctList
, decodedSCTs
, decodingErrors
);
640 Unused
<< decodingErrors
;
642 for (const auto& sct
: decodedSCTs
) {
643 timestamps
.AppendElement(new CRLiteTimestamp(sct
));
648 Result
NSSCertDBTrustDomain::CheckCRLiteStash(
649 const nsTArray
<uint8_t>& issuerSubjectPublicKeyInfoBytes
,
650 const nsTArray
<uint8_t>& serialNumberBytes
) {
651 // This information is deterministic and has already been validated by our
652 // infrastructure (it comes from signed CRLs), so if the stash says a
653 // certificate is revoked, it is.
654 bool isRevokedByStash
= false;
655 nsresult rv
= mCertStorage
->IsCertRevokedByStash(
656 issuerSubjectPublicKeyInfoBytes
, serialNumberBytes
, &isRevokedByStash
);
658 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
659 ("NSSCertDBTrustDomain::CheckCRLiteStash: IsCertRevokedByStash "
661 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
663 if (isRevokedByStash
) {
664 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
665 ("NSSCertDBTrustDomain::CheckCRLiteStash: IsCertRevokedByStash "
667 return Result::ERROR_REVOKED_CERTIFICATE
;
672 Result
NSSCertDBTrustDomain::CheckCRLite(
673 const nsTArray
<uint8_t>& issuerBytes
,
674 const nsTArray
<uint8_t>& issuerSubjectPublicKeyInfoBytes
,
675 const nsTArray
<uint8_t>& serialNumberBytes
,
676 const nsTArray
<RefPtr
<nsICRLiteTimestamp
>>& timestamps
,
677 /*out*/ bool& filterCoversCertificate
) {
678 filterCoversCertificate
= false;
679 int16_t crliteRevocationState
;
680 nsresult rv
= mCertStorage
->GetCRLiteRevocationState(
681 issuerBytes
, issuerSubjectPublicKeyInfoBytes
, serialNumberBytes
,
682 timestamps
, &crliteRevocationState
);
684 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
685 ("NSSCertDBTrustDomain::CheckCRLite: CRLite call failed"));
686 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
688 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
689 ("NSSCertDBTrustDomain::CheckCRLite: CRLite check returned "
691 crliteRevocationState
));
693 switch (crliteRevocationState
) {
694 case nsICertStorage::STATE_ENFORCE
:
695 filterCoversCertificate
= true;
696 return Result::ERROR_REVOKED_CERTIFICATE
;
697 case nsICertStorage::STATE_UNSET
:
698 filterCoversCertificate
= true;
700 case nsICertStorage::STATE_NOT_ENROLLED
:
701 filterCoversCertificate
= false;
703 case nsICertStorage::STATE_NOT_COVERED
:
704 filterCoversCertificate
= false;
706 case nsICertStorage::STATE_NO_FILTER
:
707 filterCoversCertificate
= false;
710 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
711 ("NSSCertDBTrustDomain::CheckCRLite: Unknown CRLite revocation "
713 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
717 Result
NSSCertDBTrustDomain::CheckRevocation(
718 EndEntityOrCA endEntityOrCA
, const CertID
& certID
, Time time
,
719 Duration validityDuration
,
720 /*optional*/ const Input
* stapledOCSPResponse
,
721 /*optional*/ const Input
* aiaExtension
,
722 /*optional*/ const Input
* sctExtension
) {
723 // Actively distrusted certificates will have already been blocked by
726 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
727 ("NSSCertDBTrustDomain: Top of CheckRevocation\n"));
729 // None of the revocation methods in this function are consulted for CA
730 // certificates. Revocation for CAs is handled by GetCertTrust.
731 if (endEntityOrCA
== EndEntityOrCA::MustBeCA
) {
735 // Look for an OCSP Authority Information Access URL. Our behavior in
736 // ConfirmRevocations mode depends on whether a synchronous OCSP
737 // request is possible.
738 nsCString
aiaLocation(VoidCString());
740 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
742 return Result::FATAL_ERROR_NO_MEMORY
;
745 GetOCSPAuthorityInfoAccessLocation(arena
, *aiaExtension
, aiaLocation
);
751 bool crliteCoversCertificate
= false;
752 Result crliteResult
= Success
;
753 if (mCRLiteMode
!= CRLiteMode::Disabled
&& sctExtension
) {
755 CheckRevocationByCRLite(certID
, *sctExtension
, crliteCoversCertificate
);
757 // If CheckCRLite returned an error other than "revoked certificate",
758 // propagate that error.
759 if (crliteResult
!= Success
&&
760 crliteResult
!= Result::ERROR_REVOKED_CERTIFICATE
) {
764 if (crliteCoversCertificate
) {
765 Telemetry::AccumulateCategorical(
766 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::CRLite
);
767 // If we don't return here we will consult OCSP.
768 // In Enforce CRLite mode we can return "Revoked" or "Not Revoked"
769 // without consulting OCSP.
770 if (mCRLiteMode
== CRLiteMode::Enforce
) {
773 // If we don't have a URL for an OCSP responder, then we can return any
774 // result ConfirmRevocations mode. Note that we might have a
775 // stapled or cached OCSP response which we ignore in this case.
776 if (mCRLiteMode
== CRLiteMode::ConfirmRevocations
&&
777 aiaLocation
.IsVoid()) {
780 // In ConfirmRevocations mode we can return "Not Revoked"
781 // without consulting OCSP.
782 if (mCRLiteMode
== CRLiteMode::ConfirmRevocations
&&
783 crliteResult
== Success
) {
789 bool ocspSoftFailure
= false;
790 Result ocspResult
= CheckRevocationByOCSP(
791 certID
, time
, validityDuration
, aiaLocation
, crliteCoversCertificate
,
792 crliteResult
, stapledOCSPResponse
, ocspSoftFailure
);
794 // In ConfirmRevocations mode we treat any OCSP failure as confirmation
795 // of a CRLite revoked result.
796 if (crliteCoversCertificate
&&
797 crliteResult
== Result::ERROR_REVOKED_CERTIFICATE
&&
798 mCRLiteMode
== CRLiteMode::ConfirmRevocations
&&
799 (ocspResult
!= Success
|| ocspSoftFailure
)) {
800 return Result::ERROR_REVOKED_CERTIFICATE
;
803 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
804 ("NSSCertDBTrustDomain: end of CheckRevocation"));
809 Result
NSSCertDBTrustDomain::CheckRevocationByCRLite(
810 const CertID
& certID
, const Input
& sctExtension
,
811 /*out*/ bool& crliteCoversCertificate
) {
812 crliteCoversCertificate
= false;
813 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
814 ("NSSCertDBTrustDomain::CheckRevocation: checking CRLite"));
815 nsTArray
<uint8_t> issuerSubjectPublicKeyInfoBytes
;
816 issuerSubjectPublicKeyInfoBytes
.AppendElements(
817 certID
.issuerSubjectPublicKeyInfo
.UnsafeGetData(),
818 certID
.issuerSubjectPublicKeyInfo
.GetLength());
819 nsTArray
<uint8_t> serialNumberBytes
;
820 serialNumberBytes
.AppendElements(certID
.serialNumber
.UnsafeGetData(),
821 certID
.serialNumber
.GetLength());
822 // The CRLite stash is essentially a subset of a collection of CRLs, so if
823 // it says a certificate is revoked, it is.
825 CheckCRLiteStash(issuerSubjectPublicKeyInfoBytes
, serialNumberBytes
);
827 crliteCoversCertificate
= (rv
== Result::ERROR_REVOKED_CERTIFICATE
);
831 nsTArray
<uint8_t> issuerBytes
;
832 issuerBytes
.AppendElements(certID
.issuer
.UnsafeGetData(),
833 certID
.issuer
.GetLength());
835 nsTArray
<RefPtr
<nsICRLiteTimestamp
>> timestamps
;
836 rv
= BuildCRLiteTimestampArray(sctExtension
, timestamps
);
838 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
839 ("decoding SCT extension failed - CRLite will be not be "
843 return CheckCRLite(issuerBytes
, issuerSubjectPublicKeyInfoBytes
,
844 serialNumberBytes
, timestamps
, crliteCoversCertificate
);
847 Result
NSSCertDBTrustDomain::CheckRevocationByOCSP(
848 const CertID
& certID
, Time time
, Duration validityDuration
,
849 const nsCString
& aiaLocation
, const bool crliteCoversCertificate
,
850 const Result crliteResult
,
851 /*optional*/ const Input
* stapledOCSPResponse
,
852 /*out*/ bool& softFailure
) {
854 const uint16_t maxOCSPLifetimeInDays
= 10;
855 // If we have a stapled OCSP response then the verification of that response
856 // determines the result unless the OCSP response is expired. We make an
857 // exception for expired responses because some servers, nginx in particular,
858 // are known to serve expired responses due to bugs.
859 // We keep track of the result of verifying the stapled response but don't
860 // immediately return failure if the response has expired.
861 Result stapledOCSPResponseResult
= Success
;
862 if (stapledOCSPResponse
) {
864 stapledOCSPResponseResult
= VerifyAndMaybeCacheEncodedOCSPResponse(
865 certID
, time
, maxOCSPLifetimeInDays
, *stapledOCSPResponse
,
866 ResponseWasStapled
, expired
);
867 Telemetry::AccumulateCategorical(
868 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::StapledOCSP
);
869 if (stapledOCSPResponseResult
== Success
) {
870 // stapled OCSP response present and good
871 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_GOOD
;
872 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
873 ("NSSCertDBTrustDomain: stapled OCSP response: good"));
876 if (stapledOCSPResponseResult
== Result::ERROR_OCSP_OLD_RESPONSE
||
878 // stapled OCSP response present but expired
879 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_EXPIRED
;
880 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
881 ("NSSCertDBTrustDomain: expired stapled OCSP response"));
882 } else if (stapledOCSPResponseResult
==
883 Result::ERROR_OCSP_TRY_SERVER_LATER
||
884 stapledOCSPResponseResult
==
885 Result::ERROR_OCSP_INVALID_SIGNING_CERT
) {
886 // Stapled OCSP response present but invalid for a small number of reasons
887 // CAs/servers commonly get wrong. This will be treated similarly to an
888 // expired stapled response.
889 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_INVALID
;
890 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
891 ("NSSCertDBTrustDomain: stapled OCSP response: "
892 "failure (allowed for compatibility)"));
894 // stapled OCSP response present but invalid for some reason
895 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_INVALID
;
896 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
897 ("NSSCertDBTrustDomain: stapled OCSP response: failure"));
898 return stapledOCSPResponseResult
;
901 // no stapled OCSP response
902 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_NONE
;
903 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
904 ("NSSCertDBTrustDomain: no stapled OCSP response"));
907 Result cachedResponseResult
= Success
;
908 Time
cachedResponseValidThrough(Time::uninitialized
);
909 bool cachedResponsePresent
=
910 mOCSPCache
.Get(certID
, mOriginAttributes
, cachedResponseResult
,
911 cachedResponseValidThrough
);
912 if (cachedResponsePresent
) {
913 Telemetry::AccumulateCategorical(
914 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::CachedOCSP
);
915 if (cachedResponseResult
== Success
&& cachedResponseValidThrough
>= time
) {
916 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
917 ("NSSCertDBTrustDomain: cached OCSP response: good"));
920 // If we have a cached revoked response, use it.
921 if (cachedResponseResult
== Result::ERROR_REVOKED_CERTIFICATE
) {
922 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
923 ("NSSCertDBTrustDomain: cached OCSP response: revoked"));
924 return Result::ERROR_REVOKED_CERTIFICATE
;
926 // The cached response may indicate an unknown certificate or it may be
927 // expired. Don't return with either of these statuses yet - we may be
928 // able to fetch a more recent one.
929 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
930 ("NSSCertDBTrustDomain: cached OCSP response: error %d",
931 static_cast<int>(cachedResponseResult
)));
932 // When a good cached response has expired, it is more convenient
933 // to convert that to an error code and just deal with
934 // cachedResponseResult from here on out.
935 if (cachedResponseResult
== Success
&& cachedResponseValidThrough
< time
) {
936 cachedResponseResult
= Result::ERROR_OCSP_OLD_RESPONSE
;
938 // We may have a cached indication of server failure. Ignore it if
940 if (cachedResponseResult
!= Success
&&
941 cachedResponseResult
!= Result::ERROR_OCSP_UNKNOWN_CERT
&&
942 cachedResponseResult
!= Result::ERROR_OCSP_OLD_RESPONSE
&&
943 cachedResponseValidThrough
< time
) {
944 cachedResponseResult
= Success
;
945 cachedResponsePresent
= false;
948 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
949 ("NSSCertDBTrustDomain: no cached OCSP response"));
951 // At this point, if and only if cachedErrorResult is Success, there was no
953 MOZ_ASSERT((!cachedResponsePresent
&& cachedResponseResult
== Success
) ||
954 (cachedResponsePresent
&& cachedResponseResult
!= Success
));
956 // TODO: We still need to handle the fallback for invalid stapled responses.
957 // But, if/when we disable OCSP fetching by default, it would be ambiguous
958 // whether security.OCSP.enable==0 means "I want the default" or "I really
959 // never want you to ever fetch OCSP."
960 // Additionally, this doesn't properly handle OCSP-must-staple when OCSP
961 // fetching is disabled.
962 Duration
shortLifetime(mCertShortLifetimeInDays
* Time::ONE_DAY_IN_SECONDS
);
963 if (validityDuration
< shortLifetime
) {
964 Telemetry::AccumulateCategorical(
965 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::ShortValidity
);
967 if ((mOCSPFetching
== NeverFetchOCSP
) || (validityDuration
< shortLifetime
)) {
968 // We're not going to be doing any fetching, so if there was a cached
969 // "unknown" response, say so.
970 if (cachedResponseResult
== Result::ERROR_OCSP_UNKNOWN_CERT
) {
971 return Result::ERROR_OCSP_UNKNOWN_CERT
;
973 // If we're doing hard-fail, we want to know if we have a cached response
975 if (mOCSPFetching
== FetchOCSPForDVHardFail
&&
976 cachedResponseResult
== Result::ERROR_OCSP_OLD_RESPONSE
) {
977 return Result::ERROR_OCSP_OLD_RESPONSE
;
984 if (mOCSPFetching
== LocalOnlyOCSPForEV
) {
985 if (cachedResponseResult
!= Success
) {
986 return cachedResponseResult
;
988 return Result::ERROR_OCSP_UNKNOWN_CERT
;
991 if (aiaLocation
.IsVoid()) {
992 if (mOCSPFetching
== FetchOCSPForEV
||
993 cachedResponseResult
== Result::ERROR_OCSP_UNKNOWN_CERT
) {
994 return Result::ERROR_OCSP_UNKNOWN_CERT
;
996 if (cachedResponseResult
== Result::ERROR_OCSP_OLD_RESPONSE
) {
997 return Result::ERROR_OCSP_OLD_RESPONSE
;
999 if (stapledOCSPResponseResult
!= Success
) {
1000 return stapledOCSPResponseResult
;
1003 // Nothing to do if we don't have an OCSP responder URI for the cert; just
1004 // assume it is good. Note that this is the confusing, but intended,
1005 // interpretation of "strict" revocation checking in the face of a
1006 // certificate that lacks an OCSP responder URI. There's no need to set
1007 // softFailure here---we check for the presence of an AIA before attempting
1008 // OCSP when CRLite is configured in confirm revocations mode.
1012 if (cachedResponseResult
== Success
||
1013 cachedResponseResult
== Result::ERROR_OCSP_UNKNOWN_CERT
||
1014 cachedResponseResult
== Result::ERROR_OCSP_OLD_RESPONSE
) {
1015 // Only send a request to, and process a response from, the server if we
1016 // didn't have a cached indication of failure. Also, don't keep requesting
1017 // responses from a failing server.
1018 return SynchronousCheckRevocationWithServer(
1019 certID
, aiaLocation
, time
, maxOCSPLifetimeInDays
, cachedResponseResult
,
1020 stapledOCSPResponseResult
, crliteCoversCertificate
, crliteResult
,
1024 return HandleOCSPFailure(cachedResponseResult
, stapledOCSPResponseResult
,
1025 cachedResponseResult
, softFailure
);
1028 Result
NSSCertDBTrustDomain::SynchronousCheckRevocationWithServer(
1029 const CertID
& certID
, const nsCString
& aiaLocation
, Time time
,
1030 uint16_t maxOCSPLifetimeInDays
, const Result cachedResponseResult
,
1031 const Result stapledOCSPResponseResult
, const bool crliteCoversCertificate
,
1032 const Result crliteResult
, /*out*/ bool& softFailure
) {
1033 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1034 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1037 uint8_t ocspRequestBytes
[OCSP_REQUEST_MAX_LENGTH
];
1038 size_t ocspRequestLength
;
1039 Result rv
= CreateEncodedOCSPRequest(*this, certID
, ocspRequestBytes
,
1041 if (rv
!= Success
) {
1045 Vector
<uint8_t> ocspResponse
;
1047 mOCSPFetchStatus
= OCSPFetchStatus::Fetched
;
1048 rv
= DoOCSPRequest(aiaLocation
, mOriginAttributes
, ocspRequestBytes
,
1049 ocspRequestLength
, GetOCSPTimeout(), ocspResponse
);
1050 Telemetry::AccumulateCategorical(
1051 Telemetry::LABELS_CERT_REVOCATION_MECHANISMS::OCSP
);
1052 if (rv
== Success
&&
1053 response
.Init(ocspResponse
.begin(), ocspResponse
.length()) != Success
) {
1054 rv
= Result::ERROR_OCSP_MALFORMED_RESPONSE
; // too big
1057 if (rv
!= Success
) {
1059 if (timeout
.AddSeconds(ServerFailureDelaySeconds
) != Success
) {
1060 return Result::FATAL_ERROR_LIBRARY_FAILURE
; // integer overflow
1064 mOCSPCache
.Put(certID
, mOriginAttributes
, rv
, time
, timeout
);
1065 if (cacheRV
!= Success
) {
1069 if (crliteCoversCertificate
) {
1070 if (crliteResult
== Success
) {
1071 // CRLite says the certificate is OK, but OCSP fetching failed.
1072 Telemetry::AccumulateCategorical(
1073 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteOkOCSPFail
);
1075 // CRLite says the certificate is revoked, but OCSP fetching failed.
1076 Telemetry::AccumulateCategorical(
1077 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteRevOCSPFail
);
1081 return HandleOCSPFailure(cachedResponseResult
, stapledOCSPResponseResult
,
1085 // If the response from the network has expired but indicates a revoked
1086 // or unknown certificate, PR_GetError() will return the appropriate error.
1087 // We actually ignore expired here.
1089 rv
= VerifyAndMaybeCacheEncodedOCSPResponse(certID
, time
,
1090 maxOCSPLifetimeInDays
, response
,
1091 ResponseIsFromNetwork
, expired
);
1093 // If the CRLite filter covers the certificate, compare the CRLite result
1094 // with the OCSP fetching result. OCSP may have succeeded, said the
1095 // certificate is revoked, said the certificate doesn't exist, or it may have
1096 // failed for a reason that results in a "soft fail" (i.e. there is no
1097 // indication that the certificate is either definitely revoked or definitely
1098 // not revoked, so for usability, revocation checking says the certificate is
1099 // valid by default).
1100 if (crliteCoversCertificate
) {
1101 if (rv
== Success
) {
1102 if (crliteResult
== Success
) {
1103 // CRLite and OCSP fetching agree the certificate is OK.
1104 Telemetry::AccumulateCategorical(
1105 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteOkOCSPOk
);
1107 // CRLite says the certificate is revoked, but OCSP says it is OK.
1108 Telemetry::AccumulateCategorical(
1109 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteRevOCSPOk
);
1111 } else if (rv
== Result::ERROR_REVOKED_CERTIFICATE
) {
1112 if (crliteResult
== Success
) {
1113 // CRLite says the certificate is OK, but OCSP says it is revoked.
1114 Telemetry::AccumulateCategorical(
1115 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteOkOCSPRev
);
1117 // CRLite and OCSP fetching agree the certificate is revoked.
1118 Telemetry::AccumulateCategorical(
1119 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteRevOCSPRev
);
1121 } else if (rv
== Result::ERROR_OCSP_UNKNOWN_CERT
) {
1122 if (crliteResult
== Success
) {
1123 // CRLite says the certificate is OK, but OCSP says it doesn't exist.
1124 Telemetry::AccumulateCategorical(
1125 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteOkOCSPUnk
);
1127 // CRLite says the certificate is revoked, but OCSP says it doesn't
1129 Telemetry::AccumulateCategorical(
1130 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteRevOCSPUnk
);
1133 if (crliteResult
== Success
) {
1134 // CRLite says the certificate is OK, but OCSP encountered a soft-fail
1136 Telemetry::AccumulateCategorical(
1137 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteOkOCSPSoft
);
1139 // CRLite says the certificate is revoked, but OCSP encountered a
1141 Telemetry::AccumulateCategorical(
1142 Telemetry::LABELS_CRLITE_VS_OCSP_RESULT::CRLiteRevOCSPSoft
);
1147 if (rv
== Success
|| mOCSPFetching
!= FetchOCSPForDVSoftFail
) {
1148 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1149 ("NSSCertDBTrustDomain: returning after "
1150 "VerifyEncodedOCSPResponse"));
1154 if (rv
== Result::ERROR_OCSP_UNKNOWN_CERT
||
1155 rv
== Result::ERROR_REVOKED_CERTIFICATE
) {
1159 if (stapledOCSPResponseResult
!= Success
) {
1160 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1161 ("NSSCertDBTrustDomain: returning SECFailure from expired/invalid "
1162 "stapled response after OCSP request verification failure"));
1163 return stapledOCSPResponseResult
;
1167 return Success
; // Soft fail -> success :(
1170 Result
NSSCertDBTrustDomain::HandleOCSPFailure(
1171 const Result cachedResponseResult
, const Result stapledOCSPResponseResult
,
1172 const Result error
, /*out*/ bool& softFailure
) {
1173 if (mOCSPFetching
!= FetchOCSPForDVSoftFail
) {
1174 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1175 ("NSSCertDBTrustDomain: returning SECFailure after OCSP request "
1180 if (cachedResponseResult
== Result::ERROR_OCSP_UNKNOWN_CERT
) {
1181 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1182 ("NSSCertDBTrustDomain: returning SECFailure from cached response "
1183 "after OCSP request failure"));
1184 return cachedResponseResult
;
1187 if (stapledOCSPResponseResult
!= Success
) {
1188 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1189 ("NSSCertDBTrustDomain: returning SECFailure from expired/invalid "
1190 "stapled response after OCSP request failure"));
1191 return stapledOCSPResponseResult
;
1194 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1195 ("NSSCertDBTrustDomain: returning SECSuccess after OCSP request "
1199 return Success
; // Soft fail -> success :(
1202 Result
NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
1203 const CertID
& certID
, Time time
, uint16_t maxLifetimeInDays
,
1204 Input encodedResponse
, EncodedResponseSource responseSource
,
1205 /*out*/ bool& expired
) {
1206 Time
thisUpdate(Time::uninitialized
);
1207 Time
validThrough(Time::uninitialized
);
1209 Result rv
= VerifyEncodedOCSPResponse(*this, certID
, time
, maxLifetimeInDays
,
1210 encodedResponse
, expired
, &thisUpdate
,
1212 // If a response was stapled and expired, we don't want to cache it. Return
1213 // early to simplify the logic here.
1214 if (responseSource
== ResponseWasStapled
&& expired
) {
1215 MOZ_ASSERT(rv
!= Success
);
1218 // validThrough is only trustworthy if the response successfully verifies
1219 // or it indicates a revoked or unknown certificate.
1220 // If this isn't the case, store an indication of failure (to prevent
1221 // repeatedly requesting a response from a failing server).
1222 if (rv
!= Success
&& rv
!= Result::ERROR_REVOKED_CERTIFICATE
&&
1223 rv
!= Result::ERROR_OCSP_UNKNOWN_CERT
) {
1224 validThrough
= time
;
1225 if (validThrough
.AddSeconds(ServerFailureDelaySeconds
) != Success
) {
1226 return Result::FATAL_ERROR_LIBRARY_FAILURE
; // integer overflow
1229 if (responseSource
== ResponseIsFromNetwork
|| rv
== Success
||
1230 rv
== Result::ERROR_REVOKED_CERTIFICATE
||
1231 rv
== Result::ERROR_OCSP_UNKNOWN_CERT
) {
1232 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1233 ("NSSCertDBTrustDomain: caching OCSP response"));
1235 mOCSPCache
.Put(certID
, mOriginAttributes
, rv
, thisUpdate
, validThrough
);
1236 if (putRV
!= Success
) {
1244 SECStatus
GetCertDistrustAfterValue(const SECItem
* distrustItem
,
1245 PRTime
& distrustTime
) {
1246 if (!distrustItem
|| !distrustItem
->data
|| distrustItem
->len
!= 13) {
1247 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
1250 return DER_DecodeTimeChoice(&distrustTime
, distrustItem
);
1253 SECStatus
GetCertNotBeforeValue(const CERTCertificate
* cert
,
1254 PRTime
& distrustTime
) {
1255 return DER_DecodeTimeChoice(&distrustTime
, &cert
->validity
.notBefore
);
1258 nsresult
isDistrustedCertificateChain(
1259 const nsTArray
<nsTArray
<uint8_t>>& certArray
,
1260 const SECTrustType certDBTrustType
, bool& isDistrusted
) {
1261 if (certArray
.Length() == 0) {
1262 return NS_ERROR_FAILURE
;
1265 // Set the default result to be distrusted.
1266 isDistrusted
= true;
1268 // There is no distrust to set if the certDBTrustType is not SSL or Email.
1269 if (certDBTrustType
!= trustSSL
&& certDBTrustType
!= trustEmail
) {
1270 isDistrusted
= false;
1274 SECStatus runnableRV
= SECFailure
;
1276 RefPtr
<Runnable
> isDistrustedChainTask
=
1277 NS_NewRunnableFunction("isDistrustedCertificateChain", [&]() {
1278 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1279 runnableRV
= SECFailure
;
1282 // Allocate objects and retreive the root and end-entity certificates.
1283 CERTCertDBHandle
* certDB(CERT_GetDefaultCertDB());
1284 const nsTArray
<uint8_t>& certRootDER
= certArray
.LastElement();
1285 SECItem certRootDERItem
= {
1286 siBuffer
, const_cast<unsigned char*>(certRootDER
.Elements()),
1287 AssertedCast
<unsigned int>(certRootDER
.Length())};
1288 UniqueCERTCertificate
certRoot(CERT_NewTempCertificate(
1289 certDB
, &certRootDERItem
, nullptr, false, true));
1291 runnableRV
= SECFailure
;
1294 const nsTArray
<uint8_t>& certLeafDER
= certArray
.ElementAt(0);
1295 SECItem certLeafDERItem
= {
1296 siBuffer
, const_cast<unsigned char*>(certLeafDER
.Elements()),
1297 AssertedCast
<unsigned int>(certLeafDER
.Length())};
1298 UniqueCERTCertificate
certLeaf(CERT_NewTempCertificate(
1299 certDB
, &certLeafDERItem
, nullptr, false, true));
1301 runnableRV
= SECFailure
;
1305 // Set isDistrusted to false if there is no distrust for the root.
1306 if (!certRoot
->distrust
) {
1307 isDistrusted
= false;
1308 runnableRV
= SECSuccess
;
1312 // Create a pointer to refer to the selected distrust struct.
1313 SECItem
* distrustPtr
= nullptr;
1314 if (certDBTrustType
== trustSSL
) {
1315 distrustPtr
= &certRoot
->distrust
->serverDistrustAfter
;
1317 if (certDBTrustType
== trustEmail
) {
1318 distrustPtr
= &certRoot
->distrust
->emailDistrustAfter
;
1321 // Get validity for the current end-entity certificate
1322 // and get the distrust field for the root certificate.
1323 PRTime certRootDistrustAfter
;
1324 PRTime certLeafNotBefore
;
1327 GetCertDistrustAfterValue(distrustPtr
, certRootDistrustAfter
);
1328 if (runnableRV
!= SECSuccess
) {
1332 runnableRV
= GetCertNotBeforeValue(certLeaf
.get(), certLeafNotBefore
);
1333 if (runnableRV
!= SECSuccess
) {
1337 // Compare the validity of the end-entity certificate with
1338 // the distrust value of the root.
1339 if (certLeafNotBefore
<= certRootDistrustAfter
) {
1340 isDistrusted
= false;
1343 runnableRV
= SECSuccess
;
1345 nsCOMPtr
<nsIEventTarget
> socketThread(
1346 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
));
1347 if (!socketThread
) {
1348 return NS_ERROR_FAILURE
;
1351 SyncRunnable::DispatchToThread(socketThread
, isDistrustedChainTask
);
1352 if (NS_FAILED(rv
) || runnableRV
!= SECSuccess
) {
1353 return NS_ERROR_FAILURE
;
1358 Result
NSSCertDBTrustDomain::IsChainValid(const DERArray
& reversedDERArray
,
1360 const CertPolicyId
& requiredPolicy
) {
1361 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1362 ("NSSCertDBTrustDomain: IsChainValid"));
1364 size_t numCerts
= reversedDERArray
.GetLength();
1366 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1368 nsTArray
<nsTArray
<uint8_t>> certArray
;
1369 for (size_t i
= numCerts
; i
> 0; --i
) {
1370 const Input
* derInput
= reversedDERArray
.GetDER(i
- 1);
1371 certArray
.EmplaceBack(derInput
->UnsafeGetData(), derInput
->GetLength());
1374 const nsTArray
<uint8_t>& rootBytes
= certArray
.LastElement();
1376 Result rv
= rootInput
.Init(rootBytes
.Elements(), rootBytes
.Length());
1377 if (rv
!= Success
) {
1380 rv
= IsCertBuiltInRoot(rootInput
, mIsBuiltChainRootBuiltInRoot
);
1381 if (rv
!= Result::Success
) {
1385 // If mHostname isn't set, we're not verifying in the context of a TLS
1386 // handshake, so don't verify key pinning in those cases.
1388 nsTArray
<Span
<const uint8_t>> derCertSpanList
;
1389 for (const auto& certDER
: certArray
) {
1390 derCertSpanList
.EmplaceBack(certDER
.Elements(), certDER
.Length());
1393 bool chainHasValidPins
;
1394 nsrv
= PublicKeyPinningService::ChainHasValidPins(
1395 derCertSpanList
, mHostname
, time
, mIsBuiltChainRootBuiltInRoot
,
1396 chainHasValidPins
, mPinningTelemetryInfo
);
1397 if (NS_FAILED(nsrv
)) {
1398 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1400 if (!chainHasValidPins
) {
1401 return Result::ERROR_KEY_PINNING_FAILURE
;
1405 // Check that the childs' certificate NotBefore date is anterior to
1406 // the NotAfter value of the parent when the root is a builtin.
1407 if (mIsBuiltChainRootBuiltInRoot
) {
1410 isDistrustedCertificateChain(certArray
, mCertDBTrustType
, isDistrusted
);
1411 if (NS_FAILED(nsrv
)) {
1412 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1415 return Result::ERROR_UNTRUSTED_ISSUER
;
1419 // See bug 1434300. If the root is a Symantec root, see if we distrust this
1420 // path. Since we already have the root available, we can check that cheaply
1421 // here before proceeding with the rest of the algorithm.
1423 // This algorithm only applies if we are verifying in the context of a TLS
1424 // handshake. To determine this, we check mHostname: If it isn't set, this is
1425 // not TLS, so don't run the algorithm.
1426 const nsTArray
<uint8_t>& rootCertDER
= certArray
.LastElement();
1427 if (mHostname
&& CertDNIsInList(rootCertDER
, RootSymantecDNs
)) {
1428 if (numCerts
<= 1) {
1429 // This chain is supposed to be complete, so this is an error.
1430 return Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED
;
1432 nsTArray
<Input
> intCerts
;
1434 for (size_t i
= 1; i
< certArray
.Length() - 1; ++i
) {
1435 const nsTArray
<uint8_t>& certBytes
= certArray
.ElementAt(i
);
1437 rv
= certInput
.Init(certBytes
.Elements(), certBytes
.Length());
1438 if (rv
!= Success
) {
1439 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1442 intCerts
.EmplaceBack(certInput
);
1445 bool isDistrusted
= false;
1446 nsrv
= CheckForSymantecDistrust(intCerts
, RootAppleAndGoogleSPKIs
,
1448 if (NS_FAILED(nsrv
)) {
1449 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1452 mSawDistrustedCAByPolicyError
= true;
1453 return Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED
;
1457 mBuiltChain
= std::move(certArray
);
1462 Result
NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(
1463 DigestAlgorithm aAlg
, EndEntityOrCA
/*endEntityOrCA*/, Time
/*notBefore*/) {
1465 case DigestAlgorithm::sha256
: // fall through
1466 case DigestAlgorithm::sha384
: // fall through
1467 case DigestAlgorithm::sha512
:
1469 case DigestAlgorithm::sha1
:
1470 return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
;
1472 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1475 Result
NSSCertDBTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
1476 EndEntityOrCA
/*endEntityOrCA*/, unsigned int modulusSizeInBits
) {
1477 if (modulusSizeInBits
< mMinRSABits
) {
1478 return Result::ERROR_INADEQUATE_KEY_SIZE
;
1483 Result
NSSCertDBTrustDomain::VerifyRSAPKCS1SignedData(
1484 Input data
, DigestAlgorithm digestAlgorithm
, Input signature
,
1485 Input subjectPublicKeyInfo
) {
1486 return VerifyRSAPKCS1SignedDataNSS(data
, digestAlgorithm
, signature
,
1487 subjectPublicKeyInfo
, mPinArg
);
1490 Result
NSSCertDBTrustDomain::VerifyRSAPSSSignedData(
1491 Input data
, DigestAlgorithm digestAlgorithm
, Input signature
,
1492 Input subjectPublicKeyInfo
) {
1493 return VerifyRSAPSSSignedDataNSS(data
, digestAlgorithm
, signature
,
1494 subjectPublicKeyInfo
, mPinArg
);
1497 Result
NSSCertDBTrustDomain::CheckECDSACurveIsAcceptable(
1498 EndEntityOrCA
/*endEntityOrCA*/, NamedCurve curve
) {
1500 case NamedCurve::secp256r1
: // fall through
1501 case NamedCurve::secp384r1
: // fall through
1502 case NamedCurve::secp521r1
:
1506 return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE
;
1509 Result
NSSCertDBTrustDomain::VerifyECDSASignedData(
1510 Input data
, DigestAlgorithm digestAlgorithm
, Input signature
,
1511 Input subjectPublicKeyInfo
) {
1512 return VerifyECDSASignedDataNSS(data
, digestAlgorithm
, signature
,
1513 subjectPublicKeyInfo
, mPinArg
);
1516 Result
NSSCertDBTrustDomain::CheckValidityIsAcceptable(
1517 Time notBefore
, Time notAfter
, EndEntityOrCA endEntityOrCA
,
1518 KeyPurposeId keyPurpose
) {
1519 if (endEntityOrCA
!= EndEntityOrCA::MustBeEndEntity
) {
1522 if (keyPurpose
== KeyPurposeId::id_kp_OCSPSigning
) {
1526 Duration
DURATION_27_MONTHS_PLUS_SLOP((2 * 365 + 3 * 31 + 7) *
1527 Time::ONE_DAY_IN_SECONDS
);
1528 Duration
maxValidityDuration(UINT64_MAX
);
1529 Duration
validityDuration(notBefore
, notAfter
);
1531 switch (mValidityCheckingMode
) {
1532 case ValidityCheckingMode::CheckingOff
:
1534 case ValidityCheckingMode::CheckForEV
:
1535 // The EV Guidelines say the maximum is 27 months, but we use a slightly
1536 // higher limit here to (hopefully) minimize compatibility breakage.
1537 maxValidityDuration
= DURATION_27_MONTHS_PLUS_SLOP
;
1540 MOZ_ASSERT_UNREACHABLE(
1541 "We're not handling every ValidityCheckingMode type");
1544 if (validityDuration
> maxValidityDuration
) {
1545 return Result::ERROR_VALIDITY_TOO_LONG
;
1551 Result
NSSCertDBTrustDomain::NetscapeStepUpMatchesServerAuth(
1553 /*out*/ bool& matches
) {
1554 // (new Date("2015-08-23T00:00:00Z")).getTime() / 1000
1555 static const Time AUGUST_23_2015
= TimeFromEpochInSeconds(1440288000);
1556 // (new Date("2016-08-23T00:00:00Z")).getTime() / 1000
1557 static const Time AUGUST_23_2016
= TimeFromEpochInSeconds(1471910400);
1559 switch (mNetscapeStepUpPolicy
) {
1560 case NetscapeStepUpPolicy::AlwaysMatch
:
1563 case NetscapeStepUpPolicy::MatchBefore23August2016
:
1564 matches
= notBefore
< AUGUST_23_2016
;
1566 case NetscapeStepUpPolicy::MatchBefore23August2015
:
1567 matches
= notBefore
< AUGUST_23_2015
;
1569 case NetscapeStepUpPolicy::NeverMatch
:
1573 MOZ_ASSERT_UNREACHABLE("unhandled NetscapeStepUpPolicy type");
1575 return Result::FATAL_ERROR_LIBRARY_FAILURE
;
1578 void NSSCertDBTrustDomain::ResetAccumulatedState() {
1579 mOCSPStaplingStatus
= CertVerifier::OCSP_STAPLING_NEVER_CHECKED
;
1580 mSCTListFromOCSPStapling
= nullptr;
1581 mSCTListFromCertificate
= nullptr;
1582 mSawDistrustedCAByPolicyError
= false;
1583 mIsBuiltChainRootBuiltInRoot
= false;
1584 mIssuerSources
.clear();
1587 static Input
SECItemToInput(const UniqueSECItem
& item
) {
1590 MOZ_ASSERT(item
->type
== siBuffer
);
1591 Result rv
= result
.Init(item
->data
, item
->len
);
1592 // As used here, |item| originally comes from an Input,
1593 // so there should be no issues converting it back.
1594 MOZ_ASSERT(rv
== Success
);
1595 Unused
<< rv
; // suppresses warnings in release builds
1600 Input
NSSCertDBTrustDomain::GetSCTListFromCertificate() const {
1601 return SECItemToInput(mSCTListFromCertificate
);
1604 Input
NSSCertDBTrustDomain::GetSCTListFromOCSPStapling() const {
1605 return SECItemToInput(mSCTListFromOCSPStapling
);
1608 bool NSSCertDBTrustDomain::GetIsBuiltChainRootBuiltInRoot() const {
1609 return mIsBuiltChainRootBuiltInRoot
;
1612 bool NSSCertDBTrustDomain::GetIsErrorDueToDistrustedCAPolicy() const {
1613 return mSawDistrustedCAByPolicyError
;
1616 void NSSCertDBTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension extension
,
1617 Input extensionData
) {
1618 UniqueSECItem
* out
= nullptr;
1619 switch (extension
) {
1620 case AuxiliaryExtension::EmbeddedSCTList
:
1621 out
= &mSCTListFromCertificate
;
1623 case AuxiliaryExtension::SCTListFromOCSPResponse
:
1624 out
= &mSCTListFromOCSPStapling
;
1627 MOZ_ASSERT_UNREACHABLE("unhandled AuxiliaryExtension");
1630 SECItem extensionDataItem
= UnsafeMapInputToSECItem(extensionData
);
1631 out
->reset(SECITEM_DupItem(&extensionDataItem
));
1635 SECStatus
InitializeNSS(const nsACString
& dir
, NSSDBConfig nssDbConfig
,
1636 PKCS11DBConfig pkcs11DbConfig
) {
1637 MOZ_ASSERT(NS_IsMainThread());
1639 // The NSS_INIT_NOROOTINIT flag turns off the loading of the root certs
1640 // module by NSS_Initialize because we will load it in LoadLoadableRoots
1641 // later. It also allows us to work around a bug in the system NSS in
1642 // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
1643 // "/usr/lib/nss/libnssckbi.so".
1644 uint32_t flags
= NSS_INIT_NOROOTINIT
| NSS_INIT_OPTIMIZESPACE
;
1645 if (nssDbConfig
== NSSDBConfig::ReadOnly
) {
1646 flags
|= NSS_INIT_READONLY
;
1648 if (pkcs11DbConfig
== PKCS11DBConfig::DoNotLoadModules
) {
1649 flags
|= NSS_INIT_NOMODDB
;
1651 nsAutoCString
dbTypeAndDirectory("sql:");
1652 dbTypeAndDirectory
.Append(dir
);
1653 MOZ_LOG(gCertVerifierLog
, LogLevel::Debug
,
1654 ("InitializeNSS(%s, %d, %d)", dbTypeAndDirectory
.get(),
1655 (int)nssDbConfig
, (int)pkcs11DbConfig
));
1657 NSS_Initialize(dbTypeAndDirectory
.get(), "", "", SECMOD_DB
, flags
);
1658 if (srv
!= SECSuccess
) {
1662 if (nssDbConfig
== NSSDBConfig::ReadWrite
) {
1663 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
1667 // If the key DB doesn't have a password set, PK11_NeedUserInit will return
1668 // true. For the SQL DB, we need to set a password or we won't be able to
1669 // import any certificates or change trust settings.
1670 if (PK11_NeedUserInit(slot
.get())) {
1671 srv
= PK11_InitPin(slot
.get(), nullptr, nullptr);
1672 MOZ_ASSERT(srv
== SECSuccess
);
1681 NSS_SetAlgorithmPolicy(
1683 NSS_USE_ALG_IN_CERT_SIGNATURE
| NSS_USE_ALG_IN_CMS_SIGNATURE
);
1684 NSS_SetAlgorithmPolicy(
1685 SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
, 0,
1686 NSS_USE_ALG_IN_CERT_SIGNATURE
| NSS_USE_ALG_IN_CMS_SIGNATURE
);
1687 NSS_SetAlgorithmPolicy(
1688 SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC
, 0,
1689 NSS_USE_ALG_IN_CERT_SIGNATURE
| NSS_USE_ALG_IN_CMS_SIGNATURE
);
1692 // Load a given PKCS#11 module located in the given directory. It will be named
1693 // the given module name. Optionally pass some string parameters to it via
1694 // 'params'. This argument will be provided to C_Initialize when called on the
1696 // |libraryName| and |dir| are encoded in UTF-8.
1697 bool LoadUserModuleAt(const char* moduleName
, const char* libraryName
,
1698 const nsCString
& dir
, /* optional */ const char* params
) {
1699 // If a module exists with the same name, make a best effort attempt to delete
1700 // it. Note that it isn't possible to delete the internal module, so checking
1701 // the return value would be detrimental in that case.
1703 Unused
<< SECMOD_DeleteModule(moduleName
, &unusedModType
);
1705 nsAutoCString fullLibraryPath
;
1706 if (!dir
.IsEmpty()) {
1707 fullLibraryPath
.Assign(dir
);
1708 fullLibraryPath
.AppendLiteral(FILE_PATH_SEPARATOR
);
1710 fullLibraryPath
.Append(MOZ_DLL_PREFIX
);
1711 fullLibraryPath
.Append(libraryName
);
1712 fullLibraryPath
.Append(MOZ_DLL_SUFFIX
);
1713 // Escape the \ and " characters.
1714 fullLibraryPath
.ReplaceSubstring("\\", "\\\\");
1715 fullLibraryPath
.ReplaceSubstring("\"", "\\\"");
1717 nsAutoCString
pkcs11ModuleSpec("name=\"");
1718 pkcs11ModuleSpec
.Append(moduleName
);
1719 pkcs11ModuleSpec
.AppendLiteral("\" library=\"");
1720 pkcs11ModuleSpec
.Append(fullLibraryPath
);
1721 pkcs11ModuleSpec
.AppendLiteral("\"");
1723 pkcs11ModuleSpec
.AppendLiteral("\" parameters=\"");
1724 pkcs11ModuleSpec
.Append(params
);
1725 pkcs11ModuleSpec
.AppendLiteral("\"");
1728 UniqueSECMODModule
userModule(SECMOD_LoadUserModule(
1729 const_cast<char*>(pkcs11ModuleSpec
.get()), nullptr, false));
1734 if (!userModule
->loaded
) {
1741 const char* kIPCClientCertsModuleName
= "IPC Client Cert Module";
1743 bool LoadIPCClientCertsModule(const nsCString
& dir
) {
1744 // The IPC client certs module needs to be able to call back into gecko to be
1745 // able to communicate with the parent process over IPC. This is achieved by
1746 // serializing the addresses of the relevant functions and passing them as an
1747 // extra string parameter that will be available when C_Initialize is called
1748 // on IPC client certs.
1749 nsPrintfCString
addrs("%p,%p", DoFindObjects
, DoSign
);
1750 if (!LoadUserModuleAt(kIPCClientCertsModuleName
, "ipcclientcerts", dir
,
1756 UniqueSECMODModule
ipcClientCertsModule(
1757 SECMOD_FindModule(kIPCClientCertsModuleName
));
1758 if (ipcClientCertsModule
) {
1759 SECMOD_UnloadUserModule(ipcClientCertsModule
.get());
1762 ShutdownPhase::XPCOMWillShutdown
);
1766 const char* kOSClientCertsModuleName
= "OS Client Cert Module";
1768 bool LoadOSClientCertsModule(const nsCString
& dir
) {
1769 nsLiteralCString params
=
1770 StaticPrefs::security_osclientcerts_assume_rsa_pss_support()
1773 return LoadUserModuleAt(kOSClientCertsModuleName
, "osclientcerts", dir
,
1777 bool LoadLoadableRoots(const nsCString
& dir
) {
1778 // Some NSS command-line utilities will load a roots module under the name
1779 // "Root Certs" if there happens to be a `MOZ_DLL_PREFIX "nssckbi"
1780 // MOZ_DLL_SUFFIX` file in the directory being operated on. In some cases this
1781 // can cause us to fail to load our roots module. In these cases, deleting the
1782 // "Root Certs" module allows us to load the correct one. See bug 1406396.
1784 Unused
<< SECMOD_DeleteModule("Root Certs", &unusedModType
);
1785 return LoadUserModuleAt(kRootModuleName
, "nssckbi", dir
, nullptr);
1788 nsresult
DefaultServerNicknameForCert(const CERTCertificate
* cert
,
1789 /*out*/ nsCString
& nickname
) {
1791 NS_ENSURE_ARG_POINTER(cert
);
1793 UniquePORTString
baseName(CERT_GetCommonName(&cert
->subject
));
1795 baseName
= UniquePORTString(CERT_GetOrgUnitName(&cert
->subject
));
1798 baseName
= UniquePORTString(CERT_GetOrgName(&cert
->subject
));
1801 baseName
= UniquePORTString(CERT_GetLocalityName(&cert
->subject
));
1804 baseName
= UniquePORTString(CERT_GetStateName(&cert
->subject
));
1807 baseName
= UniquePORTString(CERT_GetCountryName(&cert
->subject
));
1810 return NS_ERROR_FAILURE
;
1813 // This function is only used in contexts where a failure to find a suitable
1814 // nickname does not block the overall task from succeeding.
1815 // As such, we use an arbitrary limit to prevent this nickname searching
1816 // process from taking forever.
1817 static const uint32_t ARBITRARY_LIMIT
= 500;
1818 for (uint32_t count
= 1; count
< ARBITRARY_LIMIT
; count
++) {
1819 nickname
= baseName
.get();
1821 nickname
.AppendPrintf(" #%u", count
);
1823 if (nickname
.IsEmpty()) {
1824 return NS_ERROR_FAILURE
;
1827 bool conflict
= SEC_CertNicknameConflict(nickname
.get(), &cert
->derSubject
,
1834 return NS_ERROR_FAILURE
;
1837 Result
BuildRevocationCheckArrays(Input certDER
, EndEntityOrCA endEntityOrCA
,
1838 /*out*/ nsTArray
<uint8_t>& issuerBytes
,
1839 /*out*/ nsTArray
<uint8_t>& serialBytes
,
1840 /*out*/ nsTArray
<uint8_t>& subjectBytes
,
1841 /*out*/ nsTArray
<uint8_t>& pubKeyBytes
) {
1842 BackCert
cert(certDER
, endEntityOrCA
, nullptr);
1843 Result rv
= cert
.Init();
1844 if (rv
!= Success
) {
1847 issuerBytes
.Clear();
1848 Input
issuer(cert
.GetIssuer());
1849 issuerBytes
.AppendElements(issuer
.UnsafeGetData(), issuer
.GetLength());
1850 serialBytes
.Clear();
1851 Input
serial(cert
.GetSerialNumber());
1852 serialBytes
.AppendElements(serial
.UnsafeGetData(), serial
.GetLength());
1853 subjectBytes
.Clear();
1854 Input
subject(cert
.GetSubject());
1855 subjectBytes
.AppendElements(subject
.UnsafeGetData(), subject
.GetLength());
1856 pubKeyBytes
.Clear();
1857 Input
pubKey(cert
.GetSubjectPublicKeyInfo());
1858 pubKeyBytes
.AppendElements(pubKey
.UnsafeGetData(), pubKey
.GetLength());
1863 bool CertIsInCertStorage(const nsTArray
<uint8_t>& certDER
,
1864 nsICertStorage
* certStorage
) {
1865 MOZ_ASSERT(certStorage
);
1870 Result rv
= certInput
.Init(certDER
.Elements(), certDER
.Length());
1871 if (rv
!= Success
) {
1874 BackCert
cert(certInput
, EndEntityOrCA::MustBeCA
, nullptr);
1876 if (rv
!= Success
) {
1879 nsTArray
<uint8_t> subject
;
1880 subject
.AppendElements(cert
.GetSubject().UnsafeGetData(),
1881 cert
.GetSubject().GetLength());
1882 nsTArray
<nsTArray
<uint8_t>> certStorageCerts
;
1883 if (NS_FAILED(certStorage
->FindCertsBySubject(subject
, certStorageCerts
))) {
1886 for (const auto& certStorageCert
: certStorageCerts
) {
1887 if (certStorageCert
.Length() != certDER
.Length()) {
1890 if (memcmp(certStorageCert
.Elements(), certDER
.Elements(),
1891 certStorageCert
.Length()) == 0) {
1899 * Given a list of certificates representing a verified certificate path from an
1900 * end-entity certificate to a trust anchor, imports the intermediate
1901 * certificates into the permanent certificate database. This is an attempt to
1902 * cope with misconfigured servers that don't include the appropriate
1903 * intermediate certificates in the TLS handshake.
1905 * @param certList the verified certificate list
1907 void SaveIntermediateCerts(const nsTArray
<nsTArray
<uint8_t>>& certList
) {
1908 if (certList
.IsEmpty()) {
1911 nsTArray
<nsTArray
<uint8_t>> intermediates
;
1912 // Skip the end-entity; we only want to store intermediates. Similarly,
1913 // there's no need to save the trust anchor - it's either already a permanent
1914 // certificate or it's the Microsoft Family Safety root or an enterprise root
1915 // temporarily imported via the child mode or enterprise root features. We
1916 // don't want to import these because they're intended to be temporary (and
1917 // because importing them happens to reset their trust settings, which breaks
1919 for (size_t index
= 1; index
< certList
.Length() - 1; index
++) {
1920 intermediates
.AppendElement(certList
.ElementAt(index
).Clone());
1922 nsCOMPtr
<nsIRunnable
> importCertsRunnable(NS_NewRunnableFunction(
1923 "IdleSaveIntermediateCerts",
1924 [intermediates
= std::move(intermediates
)]() -> void {
1925 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1928 UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
1932 size_t numCertsImported
= 0;
1933 nsCOMPtr
<nsICertStorage
> certStorage(
1934 do_GetService(NS_CERT_STORAGE_CID
));
1935 for (const auto& certDER
: intermediates
) {
1936 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1939 if (CertIsInCertStorage(certDER
, certStorage
)) {
1942 SECItem certDERItem
= {siBuffer
,
1943 const_cast<unsigned char*>(certDER
.Elements()),
1944 AssertedCast
<unsigned int>(certDER
.Length())};
1945 UniqueCERTCertificate
cert(CERT_NewTempCertificate(
1946 CERT_GetDefaultCertDB(), &certDERItem
, nullptr, false, true));
1951 // This cert was found on a token; no need to remember it in the
1952 // permanent database.
1956 if (CERT_GetCertIsPerm(cert
.get(), &isperm
) != SECSuccess
) {
1960 // We don't need to remember certs already stored in perm db.
1963 // This is a best-effort attempt at avoiding unknown issuer errors
1964 // in the future, so ignore failures here.
1965 nsAutoCString nickname
;
1966 if (NS_FAILED(DefaultServerNicknameForCert(cert
.get(), nickname
))) {
1969 Unused
<< PK11_ImportCert(slot
.get(), cert
.get(), CK_INVALID_HANDLE
,
1970 nickname
.get(), false);
1974 nsCOMPtr
<nsIRunnable
> runnable(NS_NewRunnableFunction(
1975 "IdleSaveIntermediateCertsDone", [numCertsImported
]() -> void {
1976 nsCOMPtr
<nsIObserverService
> observerService
=
1977 mozilla::services::GetObserverService();
1978 if (observerService
) {
1979 NS_ConvertUTF8toUTF16
numCertsImportedString(
1980 nsPrintfCString("%zu", numCertsImported
));
1981 observerService
->NotifyObservers(
1982 nullptr, "psm:intermediate-certs-cached",
1983 numCertsImportedString
.get());
1986 Unused
<< NS_DispatchToMainThread(runnable
.forget());
1988 Unused
<< NS_DispatchToCurrentThreadQueue(importCertsRunnable
.forget(),
1989 EventQueuePriority::Idle
);
1993 } // namespace mozilla