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