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