Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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 #ifdef MOZ_LOGGING
8 #define FORCE_PR_LOG 1
9 #endif
11 #include "AppTrustDomain.h"
12 #include "certdb.h"
13 #include "pkix/pkix.h"
14 #include "mozilla/ArrayUtils.h"
15 #include "nsIX509CertDB.h"
16 #include "prerror.h"
17 #include "secerr.h"
19 // Generated in Makefile.in
20 #include "marketplace-prod-public.inc"
21 #include "marketplace-prod-reviewers.inc"
22 #include "marketplace-dev-public.inc"
23 #include "marketplace-dev-reviewers.inc"
24 #include "xpcshell.inc"
26 using namespace mozilla::pkix;
28 #ifdef PR_LOGGING
29 extern PRLogModuleInfo* gPIPNSSLog;
30 #endif
32 namespace mozilla { namespace psm {
34 AppTrustDomain::AppTrustDomain(void* pinArg)
35 : mPinArg(pinArg)
36 {
37 }
39 SECStatus
40 AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
41 {
42 SECItem trustedDER;
44 // Load the trusted certificate into the in-memory NSS database so that
45 // CERT_CreateSubjectCertList can find it.
47 switch (trustedRoot)
48 {
49 case nsIX509CertDB::AppMarketplaceProdPublicRoot:
50 trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot);
51 trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot);
52 break;
54 case nsIX509CertDB::AppMarketplaceProdReviewersRoot:
55 trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot);
56 trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot);
57 break;
59 case nsIX509CertDB::AppMarketplaceDevPublicRoot:
60 trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot);
61 trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot);
62 break;
64 case nsIX509CertDB::AppMarketplaceDevReviewersRoot:
65 trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot);
66 trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot);
67 break;
69 case nsIX509CertDB::AppXPCShellRoot:
70 trustedDER.data = const_cast<uint8_t*>(xpcshellRoot);
71 trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
72 break;
74 default:
75 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
76 return SECFailure;
77 }
79 mTrustedRoot = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
80 &trustedDER, nullptr, false, true);
81 if (!mTrustedRoot) {
82 return SECFailure;
83 }
85 return SECSuccess;
86 }
88 SECStatus
89 AppTrustDomain::FindPotentialIssuers(const SECItem* encodedIssuerName,
90 PRTime time,
91 /*out*/ mozilla::pkix::ScopedCERTCertList& results)
92 {
93 MOZ_ASSERT(mTrustedRoot);
94 if (!mTrustedRoot) {
95 PR_SetError(PR_INVALID_STATE_ERROR, 0);
96 return SECFailure;
97 }
99 results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
100 encodedIssuerName, time, true);
101 return SECSuccess;
102 }
104 SECStatus
105 AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
106 SECOidTag policy,
107 const CERTCertificate* candidateCert,
108 /*out*/ TrustLevel* trustLevel)
109 {
110 MOZ_ASSERT(policy == SEC_OID_X509_ANY_POLICY);
111 MOZ_ASSERT(candidateCert);
112 MOZ_ASSERT(trustLevel);
113 MOZ_ASSERT(mTrustedRoot);
114 if (!candidateCert || !trustLevel || policy != SEC_OID_X509_ANY_POLICY) {
115 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
116 return SECFailure;
117 }
118 if (!mTrustedRoot) {
119 PR_SetError(PR_INVALID_STATE_ERROR, 0);
120 return SECFailure;
121 }
123 // Handle active distrust of the certificate.
124 CERTCertTrust trust;
125 if (CERT_GetCertTrust(candidateCert, &trust) == SECSuccess) {
126 PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
128 // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
129 // because we can have active distrust for either type of cert. Note that
130 // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
131 // relevant trust bit isn't set then that means the cert must be considered
132 // distrusted.
133 PRUint32 relevantTrustBit = endEntityOrCA == MustBeCA
134 ? CERTDB_TRUSTED_CA
135 : CERTDB_TRUSTED;
136 if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
137 == CERTDB_TERMINAL_RECORD) {
138 *trustLevel = ActivelyDistrusted;
139 return SECSuccess;
140 }
142 #ifdef MOZ_B2G_CERTDATA
143 // XXX(Bug 972201): We have to allow the old way of supporting additional
144 // roots until we fix bug 889744. Remove this along with the rest of the
145 // MOZ_B2G_CERTDATA stuff.
147 // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't
148 // needed to consider end-entity certs to be their own trust anchors since
149 // Gecko implemented nsICertOverrideService.
150 if (flags & CERTDB_TRUSTED_CA) {
151 *trustLevel = TrustAnchor;
152 return SECSuccess;
153 }
154 #endif
155 }
157 // mTrustedRoot is the only trust anchor for this validation.
158 if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert)) {
159 *trustLevel = TrustAnchor;
160 return SECSuccess;
161 }
163 *trustLevel = InheritsTrust;
164 return SECSuccess;
165 }
167 SECStatus
168 AppTrustDomain::VerifySignedData(const CERTSignedData* signedData,
169 const CERTCertificate* cert)
170 {
171 return ::mozilla::pkix::VerifySignedData(signedData, cert, mPinArg);
172 }
174 SECStatus
175 AppTrustDomain::CheckRevocation(EndEntityOrCA,
176 const CERTCertificate*,
177 /*const*/ CERTCertificate*,
178 PRTime time,
179 /*optional*/ const SECItem*)
180 {
181 // We don't currently do revocation checking. If we need to distrust an Apps
182 // certificate, we will use the active distrust mechanism.
183 return SECSuccess;
184 }
186 } }