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 Subject. If parsing
20 // fails, this function returns false and |*tbs_certificate| is left in an
21 // undefined state.
SeekToSubject(bssl::der::Input in,bssl::der::Parser * tbs_certificate)22 bool SeekToSubject(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 // issuer
66 if (!tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE)) {
67 return false;
68 }
69 // validity
70 if (!tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE)) {
71 return false;
72 }
73 return true;
74 }
75
76 // Parses input |in| which should point to the beginning of a Certificate, and
77 // sets |*tbs_certificate| ready to parse the SubjectPublicKeyInfo. If parsing
78 // fails, this function returns false and |*tbs_certificate| is left in an
79 // undefined state.
SeekToSPKI(bssl::der::Input in,bssl::der::Parser * tbs_certificate)80 bool SeekToSPKI(bssl::der::Input in, bssl::der::Parser* tbs_certificate) {
81 return SeekToSubject(in, tbs_certificate) &&
82 // Skip over Subject.
83 tbs_certificate->SkipTag(CBS_ASN1_SEQUENCE);
84 }
85
86 // Parses input |in| which should point to the beginning of a
87 // Certificate. If parsing fails, this function returns false, with
88 // |*extensions_present| and |*extensions_parser| left in an undefined
89 // state. If parsing succeeds and extensions are present, this function
90 // sets |*extensions_present| to true and sets |*extensions_parser|
91 // ready to parse the Extensions. If extensions are not present, it sets
92 // |*extensions_present| to false and |*extensions_parser| is left in an
93 // undefined state.
SeekToExtensions(bssl::der::Input in,bool * extensions_present,bssl::der::Parser * extensions_parser)94 bool SeekToExtensions(bssl::der::Input in,
95 bool* extensions_present,
96 bssl::der::Parser* extensions_parser) {
97 bool present;
98 bssl::der::Parser tbs_cert_parser;
99 if (!SeekToSPKI(in, &tbs_cert_parser))
100 return false;
101
102 // From RFC 5280, section 4.1
103 // TBSCertificate ::= SEQUENCE {
104 // ...
105 // subjectPublicKeyInfo SubjectPublicKeyInfo,
106 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
107 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
108 // extensions [3] EXPLICIT Extensions OPTIONAL }
109
110 // subjectPublicKeyInfo
111 if (!tbs_cert_parser.SkipTag(CBS_ASN1_SEQUENCE)) {
112 return false;
113 }
114 // issuerUniqueID
115 if (!tbs_cert_parser.SkipOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
116 &present)) {
117 return false;
118 }
119 // subjectUniqueID
120 if (!tbs_cert_parser.SkipOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
121 &present)) {
122 return false;
123 }
124
125 std::optional<bssl::der::Input> extensions;
126 if (!tbs_cert_parser.ReadOptionalTag(
127 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3, &extensions)) {
128 return false;
129 }
130
131 if (!extensions) {
132 *extensions_present = false;
133 return true;
134 }
135
136 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
137 // Extension ::= SEQUENCE {
138 // extnID OBJECT IDENTIFIER,
139 // critical BOOLEAN DEFAULT FALSE,
140 // extnValue OCTET STRING }
141
142 // |extensions| was EXPLICITly tagged, so we still need to remove the
143 // ASN.1 SEQUENCE header.
144 bssl::der::Parser explicit_extensions_parser(extensions.value());
145 if (!explicit_extensions_parser.ReadSequence(extensions_parser))
146 return false;
147
148 if (explicit_extensions_parser.HasMore())
149 return false;
150
151 *extensions_present = true;
152 return true;
153 }
154
155 // Parse a DER-encoded, X.509 certificate in |cert| and find an extension with
156 // the given OID. Returns false on parse error or true if the parse was
157 // successful. |*out_extension_present| will be true iff the extension was
158 // found. In the case where it was found, |*out_extension| will describe the
159 // 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)160 bool ExtractExtensionWithOID(std::string_view cert,
161 bssl::der::Input extension_oid,
162 bool* out_extension_present,
163 bssl::ParsedExtension* out_extension) {
164 bssl::der::Parser extensions;
165 bool extensions_present;
166 if (!SeekToExtensions(bssl::der::Input(cert), &extensions_present,
167 &extensions)) {
168 return false;
169 }
170 if (!extensions_present) {
171 *out_extension_present = false;
172 return true;
173 }
174
175 while (extensions.HasMore()) {
176 bssl::der::Input extension_tlv;
177 if (!extensions.ReadRawTLV(&extension_tlv) ||
178 !ParseExtension(extension_tlv, out_extension)) {
179 return false;
180 }
181
182 if (out_extension->oid == extension_oid) {
183 *out_extension_present = true;
184 return true;
185 }
186 }
187
188 *out_extension_present = false;
189 return true;
190 }
191
192 } // namespace
193
ExtractSubjectFromDERCert(std::string_view cert,std::string_view * subject_out)194 bool ExtractSubjectFromDERCert(std::string_view cert,
195 std::string_view* subject_out) {
196 bssl::der::Parser parser;
197 if (!SeekToSubject(bssl::der::Input(cert), &parser)) {
198 return false;
199 }
200 bssl::der::Input subject;
201 if (!parser.ReadRawTLV(&subject))
202 return false;
203 *subject_out = subject.AsStringView();
204 return true;
205 }
206
ExtractSPKIFromDERCert(std::string_view cert,std::string_view * spki_out)207 bool ExtractSPKIFromDERCert(std::string_view cert, std::string_view* spki_out) {
208 bssl::der::Parser parser;
209 if (!SeekToSPKI(bssl::der::Input(cert), &parser)) {
210 return false;
211 }
212 bssl::der::Input spki;
213 if (!parser.ReadRawTLV(&spki))
214 return false;
215 *spki_out = spki.AsStringView();
216 return true;
217 }
218
ExtractSubjectPublicKeyFromSPKI(std::string_view spki,std::string_view * spk_out)219 bool ExtractSubjectPublicKeyFromSPKI(std::string_view spki,
220 std::string_view* spk_out) {
221 // From RFC 5280, Section 4.1
222 // SubjectPublicKeyInfo ::= SEQUENCE {
223 // algorithm AlgorithmIdentifier,
224 // subjectPublicKey BIT STRING }
225 //
226 // AlgorithmIdentifier ::= SEQUENCE {
227 // algorithm OBJECT IDENTIFIER,
228 // parameters ANY DEFINED BY algorithm OPTIONAL }
229
230 // Step into SubjectPublicKeyInfo sequence.
231 bssl::der::Parser parser((bssl::der::Input(spki)));
232 bssl::der::Parser spki_parser;
233 if (!parser.ReadSequence(&spki_parser))
234 return false;
235
236 // Step over algorithm field (a SEQUENCE).
237 if (!spki_parser.SkipTag(CBS_ASN1_SEQUENCE)) {
238 return false;
239 }
240
241 // Extract the subjectPublicKey field.
242 bssl::der::Input spk;
243 if (!spki_parser.ReadTag(CBS_ASN1_BITSTRING, &spk)) {
244 return false;
245 }
246 *spk_out = spk.AsStringView();
247 return true;
248 }
249
HasCanSignHttpExchangesDraftExtension(std::string_view cert)250 bool HasCanSignHttpExchangesDraftExtension(std::string_view cert) {
251 // kCanSignHttpExchangesDraftOid is the DER encoding of the OID for
252 // canSignHttpExchangesDraft defined in:
253 // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
254 static const uint8_t kCanSignHttpExchangesDraftOid[] = {
255 0x2B, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x16};
256
257 bool extension_present;
258 bssl::ParsedExtension extension;
259 if (!ExtractExtensionWithOID(cert,
260 bssl::der::Input(kCanSignHttpExchangesDraftOid),
261 &extension_present, &extension) ||
262 !extension_present) {
263 return false;
264 }
265
266 // The extension should have contents NULL.
267 static const uint8_t kNull[] = {0x05, 0x00};
268 return extension.value == bssl::der::Input(kNull);
269 }
270
ExtractSignatureAlgorithmsFromDERCert(std::string_view cert,std::string_view * cert_signature_algorithm_sequence,std::string_view * tbs_signature_algorithm_sequence)271 bool ExtractSignatureAlgorithmsFromDERCert(
272 std::string_view cert,
273 std::string_view* cert_signature_algorithm_sequence,
274 std::string_view* tbs_signature_algorithm_sequence) {
275 // From RFC 5280, section 4.1
276 // Certificate ::= SEQUENCE {
277 // tbsCertificate TBSCertificate,
278 // signatureAlgorithm AlgorithmIdentifier,
279 // signatureValue BIT STRING }
280
281 // TBSCertificate ::= SEQUENCE {
282 // version [0] EXPLICIT Version DEFAULT v1,
283 // serialNumber CertificateSerialNumber,
284 // signature AlgorithmIdentifier,
285 // issuer Name,
286 // validity Validity,
287 // subject Name,
288 // subjectPublicKeyInfo SubjectPublicKeyInfo,
289 // ... }
290
291 bssl::der::Parser parser((bssl::der::Input(cert)));
292 bssl::der::Parser certificate;
293 if (!parser.ReadSequence(&certificate))
294 return false;
295
296 bssl::der::Parser tbs_certificate;
297 if (!certificate.ReadSequence(&tbs_certificate))
298 return false;
299
300 bool unused;
301 if (!tbs_certificate.SkipOptionalTag(
302 CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0, &unused)) {
303 return false;
304 }
305
306 // serialNumber
307 if (!tbs_certificate.SkipTag(CBS_ASN1_INTEGER)) {
308 return false;
309 }
310 // signature
311 bssl::der::Input tbs_algorithm;
312 if (!tbs_certificate.ReadRawTLV(&tbs_algorithm))
313 return false;
314
315 bssl::der::Input cert_algorithm;
316 if (!certificate.ReadRawTLV(&cert_algorithm))
317 return false;
318
319 *cert_signature_algorithm_sequence = cert_algorithm.AsStringView();
320 *tbs_signature_algorithm_sequence = tbs_algorithm.AsStringView();
321 return true;
322 }
323
ExtractExtensionFromDERCert(std::string_view cert,std::string_view extension_oid,bool * out_extension_present,bool * out_extension_critical,std::string_view * out_contents)324 bool ExtractExtensionFromDERCert(std::string_view cert,
325 std::string_view extension_oid,
326 bool* out_extension_present,
327 bool* out_extension_critical,
328 std::string_view* out_contents) {
329 *out_extension_present = false;
330 *out_extension_critical = false;
331 *out_contents = std::string_view();
332
333 bssl::ParsedExtension extension;
334 if (!ExtractExtensionWithOID(cert, bssl::der::Input(extension_oid),
335 out_extension_present, &extension)) {
336 return false;
337 }
338 if (!*out_extension_present)
339 return true;
340
341 *out_extension_critical = extension.critical;
342 *out_contents = extension.value.AsStringView();
343 return true;
344 }
345
346 } // namespace net::asn1
347