blob: 644734cfebe344b7c40a3b68bb688e532e83a0e3 [file] [log] [blame]
// Copyright 2015 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/internal/parse_certificate.h"
#include <utility>
#include "base/strings/string_util.h"
#include "net/der/input.h"
#include "net/der/parse_values.h"
#include "net/der/parser.h"
namespace net {
namespace {
// Returns true if |input| is a SEQUENCE and nothing else.
WARN_UNUSED_RESULT bool IsSequenceTLV(const der::Input& input) {
der::Parser parser(input);
der::Parser unused_sequence_parser;
if (!parser.ReadSequence(&unused_sequence_parser))
return false;
// Should by a single SEQUENCE by definition of the function.
return !parser.HasMore();
}
// Reads a SEQUENCE from |parser| and writes the full tag-length-value into
// |out|. On failure |parser| may or may not have been advanced.
WARN_UNUSED_RESULT bool ReadSequenceTLV(der::Parser* parser, der::Input* out) {
return parser->ReadRawTLV(out) && IsSequenceTLV(*out);
}
// Parses a Version according to RFC 5280:
//
// Version ::= INTEGER { v1(0), v2(1), v3(2) }
//
// No value other that v1, v2, or v3 is allowed (and if given will fail). RFC
// 5280 minimally requires the handling of v3 (and overwhelmingly these are the
// certificate versions in use today):
//
// Implementations SHOULD be prepared to accept any version certificate.
// At a minimum, conforming implementations MUST recognize version 3
// certificates.
WARN_UNUSED_RESULT bool ParseVersion(const der::Input& in,
CertificateVersion* version) {
der::Parser parser(in);
uint64_t version64;
if (!parser.ReadUint64(&version64))
return false;
switch (version64) {
case 0:
*version = CertificateVersion::V1;
break;
case 1:
*version = CertificateVersion::V2;
break;
case 2:
*version = CertificateVersion::V3;
break;
default:
// Don't allow any other version identifier.
return false;
}
// By definition the input to this function was a single INTEGER, so there
// shouldn't be anything else after it.
return !parser.HasMore();
}
// Consumes a "Time" value (as defined by RFC 5280) from |parser|. On success
// writes the result to |*out| and returns true. On failure no guarantees are
// made about the state of |parser|.
//
// From RFC 5280:
//
// Time ::= CHOICE {
// utcTime UTCTime,
// generalTime GeneralizedTime }
WARN_UNUSED_RESULT bool ReadTime(der::Parser* parser,
der::GeneralizedTime* out) {
der::Input value;
der::Tag tag;
if (!parser->ReadTagAndValue(&tag, &value))
return false;
if (tag == der::kUtcTime)
return der::ParseUTCTime(value, out);
if (tag == der::kGeneralizedTime)
return der::ParseGeneralizedTime(value, out);
// Unrecognized tag.
return false;
}
// Parses a DER-encoded "Validity" as specified by RFC 5280. Returns true on
// success and sets the results in |not_before| and |not_after|:
//
// Validity ::= SEQUENCE {
// notBefore Time,
// notAfter Time }
//
// Note that upon success it is NOT guaranteed that |*not_before <= *not_after|.
bool ParseValidity(const der::Input& validity_tlv,
der::GeneralizedTime* not_before,
der::GeneralizedTime* not_after) {
der::Parser parser(validity_tlv);
// Validity ::= SEQUENCE {
der::Parser validity_parser;
if (!parser.ReadSequence(&validity_parser))
return false;
// notBefore Time,
if (!ReadTime(&validity_parser, not_before))
return false;
// notAfter Time }
if (!ReadTime(&validity_parser, not_after))
return false;
// By definition the input was a single Validity sequence, so there shouldn't
// be unconsumed data.
if (parser.HasMore())
return false;
// The Validity type does not have an extension point.
if (validity_parser.HasMore())
return false;
// Note that RFC 5280 doesn't require notBefore to be <=
// notAfter, so that will not be considered a "parsing" error here. Instead it
// will be considered an expired certificate later when testing against the
// current timestamp.
return true;
}
// Returns true if every bit in |bits| is zero (including empty).
WARN_UNUSED_RESULT bool BitStringIsAllZeros(const der::BitString& bits) {
// Note that it is OK to read from the unused bits, since BitString parsing
// guarantees they are all zero.
for (size_t i = 0; i < bits.bytes().Length(); ++i) {
if (bits.bytes().UnsafeData()[i] != 0)
return false;
}
return true;
}
} // namespace
ParsedTbsCertificate::ParsedTbsCertificate() {}
ParsedTbsCertificate::~ParsedTbsCertificate() {}
bool VerifySerialNumber(const der::Input& value) {
bool unused_negative;
if (!der::IsValidInteger(value, &unused_negative))
return false;
// Check if the serial number is too long per RFC 5280.
if (value.Length() > 20)
return false;
return true;
}
bool ParseCertificate(const der::Input& certificate_tlv,
der::Input* out_tbs_certificate_tlv,
der::Input* out_signature_algorithm_tlv,
der::BitString* out_signature_value) {
der::Parser parser(certificate_tlv);
// Certificate ::= SEQUENCE {
der::Parser certificate_parser;
if (!parser.ReadSequence(&certificate_parser))
return false;
// tbsCertificate TBSCertificate,
if (!ReadSequenceTLV(&certificate_parser, out_tbs_certificate_tlv))
return false;
// signatureAlgorithm AlgorithmIdentifier,
if (!ReadSequenceTLV(&certificate_parser, out_signature_algorithm_tlv))
return false;
// signatureValue BIT STRING }
if (!certificate_parser.ReadBitString(out_signature_value))
return false;
// There isn't an extension point at the end of Certificate.
if (certificate_parser.HasMore())
return false;
// By definition the input was a single Certificate, so there shouldn't be
// unconsumed data.
if (parser.HasMore())
return false;
return true;
}
// From RFC 5280 section 4.1:
//
// TBSCertificate ::= SEQUENCE {
// version [0] EXPLICIT Version DEFAULT v1,
// serialNumber CertificateSerialNumber,
// signature AlgorithmIdentifier,
// issuer Name,
// validity Validity,
// subject Name,
// subjectPublicKeyInfo SubjectPublicKeyInfo,
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// extensions [3] EXPLICIT Extensions OPTIONAL
// -- If present, version MUST be v3
// }
bool ParseTbsCertificate(const der::Input& tbs_tlv,
const ParseCertificateOptions& options,
ParsedTbsCertificate* out) {
der::Parser parser(tbs_tlv);
// Certificate ::= SEQUENCE {
der::Parser tbs_parser;
if (!parser.ReadSequence(&tbs_parser))
return false;
// version [0] EXPLICIT Version DEFAULT v1,
der::Input version;
bool has_version;
if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &version,
&has_version)) {
return false;
}
if (has_version) {
if (!ParseVersion(version, &out->version))
return false;
if (out->version == CertificateVersion::V1) {
// The correct way to specify v1 is to omit the version field since v1 is
// the DEFAULT.
return false;
}
} else {
out->version = CertificateVersion::V1;
}
// serialNumber CertificateSerialNumber,
if (!tbs_parser.ReadTag(der::kInteger, &out->serial_number))
return false;
if (!options.allow_invalid_serial_numbers &&
!VerifySerialNumber(out->serial_number)) {
return false;
}
// signature AlgorithmIdentifier,
if (!ReadSequenceTLV(&tbs_parser, &out->signature_algorithm_tlv))
return false;
// issuer Name,
if (!ReadSequenceTLV(&tbs_parser, &out->issuer_tlv))
return false;
// validity Validity,
der::Input validity_tlv;
if (!tbs_parser.ReadRawTLV(&validity_tlv))
return false;
if (!ParseValidity(validity_tlv, &out->validity_not_before,
&out->validity_not_after)) {
return false;
}
// subject Name,
if (!ReadSequenceTLV(&tbs_parser, &out->subject_tlv))
return false;
// subjectPublicKeyInfo SubjectPublicKeyInfo,
if (!ReadSequenceTLV(&tbs_parser, &out->spki_tlv))
return false;
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
der::Input issuer_unique_id;
if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1),
&issuer_unique_id,
&out->has_issuer_unique_id)) {
return false;
}
if (out->has_issuer_unique_id) {
if (!der::ParseBitString(issuer_unique_id, &out->issuer_unique_id))
return false;
if (out->version != CertificateVersion::V2 &&
out->version != CertificateVersion::V3) {
return false;
}
}
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
der::Input subject_unique_id;
if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(2),
&subject_unique_id,
&out->has_subject_unique_id)) {
return false;
}
if (out->has_subject_unique_id) {
if (!der::ParseBitString(subject_unique_id, &out->subject_unique_id))
return false;
if (out->version != CertificateVersion::V2 &&
out->version != CertificateVersion::V3) {
return false;
}
}
// extensions [3] EXPLICIT Extensions OPTIONAL
// -- If present, version MUST be v3
if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(3),
&out->extensions_tlv, &out->has_extensions)) {
return false;
}
if (out->has_extensions) {
// extensions_tlv must be a single element. Also check that it is a
// SEQUENCE.
if (!IsSequenceTLV(out->extensions_tlv))
return false;
if (out->version != CertificateVersion::V3)
return false;
}
// Note that there IS an extension point at the end of TBSCertificate
// (according to RFC 5912), so from that interpretation, unconsumed data would
// be allowed in |tbs_parser|.
//
// However because only v1, v2, and v3 certificates are supported by the
// parsing, there shouldn't be any subsequent data in those versions, so
// reject.
if (tbs_parser.HasMore())
return false;
// By definition the input was a single TBSCertificate, so there shouldn't be
// unconsumed data.
if (parser.HasMore())
return false;
return true;
}
// From RFC 5280:
//
// Extension ::= SEQUENCE {
// extnID OBJECT IDENTIFIER,
// critical BOOLEAN DEFAULT FALSE,
// extnValue OCTET STRING
// -- contains the DER encoding of an ASN.1 value
// -- corresponding to the extension type identified
// -- by extnID
// }
bool ParseExtension(const der::Input& extension_tlv, ParsedExtension* out) {
der::Parser parser(extension_tlv);
// Extension ::= SEQUENCE {
der::Parser extension_parser;
if (!parser.ReadSequence(&extension_parser))
return false;
// extnID OBJECT IDENTIFIER,
if (!extension_parser.ReadTag(der::kOid, &out->oid))
return false;
// critical BOOLEAN DEFAULT FALSE,
out->critical = false;
bool has_critical;
der::Input critical;
if (!extension_parser.ReadOptionalTag(der::kBool, &critical, &has_critical))
return false;
if (has_critical) {
if (!der::ParseBool(critical, &out->critical))
return false;
if (!out->critical)
return false; // DER-encoding requires DEFAULT values be omitted.
}
// extnValue OCTET STRING
if (!extension_parser.ReadTag(der::kOctetString, &out->value))
return false;
// The Extension type does not have an extension point (everything goes in
// extnValue).
if (extension_parser.HasMore())
return false;
// By definition the input was a single Extension sequence, so there shouldn't
// be unconsumed data.
if (parser.HasMore())
return false;
return true;
}
der::Input KeyUsageOid() {
// From RFC 5280:
//
// id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
//
// In dotted notation: 2.5.29.15
static const uint8_t oid[] = {0x55, 0x1d, 0x0f};
return der::Input(oid);
}
der::Input SubjectAltNameOid() {
// From RFC 5280:
//
// id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 }
//
// In dotted notation: 2.5.29.17
static const uint8_t oid[] = {0x55, 0x1d, 0x11};
return der::Input(oid);
}
der::Input BasicConstraintsOid() {
// From RFC 5280:
//
// id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 }
//
// In dotted notation: 2.5.29.19
static const uint8_t oid[] = {0x55, 0x1d, 0x13};
return der::Input(oid);
}
der::Input NameConstraintsOid() {
// From RFC 5280:
//
// id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
//
// In dotted notation: 2.5.29.30
static const uint8_t oid[] = {0x55, 0x1d, 0x1e};
return der::Input(oid);
}
der::Input CertificatePoliciesOid() {
// From RFC 5280:
//
// id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
//
// In dotted notation: 2.5.29.32
static const uint8_t oid[] = {0x55, 0x1d, 0x20};
return der::Input(oid);
}
der::Input PolicyConstraintsOid() {
// From RFC 5280:
//
// id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 }
//
// In dotted notation: 2.5.29.36
static const uint8_t oid[] = {0x55, 0x1d, 0x24};
return der::Input(oid);
}
der::Input ExtKeyUsageOid() {
// From RFC 5280:
//
// id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
//
// In dotted notation: 2.5.29.37
static const uint8_t oid[] = {0x55, 0x1d, 0x25};
return der::Input(oid);
}
der::Input AuthorityInfoAccessOid() {
// From RFC 5280:
//
// id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
//
// In dotted notation: 1.3.6.1.5.5.7.1.1
static const uint8_t oid[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01};
return der::Input(oid);
}
der::Input AdCaIssuersOid() {
// From RFC 5280:
//
// id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
//
// In dotted notation: 1.3.6.1.5.5.7.48.2
static const uint8_t oid[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02};
return der::Input(oid);
}
der::Input AdOcspOid() {
// From RFC 5280:
//
// id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
//
// In dotted notation: 1.3.6.1.5.5.7.48.1
static const uint8_t oid[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01};
return der::Input(oid);
}
NET_EXPORT bool ParseExtensions(
const der::Input& extensions_tlv,
std::map<der::Input, ParsedExtension>* extensions) {
der::Parser parser(extensions_tlv);
// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
der::Parser extensions_parser;
if (!parser.ReadSequence(&extensions_parser))
return false;
// The Extensions SEQUENCE must contains at least 1 element (otherwise it
// should have been omitted).
if (!extensions_parser.HasMore())
return false;
extensions->clear();
while (extensions_parser.HasMore()) {
ParsedExtension extension;
der::Input extension_tlv;
if (!extensions_parser.ReadRawTLV(&extension_tlv))
return false;
if (!ParseExtension(extension_tlv, &extension))
return false;
bool is_duplicate =
!extensions->insert(std::make_pair(extension.oid, extension)).second;
// RFC 5280 says that an extension should not appear more than once.
if (is_duplicate)
return false;
}
// By definition the input was a single Extensions sequence, so there
// shouldn't be unconsumed data.
if (parser.HasMore())
return false;
return true;
}
NET_EXPORT bool ConsumeExtension(
const der::Input& oid,
std::map<der::Input, ParsedExtension>* unconsumed_extensions,
ParsedExtension* extension) {
auto it = unconsumed_extensions->find(oid);
if (it == unconsumed_extensions->end())
return false;
*extension = it->second;
unconsumed_extensions->erase(it);
return true;
}
bool ParseBasicConstraints(const der::Input& basic_constraints_tlv,
ParsedBasicConstraints* out) {
der::Parser parser(basic_constraints_tlv);
// BasicConstraints ::= SEQUENCE {
der::Parser sequence_parser;
if (!parser.ReadSequence(&sequence_parser))
return false;
// cA BOOLEAN DEFAULT FALSE,
out->is_ca = false;
bool has_ca;
der::Input ca;
if (!sequence_parser.ReadOptionalTag(der::kBool, &ca, &has_ca))
return false;
if (has_ca) {
if (!der::ParseBool(ca, &out->is_ca))
return false;
// TODO(eroman): Should reject if CA was set to false, since
// DER-encoding requires DEFAULT values be omitted. In
// practice however there are a lot of certificates that use
// the broken encoding.
}
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
der::Input encoded_path_len;
if (!sequence_parser.ReadOptionalTag(der::kInteger, &encoded_path_len,
&out->has_path_len)) {
return false;
}
if (out->has_path_len) {
if (!der::ParseUint8(encoded_path_len, &out->path_len))
return false;
} else {
// Default initialize to 0 as a precaution.
out->path_len = 0;
}
// There shouldn't be any unconsumed data in the extension.
if (sequence_parser.HasMore())
return false;
// By definition the input was a single BasicConstraints sequence, so there
// shouldn't be unconsumed data.
if (parser.HasMore())
return false;
return true;
}
bool ParseKeyUsage(const der::Input& key_usage_tlv, der::BitString* key_usage) {
der::Parser parser(key_usage_tlv);
if (!parser.ReadBitString(key_usage))
return false;
// By definition the input was a single BIT STRING.
if (parser.HasMore())
return false;
// RFC 5280 section 4.2.1.3:
//
// When the keyUsage extension appears in a certificate, at least
// one of the bits MUST be set to 1.
if (BitStringIsAllZeros(*key_usage))
return false;
return true;
}
bool ParseAuthorityInfoAccess(
const der::Input& authority_info_access_tlv,
std::vector<base::StringPiece>* out_ca_issuers_uris,
std::vector<base::StringPiece>* out_ocsp_uris) {
der::Parser parser(authority_info_access_tlv);
out_ca_issuers_uris->clear();
out_ocsp_uris->clear();
// AuthorityInfoAccessSyntax ::=
// SEQUENCE SIZE (1..MAX) OF AccessDescription
der::Parser sequence_parser;
if (!parser.ReadSequence(&sequence_parser))
return false;
if (!sequence_parser.HasMore())
return false;
while (sequence_parser.HasMore()) {
// AccessDescription ::= SEQUENCE {
der::Parser access_description_sequence_parser;
if (!sequence_parser.ReadSequence(&access_description_sequence_parser))
return false;
// accessMethod OBJECT IDENTIFIER,
der::Input access_method_oid;
if (!access_description_sequence_parser.ReadTag(der::kOid,
&access_method_oid))
return false;
// accessLocation GeneralName }
der::Tag access_location_tag;
der::Input access_location_value;
if (!access_description_sequence_parser.ReadTagAndValue(
&access_location_tag, &access_location_value))
return false;
// GeneralName ::= CHOICE {
if (access_location_tag == der::ContextSpecificPrimitive(6)) {
// uniformResourceIdentifier [6] IA5String,
base::StringPiece uri = access_location_value.AsStringPiece();
if (!base::IsStringASCII(uri))
return false;
if (access_method_oid == AdCaIssuersOid())
out_ca_issuers_uris->push_back(uri);
else if (access_method_oid == AdOcspOid())
out_ocsp_uris->push_back(uri);
}
}
return true;
}
} // namespace net