// Copyright 2016 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/parsed_certificate.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/certificate_policies.h" #include "net/cert/internal/extended_key_usage.h" #include "net/cert/internal/name_constraints.h" #include "net/cert/internal/signature_algorithm.h" #include "net/cert/internal/verify_name_match.h" #include "net/der/parser.h" #include "third_party/boringssl/src/include/openssl/pool.h" namespace net { namespace { DEFINE_CERT_ERROR_ID(kFailedParsingCertificate, "Failed parsing Certificate"); DEFINE_CERT_ERROR_ID(kFailedParsingTbsCertificate, "Failed parsing TBSCertificate"); DEFINE_CERT_ERROR_ID(kFailedParsingSignatureAlgorithm, "Failed parsing SignatureAlgorithm"); DEFINE_CERT_ERROR_ID(kFailedReadingIssuerOrSubject, "Failed reading issuer or subject"); DEFINE_CERT_ERROR_ID(kFailedNormalizingSubject, "Failed normalizing subject"); DEFINE_CERT_ERROR_ID(kFailedNormalizingIssuer, "Failed normalizing issuer"); DEFINE_CERT_ERROR_ID(kFailedParsingExtensions, "Failed parsing extensions"); DEFINE_CERT_ERROR_ID(kFailedParsingBasicConstraints, "Failed parsing basic constraints"); DEFINE_CERT_ERROR_ID(kFailedParsingKeyUsage, "Failed parsing key usage"); DEFINE_CERT_ERROR_ID(kFailedParsingEku, "Failed parsing extended key usage"); DEFINE_CERT_ERROR_ID(kFailedParsingSubjectAltName, "Failed parsing subjectAltName"); DEFINE_CERT_ERROR_ID(kSubjectAltNameNotCritical, "Empty subject and subjectAltName is not critical"); DEFINE_CERT_ERROR_ID(kFailedParsingNameConstraints, "Failed parsing name constraints"); DEFINE_CERT_ERROR_ID(kFailedParsingAia, "Failed parsing authority info access"); DEFINE_CERT_ERROR_ID(kFailedParsingPolicies, "Failed parsing certificate policies"); DEFINE_CERT_ERROR_ID(kFailedParsingPolicyConstraints, "Failed parsing policy constraints"); DEFINE_CERT_ERROR_ID(kFailedParsingPolicyMappings, "Failed parsing policy mappings"); DEFINE_CERT_ERROR_ID(kFailedParsingInhibitAnyPolicy, "Failed parsing inhibit any policy"); WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv, der::Input* value) { der::Parser parser(tlv); return parser.ReadTag(der::kSequence, value) && !parser.HasMore(); } } // namespace bool ParsedCertificate::GetExtension(const der::Input& extension_oid, ParsedExtension* parsed_extension) const { if (!tbs_.has_extensions) return false; auto it = extensions_.find(extension_oid); if (it == extensions_.end()) { *parsed_extension = ParsedExtension(); return false; } *parsed_extension = it->second; return true; } ParsedCertificate::ParsedCertificate() = default; ParsedCertificate::~ParsedCertificate() = default; // static scoped_refptr ParsedCertificate::Create( bssl::UniquePtr cert_data, const ParseCertificateOptions& options, CertErrors* errors) { return CreateInternal(std::move(cert_data), der::Input(), options, errors); } // static bool ParsedCertificate::CreateAndAddToVector( bssl::UniquePtr cert_data, const ParseCertificateOptions& options, std::vector>* chain, CertErrors* errors) { scoped_refptr cert( Create(std::move(cert_data), options, errors)); if (!cert) return false; chain->push_back(std::move(cert)); return true; } // static scoped_refptr ParsedCertificate::CreateWithoutCopyingUnsafe( const uint8_t* data, size_t length, const ParseCertificateOptions& options, CertErrors* errors) { return CreateInternal(nullptr, der::Input(data, length), options, errors); } // static scoped_refptr ParsedCertificate::CreateInternal( bssl::UniquePtr backing_data, der::Input static_data, const ParseCertificateOptions& options, CertErrors* errors) { if (!errors) { CertErrors unused_errors; return CreateInternal(std::move(backing_data), static_data, options, &unused_errors); } scoped_refptr result(new ParsedCertificate); if (backing_data) { result->cert_data_ = std::move(backing_data); result->cert_ = der::Input(CRYPTO_BUFFER_data(result->cert_data_.get()), CRYPTO_BUFFER_len(result->cert_data_.get())); } else { result->cert_ = static_data; } if (!ParseCertificate(result->cert_, &result->tbs_certificate_tlv_, &result->signature_algorithm_tlv_, &result->signature_value_, errors)) { errors->AddError(kFailedParsingCertificate); return nullptr; } if (!ParseTbsCertificate(result->tbs_certificate_tlv_, options, &result->tbs_, errors)) { errors->AddError(kFailedParsingTbsCertificate); return nullptr; } // Attempt to parse the signature algorithm contained in the Certificate. result->signature_algorithm_ = SignatureAlgorithm::Create(result->signature_algorithm_tlv_, errors); if (!result->signature_algorithm_) { errors->AddError(kFailedParsingSignatureAlgorithm); return nullptr; } der::Input subject_value; if (!GetSequenceValue(result->tbs_.subject_tlv, &subject_value)) { errors->AddError(kFailedReadingIssuerOrSubject); return nullptr; } if (!NormalizeName(subject_value, &result->normalized_subject_, errors)) { errors->AddError(kFailedNormalizingSubject); return nullptr; } der::Input issuer_value; if (!GetSequenceValue(result->tbs_.issuer_tlv, &issuer_value)) { errors->AddError(kFailedReadingIssuerOrSubject); return nullptr; } if (!NormalizeName(issuer_value, &result->normalized_issuer_, errors)) { errors->AddError(kFailedNormalizingIssuer); return nullptr; } // Parse the standard X.509 extensions. if (result->tbs_.has_extensions) { // ParseExtensions() ensures there are no duplicates, and maps the (unique) // OID to the extension value. if (!ParseExtensions(result->tbs_.extensions_tlv, &result->extensions_)) { errors->AddError(kFailedParsingExtensions); return nullptr; } ParsedExtension extension; // Basic constraints. if (result->GetExtension(BasicConstraintsOid(), &extension)) { result->has_basic_constraints_ = true; if (!ParseBasicConstraints(extension.value, &result->basic_constraints_)) { errors->AddError(kFailedParsingBasicConstraints); return nullptr; } } // Key Usage. if (result->GetExtension(KeyUsageOid(), &extension)) { result->has_key_usage_ = true; if (!ParseKeyUsage(extension.value, &result->key_usage_)) { errors->AddError(kFailedParsingKeyUsage); return nullptr; } } // Extended Key Usage. if (result->GetExtension(ExtKeyUsageOid(), &extension)) { result->has_extended_key_usage_ = true; if (!ParseEKUExtension(extension.value, &result->extended_key_usage_)) { errors->AddError(kFailedParsingEku); return nullptr; } } // Subject alternative name. if (result->GetExtension(SubjectAltNameOid(), &result->subject_alt_names_extension_)) { // RFC 5280 section 4.2.1.6: // SubjectAltName ::= GeneralNames result->subject_alt_names_ = GeneralNames::Create( result->subject_alt_names_extension_.value, errors); if (!result->subject_alt_names_) { errors->AddError(kFailedParsingSubjectAltName); return nullptr; } // RFC 5280 section 4.1.2.6: // If subject naming information is present only in the subjectAltName // extension (e.g., a key bound only to an email address or URI), then the // subject name MUST be an empty sequence and the subjectAltName extension // MUST be critical. if (subject_value.Length() == 0 && !result->subject_alt_names_extension_.critical) { errors->AddError(kSubjectAltNameNotCritical); return nullptr; } } // Name constraints. if (result->GetExtension(NameConstraintsOid(), &extension)) { result->name_constraints_ = NameConstraints::Create(extension.value, extension.critical, errors); if (!result->name_constraints_) { errors->AddError(kFailedParsingNameConstraints); return nullptr; } } // Authority information access. if (result->GetExtension(AuthorityInfoAccessOid(), &result->authority_info_access_extension_)) { result->has_authority_info_access_ = true; if (!ParseAuthorityInfoAccess( result->authority_info_access_extension_.value, &result->ca_issuers_uris_, &result->ocsp_uris_)) { errors->AddError(kFailedParsingAia); return nullptr; } } // Policies. if (result->GetExtension(CertificatePoliciesOid(), &extension)) { result->has_policy_oids_ = true; if (!ParseCertificatePoliciesExtension( extension.value, false /*fail_parsing_unknown_qualifier_oids*/, &result->policy_oids_, errors)) { errors->AddError(kFailedParsingPolicies); return nullptr; } } // Policy constraints. if (result->GetExtension(PolicyConstraintsOid(), &extension)) { result->has_policy_constraints_ = true; if (!ParsePolicyConstraints(extension.value, &result->policy_constraints_)) { errors->AddError(kFailedParsingPolicyConstraints); return nullptr; } } // Policy mappings. if (result->GetExtension(PolicyMappingsOid(), &extension)) { result->has_policy_mappings_ = true; if (!ParsePolicyMappings(extension.value, &result->policy_mappings_)) { errors->AddError(kFailedParsingPolicyMappings); return nullptr; } } // Inhibit Any Policy. if (result->GetExtension(InhibitAnyPolicyOid(), &extension)) { result->has_inhibit_any_policy_ = true; if (!ParseInhibitAnyPolicy(extension.value, &result->inhibit_any_policy_)) { errors->AddError(kFailedParsingInhibitAnyPolicy); return nullptr; } } } return result; } } // namespace net