1// Copyright (c) 2011 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/base/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  if (in->size() < 2)
18    return false;
19
20  if (static_cast<unsigned char>(data[0]) != tag_value)
21    return false;
22
23  size_t len = 0;
24  if ((data[1] & 0x80) == 0) {
25    // short form length
26    if (out_header_len)
27      *out_header_len = 2;
28    len = static_cast<size_t>(data[1]) + 2;
29  } else {
30    // long form length
31    const unsigned num_bytes = data[1] & 0x7f;
32    if (num_bytes == 0 || num_bytes > 2)
33      return false;
34    if (in->size() < 2 + num_bytes)
35      return false;
36    len = data[2];
37    if (num_bytes == 2) {
38      if (len == 0) {
39        // the length encoding must be minimal.
40        return false;
41      }
42      len <<= 8;
43      len += data[3];
44    }
45    if (len < 128) {
46      // the length should have been encoded in short form. This distinguishes
47      // DER from BER encoding.
48      return false;
49    }
50    if (out_header_len)
51      *out_header_len = 2 + num_bytes;
52    len += 2 + num_bytes;
53  }
54
55  if (in->size() < len)
56    return false;
57  if (out)
58    *out = base::StringPiece(in->data(), len);
59  in->remove_prefix(len);
60  return true;
61}
62
63bool GetElement(base::StringPiece* in,
64                unsigned tag_value,
65                base::StringPiece* out) {
66  unsigned header_len;
67  if (!ParseElement(in, tag_value, out, &header_len))
68    return false;
69  if (out)
70    out->remove_prefix(header_len);
71  return true;
72}
73
74bool ExtractSPKIFromDERCert(base::StringPiece cert,
75                            base::StringPiece* spki_out) {
76  // From RFC 5280, section 4.1
77  //    Certificate  ::=  SEQUENCE  {
78  //      tbsCertificate       TBSCertificate,
79  //      signatureAlgorithm   AlgorithmIdentifier,
80  //      signatureValue       BIT STRING  }
81
82  // TBSCertificate  ::=  SEQUENCE  {
83  //      version         [0]  EXPLICIT Version DEFAULT v1,
84  //      serialNumber         CertificateSerialNumber,
85  //      signature            AlgorithmIdentifier,
86  //      issuer               Name,
87  //      validity             Validity,
88  //      subject              Name,
89  //      subjectPublicKeyInfo SubjectPublicKeyInfo,
90
91  base::StringPiece certificate;
92  if (!asn1::GetElement(&cert, asn1::kSEQUENCE, &certificate))
93    return false;
94
95  base::StringPiece tbs_certificate;
96  if (!asn1::GetElement(&certificate, asn1::kSEQUENCE, &tbs_certificate))
97    return false;
98
99  // The version is optional, so a failure to parse it is fine.
100  asn1::GetElement(&tbs_certificate,
101                   asn1::kCompound | asn1::kContextSpecific | 0,
102                   NULL);
103
104  // serialNumber
105  if (!asn1::GetElement(&tbs_certificate, asn1::kINTEGER, NULL))
106    return false;
107  // signature
108  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
109    return false;
110  // issuer
111  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
112    return false;
113  // validity
114  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
115    return false;
116  // subject
117  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
118    return false;
119  // subjectPublicKeyInfo
120  if (!asn1::ParseElement(&tbs_certificate, asn1::kSEQUENCE, spki_out, NULL))
121    return false;
122  return true;
123}
124
125} // namespace asn1
126
127} // namespace net
128