Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
13 KiB
376 lines
13 KiB
// Copyright 2015 The Chromium Authors |
|
// Use of this source code is governed by a BSD-style license that can be |
|
// found in the LICENSE file. |
|
|
|
#include <algorithm> |
|
|
|
#include "certificate_policies.h" |
|
|
|
#include "cert_error_params.h" |
|
#include "cert_errors.h" |
|
#include "input.h" |
|
#include "parse_values.h" |
|
#include "parser.h" |
|
#include "tag.h" |
|
#include <openssl/base.h> |
|
|
|
namespace bssl { |
|
|
|
namespace { |
|
|
|
// --------------------------------------------------------------- |
|
// Errors |
|
// --------------------------------------------------------------- |
|
|
|
DEFINE_CERT_ERROR_ID(kPolicyQualifiersEmptySequence, |
|
"The policy qualifiers SEQUENCE is empty"); |
|
DEFINE_CERT_ERROR_ID(kUnknownPolicyQualifierOid, |
|
"Unknown policy qualifier OID (not CPS or User Notice)"); |
|
DEFINE_CERT_ERROR_ID(kPoliciesEmptySequence, "Policies is an empty SEQUENCE"); |
|
DEFINE_CERT_ERROR_ID(kPoliciesDuplicateOid, "Policies contains duplicate OIDs"); |
|
DEFINE_CERT_ERROR_ID(kPolicyInformationTrailingData, |
|
"PolicyInformation has trailing data"); |
|
DEFINE_CERT_ERROR_ID(kFailedParsingPolicyQualifiers, |
|
"Failed parsing policy qualifiers"); |
|
DEFINE_CERT_ERROR_ID(kMissingQualifier, |
|
"PolicyQualifierInfo is missing qualifier"); |
|
DEFINE_CERT_ERROR_ID(kPolicyQualifierInfoTrailingData, |
|
"PolicyQualifierInfo has trailing data"); |
|
|
|
// Minimally parse policyQualifiers, storing in |policy_qualifiers| if non-null. |
|
// If a policy qualifier other than User Notice/CPS is present, parsing |
|
// will fail if |restrict_to_known_qualifiers| was set to true. |
|
bool ParsePolicyQualifiers(bool restrict_to_known_qualifiers, |
|
der::Parser* policy_qualifiers_sequence_parser, |
|
std::vector<PolicyQualifierInfo>* policy_qualifiers, |
|
CertErrors* errors) { |
|
BSSL_CHECK(errors); |
|
|
|
// If it is present, the policyQualifiers sequence should have at least 1 |
|
// element. |
|
// |
|
// policyQualifiers SEQUENCE SIZE (1..MAX) OF |
|
// PolicyQualifierInfo OPTIONAL } |
|
if (!policy_qualifiers_sequence_parser->HasMore()) { |
|
errors->AddError(kPolicyQualifiersEmptySequence); |
|
return false; |
|
} |
|
while (policy_qualifiers_sequence_parser->HasMore()) { |
|
// PolicyQualifierInfo ::= SEQUENCE { |
|
der::Parser policy_information_parser; |
|
if (!policy_qualifiers_sequence_parser->ReadSequence( |
|
&policy_information_parser)) { |
|
return false; |
|
} |
|
// policyQualifierId PolicyQualifierId, |
|
der::Input qualifier_oid; |
|
if (!policy_information_parser.ReadTag(der::kOid, &qualifier_oid)) |
|
return false; |
|
if (restrict_to_known_qualifiers && |
|
qualifier_oid != der::Input(kCpsPointerId) && |
|
qualifier_oid != der::Input(kUserNoticeId)) { |
|
errors->AddError(kUnknownPolicyQualifierOid, |
|
CreateCertErrorParams1Der("oid", qualifier_oid)); |
|
return false; |
|
} |
|
// qualifier ANY DEFINED BY policyQualifierId } |
|
der::Input qualifier_tlv; |
|
if (!policy_information_parser.ReadRawTLV(&qualifier_tlv)) { |
|
errors->AddError(kMissingQualifier); |
|
return false; |
|
} |
|
// Should not have trailing data after qualifier. |
|
if (policy_information_parser.HasMore()) { |
|
errors->AddError(kPolicyQualifierInfoTrailingData); |
|
return false; |
|
} |
|
|
|
if (policy_qualifiers) |
|
policy_qualifiers->push_back({qualifier_oid, qualifier_tlv}); |
|
} |
|
return true; |
|
} |
|
|
|
// RFC 5280 section 4.2.1.4. Certificate Policies: |
|
// |
|
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation |
|
// |
|
// PolicyInformation ::= SEQUENCE { |
|
// policyIdentifier CertPolicyId, |
|
// policyQualifiers SEQUENCE SIZE (1..MAX) OF |
|
// PolicyQualifierInfo OPTIONAL } |
|
// |
|
// CertPolicyId ::= OBJECT IDENTIFIER |
|
// |
|
// PolicyQualifierInfo ::= SEQUENCE { |
|
// policyQualifierId PolicyQualifierId, |
|
// qualifier ANY DEFINED BY policyQualifierId } |
|
// |
|
// PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) |
|
// |
|
// Qualifier ::= CHOICE { |
|
// cPSuri CPSuri, |
|
// userNotice UserNotice } |
|
// |
|
// CPSuri ::= IA5String |
|
// |
|
// UserNotice ::= SEQUENCE { |
|
// noticeRef NoticeReference OPTIONAL, |
|
// explicitText DisplayText OPTIONAL } |
|
// |
|
// NoticeReference ::= SEQUENCE { |
|
// organization DisplayText, |
|
// noticeNumbers SEQUENCE OF INTEGER } |
|
// |
|
// DisplayText ::= CHOICE { |
|
// ia5String IA5String (SIZE (1..200)), |
|
// visibleString VisibleString (SIZE (1..200)), |
|
// bmpString BMPString (SIZE (1..200)), |
|
// utf8String UTF8String (SIZE (1..200)) } |
|
bool ParseCertificatePoliciesExtensionImpl( |
|
const der::Input& extension_value, |
|
bool fail_parsing_unknown_qualifier_oids, |
|
std::vector<der::Input>* policy_oids, |
|
std::vector<PolicyInformation>* policy_informations, |
|
CertErrors* errors) { |
|
BSSL_CHECK(policy_oids); |
|
BSSL_CHECK(errors); |
|
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation |
|
der::Parser extension_parser(extension_value); |
|
der::Parser policies_sequence_parser; |
|
if (!extension_parser.ReadSequence(&policies_sequence_parser)) |
|
return false; |
|
// Should not have trailing data after certificatePolicies sequence. |
|
if (extension_parser.HasMore()) |
|
return false; |
|
// The certificatePolicies sequence should have at least 1 element. |
|
if (!policies_sequence_parser.HasMore()) { |
|
errors->AddError(kPoliciesEmptySequence); |
|
return false; |
|
} |
|
|
|
policy_oids->clear(); |
|
if (policy_informations) |
|
policy_informations->clear(); |
|
|
|
while (policies_sequence_parser.HasMore()) { |
|
// PolicyInformation ::= SEQUENCE { |
|
der::Parser policy_information_parser; |
|
if (!policies_sequence_parser.ReadSequence(&policy_information_parser)) |
|
return false; |
|
// policyIdentifier CertPolicyId, |
|
der::Input policy_oid; |
|
if (!policy_information_parser.ReadTag(der::kOid, &policy_oid)) |
|
return false; |
|
|
|
policy_oids->push_back(policy_oid); |
|
|
|
std::vector<PolicyQualifierInfo>* policy_qualifiers = nullptr; |
|
if (policy_informations) { |
|
policy_informations->emplace_back(); |
|
policy_informations->back().policy_oid = policy_oid; |
|
policy_qualifiers = &policy_informations->back().policy_qualifiers; |
|
} |
|
|
|
if (!policy_information_parser.HasMore()) |
|
continue; |
|
|
|
// policyQualifiers SEQUENCE SIZE (1..MAX) OF |
|
// PolicyQualifierInfo OPTIONAL } |
|
der::Parser policy_qualifiers_sequence_parser; |
|
if (!policy_information_parser.ReadSequence( |
|
&policy_qualifiers_sequence_parser)) { |
|
return false; |
|
} |
|
// Should not have trailing data after policyQualifiers sequence. |
|
if (policy_information_parser.HasMore()) { |
|
errors->AddError(kPolicyInformationTrailingData); |
|
return false; |
|
} |
|
|
|
// RFC 5280 section 4.2.1.4: When qualifiers are used with the special |
|
// policy anyPolicy, they MUST be limited to the qualifiers identified in |
|
// this section. |
|
if (!ParsePolicyQualifiers(fail_parsing_unknown_qualifier_oids || |
|
policy_oid == der::Input(kAnyPolicyOid), |
|
&policy_qualifiers_sequence_parser, |
|
policy_qualifiers, errors)) { |
|
errors->AddError(kFailedParsingPolicyQualifiers); |
|
return false; |
|
} |
|
} |
|
|
|
// RFC 5280 section 4.2.1.4: A certificate policy OID MUST NOT appear more |
|
// than once in a certificate policies extension. |
|
std::sort(policy_oids->begin(), policy_oids->end()); |
|
auto dupe_policy_iter = |
|
std::adjacent_find(policy_oids->begin(), policy_oids->end()); |
|
if (dupe_policy_iter != policy_oids->end()) { |
|
errors->AddError(kPoliciesDuplicateOid, |
|
CreateCertErrorParams1Der("oid", *dupe_policy_iter)); |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
} // namespace |
|
|
|
PolicyInformation::PolicyInformation() = default; |
|
PolicyInformation::~PolicyInformation() = default; |
|
PolicyInformation::PolicyInformation(const PolicyInformation&) = default; |
|
PolicyInformation::PolicyInformation(PolicyInformation&&) = default; |
|
|
|
bool ParseCertificatePoliciesExtension(const der::Input& extension_value, |
|
std::vector<PolicyInformation>* policies, |
|
CertErrors* errors) { |
|
std::vector<der::Input> unused_policy_oids; |
|
return ParseCertificatePoliciesExtensionImpl( |
|
extension_value, /*fail_parsing_unknown_qualifier_oids=*/false, |
|
&unused_policy_oids, policies, errors); |
|
} |
|
|
|
bool ParseCertificatePoliciesExtensionOids( |
|
const der::Input& extension_value, |
|
bool fail_parsing_unknown_qualifier_oids, |
|
std::vector<der::Input>* policy_oids, |
|
CertErrors* errors) { |
|
return ParseCertificatePoliciesExtensionImpl( |
|
extension_value, fail_parsing_unknown_qualifier_oids, policy_oids, |
|
nullptr, errors); |
|
} |
|
|
|
// From RFC 5280: |
|
// |
|
// PolicyConstraints ::= SEQUENCE { |
|
// requireExplicitPolicy [0] SkipCerts OPTIONAL, |
|
// inhibitPolicyMapping [1] SkipCerts OPTIONAL } |
|
// |
|
// SkipCerts ::= INTEGER (0..MAX) |
|
bool ParsePolicyConstraints(const der::Input& policy_constraints_tlv, |
|
ParsedPolicyConstraints* out) { |
|
der::Parser parser(policy_constraints_tlv); |
|
|
|
// PolicyConstraints ::= SEQUENCE { |
|
der::Parser sequence_parser; |
|
if (!parser.ReadSequence(&sequence_parser)) |
|
return false; |
|
|
|
// RFC 5280 prohibits CAs from issuing PolicyConstraints as an empty sequence: |
|
// |
|
// Conforming CAs MUST NOT issue certificates where policy constraints |
|
// is an empty sequence. That is, either the inhibitPolicyMapping field |
|
// or the requireExplicitPolicy field MUST be present. The behavior of |
|
// clients that encounter an empty policy constraints field is not |
|
// addressed in this profile. |
|
if (!sequence_parser.HasMore()) |
|
return false; |
|
|
|
std::optional<der::Input> require_value; |
|
if (!sequence_parser.ReadOptionalTag(der::ContextSpecificPrimitive(0), |
|
&require_value)) { |
|
return false; |
|
} |
|
|
|
if (require_value) { |
|
uint8_t require_explicit_policy; |
|
if (!ParseUint8(require_value.value(), &require_explicit_policy)) { |
|
// TODO(eroman): Surface reason for failure if length was longer than |
|
// uint8. |
|
return false; |
|
} |
|
out->require_explicit_policy = require_explicit_policy; |
|
} |
|
|
|
std::optional<der::Input> inhibit_value; |
|
if (!sequence_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1), |
|
&inhibit_value)) { |
|
return false; |
|
} |
|
|
|
if (inhibit_value) { |
|
uint8_t inhibit_policy_mapping; |
|
if (!ParseUint8(inhibit_value.value(), &inhibit_policy_mapping)) { |
|
// TODO(eroman): Surface reason for failure if length was longer than |
|
// uint8. |
|
return false; |
|
} |
|
out->inhibit_policy_mapping = inhibit_policy_mapping; |
|
} |
|
|
|
// There should be no remaining data. |
|
if (sequence_parser.HasMore() || parser.HasMore()) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// From RFC 5280: |
|
// |
|
// InhibitAnyPolicy ::= SkipCerts |
|
// |
|
// SkipCerts ::= INTEGER (0..MAX) |
|
std::optional<uint8_t> ParseInhibitAnyPolicy( |
|
const der::Input& inhibit_any_policy_tlv) { |
|
der::Parser parser(inhibit_any_policy_tlv); |
|
std::optional<uint8_t> num_certs = std::make_optional<uint8_t>(); |
|
|
|
// TODO(eroman): Surface reason for failure if length was longer than uint8. |
|
if (!parser.ReadUint8(&num_certs.value())) { |
|
return std::nullopt; |
|
} |
|
|
|
// There should be no remaining data. |
|
if (parser.HasMore()) { |
|
return std::nullopt; |
|
} |
|
|
|
return num_certs; |
|
} |
|
|
|
// From RFC 5280: |
|
// |
|
// PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { |
|
// issuerDomainPolicy CertPolicyId, |
|
// subjectDomainPolicy CertPolicyId } |
|
bool ParsePolicyMappings(const der::Input& policy_mappings_tlv, |
|
std::vector<ParsedPolicyMapping>* mappings) { |
|
mappings->clear(); |
|
|
|
der::Parser parser(policy_mappings_tlv); |
|
|
|
// PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { |
|
der::Parser sequence_parser; |
|
if (!parser.ReadSequence(&sequence_parser)) |
|
return false; |
|
|
|
// Must be at least 1 mapping. |
|
if (!sequence_parser.HasMore()) |
|
return false; |
|
|
|
while (sequence_parser.HasMore()) { |
|
der::Parser mapping_parser; |
|
if (!sequence_parser.ReadSequence(&mapping_parser)) |
|
return false; |
|
|
|
ParsedPolicyMapping mapping; |
|
if (!mapping_parser.ReadTag(der::kOid, &mapping.issuer_domain_policy)) |
|
return false; |
|
if (!mapping_parser.ReadTag(der::kOid, &mapping.subject_domain_policy)) |
|
return false; |
|
|
|
// There shouldn't be extra unconsumed data. |
|
if (mapping_parser.HasMore()) |
|
return false; |
|
|
|
mappings->push_back(mapping); |
|
} |
|
|
|
// There shouldn't be extra unconsumed data. |
|
if (parser.HasMore()) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
} // namespace net
|
|
|