Backed out changeset f53842753805 (bug 1804872) for causing reftest failures on 15535...
[gecko.git] / security / manager / ssl / AppTrustDomain.cpp
blob2cdf275adea369354915c96b01ebaf87a2da9f9d
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 "AppTrustDomain.h"
9 #include "MainThreadUtils.h"
10 #include "cert_storage/src/cert_storage.h"
11 // FIXME: these two must be included before certdb.h {
12 #include "seccomon.h"
13 #include "certt.h"
14 // }
15 #include "certdb.h"
16 #include "mozilla/ArrayUtils.h"
17 #include "mozilla/Casting.h"
18 #include "mozilla/Logging.h"
19 #include "mozilla/Preferences.h"
20 #include "mozpkix/pkixnss.h"
21 #include "NSSCertDBTrustDomain.h"
22 #include "nsComponentManagerUtils.h"
23 #include "nsDirectoryServiceUtils.h"
24 #include "nsIContentSignatureVerifier.h"
25 #include "nsIX509CertDB.h"
26 #include "nsNSSCertificate.h"
27 #include "nsNetUtil.h"
28 #include "prerror.h"
30 // Generated by gen_cert_header.py, which gets called by the build system.
31 #include "xpcshell.inc"
32 // Add-on signing Certificates
33 #include "addons-public.inc"
34 #include "addons-public-intermediate.inc"
35 #include "addons-stage.inc"
36 // Content signature root certificates
37 #include "content-signature-dev.inc"
38 #include "content-signature-local.inc"
39 #include "content-signature-prod.inc"
40 #include "content-signature-stage.inc"
42 using namespace mozilla::pkix;
44 extern mozilla::LazyLogModule gPIPNSSLog;
46 namespace mozilla {
47 namespace psm {
49 AppTrustDomain::AppTrustDomain(nsTArray<Span<const uint8_t>>&& collectedCerts)
50 : mIntermediates(std::move(collectedCerts)),
51 mCertBlocklist(do_GetService(NS_CERT_STORAGE_CID)) {}
53 nsresult AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) {
54 switch (trustedRoot) {
55 case nsIX509CertDB::AppXPCShellRoot:
56 mTrustedRoot = {xpcshellRoot};
57 break;
59 case nsIX509CertDB::AddonsPublicRoot:
60 mTrustedRoot = {addonsPublicRoot};
61 break;
63 case nsIX509CertDB::AddonsStageRoot:
64 mTrustedRoot = {addonsStageRoot};
65 break;
67 case nsIContentSignatureVerifier::ContentSignatureLocalRoot:
68 mTrustedRoot = {contentSignatureLocalRoot};
69 break;
71 case nsIContentSignatureVerifier::ContentSignatureProdRoot:
72 mTrustedRoot = {contentSignatureProdRoot};
73 break;
75 case nsIContentSignatureVerifier::ContentSignatureStageRoot:
76 mTrustedRoot = {contentSignatureStageRoot};
77 break;
79 case nsIContentSignatureVerifier::ContentSignatureDevRoot:
80 mTrustedRoot = {contentSignatureDevRoot};
81 break;
83 default:
84 return NS_ERROR_INVALID_ARG;
87 // If we're verifying add-ons signed by our production root, we want to make
88 // sure a valid intermediate certificate is available for path building.
89 if (trustedRoot == nsIX509CertDB::AddonsPublicRoot) {
90 mAddonsIntermediate = {addonsPublicIntermediate};
93 return NS_OK;
96 pkix::Result AppTrustDomain::FindIssuer(Input encodedIssuerName,
97 IssuerChecker& checker, Time) {
98 MOZ_ASSERT(!mTrustedRoot.IsEmpty());
99 if (mTrustedRoot.IsEmpty()) {
100 return pkix::Result::FATAL_ERROR_INVALID_STATE;
103 nsTArray<Input> candidates;
104 Input rootInput;
105 pkix::Result rv =
106 rootInput.Init(mTrustedRoot.Elements(), mTrustedRoot.Length());
107 // This should never fail, since the possible roots are all hard-coded and
108 // they should never be too long.
109 if (rv != Success) {
110 return rv;
112 candidates.AppendElement(std::move(rootInput));
113 if (!mAddonsIntermediate.IsEmpty()) {
114 Input intermediateInput;
115 rv = intermediateInput.Init(mAddonsIntermediate.Elements(),
116 mAddonsIntermediate.Length());
117 // Again, this should never fail for the same reason as above.
118 if (rv != Success) {
119 return rv;
121 candidates.AppendElement(std::move(intermediateInput));
123 for (const auto& intermediate : mIntermediates) {
124 Input intermediateInput;
125 rv = intermediateInput.Init(intermediate.Elements(), intermediate.Length());
126 // This is untrusted input, so skip any intermediates that are too large.
127 if (rv != Success) {
128 continue;
130 candidates.AppendElement(std::move(intermediateInput));
133 for (const auto& candidate : candidates) {
134 bool keepGoing;
135 rv = checker.Check(candidate, nullptr /*additionalNameConstraints*/,
136 keepGoing);
137 if (rv != Success) {
138 return rv;
140 if (!keepGoing) {
141 return Success;
145 // If the above did not succeed in building a verified certificate chain,
146 // fall back to searching for candidates in NSS. This is important in case an
147 // intermediate involved in add-on signing expires before it is replaced. See
148 // bug 1548973.
149 SECItem encodedIssuerNameSECItem = UnsafeMapInputToSECItem(encodedIssuerName);
150 UniqueCERTCertList nssCandidates(CERT_CreateSubjectCertList(
151 nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameSECItem, 0, false));
152 if (nssCandidates) {
153 for (CERTCertListNode* n = CERT_LIST_HEAD(nssCandidates);
154 !CERT_LIST_END(n, nssCandidates); n = CERT_LIST_NEXT(n)) {
155 Input certDER;
156 pkix::Result rv =
157 certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
158 if (rv != Success) {
159 continue; // probably too big
162 bool keepGoing;
163 rv = checker.Check(certDER, nullptr /*additionalNameConstraints*/,
164 keepGoing);
165 if (rv != Success) {
166 return rv;
168 if (!keepGoing) {
169 break;
174 return Success;
177 pkix::Result AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
178 const CertPolicyId& policy,
179 Input candidateCertDER,
180 /*out*/ TrustLevel& trustLevel) {
181 MOZ_ASSERT(policy.IsAnyPolicy());
182 MOZ_ASSERT(!mTrustedRoot.IsEmpty());
183 if (!policy.IsAnyPolicy()) {
184 return pkix::Result::FATAL_ERROR_INVALID_ARGS;
186 if (mTrustedRoot.IsEmpty()) {
187 return pkix::Result::FATAL_ERROR_INVALID_STATE;
190 nsTArray<uint8_t> issuerBytes;
191 nsTArray<uint8_t> serialBytes;
192 nsTArray<uint8_t> subjectBytes;
193 nsTArray<uint8_t> pubKeyBytes;
195 pkix::Result result =
196 BuildRevocationCheckArrays(candidateCertDER, endEntityOrCA, issuerBytes,
197 serialBytes, subjectBytes, pubKeyBytes);
198 if (result != Success) {
199 return result;
202 int16_t revocationState;
203 nsresult nsrv = mCertBlocklist->GetRevocationState(
204 issuerBytes, serialBytes, subjectBytes, pubKeyBytes, &revocationState);
205 if (NS_FAILED(nsrv)) {
206 return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
209 if (revocationState == nsICertStorage::STATE_ENFORCE) {
210 return pkix::Result::ERROR_REVOKED_CERTIFICATE;
213 // mTrustedRoot is the only trust anchor for this validation.
214 Span<const uint8_t> candidateCertDERSpan = {candidateCertDER.UnsafeGetData(),
215 candidateCertDER.GetLength()};
216 if (mTrustedRoot == candidateCertDERSpan) {
217 trustLevel = TrustLevel::TrustAnchor;
218 return Success;
221 trustLevel = TrustLevel::InheritsTrust;
222 return Success;
225 pkix::Result AppTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
226 /*out*/ uint8_t* digestBuf,
227 size_t digestBufLen) {
228 return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
231 pkix::Result AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time,
232 Duration,
233 /*optional*/ const Input*,
234 /*optional*/ const Input*,
235 /*optional*/ const Input*) {
236 // We don't currently do revocation checking. If we need to distrust an Apps
237 // certificate, we will use the active distrust mechanism.
238 return Success;
241 pkix::Result AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
242 const CertPolicyId& requiredPolicy) {
243 MOZ_ASSERT(requiredPolicy.IsAnyPolicy());
244 return Success;
247 pkix::Result AppTrustDomain::CheckSignatureDigestAlgorithm(
248 DigestAlgorithm digestAlg, EndEntityOrCA, Time) {
249 switch (digestAlg) {
250 case DigestAlgorithm::sha256: // fall through
251 case DigestAlgorithm::sha384: // fall through
252 case DigestAlgorithm::sha512:
253 return Success;
254 case DigestAlgorithm::sha1:
255 return pkix::Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
257 return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
260 pkix::Result AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
261 EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits) {
262 if (modulusSizeInBits < 2048u) {
263 return pkix::Result::ERROR_INADEQUATE_KEY_SIZE;
265 return Success;
268 pkix::Result AppTrustDomain::VerifyRSAPKCS1SignedData(
269 Input data, DigestAlgorithm digestAlgorithm, Input signature,
270 Input subjectPublicKeyInfo) {
271 // TODO: We should restrict signatures to SHA-256 or better.
272 return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
273 subjectPublicKeyInfo, nullptr);
276 pkix::Result AppTrustDomain::VerifyRSAPSSSignedData(
277 Input data, DigestAlgorithm digestAlgorithm, Input signature,
278 Input subjectPublicKeyInfo) {
279 return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
280 subjectPublicKeyInfo, nullptr);
283 pkix::Result AppTrustDomain::CheckECDSACurveIsAcceptable(
284 EndEntityOrCA /*endEntityOrCA*/, NamedCurve curve) {
285 switch (curve) {
286 case NamedCurve::secp256r1: // fall through
287 case NamedCurve::secp384r1: // fall through
288 case NamedCurve::secp521r1:
289 return Success;
292 return pkix::Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
295 pkix::Result AppTrustDomain::VerifyECDSASignedData(
296 Input data, DigestAlgorithm digestAlgorithm, Input signature,
297 Input subjectPublicKeyInfo) {
298 return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
299 subjectPublicKeyInfo, nullptr);
302 pkix::Result AppTrustDomain::CheckValidityIsAcceptable(
303 Time /*notBefore*/, Time /*notAfter*/, EndEntityOrCA /*endEntityOrCA*/,
304 KeyPurposeId /*keyPurpose*/) {
305 return Success;
308 pkix::Result AppTrustDomain::NetscapeStepUpMatchesServerAuth(
309 Time /*notBefore*/,
310 /*out*/ bool& matches) {
311 matches = false;
312 return Success;
315 void AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
316 Input /*extensionData*/) {}
318 } // namespace psm
319 } // namespace mozilla