Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=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 : #include "CSTrustDomain.h"
8 : #include "mozilla/Base64.h"
9 : #include "mozilla/Preferences.h"
10 : #include "nsNSSCertificate.h"
11 : #include "nsNSSComponent.h"
12 : #include "nsServiceManagerUtils.h"
13 : #include "nsThreadUtils.h"
14 : #include "pkix/pkixnss.h"
15 :
16 : using namespace mozilla::pkix;
17 :
18 : namespace mozilla { namespace psm {
19 :
20 : static LazyLogModule gTrustDomainPRLog("CSTrustDomain");
21 : #define CSTrust_LOG(args) MOZ_LOG(gTrustDomainPRLog, LogLevel::Debug, args)
22 :
23 0 : CSTrustDomain::CSTrustDomain(UniqueCERTCertList& certChain)
24 : : mCertChain(certChain)
25 0 : , mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID))
26 : {
27 0 : }
28 :
29 : Result
30 0 : CSTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
31 : const CertPolicyId& policy, Input candidateCertDER,
32 : /*out*/ TrustLevel& trustLevel)
33 : {
34 0 : MOZ_ASSERT(policy.IsAnyPolicy());
35 0 : if (!policy.IsAnyPolicy()) {
36 0 : return Result::FATAL_ERROR_INVALID_ARGS;
37 : }
38 :
39 0 : SECItem candidateCertDERSECItem = UnsafeMapInputToSECItem(candidateCertDER);
40 : UniqueCERTCertificate candidateCert(
41 : CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
42 0 : nullptr, false, true));
43 0 : if (!candidateCert) {
44 0 : return MapPRErrorCodeToResult(PR_GetError());
45 : }
46 :
47 : bool isCertRevoked;
48 0 : nsresult nsrv = mCertBlocklist->IsCertRevoked(
49 0 : candidateCert->derIssuer.data,
50 0 : candidateCert->derIssuer.len,
51 0 : candidateCert->serialNumber.data,
52 0 : candidateCert->serialNumber.len,
53 0 : candidateCert->derSubject.data,
54 0 : candidateCert->derSubject.len,
55 0 : candidateCert->derPublicKey.data,
56 0 : candidateCert->derPublicKey.len,
57 0 : &isCertRevoked);
58 0 : if (NS_FAILED(nsrv)) {
59 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
60 : }
61 :
62 0 : if (isCertRevoked) {
63 0 : CSTrust_LOG(("CSTrustDomain: certificate is revoked\n"));
64 0 : return Result::ERROR_REVOKED_CERTIFICATE;
65 : }
66 :
67 : // Is this cert our built-in content signing root?
68 0 : bool isRoot = false;
69 0 : nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
70 0 : if (!component) {
71 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
72 : }
73 0 : nsrv = component->IsCertContentSigningRoot(candidateCert.get(), isRoot);
74 0 : if (NS_FAILED(nsrv)) {
75 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
76 : }
77 0 : if (isRoot) {
78 0 : CSTrust_LOG(("CSTrustDomain: certificate is a trust anchor\n"));
79 0 : trustLevel = TrustLevel::TrustAnchor;
80 0 : return Success;
81 : }
82 0 : CSTrust_LOG(("CSTrustDomain: certificate is *not* a trust anchor\n"));
83 :
84 0 : trustLevel = TrustLevel::InheritsTrust;
85 0 : return Success;
86 : }
87 :
88 : Result
89 0 : CSTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
90 : Time time)
91 : {
92 : // Loop over the chain, look for a matching subject
93 0 : for (CERTCertListNode* n = CERT_LIST_HEAD(mCertChain);
94 0 : !CERT_LIST_END(n, mCertChain); n = CERT_LIST_NEXT(n)) {
95 0 : Input certDER;
96 0 : Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
97 0 : if (rv != Success) {
98 0 : continue; // probably too big
99 : }
100 :
101 : // if the subject does not match, try the next certificate
102 0 : Input subjectDER;
103 0 : rv = subjectDER.Init(n->cert->derSubject.data, n->cert->derSubject.len);
104 0 : if (rv != Success) {
105 0 : continue; // just try the next one
106 : }
107 0 : if (!InputsAreEqual(subjectDER, encodedIssuerName)) {
108 0 : CSTrust_LOG(("CSTrustDomain: subjects don't match\n"));
109 0 : continue;
110 : }
111 :
112 : // If the subject does match, try the next step
113 : bool keepGoing;
114 : rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
115 0 : keepGoing);
116 0 : if (rv != Success) {
117 0 : return rv;
118 : }
119 0 : if (!keepGoing) {
120 0 : CSTrust_LOG(("CSTrustDomain: don't keep going\n"));
121 0 : break;
122 : }
123 : }
124 :
125 0 : return Success;
126 : }
127 :
128 : Result
129 0 : CSTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
130 : const CertID& certID, Time time,
131 : Duration validityDuration,
132 : /*optional*/ const Input* stapledOCSPresponse,
133 : /*optional*/ const Input* aiaExtension)
134 : {
135 : // We're relying solely on the CertBlocklist for revocation - and we're
136 : // performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain)
137 0 : return Success;
138 : }
139 :
140 : Result
141 0 : CSTrustDomain::IsChainValid(const DERArray& certChain, Time time,
142 : const CertPolicyId& requiredPolicy)
143 : {
144 0 : MOZ_ASSERT(requiredPolicy.IsAnyPolicy());
145 : // Check that our chain is not empty
146 0 : if (certChain.GetLength() == 0) {
147 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
148 : }
149 :
150 0 : return Success;
151 : }
152 :
153 : Result
154 0 : CSTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
155 : EndEntityOrCA endEntityOrCA,
156 : Time notBefore)
157 : {
158 0 : if (digestAlg == DigestAlgorithm::sha1) {
159 0 : return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
160 : }
161 0 : return Success;
162 : }
163 :
164 : Result
165 0 : CSTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
166 : EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits)
167 : {
168 0 : if (modulusSizeInBits < 2048) {
169 0 : return Result::ERROR_INADEQUATE_KEY_SIZE;
170 : }
171 0 : return Success;
172 : }
173 :
174 : Result
175 0 : CSTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
176 : Input subjectPublicKeyInfo)
177 : {
178 : return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
179 0 : nullptr);
180 : }
181 :
182 : Result
183 0 : CSTrustDomain::CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA,
184 : NamedCurve curve)
185 : {
186 0 : switch (curve) {
187 : case NamedCurve::secp256r1: // fall through
188 : case NamedCurve::secp384r1: // fall through
189 : case NamedCurve::secp521r1:
190 0 : return Success;
191 : }
192 :
193 0 : return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
194 : }
195 :
196 : Result
197 0 : CSTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
198 : Input subjectPublicKeyInfo)
199 : {
200 : return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
201 0 : nullptr);
202 : }
203 :
204 : Result
205 0 : CSTrustDomain::CheckValidityIsAcceptable(Time notBefore, Time notAfter,
206 : EndEntityOrCA endEntityOrCA,
207 : KeyPurposeId keyPurpose)
208 : {
209 0 : return Success;
210 : }
211 :
212 : Result
213 0 : CSTrustDomain::NetscapeStepUpMatchesServerAuth(Time notBefore,
214 : /*out*/ bool& matches)
215 : {
216 0 : matches = false;
217 0 : return Success;
218 : }
219 :
220 : void
221 0 : CSTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
222 : Input /*extensionData*/)
223 : {
224 0 : }
225 :
226 : Result
227 0 : CSTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
228 : /*out*/ uint8_t* digestBuf, size_t digestBufLen)
229 : {
230 0 : return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
231 : }
232 :
233 : } } // end namespace mozilla::psm
|