Home | History | Annotate | Download | only in cert
      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 
     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 
     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.
     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 
    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 
    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 
    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