// 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