• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/cert/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   // We don't support kAny and kOptional at the same time.
18   if ((tag_value & kAny) && (tag_value & kOptional))
19     return false;
20 
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;
27   }
28 
29   if (in->size() < 2)
30     return false;
31 
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;
40     }
41     return false;
42   }
43 
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;
62       }
63       len <<= 8;
64       len += data[3];
65     }
66     if (len < 128) {
67       // the length should have been encoded in short form. This distinguishes
68       // DER from BER encoding.
69       return false;
70     }
71     if (out_header_len)
72       *out_header_len = 2 + num_bytes;
73     len += 2 + num_bytes;
74   }
75 
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;
82 }
83 
GetElement(base::StringPiece * in,unsigned tag_value,base::StringPiece * out)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;
93 }
94 
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.
SeekToSPKI(base::StringPiece * cert)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  }
104 
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,
113 
114   base::StringPiece certificate;
115   if (!GetElement(cert, kSEQUENCE, &certificate))
116     return false;
117 
118   // We don't allow junk after the certificate.
119   if (!cert->empty())
120     return false;
121 
122   base::StringPiece tbs_certificate;
123   if (!GetElement(&certificate, kSEQUENCE, &tbs_certificate))
124     return false;
125 
126   if (!GetElement(&tbs_certificate,
127                   kOptional | kConstructed | kContextSpecific | 0,
128                   NULL)) {
129     return false;
130   }
131 
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;
149 }
150 
ExtractSPKIFromDERCert(base::StringPiece cert,base::StringPiece * spki_out)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;
158 }
159 
ExtractSubjectPublicKeyFromSPKI(base::StringPiece spki,base::StringPiece * spk_out)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  }
166   //
167   //   AlgorithmIdentifier  ::=  SEQUENCE  {
168   //     algorithm               OBJECT IDENTIFIER,
169   //     parameters              ANY DEFINED BY algorithm OPTIONAL  }
170 
171   // Step into SubjectPublicKeyInfo sequence.
172   base::StringPiece spki_contents;
173   if (!asn1::GetElement(&spki, asn1::kSEQUENCE, &spki_contents))
174     return false;
175 
176   // Step over algorithm field (a SEQUENCE).
177   base::StringPiece algorithm;
178   if (!asn1::GetElement(&spki_contents, asn1::kSEQUENCE, &algorithm))
179     return false;
180 
181   // Extract the subjectPublicKey field.
182   if (!asn1::GetElement(&spki_contents, asn1::kBITSTRING, spk_out))
183     return false;
184   return true;
185 }
186 
187 
ExtractCRLURLsFromDERCert(base::StringPiece cert,std::vector<base::StringPiece> * urls_out)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;
192 
193   if (!SeekToSPKI(&cert))
194     return false;
195 
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
203 
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;
213 
214   base::StringPiece extensions_seq;
215   if (!GetElement(&cert, kOptional | kConstructed | kContextSpecific | 3,
216                   &extensions_seq)) {
217     return false;
218   }
219 
220   if (extensions_seq.empty())
221     return true;
222 
223   // Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
224   // Extension   ::=  SEQUENCE  {
225   //      extnID      OBJECT IDENTIFIER,
226   //      critical    BOOLEAN DEFAULT FALSE,
227   //      extnValue   OCTET STRING
228 
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;
234 
235   while (extensions.size() > 0) {
236     base::StringPiece extension;
237     if (!GetElement(&extensions, kSEQUENCE, &extension))
238       return false;
239 
240     base::StringPiece oid;
241     if (!GetElement(&extension, kOID, &oid))
242       return false;
243 
244     // kCRLDistributionPointsOID is the DER encoding of the OID for the X.509
245     // CRL Distribution Points extension.
246     static const uint8 kCRLDistributionPointsOID[] = {0x55, 0x1d, 0x1f};
247 
248     if (oid.size() != sizeof(kCRLDistributionPointsOID) ||
249         memcmp(oid.data(), kCRLDistributionPointsOID, oid.size()) != 0) {
250       continue;
251     }
252 
253     // critical
254     GetElement(&extension, kBOOLEAN, NULL);
255 
256     // extnValue
257     base::StringPiece extension_value;
258     if (!GetElement(&extension, kOCTETSTRING, &extension_value))
259       return false;
260 
261     // RFC 5280, section 4.2.1.13.
262     //
263     // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
264     //
265     // DistributionPoint ::= SEQUENCE {
266     //  distributionPoint       [0]     DistributionPointName OPTIONAL,
267     //  reasons                 [1]     ReasonFlags OPTIONAL,
268     //  cRLIssuer               [2]     GeneralNames OPTIONAL }
269 
270     base::StringPiece distribution_points;
271     if (!GetElement(&extension_value, kSEQUENCE, &distribution_points))
272       return false;
273 
274     while (distribution_points.size() > 0) {
275       base::StringPiece distrib_point;
276       if (!GetElement(&distribution_points, kSEQUENCE, &distrib_point))
277         return false;
278 
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;
284       }
285 
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;
291       }
292 
293       if (GetElement(&distrib_point,
294                      kContextSpecific | kConstructed | 2, NULL)) {
295         // If it contains a alternative issuer, then we skip it.
296         continue;
297       }
298 
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;
306       }
307 
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;
320         }
321       }
322     }
323   }
324 
325   urls_out->swap(tmp_urls_out);
326   return true;
327 }
328 
329 } // namespace asn1
330 
331 } // namespace net
332