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