Chromium Code Reviews| Index: net/cert/asn1_util.cc |
| diff --git a/net/cert/asn1_util.cc b/net/cert/asn1_util.cc |
| index 6b0b71d9024faf44703546602b4c8569bd8adc7a..7cc19e7b8be59a9a367d24b2b4000a1c510ae5b3 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,59 +187,15 @@ 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)) { |
| - 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)) |
| + if (!SeekToExtensions(der::Input(cert), &present, &extensions_parser)) |
| return false; |
| - if (explicit_extensions_parser.HasMore()) |
| - return false; |
| + if (!present) { |
| + LOG(ERROR) << "No extensions!"; |
|
eroman
2016/10/21 01:49:22
nit: Why add the log statement?
estark
2016/10/21 02:11:29
Doh, sorry, thought I deleted that. It's gone now.
|
| + return true; |
| + } |
| while (extensions_parser.HasMore()) { |
| der::Parser extension_parser; |
| @@ -289,6 +314,41 @@ bool ExtractCRLURLsFromDERCert(base::StringPiece cert, |
| return true; |
| } |
| +bool HasTLSFeatureExtension(base::StringPiece cert, |
| + bool* has_tls_feature_extension) { |
| + bool present; |
| + der::Parser extensions_parser; |
| + if (!SeekToExtensions(der::Input(cert), &present, &extensions_parser)) |
| + return false; |
| + if (!present) { |
| + *has_tls_feature_extension = false; |
| + return true; |
| + } |
| + |
| + 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)) { |
| + *has_tls_feature_extension = true; |
| + return true; |
| + } |
| + } |
| + |
| + *has_tls_feature_extension = false; |
| + return true; |
| +} |
| + |
| } // namespace asn1 |
| } // namespace net |