Bumping manifests a=b2g-bump
[gecko.git] / security / apps / AppTrustDomain.cpp
blobf9f01d7cd1621e95bd917e7b8c3a3b46a7de1509
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"
8 #include "certdb.h"
9 #include "pkix/pkixnss.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "nsIX509CertDB.h"
12 #include "nsNSSCertificate.h"
13 #include "prerror.h"
14 #include "secerr.h"
16 // Generated in Makefile.in
17 #include "marketplace-prod-public.inc"
18 #include "marketplace-prod-reviewers.inc"
19 #include "marketplace-dev-public.inc"
20 #include "marketplace-dev-reviewers.inc"
21 #include "marketplace-stage.inc"
22 #include "xpcshell.inc"
23 // Trusted Hosted Apps Certificates
24 #include "manifest-signing-root.inc"
25 #include "manifest-signing-test-root.inc"
27 using namespace mozilla::pkix;
29 #ifdef PR_LOGGING
30 extern PRLogModuleInfo* gPIPNSSLog;
31 #endif
33 static const unsigned int DEFAULT_MINIMUM_NON_ECC_BITS = 2048;
35 namespace mozilla { namespace psm {
37 AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg)
38 : mCertChain(certChain)
39 , mPinArg(pinArg)
40 , mMinimumNonECCBits(DEFAULT_MINIMUM_NON_ECC_BITS)
44 SECStatus
45 AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
47 SECItem trustedDER;
49 // Load the trusted certificate into the in-memory NSS database so that
50 // CERT_CreateSubjectCertList can find it.
52 switch (trustedRoot)
54 case nsIX509CertDB::AppMarketplaceProdPublicRoot:
55 trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot);
56 trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot);
57 break;
59 case nsIX509CertDB::AppMarketplaceProdReviewersRoot:
60 trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot);
61 trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot);
62 break;
64 case nsIX509CertDB::AppMarketplaceDevPublicRoot:
65 trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot);
66 trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot);
67 break;
69 case nsIX509CertDB::AppMarketplaceDevReviewersRoot:
70 trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot);
71 trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot);
72 break;
74 case nsIX509CertDB::AppMarketplaceStageRoot:
75 trustedDER.data = const_cast<uint8_t*>(marketplaceStageRoot);
76 trustedDER.len = mozilla::ArrayLength(marketplaceStageRoot);
77 // The staging root was generated with a 1024-bit key.
78 mMinimumNonECCBits = 1024u;
79 break;
81 case nsIX509CertDB::AppXPCShellRoot:
82 trustedDER.data = const_cast<uint8_t*>(xpcshellRoot);
83 trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
84 break;
86 case nsIX509CertDB::TrustedHostedAppPublicRoot:
87 trustedDER.data = const_cast<uint8_t*>(trustedAppPublicRoot);
88 trustedDER.len = mozilla::ArrayLength(trustedAppPublicRoot);
89 break;
91 case nsIX509CertDB::TrustedHostedAppTestRoot:
92 trustedDER.data = const_cast<uint8_t*>(trustedAppTestRoot);
93 trustedDER.len = mozilla::ArrayLength(trustedAppTestRoot);
94 break;
96 default:
97 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
98 return SECFailure;
101 mTrustedRoot = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
102 &trustedDER, nullptr, false, true);
103 if (!mTrustedRoot) {
104 return SECFailure;
107 return SECSuccess;
110 Result
111 AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
112 Time)
115 MOZ_ASSERT(mTrustedRoot);
116 if (!mTrustedRoot) {
117 return Result::FATAL_ERROR_INVALID_STATE;
120 // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
121 // FindIssuer must only pass certificates with a matching subject name to
122 // checker.Check, we can stop using CERT_CreateSubjectCertList and instead
123 // use logic like this:
125 // 1. First, try the trusted trust anchor.
126 // 2. Secondly, iterate through the certificates that were stored in the CMS
127 // message, passing each one to checker.Check.
128 SECItem encodedIssuerNameSECItem =
129 UnsafeMapInputToSECItem(encodedIssuerName);
130 ScopedCERTCertList
131 candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
132 &encodedIssuerNameSECItem, 0,
133 false));
134 if (candidates) {
135 for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
136 !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
137 Input certDER;
138 Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
139 if (rv != Success) {
140 continue; // probably too big
143 bool keepGoing;
144 rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
145 keepGoing);
146 if (rv != Success) {
147 return rv;
149 if (!keepGoing) {
150 break;
155 return Success;
158 Result
159 AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
160 const CertPolicyId& policy,
161 Input candidateCertDER,
162 /*out*/ TrustLevel& trustLevel)
164 MOZ_ASSERT(policy.IsAnyPolicy());
165 MOZ_ASSERT(mTrustedRoot);
166 if (!policy.IsAnyPolicy()) {
167 return Result::FATAL_ERROR_INVALID_ARGS;
169 if (!mTrustedRoot) {
170 return Result::FATAL_ERROR_INVALID_STATE;
173 // Handle active distrust of the certificate.
175 // XXX: This would be cleaner and more efficient if we could get the trust
176 // information without constructing a CERTCertificate here, but NSS doesn't
177 // expose it in any other easy-to-use fashion.
178 SECItem candidateCertDERSECItem =
179 UnsafeMapInputToSECItem(candidateCertDER);
180 ScopedCERTCertificate candidateCert(
181 CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
182 nullptr, false, true));
183 if (!candidateCert) {
184 return MapPRErrorCodeToResult(PR_GetError());
187 CERTCertTrust trust;
188 if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
189 uint32_t flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
191 // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
192 // because we can have active distrust for either type of cert. Note that
193 // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
194 // relevant trust bit isn't set then that means the cert must be considered
195 // distrusted.
196 uint32_t relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
197 ? CERTDB_TRUSTED_CA
198 : CERTDB_TRUSTED;
199 if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
200 == CERTDB_TERMINAL_RECORD) {
201 trustLevel = TrustLevel::ActivelyDistrusted;
202 return Success;
206 // mTrustedRoot is the only trust anchor for this validation.
207 if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
208 trustLevel = TrustLevel::TrustAnchor;
209 return Success;
212 trustLevel = TrustLevel::InheritsTrust;
213 return Success;
216 Result
217 AppTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
218 Input subjectPublicKeyInfo)
220 return ::mozilla::pkix::VerifySignedDataNSS(signedData, subjectPublicKeyInfo,
221 mMinimumNonECCBits, mPinArg);
224 Result
225 AppTrustDomain::DigestBuf(Input item, /*out*/ uint8_t* digestBuf,
226 size_t digestBufLen)
228 return ::mozilla::pkix::DigestBufNSS(item, digestBuf, digestBufLen);
231 Result
232 AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time,
233 /*optional*/ const Input*,
234 /*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 Result
242 AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
244 SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
245 mCertChain);
246 if (srv != SECSuccess) {
247 return MapPRErrorCodeToResult(PR_GetError());
249 return Success;
252 Result
253 AppTrustDomain::CheckPublicKey(Input subjectPublicKeyInfo)
255 return ::mozilla::pkix::CheckPublicKeyNSS(subjectPublicKeyInfo,
256 mMinimumNonECCBits);
259 } } // namespace mozilla::psm