| // Copyright 2016 The Chromium Authors | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | #include "parsed_certificate.h" | 
 |  | 
 | #include <openssl/bytestring.h> | 
 | #include <openssl/pool.h> | 
 |  | 
 | #include "cert_errors.h" | 
 | #include "certificate_policies.h" | 
 | #include "extended_key_usage.h" | 
 | #include "name_constraints.h" | 
 | #include "parser.h" | 
 | #include "signature_algorithm.h" | 
 | #include "verify_name_match.h" | 
 |  | 
 | BSSL_NAMESPACE_BEGIN | 
 |  | 
 | namespace { | 
 |  | 
 | DEFINE_CERT_ERROR_ID(kFailedParsingCertificate, "Failed parsing Certificate"); | 
 | DEFINE_CERT_ERROR_ID(kFailedParsingTbsCertificate, | 
 |                      "Failed parsing TBSCertificate"); | 
 | 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"); | 
 | DEFINE_CERT_ERROR_ID(kFailedParsingAuthorityKeyIdentifier, | 
 |                      "Failed parsing authority key identifier"); | 
 | DEFINE_CERT_ERROR_ID(kFailedParsingSubjectKeyIdentifier, | 
 |                      "Failed parsing subject key identifier"); | 
 |  | 
 | [[nodiscard]] bool GetSequenceValue(der::Input tlv, der::Input *value) { | 
 |   der::Parser parser(tlv); | 
 |   return parser.ReadTag(CBS_ASN1_SEQUENCE, value) && !parser.HasMore(); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | bool ParsedCertificate::GetExtension(der::Input extension_oid, | 
 |                                      ParsedExtension *parsed_extension) const { | 
 |   if (!tbs_.extensions_tlv) { | 
 |     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(PrivateConstructor) {} | 
 | ParsedCertificate::~ParsedCertificate() = default; | 
 |  | 
 | // static | 
 | std::shared_ptr<const ParsedCertificate> ParsedCertificate::Create( | 
 |     bssl::UniquePtr<CRYPTO_BUFFER> backing_data, | 
 |     const ParseCertificateOptions &options, CertErrors *errors) { | 
 |   // |errors| is an optional parameter, but to keep the code simpler, use a | 
 |   // dummy object when one wasn't provided. | 
 |   CertErrors unused_errors; | 
 |   if (!errors) { | 
 |     errors = &unused_errors; | 
 |   } | 
 |  | 
 |   auto result = std::make_shared<ParsedCertificate>(PrivateConstructor{}); | 
 |   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())); | 
 |  | 
 |   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_ = | 
 |       ParseSignatureAlgorithm(result->signature_algorithm_tlv_); | 
 |  | 
 |   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_.extensions_tlv) { | 
 |     // ParseExtensions() ensures there are no duplicates, and maps the (unique) | 
 |     // OID to the extension value. | 
 |     if (!ParseExtensions(result->tbs_.extensions_tlv.value(), | 
 |                          &result->extensions_)) { | 
 |       errors->AddError(kFailedParsingExtensions); | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     ParsedExtension extension; | 
 |  | 
 |     // Basic constraints. | 
 |     if (result->GetExtension(der::Input(kBasicConstraintsOid), &extension)) { | 
 |       result->has_basic_constraints_ = true; | 
 |       if (!ParseBasicConstraints(extension.value, | 
 |                                  &result->basic_constraints_)) { | 
 |         errors->AddError(kFailedParsingBasicConstraints); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Key Usage. | 
 |     if (result->GetExtension(der::Input(kKeyUsageOid), &extension)) { | 
 |       result->has_key_usage_ = true; | 
 |       if (!ParseKeyUsage(extension.value, &result->key_usage_)) { | 
 |         errors->AddError(kFailedParsingKeyUsage); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Extended Key Usage. | 
 |     if (result->GetExtension(der::Input(kExtKeyUsageOid), &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(der::Input(kSubjectAltNameOid), | 
 |                              &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.empty() && | 
 |           !result->subject_alt_names_extension_.critical) { | 
 |         errors->AddError(kSubjectAltNameNotCritical); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Name constraints. | 
 |     if (result->GetExtension(der::Input(kNameConstraintsOid), &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(der::Input(kAuthorityInfoAccessOid), | 
 |                              &result->authority_info_access_extension_)) { | 
 |       result->has_authority_info_access_ = true; | 
 |       if (!ParseAuthorityInfoAccessURIs( | 
 |               result->authority_info_access_extension_.value, | 
 |               &result->ca_issuers_uris_, &result->ocsp_uris_)) { | 
 |         errors->AddError(kFailedParsingAia); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Policies. | 
 |     if (result->GetExtension(der::Input(kCertificatePoliciesOid), &extension)) { | 
 |       result->has_policy_oids_ = true; | 
 |       if (!ParseCertificatePoliciesExtensionOids( | 
 |               extension.value, false /*fail_parsing_unknown_qualifier_oids*/, | 
 |               &result->policy_oids_, errors)) { | 
 |         errors->AddError(kFailedParsingPolicies); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Policy constraints. | 
 |     if (result->GetExtension(der::Input(kPolicyConstraintsOid), &extension)) { | 
 |       result->has_policy_constraints_ = true; | 
 |       if (!ParsePolicyConstraints(extension.value, | 
 |                                   &result->policy_constraints_)) { | 
 |         errors->AddError(kFailedParsingPolicyConstraints); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Policy mappings. | 
 |     if (result->GetExtension(der::Input(kPolicyMappingsOid), &extension)) { | 
 |       result->has_policy_mappings_ = true; | 
 |       if (!ParsePolicyMappings(extension.value, &result->policy_mappings_)) { | 
 |         errors->AddError(kFailedParsingPolicyMappings); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Inhibit Any Policy. | 
 |     if (result->GetExtension(der::Input(kInhibitAnyPolicyOid), &extension)) { | 
 |       result->inhibit_any_policy_ = ParseInhibitAnyPolicy(extension.value); | 
 |       if (!result->inhibit_any_policy_) { | 
 |         errors->AddError(kFailedParsingInhibitAnyPolicy); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Subject Key Identifier. | 
 |     if (result->GetExtension(der::Input(kSubjectKeyIdentifierOid), | 
 |                              &extension)) { | 
 |       result->subject_key_identifier_ = std::make_optional<der::Input>(); | 
 |       if (!ParseSubjectKeyIdentifier( | 
 |               extension.value, &result->subject_key_identifier_.value())) { | 
 |         errors->AddError(kFailedParsingSubjectKeyIdentifier); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |  | 
 |     // Authority Key Identifier. | 
 |     if (result->GetExtension(der::Input(kAuthorityKeyIdentifierOid), | 
 |                              &extension)) { | 
 |       result->authority_key_identifier_ = | 
 |           std::make_optional<ParsedAuthorityKeyIdentifier>(); | 
 |       if (!ParseAuthorityKeyIdentifier( | 
 |               extension.value, &result->authority_key_identifier_.value())) { | 
 |         errors->AddError(kFailedParsingAuthorityKeyIdentifier); | 
 |         return nullptr; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | // static | 
 | bool ParsedCertificate::CreateAndAddToVector( | 
 |     bssl::UniquePtr<CRYPTO_BUFFER> cert_data, | 
 |     const ParseCertificateOptions &options, | 
 |     std::vector<std::shared_ptr<const bssl::ParsedCertificate>> *chain, | 
 |     CertErrors *errors) { | 
 |   std::shared_ptr<const ParsedCertificate> cert( | 
 |       Create(std::move(cert_data), options, errors)); | 
 |   if (!cert) { | 
 |     return false; | 
 |   } | 
 |   chain->push_back(std::move(cert)); | 
 |   return true; | 
 | } | 
 |  | 
 | BSSL_NAMESPACE_END |