| Index: net/cert/asn1_util.cc
|
| diff --git a/net/cert/asn1_util.cc b/net/cert/asn1_util.cc
|
| index 6b0b71d9024faf44703546602b4c8569bd8adc7a..97e12dfc45ae72cab4f032b2159b62ae40170898 100644
|
| --- a/net/cert/asn1_util.cc
|
| +++ b/net/cert/asn1_util.cc
|
| @@ -70,6 +70,75 @@ bool SeekToSPKI(der::Input in, der::Parser* tbs_certificate) {
|
| return true;
|
| }
|
|
|
| +// Parses input |in| which should point to the beginning of a
|
| +// Certificate. If parsing fails, this function returns false, with
|
| +// |*extensions_present| and |*extensions_parser| left in an undefined
|
| +// state. If parsing succeeds and extensions are present, this function
|
| +// sets |*extensions_present| to true and sets |*extensions_parser|
|
| +// ready to parse the Extensions. If extensions are not present, it sets
|
| +// |*extensions_present| to false and |*extensions_parser| is left in an
|
| +// undefined state.
|
| +bool SeekToExtensions(der::Input in,
|
| + bool* extensions_present,
|
| + der::Parser* extensions_parser) {
|
| + bool present;
|
| + der::Parser tbs_cert_parser;
|
| + if (!SeekToSPKI(in, &tbs_cert_parser))
|
| + return false;
|
| +
|
| + // From RFC 5280, section 4.1
|
| + // TBSCertificate ::= SEQUENCE {
|
| + // ...
|
| + // subjectPublicKeyInfo SubjectPublicKeyInfo,
|
| + // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
| + // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
| + // extensions [3] EXPLICIT Extensions OPTIONAL }
|
| +
|
| + // subjectPublicKeyInfo
|
| + if (!tbs_cert_parser.SkipTag(der::kSequence))
|
| + return false;
|
| + // issuerUniqueID
|
| + if (!tbs_cert_parser.SkipOptionalTag(
|
| + der::kTagConstructed | der::kTagContextSpecific | 1, &present)) {
|
| + return false;
|
| + }
|
| + // subjectUniqueID
|
| + if (!tbs_cert_parser.SkipOptionalTag(
|
| + der::kTagConstructed | der::kTagContextSpecific | 2, &present)) {
|
| + return false;
|
| + }
|
| +
|
| + der::Input extensions;
|
| + if (!tbs_cert_parser.ReadOptionalTag(
|
| + der::kTagConstructed | der::kTagContextSpecific | 3, &extensions,
|
| + &present)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!present) {
|
| + *extensions_present = false;
|
| + return true;
|
| + }
|
| +
|
| + // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
|
| + // Extension ::= SEQUENCE {
|
| + // extnID OBJECT IDENTIFIER,
|
| + // critical BOOLEAN DEFAULT FALSE,
|
| + // extnValue OCTET STRING }
|
| +
|
| + // |extensions| was EXPLICITly tagged, so we still need to remove the
|
| + // ASN.1 SEQUENCE header.
|
| + der::Parser explicit_extensions_parser(extensions);
|
| + if (!explicit_extensions_parser.ReadSequence(extensions_parser))
|
| + return false;
|
| +
|
| + if (explicit_extensions_parser.HasMore())
|
| + return false;
|
| +
|
| + *extensions_present = true;
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| bool ExtractSPKIFromDERCert(base::StringPiece cert,
|
| @@ -118,60 +187,14 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert,
|
| std::vector<base::StringPiece>* urls_out) {
|
| urls_out->clear();
|
| std::vector<base::StringPiece> tmp_urls_out;
|
| -
|
| bool present;
|
| - der::Parser tbs_cert_parser;
|
| - if (!SeekToSPKI(der::Input(cert), &tbs_cert_parser))
|
| - return false;
|
| -
|
| - // From RFC 5280, section 4.1
|
| - // TBSCertificate ::= SEQUENCE {
|
| - // ...
|
| - // subjectPublicKeyInfo SubjectPublicKeyInfo,
|
| - // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
| - // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
| - // extensions [3] EXPLICIT Extensions OPTIONAL }
|
| -
|
| - // subjectPublicKeyInfo
|
| - if (!tbs_cert_parser.SkipTag(der::kSequence))
|
| - return false;
|
| - // issuerUniqueID
|
| - if (!tbs_cert_parser.SkipOptionalTag(
|
| - der::kTagConstructed | der::kTagContextSpecific | 1, &present)) {
|
| - return false;
|
| - }
|
| - // subjectUniqueID
|
| - if (!tbs_cert_parser.SkipOptionalTag(
|
| - der::kTagConstructed | der::kTagContextSpecific | 2, &present)) {
|
| - return false;
|
| - }
|
| -
|
| - der::Input extensions;
|
| - if (!tbs_cert_parser.ReadOptionalTag(
|
| - der::kTagConstructed | der::kTagContextSpecific | 3, &extensions,
|
| - &present)) {
|
| + der::Parser extensions_parser;
|
| + if (!SeekToExtensions(der::Input(cert), &present, &extensions_parser))
|
| return false;
|
| - }
|
|
|
| if (!present)
|
| return true;
|
|
|
| - // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
|
| - // Extension ::= SEQUENCE {
|
| - // extnID OBJECT IDENTIFIER,
|
| - // critical BOOLEAN DEFAULT FALSE,
|
| - // extnValue OCTET STRING }
|
| -
|
| - // |extensions| was EXPLICITly tagged, so we still need to remove the
|
| - // ASN.1 SEQUENCE header.
|
| - der::Parser explicit_extensions_parser(extensions);
|
| - der::Parser extensions_parser;
|
| - if (!explicit_extensions_parser.ReadSequence(&extensions_parser))
|
| - return false;
|
| -
|
| - if (explicit_extensions_parser.HasMore())
|
| - return false;
|
| -
|
| while (extensions_parser.HasMore()) {
|
| der::Parser extension_parser;
|
| if (!extensions_parser.ReadSequence(&extension_parser))
|
| @@ -289,6 +312,34 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert,
|
| return true;
|
| }
|
|
|
| +bool HasTLSFeatureExtension(base::StringPiece cert) {
|
| + bool present;
|
| + der::Parser extensions_parser;
|
| + if (!SeekToExtensions(der::Input(cert), &present, &extensions_parser))
|
| + return false;
|
| + if (!present)
|
| + return false;
|
| +
|
| + while (extensions_parser.HasMore()) {
|
| + der::Parser extension_parser;
|
| + if (!extensions_parser.ReadSequence(&extension_parser))
|
| + return false;
|
| +
|
| + der::Input oid;
|
| + if (!extension_parser.ReadTag(der::kOid, &oid))
|
| + return false;
|
| +
|
| + // kTLSFeatureExtensionOID is the DER encoding of the OID for the
|
| + // X.509 TLS Feature Extension.
|
| + static const uint8_t kTLSFeatureExtensionOID[] = {0x2B, 0x06, 0x01, 0x05,
|
| + 0x05, 0x07, 0x01, 0x18};
|
| + if (oid == der::Input(kTLSFeatureExtensionOID))
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| } // namespace asn1
|
|
|
| } // namespace net
|
|
|