1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/asn1_util.h"
6
7 #include <optional>
8 #include <string_view>
9
10 #include "third_party/boringssl/src/pki/input.h"
11 #include "third_party/boringssl/src/pki/parse_certificate.h"
12 #include "third_party/boringssl/src/pki/parser.h"
13
14 namespace net::asn1 {
15
16 namespace {
17
18 // Parses input |in| which should point to the beginning of a Certificate, and
19 // sets |*tbs_certificate| ready to parse the Issuer. If parsing
20 // fails, this function returns false and |*tbs_certificate| is left in an
21 // undefined state.
SeekToIssuer(bssl::der::Input in,bssl::der::Parser * tbs_certificate)22 bool SeekToIssuer(bssl::der::Input in, bssl::der::Parser* tbs_certificate) {
23 // From RFC 5280, section 4.1
24 // Certificate ::= SEQUENCE {
25 // tbsCertificate TBSCertificate,
26 // signatureAlgorithm AlgorithmIdentifier,
27 // signatureValue BIT STRING }
28
29 // TBSCertificate ::= SEQUENCE {
30 // version [0] EXPLICIT Version DEFAULT v1,
31 // serialNumber CertificateSerialNumber,
32 // signature AlgorithmIdentifier,
33 // issuer Name,
34 // validity Validity,
35 // subject Name,
36 // subjectPublicKeyInfo SubjectPublicKeyInfo,
37 // ... }
38
39 bssl::der::Parser parser(in);
40 bssl::der::Parser certificate;
41 if (!parser.ReadSequence(&certificate))
42 return false;
43
44 // We don't allow junk after the certificate.
45 if (parser.HasMore())
46 return false;
47
48 if (!certificate.ReadSequence(tbs_certificate))
49 return false;
50
51 bool unused;
52 if (!tbs_certificate->SkipOptionalTag(
53 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0, &unused)) {
54 return false;
55 }
56
57 // serialNumber
58 if (!tbs_certificate->SkipTag(CBS_ASN1_INTEGER)) {
59 return false;
60 }
61 // signature
62 if (!tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE)) {
63 return false;
64 }
65
66 return true;
67 }
68
69 // Parses input |in| which should point to the beginning of a Certificate, and
70 // sets |*tbs_certificate| ready to parse the Subject. If parsing
71 // fails, this function returns false and |*tbs_certificate| is left in an
72 // undefined state.
SeekToSubject(bssl::der::Input in,bssl::der::Parser * tbs_certificate)73 bool SeekToSubject(bssl::der::Input in, bssl::der::Parser* tbs_certificate) {
74 if (!SeekToIssuer(in, tbs_certificate)) {
75 return false;
76 }
77 // issuer
78 if (!tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE)) {
79 return false;
80 }
81 // validity
82 if (!tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE)) {
83 return false;
84 }
85 return true;
86 }
87
88 // Parses input |in| which should point to the beginning of a Certificate, and
89 // sets |*tbs_certificate| ready to parse the SubjectPublicKeyInfo. If parsing
90 // fails, this function returns false and |*tbs_certificate| is left in an
91 // undefined state.
SeekToSPKI(bssl::der::Input in,bssl::der::Parser * tbs_certificate)92 bool SeekToSPKI(bssl::der::Input in, bssl::der::Parser* tbs_certificate) {
93 return SeekToSubject(in, tbs_certificate) &&
94 // Skip over Subject.
95 tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE);
96 }
97
98 // Parses input |in| which should point to the beginning of a
99 // Certificate. If parsing fails, this function returns false, with
100 // |*extensions_present| and |*extensions_parser| left in an undefined
101 // state. If parsing succeeds and extensions are present, this function
102 // sets |*extensions_present| to true and sets |*extensions_parser|
103 // ready to parse the Extensions. If extensions are not present, it sets
104 // |*extensions_present| to false and |*extensions_parser| is left in an
105 // undefined state.
SeekToExtensions(bssl::der::Input in,bool * extensions_present,bssl::der::Parser * extensions_parser)106 bool SeekToExtensions(bssl::der::Input in,
107 bool* extensions_present,
108 bssl::der::Parser* extensions_parser) {
109 bool present;
110 bssl::der::Parser tbs_cert_parser;
111 if (!SeekToSPKI(in, &tbs_cert_parser))
112 return false;
113
114 // From RFC 5280, section 4.1
115 // TBSCertificate ::= SEQUENCE {
116 // ...
117 // subjectPublicKeyInfo SubjectPublicKeyInfo,
118 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
119 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
120 // extensions [3] EXPLICIT Extensions OPTIONAL }
121
122 // subjectPublicKeyInfo
123 if (!tbs_cert_parser.SkipTag(CBS_ASN1_SEQUENCE)) {
124 return false;
125 }
126 // issuerUniqueID
127 if (!tbs_cert_parser.SkipOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
128 &present)) {
129 return false;
130 }
131 // subjectUniqueID
132 if (!tbs_cert_parser.SkipOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
133 &present)) {
134 return false;
135 }
136
137 std::optional<bssl::der::Input> extensions;
138 if (!tbs_cert_parser.ReadOptionalTag(
139 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3, &extensions)) {
140 return false;
141 }
142
143 if (!extensions) {
144 *extensions_present = false;
145 return true;
146 }
147
148 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
149 // Extension ::= SEQUENCE {
150 // extnID OBJECT IDENTIFIER,
151 // critical BOOLEAN DEFAULT FALSE,
152 // extnValue OCTET STRING }
153
154 // |extensions| was EXPLICITly tagged, so we still need to remove the
155 // ASN.1 SEQUENCE header.
156 bssl::der::Parser explicit_extensions_parser(extensions.value());
157 if (!explicit_extensions_parser.ReadSequence(extensions_parser))
158 return false;
159
160 if (explicit_extensions_parser.HasMore())
161 return false;
162
163 *extensions_present = true;
164 return true;
165 }
166
167 // Parse a DER-encoded, X.509 certificate in |cert| and find an extension with
168 // the given OID. Returns false on parse error or true if the parse was
169 // successful. |*out_extension_present| will be true iff the extension was
170 // found. In the case where it was found, |*out_extension| will describe the
171 // extension, or is undefined on parse error or if the extension is missing.
ExtractExtensionWithOID(std::string_view cert,bssl::der::Input extension_oid,bool * out_extension_present,bssl::ParsedExtension * out_extension)172 bool ExtractExtensionWithOID(std::string_view cert,
173 bssl::der::Input extension_oid,
174 bool* out_extension_present,
175 bssl::ParsedExtension* out_extension) {
176 bssl::der::Parser extensions;
177 bool extensions_present;
178 if (!SeekToExtensions(bssl::der::Input(cert), &extensions_present,
179 &extensions)) {
180 return false;
181 }
182 if (!extensions_present) {
183 *out_extension_present = false;
184 return true;
185 }
186
187 while (extensions.HasMore()) {
188 bssl::der::Input extension_tlv;
189 if (!extensions.ReadRawTLV(&extension_tlv) ||
190 !ParseExtension(extension_tlv, out_extension)) {
191 return false;
192 }
193
194 if (out_extension->oid == extension_oid) {
195 *out_extension_present = true;
196 return true;
197 }
198 }
199
200 *out_extension_present = false;
201 return true;
202 }
203
204 } // namespace
205
ExtractSubjectFromDERCert(std::string_view cert,std::string_view * subject_out)206 bool ExtractSubjectFromDERCert(std::string_view cert,
207 std::string_view* subject_out) {
208 bssl::der::Parser parser;
209 if (!SeekToSubject(bssl::der::Input(cert), &parser)) {
210 return false;
211 }
212 bssl::der::Input subject;
213 if (!parser.ReadRawTLV(&subject))
214 return false;
215 *subject_out = subject.AsStringView();
216 return true;
217 }
218
ExtractIssuerAndSubjectFromDERCert(base::span<const uint8_t> cert,base::span<const uint8_t> * issuer_out,base::span<const uint8_t> * subject_out)219 bool ExtractIssuerAndSubjectFromDERCert(
220 base::span<const uint8_t> cert,
221 base::span<const uint8_t>* issuer_out,
222 base::span<const uint8_t>* subject_out) {
223 bssl::der::Parser parser;
224 if (!SeekToIssuer(bssl::der::Input(cert), &parser)) {
225 return false;
226 }
227 bssl::der::Input issuer;
228 if (!parser.ReadRawTLV(&issuer)) {
229 return false;
230 }
231 *issuer_out = issuer.AsSpan();
232 // skip validity
233 if (!parser.SkipTag(CBS_ASN1_SEQUENCE)) {
234 return false;
235 }
236 bssl::der::Input subject;
237 if (!parser.ReadRawTLV(&subject)) {
238 return false;
239 }
240 *subject_out = subject.AsSpan();
241 return true;
242 }
243
ExtractSPKIFromDERCert(std::string_view cert,std::string_view * spki_out)244 bool ExtractSPKIFromDERCert(std::string_view cert, std::string_view* spki_out) {
245 bssl::der::Parser parser;
246 if (!SeekToSPKI(bssl::der::Input(cert), &parser)) {
247 return false;
248 }
249 bssl::der::Input spki;
250 if (!parser.ReadRawTLV(&spki))
251 return false;
252 *spki_out = spki.AsStringView();
253 return true;
254 }
255
ExtractSubjectPublicKeyFromSPKI(std::string_view spki,std::string_view * spk_out)256 bool ExtractSubjectPublicKeyFromSPKI(std::string_view spki,
257 std::string_view* spk_out) {
258 // From RFC 5280, Section 4.1
259 // SubjectPublicKeyInfo ::= SEQUENCE {
260 // algorithm AlgorithmIdentifier,
261 // subjectPublicKey BIT STRING }
262 //
263 // AlgorithmIdentifier ::= SEQUENCE {
264 // algorithm OBJECT IDENTIFIER,
265 // parameters ANY DEFINED BY algorithm OPTIONAL }
266
267 // Step into SubjectPublicKeyInfo sequence.
268 bssl::der::Parser parser((bssl::der::Input(spki)));
269 bssl::der::Parser spki_parser;
270 if (!parser.ReadSequence(&spki_parser))
271 return false;
272
273 // Step over algorithm field (a SEQUENCE).
274 if (!spki_parser.SkipTag(CBS_ASN1_SEQUENCE)) {
275 return false;
276 }
277
278 // Extract the subjectPublicKey field.
279 bssl::der::Input spk;
280 if (!spki_parser.ReadTag(CBS_ASN1_BITSTRING, &spk)) {
281 return false;
282 }
283 *spk_out = spk.AsStringView();
284 return true;
285 }
286
HasCanSignHttpExchangesDraftExtension(std::string_view cert)287 bool HasCanSignHttpExchangesDraftExtension(std::string_view cert) {
288 // kCanSignHttpExchangesDraftOid is the DER encoding of the OID for
289 // canSignHttpExchangesDraft defined in:
290 // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
291 static const uint8_t kCanSignHttpExchangesDraftOid[] = {
292 0x2B, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x16};
293
294 bool extension_present;
295 bssl::ParsedExtension extension;
296 if (!ExtractExtensionWithOID(cert,
297 bssl::der::Input(kCanSignHttpExchangesDraftOid),
298 &extension_present, &extension) ||
299 !extension_present) {
300 return false;
301 }
302
303 // The extension should have contents NULL.
304 static const uint8_t kNull[] = {0x05, 0x00};
305 return extension.value == bssl::der::Input(kNull);
306 }
307
ExtractSignatureAlgorithmsFromDERCert(std::string_view cert,std::string_view * cert_signature_algorithm_sequence,std::string_view * tbs_signature_algorithm_sequence)308 bool ExtractSignatureAlgorithmsFromDERCert(
309 std::string_view cert,
310 std::string_view* cert_signature_algorithm_sequence,
311 std::string_view* tbs_signature_algorithm_sequence) {
312 // From RFC 5280, section 4.1
313 // Certificate ::= SEQUENCE {
314 // tbsCertificate TBSCertificate,
315 // signatureAlgorithm AlgorithmIdentifier,
316 // signatureValue BIT STRING }
317
318 // TBSCertificate ::= SEQUENCE {
319 // version [0] EXPLICIT Version DEFAULT v1,
320 // serialNumber CertificateSerialNumber,
321 // signature AlgorithmIdentifier,
322 // issuer Name,
323 // validity Validity,
324 // subject Name,
325 // subjectPublicKeyInfo SubjectPublicKeyInfo,
326 // ... }
327
328 bssl::der::Parser parser((bssl::der::Input(cert)));
329 bssl::der::Parser certificate;
330 if (!parser.ReadSequence(&certificate))
331 return false;
332
333 bssl::der::Parser tbs_certificate;
334 if (!certificate.ReadSequence(&tbs_certificate))
335 return false;
336
337 bool unused;
338 if (!tbs_certificate.SkipOptionalTag(
339 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0, &unused)) {
340 return false;
341 }
342
343 // serialNumber
344 if (!tbs_certificate.SkipTag(CBS_ASN1_INTEGER)) {
345 return false;
346 }
347 // signature
348 bssl::der::Input tbs_algorithm;
349 if (!tbs_certificate.ReadRawTLV(&tbs_algorithm))
350 return false;
351
352 bssl::der::Input cert_algorithm;
353 if (!certificate.ReadRawTLV(&cert_algorithm))
354 return false;
355
356 *cert_signature_algorithm_sequence = cert_algorithm.AsStringView();
357 *tbs_signature_algorithm_sequence = tbs_algorithm.AsStringView();
358 return true;
359 }
360
ExtractExtensionFromDERCert(std::string_view cert,std::string_view extension_oid,bool * out_extension_present,bool * out_extension_critical,std::string_view * out_contents)361 bool ExtractExtensionFromDERCert(std::string_view cert,
362 std::string_view extension_oid,
363 bool* out_extension_present,
364 bool* out_extension_critical,
365 std::string_view* out_contents) {
366 *out_extension_present = false;
367 *out_extension_critical = false;
368 *out_contents = std::string_view();
369
370 bssl::ParsedExtension extension;
371 if (!ExtractExtensionWithOID(cert, bssl::der::Input(extension_oid),
372 out_extension_present, &extension)) {
373 return false;
374 }
375 if (!*out_extension_present)
376 return true;
377
378 *out_extension_critical = extension.critical;
379 *out_contents = extension.value.AsStringView();
380 return true;
381 }
382
383 } // namespace net::asn1
384