Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / cert / asn1_util.cc
blob4bc37a677578973b31714cf3bbac3c79d38d8c86
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.
5 #include "net/cert/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_t* data = reinterpret_cast<const uint8_t*>(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 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 }
167 // AlgorithmIdentifier ::= SEQUENCE {
168 // algorithm OBJECT IDENTIFIER,
169 // parameters ANY DEFINED BY algorithm OPTIONAL }
171 // Step into SubjectPublicKeyInfo sequence.
172 base::StringPiece spki_contents;
173 if (!asn1::GetElement(&spki, asn1::kSEQUENCE, &spki_contents))
174 return false;
176 // Step over algorithm field (a SEQUENCE).
177 base::StringPiece algorithm;
178 if (!asn1::GetElement(&spki_contents, asn1::kSEQUENCE, &algorithm))
179 return false;
181 // Extract the subjectPublicKey field.
182 if (!asn1::GetElement(&spki_contents, asn1::kBITSTRING, spk_out))
183 return false;
184 return true;
188 bool ExtractCRLURLsFromDERCert(base::StringPiece cert,
189 std::vector<base::StringPiece>* urls_out) {
190 urls_out->clear();
191 std::vector<base::StringPiece> tmp_urls_out;
193 if (!SeekToSPKI(&cert))
194 return false;
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
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;
214 base::StringPiece extensions_seq;
215 if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3,
216 &extensions_seq)) {
217 return false;
220 if (extensions_seq.empty())
221 return true;
223 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
224 // Extension ::= SEQUENCE {
225 // extnID OBJECT IDENTIFIER,
226 // critical BOOLEAN DEFAULT FALSE,
227 // extnValue OCTET STRING
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;
235 while (extensions.size() > 0) {
236 base::StringPiece extension;
237 if (!GetElement(&extensions, kSEQUENCE, &extension))
238 return false;
240 base::StringPiece oid;
241 if (!GetElement(&extension, kOID, &oid))
242 return false;
244 // kCRLDistributionPointsOID is the DER encoding of the OID for the X.509
245 // CRL Distribution Points extension.
246 static const uint8_t kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f};
248 if (oid.size() != sizeof(kCRLDistributionPointsOID) ||
249 memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) {
250 continue;
253 // critical
254 GetElement(&extension, kBOOLEAN, NULL);
256 // extnValue
257 base::StringPiece extension_value;
258 if (!GetElement(&extension, kOCTETSTRING, &extension_value))
259 return false;
261 // RFC 5280, section 4.2.1.13.
263 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
265 // DistributionPoint ::= SEQUENCE {
266 // distributionPoint [0] DistributionPointName OPTIONAL,
267 // reasons [1] ReasonFlags OPTIONAL,
268 // cRLIssuer [2] GeneralNames OPTIONAL }
270 base::StringPiece distribution_points;
271 if (!GetElement(&extension_value, kSEQUENCE, &distribution_points))
272 return false;
274 while (distribution_points.size() > 0) {
275 base::StringPiece distrib_point;
276 if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point))
277 return false;
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;
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;
293 if (GetElement(&distrib_point,
294 kContextSpecific | kConstructed | 2, NULL)) {
295 // If it contains a alternative issuer, then we skip it.
296 continue;
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;
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;
325 urls_out->swap(tmp_urls_out);
326 return true;
329 } // namespace asn1
331 } // namespace net