1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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
7namespace net {
8
9namespace asn1 {
10
11bool ParseElement(base::StringPiece* in,
12                  unsigned tag_value,
13                  base::StringPiece* out,
14                  unsigned *out_header_len) {
15  const uint8* data = reinterpret_cast<const uint8*>(in->data());
16
17  // We don't support kAny and kOptional at the same time.
18  if ((tag_value & kAny) && (tag_value & kOptional))
19    return false;
20
21  if (in->empty() && (tag_value & kOptional)) {
22    if (out_header_len)
23      *out_header_len = 0;
24    if (out)
25      *out = base::StringPiece();
26    return true;
27  }
28
29  if (in->size() < 2)
30    return false;
31
32  if (tag_value != kAny &&
33      static_cast<unsigned char>(data[0]) != (tag_value & 0xff)) {
34    if (tag_value & kOptional) {
35      if (out_header_len)
36        *out_header_len = 0;
37      if (out)
38        *out = base::StringPiece();
39      return true;
40    }
41    return false;
42  }
43
44  size_t len = 0;
45  if ((data[1] & 0x80) == 0) {
46    // short form length
47    if (out_header_len)
48      *out_header_len = 2;
49    len = static_cast<size_t>(data[1]) + 2;
50  } else {
51    // long form length
52    const unsigned num_bytes = data[1] & 0x7f;
53    if (num_bytes == 0 || num_bytes > 2)
54      return false;
55    if (in->size() < 2 + num_bytes)
56      return false;
57    len = data[2];
58    if (num_bytes == 2) {
59      if (len == 0) {
60        // the length encoding must be minimal.
61        return false;
62      }
63      len <<= 8;
64      len += data[3];
65    }
66    if (len < 128) {
67      // the length should have been encoded in short form. This distinguishes
68      // DER from BER encoding.
69      return false;
70    }
71    if (out_header_len)
72      *out_header_len = 2 + num_bytes;
73    len += 2 + num_bytes;
74  }
75
76  if (in->size() < len)
77    return false;
78  if (out)
79    *out = base::StringPiece(in->data(), len);
80  in->remove_prefix(len);
81  return true;
82}
83
84bool GetElement(base::StringPiece* in,
85                unsigned tag_value,
86                base::StringPiece* out) {
87  unsigned header_len;
88  if (!ParseElement(in, tag_value, out, &header_len))
89    return false;
90  if (out)
91    out->remove_prefix(header_len);
92  return true;
93}
94
95// SeekToSPKI changes |cert| so that it points to a suffix of the
96// TBSCertificate where the suffix begins at the start of the ASN.1
97// SubjectPublicKeyInfo value.
98static bool SeekToSPKI(base::StringPiece* cert) {
99  // From RFC 5280, section 4.1
100  //    Certificate  ::=  SEQUENCE  {
101  //      tbsCertificate       TBSCertificate,
102  //      signatureAlgorithm   AlgorithmIdentifier,
103  //      signatureValue       BIT STRING  }
104
105  // TBSCertificate  ::=  SEQUENCE  {
106  //      version         [0]  EXPLICIT Version DEFAULT v1,
107  //      serialNumber         CertificateSerialNumber,
108  //      signature            AlgorithmIdentifier,
109  //      issuer               Name,
110  //      validity             Validity,
111  //      subject              Name,
112  //      subjectPublicKeyInfo SubjectPublicKeyInfo,
113
114  base::StringPiece certificate;
115  if (!GetElement(cert, kSEQUENCE, &certificate))
116    return false;
117
118  // We don't allow junk after the certificate.
119  if (!cert->empty())
120    return false;
121
122  base::StringPiece tbs_certificate;
123  if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate))
124    return false;
125
126  if (!GetElement(&tbs_certificate,
127                  kOptional | kConstructed | kContextSpecific | 0,
128                  NULL)) {
129    return false;
130  }
131
132  // serialNumber
133  if (!GetElement(&tbs_certificate, kINTEGER, NULL))
134    return false;
135  // signature
136  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
137    return false;
138  // issuer
139  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
140    return false;
141  // validity
142  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
143    return false;
144  // subject
145  if (!GetElement(&tbs_certificate, kSEQUENCE, NULL))
146    return false;
147  *cert = tbs_certificate;
148  return true;
149}
150
151bool ExtractSPKIFromDERCert(base::StringPiece cert,
152                            base::StringPiece* spki_out) {
153  if (!SeekToSPKI(&cert))
154    return false;
155  if (!ParseElement(&cert, kSEQUENCE, spki_out, NULL))
156    return false;
157  return true;
158}
159
160bool ExtractSubjectPublicKeyFromSPKI(base::StringPiece spki,
161                                     base::StringPiece* spk_out) {
162  // From RFC 5280, Section 4.1
163  //   SubjectPublicKeyInfo  ::=  SEQUENCE  {
164  //     algorithm            AlgorithmIdentifier,
165  //     subjectPublicKey     BIT STRING  }
166  //
167  //   AlgorithmIdentifier  ::=  SEQUENCE  {
168  //     algorithm               OBJECT IDENTIFIER,
169  //     parameters              ANY DEFINED BY algorithm OPTIONAL  }
170
171  // Step into SubjectPublicKeyInfo sequence.
172  base::StringPiece spki_contents;
173  if (!asn1::GetElement(&spki, asn1::kSEQUENCE, &spki_contents))
174    return false;
175
176  // Step over algorithm field (a SEQUENCE).
177  base::StringPiece algorithm;
178  if (!asn1::GetElement(&spki_contents, asn1::kSEQUENCE, &algorithm))
179    return false;
180
181  // Extract the subjectPublicKey field.
182  if (!asn1::GetElement(&spki_contents, asn1::kBITSTRING, spk_out))
183    return false;
184  return true;
185}
186
187
188bool ExtractCRLURLsFromDERCert(base::StringPiece cert,
189                               std::vector<base::StringPiece>* urls_out) {
190  urls_out->clear();
191  std::vector<base::StringPiece> tmp_urls_out;
192
193  if (!SeekToSPKI(&cert))
194    return false;
195
196  // From RFC 5280, section 4.1
197  // TBSCertificate  ::=  SEQUENCE  {
198  //      ...
199  //      subjectPublicKeyInfo SubjectPublicKeyInfo,
200  //      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
201  //      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
202  //      extensions      [3]  EXPLICIT Extensions OPTIONAL
203
204  // subjectPublicKeyInfo
205  if (!GetElement(&cert, kSEQUENCE, NULL))
206    return false;
207  // issuerUniqueID
208  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 1, NULL))
209    return false;
210  // subjectUniqueID
211  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 2, NULL))
212    return false;
213
214  base::StringPiece extensions_seq;
215  if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3,
216                  &extensions_seq)) {
217    return false;
218  }
219
220  if (extensions_seq.empty())
221    return true;
222
223  // Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
224  // Extension   ::=  SEQUENCE  {
225  //      extnID      OBJECT IDENTIFIER,
226  //      critical    BOOLEAN DEFAULT FALSE,
227  //      extnValue   OCTET STRING
228
229  // |extensions_seq| was EXPLICITly tagged, so we still need to remove the
230  // ASN.1 SEQUENCE header.
231  base::StringPiece extensions;
232  if (!GetElement(&extensions_seq, kSEQUENCE, &extensions))
233    return false;
234
235  while (extensions.size() > 0) {
236    base::StringPiece extension;
237    if (!GetElement(&extensions, kSEQUENCE, &extension))
238      return false;
239
240    base::StringPiece oid;
241    if (!GetElement(&extension, kOID, &oid))
242      return false;
243
244    // kCRLDistributionPointsOID is the DER encoding of the OID for the X.509
245    // CRL Distribution Points extension.
246    static const uint8 kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f};
247
248    if (oid.size() != sizeof(kCRLDistributionPointsOID) ||
249        memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) {
250      continue;
251    }
252
253    // critical
254    GetElement(&extension, kBOOLEAN, NULL);
255
256    // extnValue
257    base::StringPiece extension_value;
258    if (!GetElement(&extension, kOCTETSTRING, &extension_value))
259      return false;
260
261    // RFC 5280, section 4.2.1.13.
262    //
263    // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
264    //
265    // DistributionPoint ::= SEQUENCE {
266    //  distributionPoint       [0]     DistributionPointName OPTIONAL,
267    //  reasons                 [1]     ReasonFlags OPTIONAL,
268    //  cRLIssuer               [2]     GeneralNames OPTIONAL }
269
270    base::StringPiece distribution_points;
271    if (!GetElement(&extension_value, kSEQUENCE, &distribution_points))
272      return false;
273
274    while (distribution_points.size() > 0) {
275      base::StringPiece distrib_point;
276      if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point))
277        return false;
278
279      base::StringPiece name;
280      if (!GetElement(&distrib_point, kContextSpecific | kConstructed | 0,
281                      &name)) {
282        // If it doesn't contain a name then we skip it.
283        continue;
284      }
285
286      if (GetElement(&distrib_point, kContextSpecific | 1, NULL)) {
287        // If it contains a subset of reasons then we skip it. We aren't
288        // interested in subsets of CRLs and the RFC states that there MUST be
289        // a CRL that covers all reasons.
290        continue;
291      }
292
293      if (GetElement(&distrib_point,
294                     kContextSpecific | kConstructed | 2, NULL)) {
295        // If it contains a alternative issuer, then we skip it.
296        continue;
297      }
298
299      // DistributionPointName ::= CHOICE {
300      //   fullName                [0]     GeneralNames,
301      //   nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
302      base::StringPiece general_names;
303      if (!GetElement(&name,
304                      kContextSpecific | kConstructed | 0, &general_names)) {
305        continue;
306      }
307
308      // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
309      // GeneralName ::= CHOICE {
310      //   ...
311      //   uniformResourceIdentifier [6]  IA5String,
312      //   ...
313      while (general_names.size() > 0) {
314        base::StringPiece url;
315        if (GetElement(&general_names, kContextSpecific | 6, &url)) {
316          tmp_urls_out.push_back(url);
317        } else {
318          if (!GetElement(&general_names, kAny, NULL))
319            return false;
320        }
321      }
322    }
323  }
324
325  urls_out->swap(tmp_urls_out);
326  return true;
327}
328
329} // namespace asn1
330
331} // namespace net
332