Bug 1928997: Update tabs icon in Unified Search popup r=desktop-theme-reviewers,daleh...
[gecko.git] / security / manager / ssl / AppTrustDomain.cpp
blobab49d7eb1f3623d6e427d49635d1854cb354b737
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 #include "addons-stage-intermediate.inc"
37 // Content signature root certificates
38 #include "content-signature-dev.inc"
39 #include "content-signature-local.inc"
40 #include "content-signature-prod.inc"
41 #include "content-signature-stage.inc"
43 using namespace mozilla::pkix;
45 extern mozilla::LazyLogModule gPIPNSSLog;
47 namespace mozilla {
48 namespace psm {
50 AppTrustDomain::AppTrustDomain(nsTArray<Span<const uint8_t>>&& collectedCerts)
51 : mIntermediates(std::move(collectedCerts)),
52 mCertBlocklist(do_GetService(NS_CERT_STORAGE_CID)) {}
54 nsresult AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) {
55 if (!mTrustedRoots.IsEmpty()) {
56 return NS_ERROR_ALREADY_INITIALIZED;
58 switch (trustedRoot) {
59 case nsIX509CertDB::AppXPCShellRoot:
60 mTrustedRoots.AppendElements(xpcshellRoots, std::size(xpcshellRoots));
61 break;
63 case nsIX509CertDB::AddonsPublicRoot:
64 mTrustedRoots.AppendElements(addonsPublicRoots,
65 std::size(addonsPublicRoots));
66 break;
68 case nsIX509CertDB::AddonsStageRoot:
69 mTrustedRoots.AppendElements(addonsStageRoots,
70 std::size(addonsStageRoots));
71 break;
73 case nsIContentSignatureVerifier::ContentSignatureLocalRoot:
74 mTrustedRoots.AppendElements(contentSignatureLocalRoots,
75 std::size(contentSignatureLocalRoots));
76 break;
78 case nsIContentSignatureVerifier::ContentSignatureProdRoot:
79 mTrustedRoots.AppendElements(contentSignatureProdRoots,
80 std::size(contentSignatureProdRoots));
81 break;
83 case nsIContentSignatureVerifier::ContentSignatureStageRoot:
84 mTrustedRoots.AppendElements(contentSignatureStageRoots,
85 std::size(contentSignatureStageRoots));
86 break;
88 case nsIContentSignatureVerifier::ContentSignatureDevRoot:
89 mTrustedRoots.AppendElements(contentSignatureDevRoots,
90 std::size(contentSignatureDevRoots));
91 break;
93 default:
94 return NS_ERROR_INVALID_ARG;
97 // If we're verifying add-ons signed by our production root, we want to make
98 // sure a valid intermediate certificate is available for path building.
99 // The intermediate bundled with signed XPI files may have expired and be
100 // considered invalid, which can result in bug 1548973.
101 if (trustedRoot == nsIX509CertDB::AddonsPublicRoot) {
102 mAddonsIntermediates.AppendElements(addonsPublicIntermediates,
103 std::size(addonsPublicIntermediates));
105 // Similarly to the above logic for production, we hardcode the intermediate
106 // stage certificate here, so that stage is equivalent to production.
107 if (trustedRoot == nsIX509CertDB::AddonsStageRoot) {
108 mAddonsIntermediates.AppendElements(addonsStageIntermediates,
109 std::size(addonsStageIntermediates));
112 return NS_OK;
115 pkix::Result AppTrustDomain::FindIssuer(Input encodedIssuerName,
116 IssuerChecker& checker, Time) {
117 MOZ_ASSERT(!mTrustedRoots.IsEmpty());
118 if (mTrustedRoots.IsEmpty()) {
119 return pkix::Result::FATAL_ERROR_INVALID_STATE;
122 nsTArray<Input> candidates;
123 for (const auto& root : mTrustedRoots) {
124 Input rootInput;
125 pkix::Result rv = rootInput.Init(root.Elements(), root.Length());
126 // This should never fail, since the possible roots are all hard-coded and
127 // they should never be too long.
128 if (rv != Success) {
129 return rv;
131 candidates.AppendElement(std::move(rootInput));
133 for (const auto& intermediate : mAddonsIntermediates) {
134 Input intermediateInput;
135 pkix::Result rv =
136 intermediateInput.Init(intermediate.Elements(), intermediate.Length());
137 // Again, this should never fail for the same reason as above.
138 if (rv != Success) {
139 return rv;
141 candidates.AppendElement(std::move(intermediateInput));
143 for (const auto& intermediate : mIntermediates) {
144 Input intermediateInput;
145 pkix::Result rv =
146 intermediateInput.Init(intermediate.Elements(), intermediate.Length());
147 // This is untrusted input, so skip any intermediates that are too large.
148 if (rv != Success) {
149 continue;
151 candidates.AppendElement(std::move(intermediateInput));
154 for (const auto& candidate : candidates) {
155 bool keepGoing;
156 pkix::Result rv = checker.Check(
157 candidate, nullptr /*additionalNameConstraints*/, keepGoing);
158 if (rv != Success) {
159 return rv;
161 if (!keepGoing) {
162 return Success;
166 // If the above did not succeed in building a verified certificate chain,
167 // fall back to searching for candidates in NSS. This is important in case an
168 // intermediate involved in add-on signing expires before it is replaced. See
169 // bug 1548973.
170 SECItem encodedIssuerNameSECItem = UnsafeMapInputToSECItem(encodedIssuerName);
171 UniqueCERTCertList nssCandidates(CERT_CreateSubjectCertList(
172 nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameSECItem, 0, false));
173 if (nssCandidates) {
174 for (CERTCertListNode* n = CERT_LIST_HEAD(nssCandidates);
175 !CERT_LIST_END(n, nssCandidates); n = CERT_LIST_NEXT(n)) {
176 Input certDER;
177 pkix::Result rv =
178 certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
179 if (rv != Success) {
180 continue; // probably too big
183 bool keepGoing;
184 rv = checker.Check(certDER, nullptr /*additionalNameConstraints*/,
185 keepGoing);
186 if (rv != Success) {
187 return rv;
189 if (!keepGoing) {
190 break;
195 return Success;
198 pkix::Result AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
199 const CertPolicyId& policy,
200 Input candidateCertDER,
201 /*out*/ TrustLevel& trustLevel) {
202 MOZ_ASSERT(policy.IsAnyPolicy());
203 MOZ_ASSERT(!mTrustedRoots.IsEmpty());
204 if (!policy.IsAnyPolicy()) {
205 return pkix::Result::FATAL_ERROR_INVALID_ARGS;
207 if (mTrustedRoots.IsEmpty()) {
208 return pkix::Result::FATAL_ERROR_INVALID_STATE;
211 nsTArray<uint8_t> issuerBytes;
212 nsTArray<uint8_t> serialBytes;
213 nsTArray<uint8_t> subjectBytes;
214 nsTArray<uint8_t> pubKeyBytes;
216 pkix::Result result =
217 BuildRevocationCheckArrays(candidateCertDER, endEntityOrCA, issuerBytes,
218 serialBytes, subjectBytes, pubKeyBytes);
219 if (result != Success) {
220 return result;
223 int16_t revocationState;
224 nsresult nsrv = mCertBlocklist->GetRevocationState(
225 issuerBytes, serialBytes, subjectBytes, pubKeyBytes, &revocationState);
226 if (NS_FAILED(nsrv)) {
227 return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
230 if (revocationState == nsICertStorage::STATE_ENFORCE) {
231 return pkix::Result::ERROR_REVOKED_CERTIFICATE;
234 // mTrustedRoots are the only trust anchors for this validation.
235 Span<const uint8_t> candidateCertDERSpan = {candidateCertDER.UnsafeGetData(),
236 candidateCertDER.GetLength()};
237 for (const auto& trustedRoot : mTrustedRoots) {
238 if (trustedRoot == candidateCertDERSpan) {
239 trustLevel = TrustLevel::TrustAnchor;
240 return Success;
244 trustLevel = TrustLevel::InheritsTrust;
245 return Success;
248 pkix::Result AppTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
249 /*out*/ uint8_t* digestBuf,
250 size_t digestBufLen) {
251 return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
254 pkix::Result AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time,
255 Duration,
256 /*optional*/ const Input*,
257 /*optional*/ const Input*,
258 /*optional*/ const Input*) {
259 // We don't currently do revocation checking. If we need to distrust an Apps
260 // certificate, we will use the active distrust mechanism.
261 return Success;
264 pkix::Result AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
265 const CertPolicyId& requiredPolicy) {
266 MOZ_ASSERT(requiredPolicy.IsAnyPolicy());
267 return Success;
270 pkix::Result AppTrustDomain::CheckSignatureDigestAlgorithm(
271 DigestAlgorithm digestAlg, EndEntityOrCA, Time) {
272 switch (digestAlg) {
273 case DigestAlgorithm::sha256: // fall through
274 case DigestAlgorithm::sha384: // fall through
275 case DigestAlgorithm::sha512:
276 return Success;
277 case DigestAlgorithm::sha1:
278 return pkix::Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
280 return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
283 pkix::Result AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
284 EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits) {
285 if (modulusSizeInBits < 2048u) {
286 return pkix::Result::ERROR_INADEQUATE_KEY_SIZE;
288 return Success;
291 pkix::Result AppTrustDomain::VerifyRSAPKCS1SignedData(
292 Input data, DigestAlgorithm digestAlgorithm, Input signature,
293 Input subjectPublicKeyInfo) {
294 // TODO: We should restrict signatures to SHA-256 or better.
295 return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
296 subjectPublicKeyInfo, nullptr);
299 pkix::Result AppTrustDomain::VerifyRSAPSSSignedData(
300 Input data, DigestAlgorithm digestAlgorithm, Input signature,
301 Input subjectPublicKeyInfo) {
302 return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
303 subjectPublicKeyInfo, nullptr);
306 pkix::Result AppTrustDomain::CheckECDSACurveIsAcceptable(
307 EndEntityOrCA /*endEntityOrCA*/, NamedCurve curve) {
308 switch (curve) {
309 case NamedCurve::secp256r1: // fall through
310 case NamedCurve::secp384r1: // fall through
311 case NamedCurve::secp521r1:
312 return Success;
315 return pkix::Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
318 pkix::Result AppTrustDomain::VerifyECDSASignedData(
319 Input data, DigestAlgorithm digestAlgorithm, Input signature,
320 Input subjectPublicKeyInfo) {
321 return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
322 subjectPublicKeyInfo, nullptr);
325 pkix::Result AppTrustDomain::CheckValidityIsAcceptable(
326 Time /*notBefore*/, Time /*notAfter*/, EndEntityOrCA /*endEntityOrCA*/,
327 KeyPurposeId /*keyPurpose*/) {
328 return Success;
331 pkix::Result AppTrustDomain::NetscapeStepUpMatchesServerAuth(
332 Time /*notBefore*/,
333 /*out*/ bool& matches) {
334 matches = false;
335 return Success;
338 void AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
339 Input /*extensionData*/) {}
341 } // namespace psm
342 } // namespace mozilla