Line data Source code
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 code is made available to you under your choice of the following sets
4 : * of licensing terms:
5 : */
6 : /* This Source Code Form is subject to the terms of the Mozilla Public
7 : * License, v. 2.0. If a copy of the MPL was not distributed with this
8 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 : */
10 : /* Copyright 2014 Mozilla Contributors
11 : *
12 : * Licensed under the Apache License, Version 2.0 (the "License");
13 : * you may not use this file except in compliance with the License.
14 : * You may obtain a copy of the License at
15 : *
16 : * http://www.apache.org/licenses/LICENSE-2.0
17 : *
18 : * Unless required by applicable law or agreed to in writing, software
19 : * distributed under the License is distributed on an "AS IS" BASIS,
20 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 : * See the License for the specific language governing permissions and
22 : * limitations under the License.
23 : */
24 :
25 : #include "pkixutil.h"
26 :
27 : namespace mozilla { namespace pkix {
28 :
29 : Result
30 0 : BackCert::Init()
31 : {
32 : Result rv;
33 :
34 : // Certificate ::= SEQUENCE {
35 : // tbsCertificate TBSCertificate,
36 : // signatureAlgorithm AlgorithmIdentifier,
37 : // signatureValue BIT STRING }
38 :
39 0 : Reader tbsCertificate;
40 :
41 : // The scope of |input| and |certificate| are limited to this block so we
42 : // don't accidentally confuse them for tbsCertificate later.
43 : {
44 0 : Reader certificate;
45 0 : rv = der::ExpectTagAndGetValueAtEnd(der, der::SEQUENCE, certificate);
46 0 : if (rv != Success) {
47 0 : return rv;
48 : }
49 0 : rv = der::SignedData(certificate, tbsCertificate, signedData);
50 0 : if (rv != Success) {
51 0 : return rv;
52 : }
53 0 : rv = der::End(certificate);
54 0 : if (rv != Success) {
55 0 : return rv;
56 : }
57 : }
58 :
59 : // TBSCertificate ::= SEQUENCE {
60 : // version [0] EXPLICIT Version DEFAULT v1,
61 : // serialNumber CertificateSerialNumber,
62 : // signature AlgorithmIdentifier,
63 : // issuer Name,
64 : // validity Validity,
65 : // subject Name,
66 : // subjectPublicKeyInfo SubjectPublicKeyInfo,
67 : // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
68 : // -- If present, version MUST be v2 or v3
69 : // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
70 : // -- If present, version MUST be v2 or v3
71 : // extensions [3] EXPLICIT Extensions OPTIONAL
72 : // -- If present, version MUST be v3
73 : // }
74 0 : rv = der::OptionalVersion(tbsCertificate, version);
75 0 : if (rv != Success) {
76 0 : return rv;
77 : }
78 0 : rv = der::CertificateSerialNumber(tbsCertificate, serialNumber);
79 0 : if (rv != Success) {
80 0 : return rv;
81 : }
82 0 : rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
83 0 : if (rv != Success) {
84 0 : return rv;
85 : }
86 0 : rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer);
87 0 : if (rv != Success) {
88 0 : return rv;
89 : }
90 0 : rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity);
91 0 : if (rv != Success) {
92 0 : return rv;
93 : }
94 : // TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
95 : // that the name is syntactically valid, if they care. In Gecko we do this
96 : // implicitly by parsing the certificate into a CERTCertificate object.
97 : // Instead of relying on the caller to do this, we should do it ourselves.
98 0 : rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject);
99 0 : if (rv != Success) {
100 0 : return rv;
101 : }
102 0 : rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
103 0 : subjectPublicKeyInfo);
104 0 : if (rv != Success) {
105 0 : return rv;
106 : }
107 :
108 : static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;
109 :
110 : // According to RFC 5280, all fields below this line are forbidden for
111 : // certificate versions less than v3. However, for compatibility reasons,
112 : // we parse v1/v2 certificates in the same way as v3 certificates. So if
113 : // these fields appear in a v1 certificate, they will be used.
114 :
115 : // Ignore issuerUniqueID if present.
116 0 : if (tbsCertificate.Peek(CSC | 1)) {
117 0 : rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1);
118 0 : if (rv != Success) {
119 0 : return rv;
120 : }
121 : }
122 :
123 : // Ignore subjectUniqueID if present.
124 0 : if (tbsCertificate.Peek(CSC | 2)) {
125 0 : rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2);
126 0 : if (rv != Success) {
127 0 : return rv;
128 : }
129 : }
130 :
131 0 : rv = der::OptionalExtensions(
132 : tbsCertificate, CSC | 3,
133 : [this](Reader& extnID, const Input& extnValue, bool critical,
134 0 : /*out*/ bool& understood) {
135 0 : return RememberExtension(extnID, extnValue, critical, understood);
136 0 : });
137 0 : if (rv != Success) {
138 0 : return rv;
139 : }
140 :
141 : // The Netscape Certificate Type extension is an obsolete
142 : // Netscape-proprietary mechanism that we ignore in favor of the standard
143 : // extensions. However, some CAs have issued certificates with the Netscape
144 : // Cert Type extension marked critical. Thus, for compatibility reasons, we
145 : // "understand" this extension by ignoring it when it is not critical, and
146 : // by ensuring that the equivalent standardized extensions are present when
147 : // it is marked critical, based on the assumption that the information in
148 : // the Netscape Cert Type extension is consistent with the information in
149 : // the standard extensions.
150 : //
151 : // Here is a mapping between the Netscape Cert Type extension and the
152 : // standard extensions:
153 : //
154 : // Netscape Cert Type | BasicConstraints.cA | Extended Key Usage
155 : // --------------------+-----------------------+----------------------
156 : // SSL Server | false | id_kp_serverAuth
157 : // SSL Client | false | id_kp_clientAuth
158 : // S/MIME Client | false | id_kp_emailProtection
159 : // Object Signing | false | id_kp_codeSigning
160 : // SSL Server CA | true | id_pk_serverAuth
161 : // SSL Client CA | true | id_kp_clientAuth
162 : // S/MIME CA | true | id_kp_emailProtection
163 : // Object Signing CA | true | id_kp_codeSigning
164 0 : if (criticalNetscapeCertificateType.GetLength() > 0 &&
165 0 : (basicConstraints.GetLength() == 0 || extKeyUsage.GetLength() == 0)) {
166 0 : return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
167 : }
168 :
169 0 : return der::End(tbsCertificate);
170 : }
171 :
172 : Result
173 0 : BackCert::RememberExtension(Reader& extnID, Input extnValue,
174 : bool critical, /*out*/ bool& understood)
175 : {
176 0 : understood = false;
177 :
178 : // python DottedOIDToCode.py id-ce-keyUsage 2.5.29.15
179 : static const uint8_t id_ce_keyUsage[] = {
180 : 0x55, 0x1d, 0x0f
181 : };
182 : // python DottedOIDToCode.py id-ce-subjectAltName 2.5.29.17
183 : static const uint8_t id_ce_subjectAltName[] = {
184 : 0x55, 0x1d, 0x11
185 : };
186 : // python DottedOIDToCode.py id-ce-basicConstraints 2.5.29.19
187 : static const uint8_t id_ce_basicConstraints[] = {
188 : 0x55, 0x1d, 0x13
189 : };
190 : // python DottedOIDToCode.py id-ce-nameConstraints 2.5.29.30
191 : static const uint8_t id_ce_nameConstraints[] = {
192 : 0x55, 0x1d, 0x1e
193 : };
194 : // python DottedOIDToCode.py id-ce-certificatePolicies 2.5.29.32
195 : static const uint8_t id_ce_certificatePolicies[] = {
196 : 0x55, 0x1d, 0x20
197 : };
198 : // python DottedOIDToCode.py id-ce-policyConstraints 2.5.29.36
199 : static const uint8_t id_ce_policyConstraints[] = {
200 : 0x55, 0x1d, 0x24
201 : };
202 : // python DottedOIDToCode.py id-ce-extKeyUsage 2.5.29.37
203 : static const uint8_t id_ce_extKeyUsage[] = {
204 : 0x55, 0x1d, 0x25
205 : };
206 : // python DottedOIDToCode.py id-ce-inhibitAnyPolicy 2.5.29.54
207 : static const uint8_t id_ce_inhibitAnyPolicy[] = {
208 : 0x55, 0x1d, 0x36
209 : };
210 : // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
211 : static const uint8_t id_pe_authorityInfoAccess[] = {
212 : 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
213 : };
214 : // python DottedOIDToCode.py id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
215 : static const uint8_t id_pkix_ocsp_nocheck[] = {
216 : 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
217 : };
218 : // python DottedOIDToCode.py Netscape-certificate-type 2.16.840.1.113730.1.1
219 : static const uint8_t Netscape_certificate_type[] = {
220 : 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01
221 : };
222 : // python DottedOIDToCode.py id-pe-tlsfeature 1.3.6.1.5.5.7.1.24
223 : static const uint8_t id_pe_tlsfeature[] = {
224 : 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x18
225 : };
226 : // python DottedOIDToCode.py id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
227 : // See Section 3.3 of RFC 6962.
228 : static const uint8_t id_embeddedSctList[] = {
229 : 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
230 : };
231 :
232 0 : Input* out = nullptr;
233 :
234 : // We already enforce the maximum possible constraints for policies so we
235 : // can safely ignore even critical policy constraint extensions.
236 : //
237 : // XXX: Doing it this way won't allow us to detect duplicate
238 : // policyConstraints extensions, but that's OK because (and only because) we
239 : // ignore the extension.
240 0 : Input dummyPolicyConstraints;
241 :
242 : // We don't need to save the contents of this extension if it is present. We
243 : // just need to handle its presence (it is essentially ignored right now).
244 0 : Input dummyOCSPNocheck;
245 :
246 : // For compatibility reasons, for some extensions we have to allow empty
247 : // extension values. This would normally interfere with our duplicate
248 : // extension checking code. However, as long as the extensions we allow to
249 : // have empty values are also the ones we implicitly allow duplicates of,
250 : // this will work fine.
251 0 : bool emptyValueAllowed = false;
252 :
253 : // RFC says "Conforming CAs MUST mark this extension as non-critical" for
254 : // both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
255 : // them for anything, so we totally ignore them here.
256 :
257 0 : if (extnID.MatchRest(id_ce_keyUsage)) {
258 0 : out = &keyUsage;
259 0 : } else if (extnID.MatchRest(id_ce_subjectAltName)) {
260 0 : out = &subjectAltName;
261 0 : } else if (extnID.MatchRest(id_ce_basicConstraints)) {
262 0 : out = &basicConstraints;
263 0 : } else if (extnID.MatchRest(id_ce_nameConstraints)) {
264 0 : out = &nameConstraints;
265 0 : } else if (extnID.MatchRest(id_ce_certificatePolicies)) {
266 0 : out = &certificatePolicies;
267 0 : } else if (extnID.MatchRest(id_ce_policyConstraints)) {
268 0 : out = &dummyPolicyConstraints;
269 0 : } else if (extnID.MatchRest(id_ce_extKeyUsage)) {
270 0 : out = &extKeyUsage;
271 0 : } else if (extnID.MatchRest(id_ce_inhibitAnyPolicy)) {
272 0 : out = &inhibitAnyPolicy;
273 0 : } else if (extnID.MatchRest(id_pe_authorityInfoAccess)) {
274 0 : out = &authorityInfoAccess;
275 0 : } else if (extnID.MatchRest(id_pe_tlsfeature)) {
276 0 : out = &requiredTLSFeatures;
277 0 : } else if (extnID.MatchRest(id_embeddedSctList)) {
278 0 : out = &signedCertificateTimestamps;
279 0 : } else if (extnID.MatchRest(id_pkix_ocsp_nocheck) && critical) {
280 : // We need to make sure we don't reject delegated OCSP response signing
281 : // certificates that contain the id-pkix-ocsp-nocheck extension marked as
282 : // critical when validating OCSP responses. Without this, an application
283 : // that implements soft-fail OCSP might ignore a valid Revoked or Unknown
284 : // response, and an application that implements hard-fail OCSP might fail
285 : // to connect to a server given a valid Good response.
286 0 : out = &dummyOCSPNocheck;
287 : // We allow this extension to have an empty value.
288 : // See http://comments.gmane.org/gmane.ietf.x509/30947
289 0 : emptyValueAllowed = true;
290 0 : } else if (extnID.MatchRest(Netscape_certificate_type) && critical) {
291 0 : out = &criticalNetscapeCertificateType;
292 : }
293 :
294 0 : if (out) {
295 : // Don't allow an empty value for any extension we understand. This way, we
296 : // can test out->GetLength() != 0 or out->Init() to check for duplicates.
297 0 : if (extnValue.GetLength() == 0 && !emptyValueAllowed) {
298 0 : return Result::ERROR_EXTENSION_VALUE_INVALID;
299 : }
300 0 : if (out->Init(extnValue) != Success) {
301 : // Duplicate extension
302 0 : return Result::ERROR_EXTENSION_VALUE_INVALID;
303 : }
304 0 : understood = true;
305 : }
306 :
307 0 : return Success;
308 : }
309 :
310 : Result
311 0 : ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
312 : Input& sctList)
313 : {
314 0 : Reader decodedValue;
315 : Result rv = der::ExpectTagAndGetValueAtEnd(extnValue, der::OCTET_STRING,
316 0 : decodedValue);
317 0 : if (rv != Success) {
318 0 : return rv;
319 : }
320 0 : return decodedValue.SkipToEnd(sctList);
321 : }
322 :
323 : } } // namespace mozilla::pkix
|