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