roll skia to 4276
[chromium-blink-merge.git] / net / base / asn1_util.cc
bloba1e8637f8706a95f0aacdc8ad295e6f785322952
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.
5 #include "net/base/asn1_util.h"
7 namespace net {
9 namespace asn1 {
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());
17 // We don't support kAny and kOptional at the same time.
18 if ((tag_value & kAny) && (tag_value & kOptional))
19 return false;
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;
29 if (in->size() < 2)
30 return false;
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;
41 return false;
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;
63 len <<= 8;
64 len += data[3];
66 if (len < 128) {
67 // the length should have been encoded in short form. This distinguishes
68 // DER from BER encoding.
69 return false;
71 if (out_header_len)
72 *out_header_len = 2 + num_bytes;
73 len += 2 + num_bytes;
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;
84 bool 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;
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.
98 static 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 }
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,
114 base::StringPiece certificate;
115 if (!GetElement(cert, kSEQUENCE, &certificate))
116 return false;
118 // We don't allow junk after the certificate.
119 if (!cert->empty())
120 return false;
122 base::StringPiece tbs_certificate;
123 if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate))
124 return false;
126 if (!GetElement(&tbs_certificate,
127 kOptional | kConstructed | kContextSpecific | 0,
128 NULL)) {
129 return false;
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;
151 bool 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;
160 bool ExtractCRLURLsFromDERCert(base::StringPiece cert,
161 std::vector<base::StringPiece>* urls_out) {
162 urls_out->clear();
163 std::vector<base::StringPiece> tmp_urls_out;
165 if (!SeekToSPKI(&cert))
166 return false;
168 // From RFC 5280, section 4.1
169 // TBSCertificate ::= SEQUENCE {
170 // ...
171 // subjectPublicKeyInfo SubjectPublicKeyInfo,
172 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
173 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
174 // extensions [3] EXPLICIT Extensions OPTIONAL
176 // subjectPublicKeyInfo
177 if (!GetElement(&cert, kSEQUENCE, NULL))
178 return false;
179 // issuerUniqueID
180 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 1, NULL))
181 return false;
182 // subjectUniqueID
183 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 2, NULL))
184 return false;
186 base::StringPiece extensions_seq;
187 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3,
188 &extensions_seq)) {
189 return false;
192 if (extensions_seq.empty())
193 return true;
195 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
196 // Extension ::= SEQUENCE {
197 // extnID OBJECT IDENTIFIER,
198 // critical BOOLEAN DEFAULT FALSE,
199 // extnValue OCTET STRING
201 // |extensions_seq| was EXPLICITly tagged, so we still need to remove the
202 // ASN.1 SEQUENCE header.
203 base::StringPiece extensions;
204 if (!GetElement(&extensions_seq, kSEQUENCE, &extensions))
205 return false;
207 while (extensions.size() > 0) {
208 base::StringPiece extension;
209 if (!GetElement(&extensions, kSEQUENCE, &extension))
210 return false;
212 base::StringPiece oid;
213 if (!GetElement(&extension, kOID, &oid))
214 return false;
216 // kCRLDistributionPointsOID is the DER encoding of the OID for the X.509
217 // CRL Distribution Points extension.
218 static const uint8 kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f};
220 if (oid.size() != sizeof(kCRLDistributionPointsOID) ||
221 memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) {
222 continue;
225 // critical
226 GetElement(&extension, kBOOLEAN, NULL);
228 // extnValue
229 base::StringPiece extension_value;
230 if (!GetElement(&extension, kOCTETSTRING, &extension_value))
231 return false;
233 // RFC 5280, section 4.2.1.13.
235 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
237 // DistributionPoint ::= SEQUENCE {
238 // distributionPoint [0] DistributionPointName OPTIONAL,
239 // reasons [1] ReasonFlags OPTIONAL,
240 // cRLIssuer [2] GeneralNames OPTIONAL }
242 base::StringPiece distribution_points;
243 if (!GetElement(&extension_value, kSEQUENCE, &distribution_points))
244 return false;
246 while (distribution_points.size() > 0) {
247 base::StringPiece distrib_point;
248 if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point))
249 return false;
251 base::StringPiece name;
252 if (!GetElement(&distrib_point, kContextSpecific | kConstructed | 0,
253 &name)) {
254 // If it doesn't contain a name then we skip it.
255 continue;
258 if (GetElement(&distrib_point, kContextSpecific | 1, NULL)) {
259 // If it contains a subset of reasons then we skip it. We aren't
260 // interested in subsets of CRLs and the RFC states that there MUST be
261 // a CRL that covers all reasons.
262 continue;
265 if (GetElement(&distrib_point,
266 kContextSpecific | kConstructed | 2, NULL)) {
267 // If it contains a alternative issuer, then we skip it.
268 continue;
271 // DistributionPointName ::= CHOICE {
272 // fullName [0] GeneralNames,
273 // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
274 base::StringPiece general_names;
275 if (!GetElement(&name,
276 kContextSpecific | kConstructed | 0, &general_names)) {
277 continue;
280 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
281 // GeneralName ::= CHOICE {
282 // ...
283 // uniformResourceIdentifier [6] IA5String,
284 // ...
285 while (general_names.size() > 0) {
286 base::StringPiece url;
287 if (GetElement(&general_names, kContextSpecific | 6, &url)) {
288 tmp_urls_out.push_back(url);
289 } else {
290 if (!GetElement(&general_names, kAny, NULL))
291 return false;
297 urls_out->swap(tmp_urls_out);
298 return true;
301 } // namespace asn1
303 } // namespace net