xref: /aosp_15_r20/external/cronet/net/cert/asn1_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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