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/. */
11 #include "AppTrustDomain.h"
13 #include "pkix/pkix.h"
14 #include "mozilla/ArrayUtils.h"
15 #include "nsIX509CertDB.h"
16 #include "nsNSSCertificate.h"
20 // Generated in Makefile.in
21 #include "marketplace-prod-public.inc"
22 #include "marketplace-prod-reviewers.inc"
23 #include "marketplace-dev-public.inc"
24 #include "marketplace-dev-reviewers.inc"
25 #include "xpcshell.inc"
27 using namespace mozilla::pkix
;
30 extern PRLogModuleInfo
* gPIPNSSLog
;
33 namespace mozilla
{ namespace psm
{
35 AppTrustDomain::AppTrustDomain(ScopedCERTCertList
& certChain
, void* pinArg
)
36 : mCertChain(certChain
)
42 AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot
)
46 // Load the trusted certificate into the in-memory NSS database so that
47 // CERT_CreateSubjectCertList can find it.
51 case nsIX509CertDB::AppMarketplaceProdPublicRoot
:
52 trustedDER
.data
= const_cast<uint8_t*>(marketplaceProdPublicRoot
);
53 trustedDER
.len
= mozilla::ArrayLength(marketplaceProdPublicRoot
);
56 case nsIX509CertDB::AppMarketplaceProdReviewersRoot
:
57 trustedDER
.data
= const_cast<uint8_t*>(marketplaceProdReviewersRoot
);
58 trustedDER
.len
= mozilla::ArrayLength(marketplaceProdReviewersRoot
);
61 case nsIX509CertDB::AppMarketplaceDevPublicRoot
:
62 trustedDER
.data
= const_cast<uint8_t*>(marketplaceDevPublicRoot
);
63 trustedDER
.len
= mozilla::ArrayLength(marketplaceDevPublicRoot
);
66 case nsIX509CertDB::AppMarketplaceDevReviewersRoot
:
67 trustedDER
.data
= const_cast<uint8_t*>(marketplaceDevReviewersRoot
);
68 trustedDER
.len
= mozilla::ArrayLength(marketplaceDevReviewersRoot
);
71 case nsIX509CertDB::AppXPCShellRoot
:
72 trustedDER
.data
= const_cast<uint8_t*>(xpcshellRoot
);
73 trustedDER
.len
= mozilla::ArrayLength(xpcshellRoot
);
77 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
81 mTrustedRoot
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
82 &trustedDER
, nullptr, false, true);
91 AppTrustDomain::FindIssuer(const SECItem
& encodedIssuerName
,
92 IssuerChecker
& checker
, PRTime time
)
95 MOZ_ASSERT(mTrustedRoot
);
97 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
101 // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
102 // FindIssuer must only pass certificates with a matching subject name to
103 // checker.Check, we can stop using CERT_CreateSubjectCertList and instead
104 // use logic like this:
106 // 1. First, try the trusted trust anchor.
107 // 2. Secondly, iterate through the certificates that were stored in the CMS
108 // message, passing each one to checker.Check.
110 candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
111 &encodedIssuerName
, time
, true));
113 for (CERTCertListNode
* n
= CERT_LIST_HEAD(candidates
);
114 !CERT_LIST_END(n
, candidates
); n
= CERT_LIST_NEXT(n
)) {
116 SECStatus srv
= checker
.Check(n
->cert
->derCert
,
117 nullptr/*additionalNameConstraints*/,
119 if (srv
!= SECSuccess
) {
132 AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA
,
133 const CertPolicyId
& policy
,
134 const SECItem
& candidateCertDER
,
135 /*out*/ TrustLevel
* trustLevel
)
137 MOZ_ASSERT(policy
.IsAnyPolicy());
138 MOZ_ASSERT(trustLevel
);
139 MOZ_ASSERT(mTrustedRoot
);
140 if (!trustLevel
|| !policy
.IsAnyPolicy()) {
141 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
145 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
149 // Handle active distrust of the certificate.
151 // XXX: This would be cleaner and more efficient if we could get the trust
152 // information without constructing a CERTCertificate here, but NSS doesn't
153 // expose it in any other easy-to-use fashion.
154 ScopedCERTCertificate
candidateCert(
155 CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
156 const_cast<SECItem
*>(&candidateCertDER
), nullptr,
158 if (!candidateCert
) {
163 if (CERT_GetCertTrust(candidateCert
.get(), &trust
) == SECSuccess
) {
164 PRUint32 flags
= SEC_GET_TRUST_FLAGS(&trust
, trustObjectSigning
);
166 // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
167 // because we can have active distrust for either type of cert. Note that
168 // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
169 // relevant trust bit isn't set then that means the cert must be considered
171 PRUint32 relevantTrustBit
= endEntityOrCA
== EndEntityOrCA::MustBeCA
174 if (((flags
& (relevantTrustBit
| CERTDB_TERMINAL_RECORD
)))
175 == CERTDB_TERMINAL_RECORD
) {
176 *trustLevel
= TrustLevel::ActivelyDistrusted
;
181 // mTrustedRoot is the only trust anchor for this validation.
182 if (CERT_CompareCerts(mTrustedRoot
.get(), candidateCert
.get())) {
183 *trustLevel
= TrustLevel::TrustAnchor
;
187 *trustLevel
= TrustLevel::InheritsTrust
;
192 AppTrustDomain::VerifySignedData(const SignedDataWithSignature
& signedData
,
193 const SECItem
& subjectPublicKeyInfo
)
195 return ::mozilla::pkix::VerifySignedData(signedData
, subjectPublicKeyInfo
,
200 AppTrustDomain::DigestBuf(const SECItem
& item
, /*out*/ uint8_t* digestBuf
,
203 return ::mozilla::pkix::DigestBuf(item
, digestBuf
, digestBufLen
);
207 AppTrustDomain::CheckRevocation(EndEntityOrCA
, const CertID
&, PRTime time
,
208 /*optional*/ const SECItem
*,
209 /*optional*/ const SECItem
*)
211 // We don't currently do revocation checking. If we need to distrust an Apps
212 // certificate, we will use the active distrust mechanism.
217 AppTrustDomain::IsChainValid(const DERArray
& certChain
)
219 return ConstructCERTCertListFromReversedDERArray(certChain
, mCertChain
);
223 AppTrustDomain::CheckPublicKey(const SECItem
& subjectPublicKeyInfo
)
225 return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo
);
228 } } // namespace mozilla::psm