• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 namespace net {
8 
9 namespace asn1 {
10 
ParseElement(base::StringPiece * in,unsigned tag_value,base::StringPiece * out,unsigned * out_header_len)11 bool 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 
GetElement(base::StringPiece * in,unsigned tag_value,base::StringPiece * out)63 bool 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 
ExtractSPKIFromDERCert(base::StringPiece cert,base::StringPiece * spki_out)74 bool 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