|
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/. */ |
|
6 |
|
7 #ifdef MOZ_LOGGING |
|
8 #define FORCE_PR_LOG 1 |
|
9 #endif |
|
10 |
|
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" |
|
18 |
|
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" |
|
25 |
|
26 using namespace mozilla::pkix; |
|
27 |
|
28 #ifdef PR_LOGGING |
|
29 extern PRLogModuleInfo* gPIPNSSLog; |
|
30 #endif |
|
31 |
|
32 namespace mozilla { namespace psm { |
|
33 |
|
34 AppTrustDomain::AppTrustDomain(void* pinArg) |
|
35 : mPinArg(pinArg) |
|
36 { |
|
37 } |
|
38 |
|
39 SECStatus |
|
40 AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) |
|
41 { |
|
42 SECItem trustedDER; |
|
43 |
|
44 // Load the trusted certificate into the in-memory NSS database so that |
|
45 // CERT_CreateSubjectCertList can find it. |
|
46 |
|
47 switch (trustedRoot) |
|
48 { |
|
49 case nsIX509CertDB::AppMarketplaceProdPublicRoot: |
|
50 trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot); |
|
51 trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot); |
|
52 break; |
|
53 |
|
54 case nsIX509CertDB::AppMarketplaceProdReviewersRoot: |
|
55 trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot); |
|
56 trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot); |
|
57 break; |
|
58 |
|
59 case nsIX509CertDB::AppMarketplaceDevPublicRoot: |
|
60 trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot); |
|
61 trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot); |
|
62 break; |
|
63 |
|
64 case nsIX509CertDB::AppMarketplaceDevReviewersRoot: |
|
65 trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot); |
|
66 trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot); |
|
67 break; |
|
68 |
|
69 case nsIX509CertDB::AppXPCShellRoot: |
|
70 trustedDER.data = const_cast<uint8_t*>(xpcshellRoot); |
|
71 trustedDER.len = mozilla::ArrayLength(xpcshellRoot); |
|
72 break; |
|
73 |
|
74 default: |
|
75 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
76 return SECFailure; |
|
77 } |
|
78 |
|
79 mTrustedRoot = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), |
|
80 &trustedDER, nullptr, false, true); |
|
81 if (!mTrustedRoot) { |
|
82 return SECFailure; |
|
83 } |
|
84 |
|
85 return SECSuccess; |
|
86 } |
|
87 |
|
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 } |
|
98 |
|
99 results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(), |
|
100 encodedIssuerName, time, true); |
|
101 return SECSuccess; |
|
102 } |
|
103 |
|
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 } |
|
122 |
|
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); |
|
127 |
|
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 } |
|
141 |
|
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. |
|
146 |
|
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 } |
|
156 |
|
157 // mTrustedRoot is the only trust anchor for this validation. |
|
158 if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert)) { |
|
159 *trustLevel = TrustAnchor; |
|
160 return SECSuccess; |
|
161 } |
|
162 |
|
163 *trustLevel = InheritsTrust; |
|
164 return SECSuccess; |
|
165 } |
|
166 |
|
167 SECStatus |
|
168 AppTrustDomain::VerifySignedData(const CERTSignedData* signedData, |
|
169 const CERTCertificate* cert) |
|
170 { |
|
171 return ::mozilla::pkix::VerifySignedData(signedData, cert, mPinArg); |
|
172 } |
|
173 |
|
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 } |
|
185 |
|
186 } } |