普通文本  |  128行  |  3.54 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/asn1_util.h"

namespace net {

namespace asn1 {

bool ParseElement(base::StringPiece* in,
                  unsigned tag_value,
                  base::StringPiece* out,
                  unsigned *out_header_len) {
  const uint8* data = reinterpret_cast<const uint8*>(in->data());

  if (in->size() < 2)
    return false;

  if (static_cast<unsigned char>(data[0]) != tag_value)
    return false;

  size_t len = 0;
  if ((data[1] & 0x80) == 0) {
    // short form length
    if (out_header_len)
      *out_header_len = 2;
    len = static_cast<size_t>(data[1]) + 2;
  } else {
    // long form length
    const unsigned num_bytes = data[1] & 0x7f;
    if (num_bytes == 0 || num_bytes > 2)
      return false;
    if (in->size() < 2 + num_bytes)
      return false;
    len = data[2];
    if (num_bytes == 2) {
      if (len == 0) {
        // the length encoding must be minimal.
        return false;
      }
      len <<= 8;
      len += data[3];
    }
    if (len < 128) {
      // the length should have been encoded in short form. This distinguishes
      // DER from BER encoding.
      return false;
    }
    if (out_header_len)
      *out_header_len = 2 + num_bytes;
    len += 2 + num_bytes;
  }

  if (in->size() < len)
    return false;
  if (out)
    *out = base::StringPiece(in->data(), len);
  in->remove_prefix(len);
  return true;
}

bool GetElement(base::StringPiece* in,
                unsigned tag_value,
                base::StringPiece* out) {
  unsigned header_len;
  if (!ParseElement(in, tag_value, out, &header_len))
    return false;
  if (out)
    out->remove_prefix(header_len);
  return true;
}

bool ExtractSPKIFromDERCert(base::StringPiece cert,
                            base::StringPiece* spki_out) {
  // From RFC 5280, section 4.1
  //    Certificate  ::=  SEQUENCE  {
  //      tbsCertificate       TBSCertificate,
  //      signatureAlgorithm   AlgorithmIdentifier,
  //      signatureValue       BIT STRING  }

  // TBSCertificate  ::=  SEQUENCE  {
  //      version         [0]  EXPLICIT Version DEFAULT v1,
  //      serialNumber         CertificateSerialNumber,
  //      signature            AlgorithmIdentifier,
  //      issuer               Name,
  //      validity             Validity,
  //      subject              Name,
  //      subjectPublicKeyInfo SubjectPublicKeyInfo,

  base::StringPiece certificate;
  if (!asn1::GetElement(&cert, asn1::kSEQUENCE, &certificate))
    return false;

  base::StringPiece tbs_certificate;
  if (!asn1::GetElement(&certificate, asn1::kSEQUENCE, &tbs_certificate))
    return false;

  // The version is optional, so a failure to parse it is fine.
  asn1::GetElement(&tbs_certificate,
                   asn1::kCompound | asn1::kContextSpecific | 0,
                   NULL);

  // serialNumber
  if (!asn1::GetElement(&tbs_certificate, asn1::kINTEGER, NULL))
    return false;
  // signature
  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
    return false;
  // issuer
  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
    return false;
  // validity
  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
    return false;
  // subject
  if (!asn1::GetElement(&tbs_certificate, asn1::kSEQUENCE, NULL))
    return false;
  // subjectPublicKeyInfo
  if (!asn1::ParseElement(&tbs_certificate, asn1::kSEQUENCE, spki_out, NULL))
    return false;
  return true;
}

} // namespace asn1

} // namespace net