123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- // Copyright (c) 2012 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/cert/asn1_util.h"
- #include "net/cert/pki/parse_certificate.h"
- #include "net/der/input.h"
- #include "net/der/parser.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace net::asn1 {
- namespace {
- // Parses input |in| which should point to the beginning of a Certificate, and
- // sets |*tbs_certificate| ready to parse the Subject. If parsing
- // fails, this function returns false and |*tbs_certificate| is left in an
- // undefined state.
- bool SeekToSubject(der::Input in, der::Parser* tbs_certificate) {
- // 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,
- // ... }
- der::Parser parser(in);
- der::Parser certificate;
- if (!parser.ReadSequence(&certificate))
- return false;
- // We don't allow junk after the certificate.
- if (parser.HasMore())
- return false;
- if (!certificate.ReadSequence(tbs_certificate))
- return false;
- bool unused;
- if (!tbs_certificate->SkipOptionalTag(
- der::kTagConstructed | der::kTagContextSpecific | 0, &unused)) {
- return false;
- }
- // serialNumber
- if (!tbs_certificate->SkipTag(der::kInteger))
- return false;
- // signature
- if (!tbs_certificate->SkipTag(der::kSequence))
- return false;
- // issuer
- if (!tbs_certificate->SkipTag(der::kSequence))
- return false;
- // validity
- if (!tbs_certificate->SkipTag(der::kSequence))
- return false;
- return true;
- }
- // Parses input |in| which should point to the beginning of a Certificate, and
- // sets |*tbs_certificate| ready to parse the SubjectPublicKeyInfo. If parsing
- // fails, this function returns false and |*tbs_certificate| is left in an
- // undefined state.
- bool SeekToSPKI(der::Input in, der::Parser* tbs_certificate) {
- return SeekToSubject(in, tbs_certificate) &&
- // Skip over Subject.
- tbs_certificate->SkipTag(der::kSequence);
- }
- // 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::kTagContextSpecific | 1,
- &present)) {
- return false;
- }
- // subjectUniqueID
- if (!tbs_cert_parser.SkipOptionalTag(der::kTagContextSpecific | 2,
- &present)) {
- return false;
- }
- absl::optional<der::Input> extensions;
- if (!tbs_cert_parser.ReadOptionalTag(
- der::kTagConstructed | der::kTagContextSpecific | 3, &extensions)) {
- return false;
- }
- if (!extensions) {
- *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.value());
- if (!explicit_extensions_parser.ReadSequence(extensions_parser))
- return false;
- if (explicit_extensions_parser.HasMore())
- return false;
- *extensions_present = true;
- return true;
- }
- // Parse a DER-encoded, X.509 certificate in |cert| and find an extension with
- // the given OID. Returns false on parse error or true if the parse was
- // successful. |*out_extension_present| will be true iff the extension was
- // found. In the case where it was found, |*out_extension| will describe the
- // extension, or is undefined on parse error or if the extension is missing.
- bool ExtractExtensionWithOID(base::StringPiece cert,
- der::Input extension_oid,
- bool* out_extension_present,
- ParsedExtension* out_extension) {
- der::Parser extensions;
- bool extensions_present;
- if (!SeekToExtensions(der::Input(cert), &extensions_present, &extensions))
- return false;
- if (!extensions_present) {
- *out_extension_present = false;
- return true;
- }
- while (extensions.HasMore()) {
- der::Input extension_tlv;
- if (!extensions.ReadRawTLV(&extension_tlv) ||
- !ParseExtension(extension_tlv, out_extension)) {
- return false;
- }
- if (out_extension->oid == extension_oid) {
- *out_extension_present = true;
- return true;
- }
- }
- *out_extension_present = false;
- return true;
- }
- } // namespace
- bool ExtractSubjectFromDERCert(base::StringPiece cert,
- base::StringPiece* subject_out) {
- der::Parser parser;
- if (!SeekToSubject(der::Input(cert), &parser))
- return false;
- der::Input subject;
- if (!parser.ReadRawTLV(&subject))
- return false;
- *subject_out = subject.AsStringPiece();
- return true;
- }
- bool ExtractSPKIFromDERCert(base::StringPiece cert,
- base::StringPiece* spki_out) {
- der::Parser parser;
- if (!SeekToSPKI(der::Input(cert), &parser))
- return false;
- der::Input spki;
- if (!parser.ReadRawTLV(&spki))
- return false;
- *spki_out = spki.AsStringPiece();
- return true;
- }
- bool ExtractSubjectPublicKeyFromSPKI(base::StringPiece spki,
- base::StringPiece* spk_out) {
- // From RFC 5280, Section 4.1
- // SubjectPublicKeyInfo ::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- //
- // AlgorithmIdentifier ::= SEQUENCE {
- // algorithm OBJECT IDENTIFIER,
- // parameters ANY DEFINED BY algorithm OPTIONAL }
- // Step into SubjectPublicKeyInfo sequence.
- der::Parser parser((der::Input(spki)));
- der::Parser spki_parser;
- if (!parser.ReadSequence(&spki_parser))
- return false;
- // Step over algorithm field (a SEQUENCE).
- if (!spki_parser.SkipTag(der::kSequence))
- return false;
- // Extract the subjectPublicKey field.
- der::Input spk;
- if (!spki_parser.ReadTag(der::kBitString, &spk))
- return false;
- *spk_out = spk.AsStringPiece();
- return true;
- }
- bool HasCanSignHttpExchangesDraftExtension(base::StringPiece cert) {
- // kCanSignHttpExchangesDraftOid is the DER encoding of the OID for
- // canSignHttpExchangesDraft defined in:
- // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
- static const uint8_t kCanSignHttpExchangesDraftOid[] = {
- 0x2B, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x16};
- bool extension_present;
- ParsedExtension extension;
- if (!ExtractExtensionWithOID(cert, der::Input(kCanSignHttpExchangesDraftOid),
- &extension_present, &extension) ||
- !extension_present) {
- return false;
- }
- // The extension should have contents NULL.
- static const uint8_t kNull[] = {0x05, 0x00};
- return extension.value == der::Input(kNull);
- }
- bool ExtractSignatureAlgorithmsFromDERCert(
- base::StringPiece cert,
- base::StringPiece* cert_signature_algorithm_sequence,
- base::StringPiece* tbs_signature_algorithm_sequence) {
- // 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,
- // ... }
- der::Parser parser((der::Input(cert)));
- der::Parser certificate;
- if (!parser.ReadSequence(&certificate))
- return false;
- der::Parser tbs_certificate;
- if (!certificate.ReadSequence(&tbs_certificate))
- return false;
- bool unused;
- if (!tbs_certificate.SkipOptionalTag(
- der::kTagConstructed | der::kTagContextSpecific | 0, &unused)) {
- return false;
- }
- // serialNumber
- if (!tbs_certificate.SkipTag(der::kInteger))
- return false;
- // signature
- der::Input tbs_algorithm;
- if (!tbs_certificate.ReadRawTLV(&tbs_algorithm))
- return false;
- der::Input cert_algorithm;
- if (!certificate.ReadRawTLV(&cert_algorithm))
- return false;
- *cert_signature_algorithm_sequence = cert_algorithm.AsStringPiece();
- *tbs_signature_algorithm_sequence = tbs_algorithm.AsStringPiece();
- return true;
- }
- bool ExtractExtensionFromDERCert(base::StringPiece cert,
- base::StringPiece extension_oid,
- bool* out_extension_present,
- bool* out_extension_critical,
- base::StringPiece* out_contents) {
- *out_extension_present = false;
- *out_extension_critical = false;
- *out_contents = base::StringPiece();
- ParsedExtension extension;
- if (!ExtractExtensionWithOID(cert, der::Input(extension_oid),
- out_extension_present, &extension))
- return false;
- if (!*out_extension_present)
- return true;
- *out_extension_critical = extension.critical;
- *out_contents = extension.value.AsStringPiece();
- return true;
- }
- } // namespace net::asn1
|