Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "verify_certificate_chain.h" |
| 6 | |
| 7 | #include <algorithm> |
| 8 | #include <cassert> |
| 9 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 10 | #include <openssl/base.h> |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 11 | #include "cert_error_params.h" |
| 12 | #include "cert_errors.h" |
| 13 | #include "common_cert_errors.h" |
| 14 | #include "extended_key_usage.h" |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 15 | #include "input.h" |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 16 | #include "name_constraints.h" |
| 17 | #include "parse_certificate.h" |
| 18 | #include "signature_algorithm.h" |
| 19 | #include "trust_store.h" |
| 20 | #include "verify_signed_data.h" |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 21 | |
| 22 | namespace bssl { |
| 23 | |
| 24 | namespace { |
| 25 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 26 | bool IsHandledCriticalExtension(const ParsedExtension &extension, |
| 27 | const ParsedCertificate &cert) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 28 | if (extension.oid == der::Input(kBasicConstraintsOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 29 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 30 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 31 | // Key Usage is NOT processed for end-entity certificates (this is the |
| 32 | // responsibility of callers), however it is considered "handled" here in |
| 33 | // order to allow being marked as critical. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 34 | if (extension.oid == der::Input(kKeyUsageOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 35 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 36 | } |
| 37 | if (extension.oid == der::Input(kExtKeyUsageOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 38 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 39 | } |
| 40 | if (extension.oid == der::Input(kNameConstraintsOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 41 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 42 | } |
| 43 | if (extension.oid == der::Input(kSubjectAltNameOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 44 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 45 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 46 | if (extension.oid == der::Input(kCertificatePoliciesOid)) { |
| 47 | // Policy qualifiers are skipped during processing, so if the |
| 48 | // extension is marked critical need to ensure there weren't any |
| 49 | // qualifiers other than User Notice / CPS. |
| 50 | // |
| 51 | // This follows from RFC 5280 section 4.2.1.4: |
| 52 | // |
| 53 | // If this extension is critical, the path validation software MUST |
| 54 | // be able to interpret this extension (including the optional |
| 55 | // qualifier), or MUST reject the certificate. |
| 56 | std::vector<der::Input> unused_policies; |
| 57 | CertErrors unused_errors; |
| 58 | return ParseCertificatePoliciesExtensionOids( |
| 59 | extension.value, true /*fail_parsing_unknown_qualifier_oids*/, |
| 60 | &unused_policies, &unused_errors); |
| 61 | |
| 62 | // TODO(eroman): Give a better error message. |
| 63 | } |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 64 | if (extension.oid == der::Input(kPolicyMappingsOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 65 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 66 | } |
| 67 | if (extension.oid == der::Input(kPolicyConstraintsOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 68 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 69 | } |
| 70 | if (extension.oid == der::Input(kInhibitAnyPolicyOid)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 71 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 72 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 73 | if (extension.oid == der::Input(kMSApplicationPoliciesOid)) { |
| 74 | // Per https://crbug.com/1439638 and |
| 75 | // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/supported-extensions#msapplicationpolicies |
| 76 | // The MSApplicationPolicies extension may be ignored if the |
| 77 | // extendedKeyUsage extension is also present. |
| 78 | return cert.has_extended_key_usage(); |
| 79 | } |
| 80 | |
| 81 | return false; |
| 82 | } |
| 83 | |
| 84 | // Adds errors to |errors| if the certificate contains unconsumed _critical_ |
| 85 | // extensions. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 86 | void VerifyNoUnconsumedCriticalExtensions(const ParsedCertificate &cert, |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 87 | CertErrors *errors, |
| 88 | bool allow_precertificate) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 89 | for (const auto &it : cert.extensions()) { |
| 90 | const ParsedExtension &extension = it.second; |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 91 | if (allow_precertificate && extension.oid == der::Input(kCtPoisonOid)) { |
| 92 | continue; |
| 93 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 94 | if (extension.critical && !IsHandledCriticalExtension(extension, cert)) { |
| 95 | errors->AddError(cert_errors::kUnconsumedCriticalExtension, |
| 96 | CreateCertErrorParams2Der("oid", extension.oid, "value", |
| 97 | extension.value)); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | // Returns true if |cert| was self-issued. The definition of self-issuance |
| 103 | // comes from RFC 5280 section 6.1: |
| 104 | // |
| 105 | // A certificate is self-issued if the same DN appears in the subject |
| 106 | // and issuer fields (the two DNs are the same if they match according |
| 107 | // to the rules specified in Section 7.1). In general, the issuer and |
| 108 | // subject of the certificates that make up a path are different for |
| 109 | // each certificate. However, a CA may issue a certificate to itself to |
| 110 | // support key rollover or changes in certificate policies. These |
| 111 | // self-issued certificates are not counted when evaluating path length |
| 112 | // or name constraints. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 113 | [[nodiscard]] bool IsSelfIssued(const ParsedCertificate &cert) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 114 | return cert.normalized_subject() == cert.normalized_issuer(); |
| 115 | } |
| 116 | |
| 117 | // Adds errors to |errors| if |cert| is not valid at time |time|. |
| 118 | // |
| 119 | // The certificate's validity requirements are described by RFC 5280 section |
| 120 | // 4.1.2.5: |
| 121 | // |
| 122 | // The validity period for a certificate is the period of time from |
| 123 | // notBefore through notAfter, inclusive. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 124 | void VerifyTimeValidity(const ParsedCertificate &cert, |
| 125 | const der::GeneralizedTime &time, CertErrors *errors) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 126 | if (time < cert.tbs().validity_not_before) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 127 | errors->AddError(cert_errors::kValidityFailedNotBefore); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 128 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 129 | |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 130 | if (cert.tbs().validity_not_after < time) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 131 | errors->AddError(cert_errors::kValidityFailedNotAfter); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 132 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | // Adds errors to |errors| if |cert| has internally inconsistent signature |
| 136 | // algorithms. |
| 137 | // |
| 138 | // X.509 certificates contain two different signature algorithms: |
| 139 | // (1) The signatureAlgorithm field of Certificate |
| 140 | // (2) The signature field of TBSCertificate |
| 141 | // |
| 142 | // According to RFC 5280 section 4.1.1.2 and 4.1.2.3 these two fields must be |
| 143 | // equal: |
| 144 | // |
| 145 | // This field MUST contain the same algorithm identifier as the |
| 146 | // signature field in the sequence tbsCertificate (Section 4.1.2.3). |
| 147 | // |
| 148 | // The spec is not explicit about what "the same algorithm identifier" means. |
| 149 | // Our interpretation is that the two DER-encoded fields must be byte-for-byte |
| 150 | // identical. |
| 151 | // |
| 152 | // In practice however there are certificates which use different encodings for |
| 153 | // specifying RSA with SHA1 (different OIDs). This is special-cased for |
| 154 | // compatibility sake. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 155 | bool VerifySignatureAlgorithmsMatch(const ParsedCertificate &cert, |
| 156 | CertErrors *errors) { |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 157 | der::Input alg1_tlv = cert.signature_algorithm_tlv(); |
| 158 | der::Input alg2_tlv = cert.tbs().signature_algorithm_tlv; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 159 | |
| 160 | // Ensure that the two DER-encoded signature algorithms are byte-for-byte |
| 161 | // equal. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 162 | if (alg1_tlv == alg2_tlv) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 163 | return true; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 164 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 165 | |
| 166 | // But make a compatibility concession if alternate encodings are used |
| 167 | // TODO(eroman): Turn this warning into an error. |
| 168 | // TODO(eroman): Add a unit-test that exercises this case. |
| 169 | std::optional<SignatureAlgorithm> alg1 = ParseSignatureAlgorithm(alg1_tlv); |
| 170 | if (!alg1) { |
| 171 | errors->AddError(cert_errors::kUnacceptableSignatureAlgorithm); |
| 172 | return false; |
| 173 | } |
| 174 | std::optional<SignatureAlgorithm> alg2 = ParseSignatureAlgorithm(alg2_tlv); |
| 175 | if (!alg2) { |
| 176 | errors->AddError(cert_errors::kUnacceptableSignatureAlgorithm); |
| 177 | return false; |
| 178 | } |
| 179 | |
| 180 | if (*alg1 == *alg2) { |
| 181 | errors->AddWarning( |
| 182 | cert_errors::kSignatureAlgorithmsDifferentEncoding, |
| 183 | CreateCertErrorParams2Der("Certificate.algorithm", alg1_tlv, |
| 184 | "TBSCertificate.signature", alg2_tlv)); |
| 185 | return true; |
| 186 | } |
| 187 | |
| 188 | errors->AddError( |
| 189 | cert_errors::kSignatureAlgorithmMismatch, |
| 190 | CreateCertErrorParams2Der("Certificate.algorithm", alg1_tlv, |
| 191 | "TBSCertificate.signature", alg2_tlv)); |
| 192 | return false; |
| 193 | } |
| 194 | |
| 195 | // Verify that |cert| can be used for |required_key_purpose|. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 196 | void VerifyExtendedKeyUsage(const ParsedCertificate &cert, |
| 197 | KeyPurpose required_key_purpose, CertErrors *errors, |
| 198 | bool is_target_cert, bool is_target_cert_issuer) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 199 | // We treat a required KeyPurpose of ANY_EKU to mean "Do not check EKU" |
| 200 | if (required_key_purpose == KeyPurpose::ANY_EKU) { |
| 201 | return; |
| 202 | } |
| 203 | bool has_any_eku = false; |
| 204 | bool has_server_auth_eku = false; |
| 205 | bool has_client_auth_eku = false; |
| 206 | bool has_code_signing_eku = false; |
| 207 | bool has_time_stamping_eku = false; |
| 208 | bool has_ocsp_signing_eku = false; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 209 | if (cert.has_extended_key_usage()) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 210 | for (const auto &key_purpose_oid : cert.extended_key_usage()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 211 | if (key_purpose_oid == der::Input(kAnyEKU)) { |
| 212 | has_any_eku = true; |
| 213 | } |
| 214 | if (key_purpose_oid == der::Input(kServerAuth)) { |
| 215 | has_server_auth_eku = true; |
| 216 | } |
| 217 | if (key_purpose_oid == der::Input(kClientAuth)) { |
| 218 | has_client_auth_eku = true; |
| 219 | } |
| 220 | if (key_purpose_oid == der::Input(kCodeSigning)) { |
| 221 | has_code_signing_eku = true; |
| 222 | } |
| 223 | if (key_purpose_oid == der::Input(kTimeStamping)) { |
| 224 | has_time_stamping_eku = true; |
| 225 | } |
| 226 | if (key_purpose_oid == der::Input(kOCSPSigning)) { |
| 227 | has_ocsp_signing_eku = true; |
| 228 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 229 | } |
| 230 | } |
| 231 | |
| 232 | auto add_error_if_strict = [&](CertErrorId id) { |
| 233 | if (required_key_purpose == KeyPurpose::SERVER_AUTH_STRICT || |
| 234 | required_key_purpose == KeyPurpose::CLIENT_AUTH_STRICT) { |
| 235 | errors->AddError(id); |
| 236 | } else { |
| 237 | errors->AddWarning(id); |
| 238 | } |
| 239 | }; |
| 240 | if (is_target_cert) { |
| 241 | // Loosely based upon CABF BR version 1.8.4, 7.1.2.3(f). We are more |
| 242 | // permissive in that we still allow EKU any to be present in a leaf |
| 243 | // certificate, but we ignore it for purposes of server or client auth. We |
| 244 | // are less permissive in that we prohibit Code Signing, OCSP Signing, and |
| 245 | // Time Stamping which are currently only a SHOULD NOT. The BR does |
| 246 | // explicitly allow Email authentication to be present, as this still exists |
| 247 | // in the wild (2022), so we do not prohibit Email authentication here (and |
| 248 | // by extension must allow it to be present in the signer, below). |
| 249 | if (!cert.has_extended_key_usage()) { |
| 250 | // This is added as a warning, an error will be added in STRICT modes |
| 251 | // if we then lack client or server auth due to this not being present. |
| 252 | errors->AddWarning(cert_errors::kEkuNotPresent); |
| 253 | } else { |
| 254 | if (has_code_signing_eku) { |
| 255 | add_error_if_strict(cert_errors::kEkuHasProhibitedCodeSigning); |
| 256 | } |
| 257 | if (has_ocsp_signing_eku) { |
| 258 | add_error_if_strict(cert_errors::kEkuHasProhibitedOCSPSigning); |
| 259 | } |
| 260 | if (has_time_stamping_eku) { |
| 261 | add_error_if_strict(cert_errors::kEkuHasProhibitedTimeStamping); |
| 262 | } |
| 263 | } |
| 264 | } else if (is_target_cert_issuer) { |
| 265 | // Handle the decision to overload EKU as a constraint on issuers. |
| 266 | // |
| 267 | // CABF BR version 1.8.4, 7.1.2.2(g) pertains to the case of "Certs used to |
| 268 | // issue TLS certificates", While the BR refers to the entire chain of |
| 269 | // intermediates, there are a number of exceptions regarding CA ownership |
| 270 | // and cross signing which are impossible for us to know or enforce here. |
| 271 | // Therefore, we can only enforce at the level of the intermediate that |
| 272 | // issued our target certificate. This means we we differ in the following |
| 273 | // ways: |
| 274 | // - We only enforce at the issuer of the TLS certificate. |
| 275 | // - We allow email protection to exist in the issuer, since without |
| 276 | // this it can not be allowed in the client (other than via EKU any)) |
| 277 | // - As in the leaf certificate case, we allow EKU any to be present, but |
| 278 | // we ignore it for the purposes of server or client auth. |
| 279 | // |
| 280 | // At this time (until at least 2023) some intermediates are lacking EKU in |
| 281 | // the world at large from common CA's, so we allow the noEKU case to permit |
| 282 | // everything. |
| 283 | // TODO(bbe): enforce requiring EKU in the issuer when we can manage it. |
| 284 | if (cert.has_extended_key_usage()) { |
| 285 | if (has_code_signing_eku) { |
| 286 | add_error_if_strict(cert_errors::kEkuHasProhibitedCodeSigning); |
| 287 | } |
| 288 | if (has_time_stamping_eku) { |
| 289 | add_error_if_strict(cert_errors::kEkuHasProhibitedTimeStamping); |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | // Otherwise, we are a parent of an issuer of a TLS certificate. The CABF |
| 294 | // BR version 1.8.4, 7.1.2.2(g) goes as far as permitting EKU any in certain |
| 295 | // cases of Cross Signing and CA Ownership, having permitted cases where EKU |
| 296 | // is permitted to not be present at all. These cases are not practical to |
| 297 | // differentiate here and therefore we don't attempt to enforce any further |
| 298 | // EKU "constraints" on such certificates. Unlike the above cases we also |
| 299 | // allow the use of EKU any for client or server auth constraint purposes. |
| 300 | |
| 301 | switch (required_key_purpose) { |
| 302 | case KeyPurpose::ANY_EKU: |
| 303 | assert(0); // NOTREACHED |
| 304 | return; |
| 305 | case KeyPurpose::SERVER_AUTH: |
| 306 | case KeyPurpose::SERVER_AUTH_STRICT: { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 307 | if (has_any_eku && !has_server_auth_eku) { |
| 308 | if (is_target_cert || is_target_cert_issuer) { |
| 309 | errors->AddWarning(cert_errors::kEkuLacksServerAuthButHasAnyEKU); |
| 310 | } else { |
| 311 | // Accept anyEKU for server auth below target issuer. |
| 312 | has_server_auth_eku = true; |
| 313 | } |
| 314 | } |
| 315 | if (is_target_cert_issuer && !cert.has_extended_key_usage()) { |
| 316 | // Accept noEKU for server auth in target issuer. |
| 317 | // TODO(bbe): remove this once BR requirements catch up with CA's. |
| 318 | has_server_auth_eku = true; |
| 319 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 320 | if (required_key_purpose == KeyPurpose::SERVER_AUTH) { |
| 321 | // Legacy compatible. |
| 322 | if (cert.has_extended_key_usage() && !has_server_auth_eku && |
David Benjamin | cf00b17 | 2023-12-25 23:57:22 -0500 | [diff] [blame] | 323 | !has_any_eku) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 324 | errors->AddError(cert_errors::kEkuLacksServerAuth); |
| 325 | } |
| 326 | } else { |
| 327 | if (!has_server_auth_eku) { |
| 328 | errors->AddError(cert_errors::kEkuLacksServerAuth); |
| 329 | } |
| 330 | } |
| 331 | break; |
| 332 | } |
| 333 | case KeyPurpose::CLIENT_AUTH: |
| 334 | case KeyPurpose::CLIENT_AUTH_STRICT: { |
| 335 | if (has_any_eku && !has_client_auth_eku) { |
| 336 | if (is_target_cert || is_target_cert_issuer) { |
| 337 | errors->AddWarning(cert_errors::kEkuLacksClientAuthButHasAnyEKU); |
| 338 | } else { |
| 339 | // accept anyEKU for client auth. |
| 340 | has_client_auth_eku = true; |
| 341 | } |
| 342 | } |
| 343 | if (required_key_purpose == KeyPurpose::CLIENT_AUTH) { |
| 344 | // Legacy-compatible. |
| 345 | if (cert.has_extended_key_usage() && !has_client_auth_eku && |
| 346 | !has_any_eku) { |
| 347 | errors->AddError(cert_errors::kEkuLacksClientAuth); |
| 348 | } |
| 349 | } else { |
| 350 | if (!has_client_auth_eku) { |
| 351 | errors->AddError(cert_errors::kEkuLacksClientAuth); |
| 352 | } |
| 353 | } |
| 354 | break; |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | // Representation of RFC 5280's "valid_policy_tree", used to keep track of the |
| 360 | // valid policies and policy re-mappings. This structure is defined in |
| 361 | // section 6.1.2. |
| 362 | // |
| 363 | // ValidPolicyGraph differs from RFC 5280's description in that: |
| 364 | // |
| 365 | // (1) It does not track "qualifier_set". This is not needed as it is not |
| 366 | // output by this implementation. |
| 367 | // |
| 368 | // (2) It builds a directed acyclic graph, rather than a tree. When a given |
| 369 | // policy matches multiple parents, RFC 5280 makes a separate node for |
| 370 | // each parent. This representation condenses them into one node with |
| 371 | // multiple parents. |
| 372 | // |
| 373 | // (3) It does not track "expected_policy_set" or anyPolicy nodes directly. |
| 374 | // Rather it maintains, only for the most recent level, whether there is an |
| 375 | // anyPolicy node and an inverted map of all "expected_policy_set" values. |
| 376 | // |
| 377 | // (4) Some pruning steps are deferred to when policies are evaluated, as a |
| 378 | // reachability pass. |
| 379 | class ValidPolicyGraph { |
| 380 | public: |
| 381 | ValidPolicyGraph() = default; |
| 382 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 383 | ValidPolicyGraph(const ValidPolicyGraph &) = delete; |
| 384 | ValidPolicyGraph &operator=(const ValidPolicyGraph &) = delete; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 385 | |
| 386 | // A Node is an entry in the policy graph. It contains information about some |
| 387 | // policy asserted by a certificate in the chain. The policy OID itself is |
| 388 | // omitted because it is the key in the Level map. |
| 389 | struct Node { |
| 390 | // The list of "valid_policy" values for all nodes which are a parent of |
| 391 | // this node, other than anyPolicy. If empty, this node has a single parent, |
| 392 | // anyPolicy. |
| 393 | // |
| 394 | // Nodes whose parent is anyPolicy are root policies, and may be returned |
| 395 | // in the authorities-constrained-policy-set. Nodes with a concrete policy |
| 396 | // as a parent are derived from that policy in the issuer certificate, |
| 397 | // possibly with a policy mapping applied. |
| 398 | // |
| 399 | // Note it is not possible for a policy to have both anyPolicy and a |
| 400 | // concrete policy as a parent. Section 6.1.3, step d.1.ii only runs if |
| 401 | // there was no match in step d.1.i. |
| 402 | std::vector<der::Input> parent_policies; |
| 403 | |
| 404 | // Whether this node matches a policy mapping in the certificate. If true, |
| 405 | // its "expected_policy_set" comes from the policy mappings extension. If |
| 406 | // false, its "expected_policy_set" is itself. |
| 407 | bool mapped = false; |
| 408 | |
| 409 | // Whether this node is reachable from some valid policy in the end-entity |
| 410 | // certificate. Computed during GetValidRootPolicySet(). |
| 411 | bool reachable = false; |
| 412 | }; |
| 413 | |
| 414 | // The policy graph is organized into "levels", each corresponding to a |
| 415 | // certificate in the chain. We maintain a map from "valid_policy" to the |
| 416 | // corresponding Node. This is the set of policies asserted by this |
| 417 | // certificate. The special anyPolicy OID is handled separately below. |
| 418 | using Level = std::map<der::Input, Node>; |
| 419 | |
| 420 | // Additional per-level information that only needs to be maintained for the |
| 421 | // bottom-most level. |
| 422 | struct LevelDetails { |
| 423 | // Maintains the "expected_policy_set" values for nodes in a level of the |
| 424 | // graph, but the map is inverted from RFC 5280's formulation. For a given |
| 425 | // policy OID P, other than anyPolicy, this map gives the set of nodes where |
| 426 | // P appears in the node's "expected_policy_set". anyPolicy is handled |
| 427 | // separately below. |
| 428 | std::map<der::Input, std::vector<der::Input>> expected_policy_map; |
| 429 | |
| 430 | // Whether there is a node at this level whose "valid_policy" is anyPolicy. |
| 431 | // |
| 432 | // Note anyPolicy's "expected_policy_set" always {anyPolicy}, and anyPolicy |
| 433 | // will never appear in the "expected_policy_set" of any other policy. That |
| 434 | // means this field also captures how anyPolicy appears in |
| 435 | // "expected_policy_set". |
| 436 | bool has_any_policy = false; |
| 437 | }; |
| 438 | |
| 439 | // Initializes the ValidPolicyGraph. |
| 440 | void Init() { |
| 441 | SetNull(); |
| 442 | StartLevel(); |
| 443 | AddAnyPolicyNode(); |
| 444 | } |
| 445 | |
| 446 | // In RFC 5280 valid_policy_tree may be set to null. That is represented here |
| 447 | // by emptiness. |
| 448 | bool IsNull() const { |
| 449 | return !current_level_.has_any_policy && |
| 450 | (levels_.empty() || levels_.back().empty()); |
| 451 | } |
| 452 | void SetNull() { |
| 453 | levels_.clear(); |
| 454 | current_level_ = LevelDetails{}; |
| 455 | } |
| 456 | |
| 457 | // Completes the previous level, returning a corresponding LevelDetails |
| 458 | // structure, and starts a new level. |
| 459 | LevelDetails StartLevel() { |
| 460 | // Finish building expected_policy_map for the previous level. |
| 461 | if (!levels_.empty()) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 462 | for (const auto &[policy, node] : levels_.back()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 463 | if (!node.mapped) { |
| 464 | current_level_.expected_policy_map[policy].push_back(policy); |
| 465 | } |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | LevelDetails prev_level = std::move(current_level_); |
| 470 | levels_.emplace_back(); |
| 471 | current_level_ = LevelDetails{}; |
| 472 | return prev_level; |
| 473 | } |
| 474 | |
| 475 | // Gets the set of policies (in terms of root authority's policy domain) that |
| 476 | // are valid at the bottom level of the policy graph, intersected with |
| 477 | // |user_initial_policy_set|. This is what X.509 calls |
| 478 | // "user-constrained-policy-set". |
| 479 | // |
| 480 | // This method may only be called once, after the policy graph is constructed. |
| 481 | std::set<der::Input> GetUserConstrainedPolicySet( |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 482 | const std::set<der::Input> &user_initial_policy_set) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 483 | if (levels_.empty()) { |
| 484 | return {}; |
| 485 | } |
| 486 | |
| 487 | bool user_has_any_policy = |
| 488 | user_initial_policy_set.count(der::Input(kAnyPolicyOid)) != 0; |
| 489 | if (current_level_.has_any_policy) { |
| 490 | if (user_has_any_policy) { |
| 491 | return {der::Input(kAnyPolicyOid)}; |
| 492 | } |
| 493 | return user_initial_policy_set; |
| 494 | } |
| 495 | |
| 496 | // The root's policy domain is determined by nodes with anyPolicy as a |
| 497 | // parent. However, we must limit to those which are reachable from the |
| 498 | // end-entity certificate because we defer some pruning steps. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 499 | for (auto &[policy, node] : levels_.back()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 500 | // GCC before 8.1 tracks individual unused bindings and does not support |
| 501 | // marking them [[maybe_unused]]. |
| 502 | (void)policy; |
| 503 | node.reachable = true; |
| 504 | } |
| 505 | std::set<der::Input> policy_set; |
| 506 | for (size_t i = levels_.size() - 1; i < levels_.size(); i--) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 507 | for (auto &[policy, node] : levels_[i]) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 508 | if (!node.reachable) { |
| 509 | continue; |
| 510 | } |
| 511 | if (node.parent_policies.empty()) { |
| 512 | // |node|'s parent is anyPolicy, so this is in the root policy domain. |
| 513 | // Add it to the set if it is also in user's list. |
| 514 | if (user_has_any_policy || |
| 515 | user_initial_policy_set.count(policy) > 0) { |
| 516 | policy_set.insert(policy); |
| 517 | } |
| 518 | } else if (i > 0) { |
| 519 | // Otherwise, continue searching the previous level. |
| 520 | for (der::Input parent : node.parent_policies) { |
| 521 | auto iter = levels_[i - 1].find(parent); |
| 522 | if (iter != levels_[i - 1].end()) { |
| 523 | iter->second.reachable = true; |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | } |
| 528 | } |
| 529 | return policy_set; |
| 530 | } |
| 531 | |
| 532 | // Adds a node with policy anyPolicy to the current level. |
| 533 | void AddAnyPolicyNode() { |
| 534 | assert(!levels_.empty()); |
| 535 | current_level_.has_any_policy = true; |
| 536 | } |
| 537 | |
| 538 | // Adds a node to the current level which is a child of |parent_policies| with |
| 539 | // the specified policy. |
| 540 | void AddNode(der::Input policy, std::vector<der::Input> parent_policies) { |
| 541 | assert(policy != der::Input(kAnyPolicyOid)); |
| 542 | AddNodeReturningIterator(policy, std::move(parent_policies)); |
| 543 | } |
| 544 | |
| 545 | // Adds a node to the current level which is a child of anyPolicy with the |
| 546 | // specified policy. |
| 547 | void AddNodeWithParentAnyPolicy(der::Input policy) { |
| 548 | // An empty parent set represents a node parented by anyPolicy. |
| 549 | AddNode(policy, {}); |
| 550 | } |
| 551 | |
| 552 | // Maps |issuer_policy| to |subject_policy|, as in RFC 5280, section 6.1.4, |
| 553 | // step b.1. |
| 554 | void AddPolicyMapping(der::Input issuer_policy, der::Input subject_policy) { |
| 555 | assert(issuer_policy != der::Input(kAnyPolicyOid)); |
| 556 | assert(subject_policy != der::Input(kAnyPolicyOid)); |
| 557 | if (levels_.empty()) { |
| 558 | return; |
| 559 | } |
| 560 | |
| 561 | // The mapping only applies if |issuer_policy| exists in the current level. |
| 562 | auto issuer_policy_iter = levels_.back().find(issuer_policy); |
| 563 | if (issuer_policy_iter == levels_.back().end()) { |
| 564 | // If there is no match, it can instead match anyPolicy. |
| 565 | if (!current_level_.has_any_policy) { |
| 566 | return; |
| 567 | } |
| 568 | |
| 569 | // From RFC 5280, section 6.1.4, step b.1: |
| 570 | // |
| 571 | // If no node of depth i in the valid_policy_tree has a |
| 572 | // valid_policy of ID-P but there is a node of depth i with a |
| 573 | // valid_policy of anyPolicy, then generate a child node of |
| 574 | // the node of depth i-1 that has a valid_policy of anyPolicy |
| 575 | // as follows: [...] |
| 576 | // |
| 577 | // The anyPolicy node of depth i-1 is referring to the parent of the |
| 578 | // anyPolicy node of depth i. The parent of anyPolicy is always anyPolicy. |
| 579 | issuer_policy_iter = AddNodeReturningIterator(issuer_policy, {}); |
| 580 | } |
| 581 | |
| 582 | // Unmapped nodes have a singleton "expected_policy_set" containing their |
| 583 | // valid_policy. Track whether nodes have been mapped so this can be filled |
| 584 | // in at StartLevel(). |
| 585 | issuer_policy_iter->second.mapped = true; |
| 586 | |
| 587 | // Add |subject_policy| to |issuer_policy|'s "expected_policy_set". |
| 588 | current_level_.expected_policy_map[subject_policy].push_back(issuer_policy); |
| 589 | } |
| 590 | |
| 591 | // Removes the node with the specified policy from the current level. |
| 592 | void DeleteNode(der::Input policy) { |
| 593 | if (!levels_.empty()) { |
| 594 | levels_.back().erase(policy); |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | private: |
| 599 | Level::iterator AddNodeReturningIterator( |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 600 | der::Input policy, std::vector<der::Input> parent_policies) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 601 | assert(policy != der::Input(kAnyPolicyOid)); |
| 602 | auto [iter, inserted] = levels_.back().insert( |
| 603 | std::pair{policy, Node{std::move(parent_policies)}}); |
| 604 | // GCC before 8.1 tracks individual unused bindings and does not support |
| 605 | // marking them [[maybe_unused]]. |
| 606 | (void)inserted; |
| 607 | assert(inserted); |
| 608 | return iter; |
| 609 | } |
| 610 | |
| 611 | // The list of levels, starting from the root. |
| 612 | std::vector<Level> levels_; |
| 613 | // Additional information about the current level. |
| 614 | LevelDetails current_level_; |
| 615 | }; |
| 616 | |
| 617 | // Class that encapsulates the state variables used by certificate path |
| 618 | // validation. |
| 619 | class PathVerifier { |
| 620 | public: |
| 621 | // Same parameters and meaning as VerifyCertificateChain(). |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 622 | void Run(const ParsedCertificateList &certs, |
| 623 | const CertificateTrust &last_cert_trust, |
| 624 | VerifyCertificateChainDelegate *delegate, |
| 625 | const der::GeneralizedTime &time, KeyPurpose required_key_purpose, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 626 | InitialExplicitPolicy initial_explicit_policy, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 627 | const std::set<der::Input> &user_initial_policy_set, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 628 | InitialPolicyMappingInhibit initial_policy_mapping_inhibit, |
| 629 | InitialAnyPolicyInhibit initial_any_policy_inhibit, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 630 | std::set<der::Input> *user_constrained_policy_set, |
| 631 | CertPathErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 632 | |
| 633 | private: |
| 634 | // Verifies and updates the valid policies. This corresponds with RFC 5280 |
| 635 | // section 6.1.3 steps d-f. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 636 | void VerifyPolicies(const ParsedCertificate &cert, bool is_target_cert, |
| 637 | CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 638 | |
| 639 | // Applies the policy mappings. This corresponds with RFC 5280 section 6.1.4 |
| 640 | // steps a-b. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 641 | void VerifyPolicyMappings(const ParsedCertificate &cert, CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 642 | |
| 643 | // Applies policyConstraints and inhibitAnyPolicy. This corresponds with RFC |
| 644 | // 5280 section 6.1.4 steps i-j. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 645 | void ApplyPolicyConstraints(const ParsedCertificate &cert); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 646 | |
| 647 | // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate |
| 648 | // Processing" procedure. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 649 | void BasicCertificateProcessing(const ParsedCertificate &cert, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 650 | bool is_target_cert, |
| 651 | bool is_target_cert_issuer, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 652 | const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 653 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 654 | CertErrors *errors, |
| 655 | bool *shortcircuit_chain_validation); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 656 | |
| 657 | // This function corresponds to RFC 5280 section 6.1.4's "Preparation for |
| 658 | // Certificate i+1" procedure. |cert| is expected to be an intermediate. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 659 | void PrepareForNextCertificate(const ParsedCertificate &cert, |
| 660 | CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 661 | |
| 662 | // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up |
| 663 | // Procedure". It does processing for the final certificate (the target cert). |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 664 | void WrapUp(const ParsedCertificate &cert, KeyPurpose required_key_purpose, |
| 665 | const std::set<der::Input> &user_initial_policy_set, |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 666 | bool allow_precertificate, CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 667 | |
| 668 | // Enforces trust anchor constraints compatibile with RFC 5937. |
| 669 | // |
| 670 | // Note that the anchor constraints are encoded via the attached certificate |
| 671 | // itself. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 672 | void ApplyTrustAnchorConstraints(const ParsedCertificate &cert, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 673 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 674 | CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 675 | |
| 676 | // Initializes the path validation algorithm given anchor constraints. This |
| 677 | // follows the description in RFC 5937 |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 678 | void ProcessRootCertificate(const ParsedCertificate &cert, |
| 679 | const CertificateTrust &trust, |
| 680 | const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 681 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 682 | CertErrors *errors, |
| 683 | bool *shortcircuit_chain_validation); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 684 | |
| 685 | // Processes verification when the input is a single certificate. This is not |
| 686 | // defined by any standard. We attempt to match the de-facto behaviour of |
| 687 | // Operating System verifiers. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 688 | void ProcessSingleCertChain(const ParsedCertificate &cert, |
| 689 | const CertificateTrust &trust, |
| 690 | const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 691 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 692 | CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 693 | |
| 694 | // Parses |spki| to an EVP_PKEY and checks whether the public key is accepted |
| 695 | // by |delegate_|. On failure parsing returns nullptr. If either parsing the |
| 696 | // key or key policy failed, adds a high-severity error to |errors|. |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 697 | bssl::UniquePtr<EVP_PKEY> ParseAndCheckPublicKey(der::Input spki, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 698 | CertErrors *errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 699 | |
| 700 | ValidPolicyGraph valid_policy_graph_; |
| 701 | |
| 702 | std::set<der::Input> user_constrained_policy_set_; |
| 703 | |
| 704 | // Will contain a NameConstraints for each previous cert in the chain which |
| 705 | // had nameConstraints. This corresponds to the permitted_subtrees and |
| 706 | // excluded_subtrees state variables from RFC 5280. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 707 | std::vector<const NameConstraints *> name_constraints_list_; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 708 | |
| 709 | // |explicit_policy_| corresponds with the same named variable from RFC 5280 |
| 710 | // section 6.1.2: |
| 711 | // |
| 712 | // explicit_policy: an integer that indicates if a non-NULL |
| 713 | // valid_policy_tree is required. The integer indicates the |
| 714 | // number of non-self-issued certificates to be processed before |
| 715 | // this requirement is imposed. Once set, this variable may be |
| 716 | // decreased, but may not be increased. That is, if a certificate in the |
| 717 | // path requires a non-NULL valid_policy_tree, a later certificate cannot |
| 718 | // remove this requirement. If initial-explicit-policy is set, then the |
| 719 | // initial value is 0, otherwise the initial value is n+1. |
| 720 | size_t explicit_policy_; |
| 721 | |
| 722 | // |inhibit_any_policy_| corresponds with the same named variable from RFC |
| 723 | // 5280 section 6.1.2: |
| 724 | // |
| 725 | // inhibit_anyPolicy: an integer that indicates whether the |
| 726 | // anyPolicy policy identifier is considered a match. The |
| 727 | // integer indicates the number of non-self-issued certificates |
| 728 | // to be processed before the anyPolicy OID, if asserted in a |
| 729 | // certificate other than an intermediate self-issued |
| 730 | // certificate, is ignored. Once set, this variable may be |
| 731 | // decreased, but may not be increased. That is, if a |
| 732 | // certificate in the path inhibits processing of anyPolicy, a |
| 733 | // later certificate cannot permit it. If initial-any-policy- |
| 734 | // inhibit is set, then the initial value is 0, otherwise the |
| 735 | // initial value is n+1. |
| 736 | size_t inhibit_any_policy_; |
| 737 | |
| 738 | // |policy_mapping_| corresponds with the same named variable from RFC 5280 |
| 739 | // section 6.1.2: |
| 740 | // |
| 741 | // policy_mapping: an integer that indicates if policy mapping |
| 742 | // is permitted. The integer indicates the number of non-self- |
| 743 | // issued certificates to be processed before policy mapping is |
| 744 | // inhibited. Once set, this variable may be decreased, but may |
| 745 | // not be increased. That is, if a certificate in the path |
| 746 | // specifies that policy mapping is not permitted, it cannot be |
| 747 | // overridden by a later certificate. If initial-policy- |
| 748 | // mapping-inhibit is set, then the initial value is 0, |
| 749 | // otherwise the initial value is n+1. |
| 750 | size_t policy_mapping_; |
| 751 | |
| 752 | // |working_public_key_| is an amalgamation of 3 separate variables from RFC |
| 753 | // 5280: |
| 754 | // * working_public_key |
| 755 | // * working_public_key_algorithm |
| 756 | // * working_public_key_parameters |
| 757 | // |
| 758 | // They are combined for simplicity since the signature verification takes an |
| 759 | // EVP_PKEY, and the parameter inheritence is not applicable for the supported |
| 760 | // key types. |working_public_key_| may be null if parsing failed. |
| 761 | // |
| 762 | // An approximate explanation of |working_public_key_| is this description |
| 763 | // from RFC 5280 section 6.1.2: |
| 764 | // |
| 765 | // working_public_key: the public key used to verify the |
| 766 | // signature of a certificate. |
| 767 | bssl::UniquePtr<EVP_PKEY> working_public_key_; |
| 768 | |
| 769 | // |working_normalized_issuer_name_| is the normalized value of the |
| 770 | // working_issuer_name variable in RFC 5280 section 6.1.2: |
| 771 | // |
| 772 | // working_issuer_name: the issuer distinguished name expected |
| 773 | // in the next certificate in the chain. |
| 774 | der::Input working_normalized_issuer_name_; |
| 775 | |
| 776 | // |max_path_length_| corresponds with the same named variable in RFC 5280 |
| 777 | // section 6.1.2. |
| 778 | // |
| 779 | // max_path_length: this integer is initialized to n, is |
| 780 | // decremented for each non-self-issued certificate in the path, |
| 781 | // and may be reduced to the value in the path length constraint |
| 782 | // field within the basic constraints extension of a CA |
| 783 | // certificate. |
| 784 | size_t max_path_length_; |
| 785 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 786 | VerifyCertificateChainDelegate *delegate_; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 787 | }; |
| 788 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 789 | void PathVerifier::VerifyPolicies(const ParsedCertificate &cert, |
| 790 | bool is_target_cert, CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 791 | // From RFC 5280 section 6.1.3: |
| 792 | // |
| 793 | // (d) If the certificate policies extension is present in the |
| 794 | // certificate and the valid_policy_tree is not NULL, process |
| 795 | // the policy information by performing the following steps in |
| 796 | // order: |
| 797 | if (cert.has_policy_oids() && !valid_policy_graph_.IsNull()) { |
| 798 | ValidPolicyGraph::LevelDetails previous_level = |
| 799 | valid_policy_graph_.StartLevel(); |
| 800 | |
| 801 | // (1) For each policy P not equal to anyPolicy in the |
| 802 | // certificate policies extension, let P-OID denote the OID |
| 803 | // for policy P and P-Q denote the qualifier set for policy |
| 804 | // P. Perform the following steps in order: |
| 805 | bool cert_has_any_policy = false; |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 806 | for (der::Input p_oid : cert.policy_oids()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 807 | if (p_oid == der::Input(kAnyPolicyOid)) { |
| 808 | cert_has_any_policy = true; |
| 809 | continue; |
| 810 | } |
| 811 | |
| 812 | // (i) For each node of depth i-1 in the valid_policy_tree |
| 813 | // where P-OID is in the expected_policy_set, create a |
| 814 | // child node as follows: set the valid_policy to P-OID, |
| 815 | // set the qualifier_set to P-Q, and set the |
| 816 | // expected_policy_set to {P-OID}. |
| 817 | auto iter = previous_level.expected_policy_map.find(p_oid); |
| 818 | if (iter != previous_level.expected_policy_map.end()) { |
| 819 | valid_policy_graph_.AddNode( |
| 820 | p_oid, /*parent_policies=*/std::move(iter->second)); |
| 821 | previous_level.expected_policy_map.erase(iter); |
| 822 | } else if (previous_level.has_any_policy) { |
| 823 | // (ii) If there was no match in step (i) and the |
| 824 | // valid_policy_tree includes a node of depth i-1 with |
| 825 | // the valid_policy anyPolicy, generate a child node with |
| 826 | // the following values: set the valid_policy to P-OID, |
| 827 | // set the qualifier_set to P-Q, and set the |
| 828 | // expected_policy_set to {P-OID}. |
| 829 | valid_policy_graph_.AddNodeWithParentAnyPolicy(p_oid); |
| 830 | } |
| 831 | } |
| 832 | |
| 833 | // (2) If the certificate policies extension includes the policy |
| 834 | // anyPolicy with the qualifier set AP-Q and either (a) |
| 835 | // inhibit_anyPolicy is greater than 0 or (b) i<n and the |
| 836 | // certificate is self-issued, then: |
| 837 | // |
| 838 | // For each node in the valid_policy_tree of depth i-1, for |
| 839 | // each value in the expected_policy_set (including |
| 840 | // anyPolicy) that does not appear in a child node, create a |
| 841 | // child node with the following values: set the valid_policy |
| 842 | // to the value from the expected_policy_set in the parent |
| 843 | // node, set the qualifier_set to AP-Q, and set the |
| 844 | // expected_policy_set to the value in the valid_policy from |
| 845 | // this node. |
| 846 | if (cert_has_any_policy && ((inhibit_any_policy_ > 0) || |
| 847 | (!is_target_cert && IsSelfIssued(cert)))) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 848 | for (auto &[p_oid, parent_policies] : |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 849 | previous_level.expected_policy_map) { |
| 850 | valid_policy_graph_.AddNode(p_oid, std::move(parent_policies)); |
| 851 | } |
| 852 | if (previous_level.has_any_policy) { |
| 853 | valid_policy_graph_.AddAnyPolicyNode(); |
| 854 | } |
| 855 | } |
| 856 | |
| 857 | // (3) If there is a node in the valid_policy_tree of depth i-1 |
| 858 | // or less without any child nodes, delete that node. Repeat |
| 859 | // this step until there are no nodes of depth i-1 or less |
| 860 | // without children. |
| 861 | // |
| 862 | // This implementation does this as part of GetUserConstrainedPolicySet(). |
| 863 | // Only the current level needs to be pruned to compute the policy graph. |
| 864 | } |
| 865 | |
| 866 | // (e) If the certificate policies extension is not present, set the |
| 867 | // valid_policy_tree to NULL. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 868 | if (!cert.has_policy_oids()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 869 | valid_policy_graph_.SetNull(); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 870 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 871 | |
| 872 | // (f) Verify that either explicit_policy is greater than 0 or the |
| 873 | // valid_policy_tree is not equal to NULL; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 874 | if (!((explicit_policy_ > 0) || !valid_policy_graph_.IsNull())) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 875 | errors->AddError(cert_errors::kNoValidPolicy); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 876 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 877 | } |
| 878 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 879 | void PathVerifier::VerifyPolicyMappings(const ParsedCertificate &cert, |
| 880 | CertErrors *errors) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 881 | if (!cert.has_policy_mappings()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 882 | return; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 883 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 884 | |
| 885 | // From RFC 5280 section 6.1.4: |
| 886 | // |
| 887 | // (a) If a policy mappings extension is present, verify that the |
| 888 | // special value anyPolicy does not appear as an |
| 889 | // issuerDomainPolicy or a subjectDomainPolicy. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 890 | for (const ParsedPolicyMapping &mapping : cert.policy_mappings()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 891 | if (mapping.issuer_domain_policy == der::Input(kAnyPolicyOid) || |
| 892 | mapping.subject_domain_policy == der::Input(kAnyPolicyOid)) { |
| 893 | // Because this implementation continues processing certificates after |
| 894 | // this error, clear the valid policy graph to ensure the |
| 895 | // "user_constrained_policy_set" output upon failure is empty. |
| 896 | valid_policy_graph_.SetNull(); |
| 897 | errors->AddError(cert_errors::kPolicyMappingAnyPolicy); |
| 898 | return; |
| 899 | } |
| 900 | } |
| 901 | |
| 902 | // (b) If a policy mappings extension is present, then for each |
| 903 | // issuerDomainPolicy ID-P in the policy mappings extension: |
| 904 | // |
| 905 | // (1) If the policy_mapping variable is greater than 0, for each |
| 906 | // node in the valid_policy_tree of depth i where ID-P is the |
| 907 | // valid_policy, set expected_policy_set to the set of |
| 908 | // subjectDomainPolicy values that are specified as |
| 909 | // equivalent to ID-P by the policy mappings extension. |
| 910 | // |
| 911 | // If no node of depth i in the valid_policy_tree has a |
| 912 | // valid_policy of ID-P but there is a node of depth i with a |
| 913 | // valid_policy of anyPolicy, then generate a child node of |
| 914 | // the node of depth i-1 that has a valid_policy of anyPolicy |
| 915 | // as follows: |
| 916 | // |
| 917 | // (i) set the valid_policy to ID-P; |
| 918 | // |
| 919 | // (ii) set the qualifier_set to the qualifier set of the |
| 920 | // policy anyPolicy in the certificate policies |
| 921 | // extension of certificate i; and |
| 922 | // |
| 923 | // (iii) set the expected_policy_set to the set of |
| 924 | // subjectDomainPolicy values that are specified as |
| 925 | // equivalent to ID-P by the policy mappings extension. |
| 926 | // |
| 927 | if (policy_mapping_ > 0) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 928 | for (const ParsedPolicyMapping &mapping : cert.policy_mappings()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 929 | valid_policy_graph_.AddPolicyMapping(mapping.issuer_domain_policy, |
| 930 | mapping.subject_domain_policy); |
| 931 | } |
| 932 | } |
| 933 | |
| 934 | // (b) If a policy mappings extension is present, then for each |
| 935 | // issuerDomainPolicy ID-P in the policy mappings extension: |
| 936 | // |
| 937 | // ... |
| 938 | // |
| 939 | // (2) If the policy_mapping variable is equal to 0: |
| 940 | // |
| 941 | // (i) delete each node of depth i in the valid_policy_tree |
| 942 | // where ID-P is the valid_policy. |
| 943 | // |
| 944 | // (ii) If there is a node in the valid_policy_tree of depth |
| 945 | // i-1 or less without any child nodes, delete that |
| 946 | // node. Repeat this step until there are no nodes of |
| 947 | // depth i-1 or less without children. |
| 948 | // |
| 949 | // Step (ii) is deferred to part of GetUserConstrainedPolicySet(). |
| 950 | if (policy_mapping_ == 0) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 951 | for (const ParsedPolicyMapping &mapping : cert.policy_mappings()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 952 | valid_policy_graph_.DeleteNode(mapping.issuer_domain_policy); |
| 953 | } |
| 954 | } |
| 955 | } |
| 956 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 957 | void PathVerifier::ApplyPolicyConstraints(const ParsedCertificate &cert) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 958 | // RFC 5280 section 6.1.4 step i-j: |
| 959 | // (i) If a policy constraints extension is included in the |
| 960 | // certificate, modify the explicit_policy and policy_mapping |
| 961 | // state variables as follows: |
| 962 | if (cert.has_policy_constraints()) { |
| 963 | // (1) If requireExplicitPolicy is present and is less than |
| 964 | // explicit_policy, set explicit_policy to the value of |
| 965 | // requireExplicitPolicy. |
| 966 | if (cert.policy_constraints().require_explicit_policy && |
| 967 | cert.policy_constraints().require_explicit_policy.value() < |
| 968 | explicit_policy_) { |
| 969 | explicit_policy_ = |
| 970 | cert.policy_constraints().require_explicit_policy.value(); |
| 971 | } |
| 972 | |
| 973 | // (2) If inhibitPolicyMapping is present and is less than |
| 974 | // policy_mapping, set policy_mapping to the value of |
| 975 | // inhibitPolicyMapping. |
| 976 | if (cert.policy_constraints().inhibit_policy_mapping && |
| 977 | cert.policy_constraints().inhibit_policy_mapping.value() < |
| 978 | policy_mapping_) { |
| 979 | policy_mapping_ = |
| 980 | cert.policy_constraints().inhibit_policy_mapping.value(); |
| 981 | } |
| 982 | } |
| 983 | |
| 984 | // (j) If the inhibitAnyPolicy extension is included in the |
| 985 | // certificate and is less than inhibit_anyPolicy, set |
| 986 | // inhibit_anyPolicy to the value of inhibitAnyPolicy. |
Bob Beck | d24a382 | 2023-09-26 17:06:37 -0600 | [diff] [blame] | 987 | if (cert.inhibit_any_policy() && |
| 988 | cert.inhibit_any_policy().value() < inhibit_any_policy_) { |
| 989 | inhibit_any_policy_ = cert.inhibit_any_policy().value(); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 990 | } |
| 991 | } |
| 992 | |
| 993 | void PathVerifier::BasicCertificateProcessing( |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 994 | const ParsedCertificate &cert, bool is_target_cert, |
| 995 | bool is_target_cert_issuer, const der::GeneralizedTime &time, |
| 996 | KeyPurpose required_key_purpose, CertErrors *errors, |
| 997 | bool *shortcircuit_chain_validation) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 998 | *shortcircuit_chain_validation = false; |
| 999 | // Check that the signature algorithms in Certificate vs TBSCertificate |
| 1000 | // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by |
| 1001 | // sections 4.1.1.2 and 4.1.2.3. |
| 1002 | if (!VerifySignatureAlgorithmsMatch(cert, errors)) { |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 1003 | BSSL_CHECK(errors->ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH)); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1004 | *shortcircuit_chain_validation = true; |
| 1005 | } |
| 1006 | |
| 1007 | // Check whether this signature algorithm is allowed. |
| 1008 | if (!cert.signature_algorithm().has_value() || |
| 1009 | !delegate_->IsSignatureAlgorithmAcceptable(*cert.signature_algorithm(), |
| 1010 | errors)) { |
| 1011 | *shortcircuit_chain_validation = true; |
| 1012 | errors->AddError(cert_errors::kUnacceptableSignatureAlgorithm); |
| 1013 | return; |
| 1014 | } |
| 1015 | |
| 1016 | if (working_public_key_) { |
| 1017 | // Verify the digital signature using the previous certificate's key (RFC |
| 1018 | // 5280 section 6.1.3 step a.1). |
| 1019 | if (!VerifySignedData(*cert.signature_algorithm(), |
| 1020 | cert.tbs_certificate_tlv(), cert.signature_value(), |
| 1021 | working_public_key_.get(), |
| 1022 | delegate_->GetVerifyCache())) { |
| 1023 | *shortcircuit_chain_validation = true; |
| 1024 | errors->AddError(cert_errors::kVerifySignedDataFailed); |
| 1025 | } |
| 1026 | } |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1027 | if (*shortcircuit_chain_validation) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1028 | return; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1029 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1030 | |
| 1031 | // Check the time range for the certificate's validity, ensuring it is valid |
| 1032 | // at |time|. |
| 1033 | // (RFC 5280 section 6.1.3 step a.2) |
| 1034 | VerifyTimeValidity(cert, time, errors); |
| 1035 | |
| 1036 | // RFC 5280 section 6.1.3 step a.3 calls for checking the certificate's |
| 1037 | // revocation status here. In this implementation revocation checking is |
| 1038 | // implemented separately from path validation. |
| 1039 | |
| 1040 | // Verify the certificate's issuer name matches the issuing certificate's |
| 1041 | // subject name. (RFC 5280 section 6.1.3 step a.4) |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1042 | if (cert.normalized_issuer() != working_normalized_issuer_name_) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1043 | errors->AddError(cert_errors::kSubjectDoesNotMatchIssuer); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1044 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1045 | |
| 1046 | // Name constraints (RFC 5280 section 6.1.3 step b & c) |
| 1047 | // If certificate i is self-issued and it is not the final certificate in the |
| 1048 | // path, skip this step for certificate i. |
| 1049 | if (!name_constraints_list_.empty() && |
| 1050 | (!IsSelfIssued(cert) || is_target_cert)) { |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1051 | for (const NameConstraints *nc : name_constraints_list_) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1052 | nc->IsPermittedCert(cert.normalized_subject(), cert.subject_alt_names(), |
| 1053 | errors); |
| 1054 | } |
| 1055 | } |
| 1056 | |
| 1057 | // RFC 5280 section 6.1.3 step d - f. |
| 1058 | VerifyPolicies(cert, is_target_cert, errors); |
| 1059 | |
| 1060 | // The key purpose is checked not just for the end-entity certificate, but |
| 1061 | // also interpreted as a constraint when it appears in intermediates. This |
| 1062 | // goes beyond what RFC 5280 describes, but is the de-facto standard. See |
| 1063 | // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions |
| 1064 | VerifyExtendedKeyUsage(cert, required_key_purpose, errors, is_target_cert, |
| 1065 | is_target_cert_issuer); |
| 1066 | } |
| 1067 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1068 | void PathVerifier::PrepareForNextCertificate(const ParsedCertificate &cert, |
| 1069 | CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1070 | // RFC 5280 section 6.1.4 step a-b |
| 1071 | VerifyPolicyMappings(cert, errors); |
| 1072 | |
| 1073 | // From RFC 5280 section 6.1.4 step c: |
| 1074 | // |
| 1075 | // Assign the certificate subject name to working_normalized_issuer_name. |
| 1076 | working_normalized_issuer_name_ = cert.normalized_subject(); |
| 1077 | |
| 1078 | // From RFC 5280 section 6.1.4 step d: |
| 1079 | // |
| 1080 | // Assign the certificate subjectPublicKey to working_public_key. |
| 1081 | working_public_key_ = ParseAndCheckPublicKey(cert.tbs().spki_tlv, errors); |
| 1082 | |
| 1083 | // Note that steps e and f are omitted as they are handled by |
| 1084 | // the assignment to |working_spki| above. See the definition |
| 1085 | // of |working_spki|. |
| 1086 | |
| 1087 | // From RFC 5280 section 6.1.4 step g: |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1088 | if (cert.has_name_constraints()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1089 | name_constraints_list_.push_back(&cert.name_constraints()); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1090 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1091 | |
| 1092 | // (h) If certificate i is not self-issued: |
| 1093 | if (!IsSelfIssued(cert)) { |
| 1094 | // (1) If explicit_policy is not 0, decrement explicit_policy by |
| 1095 | // 1. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1096 | if (explicit_policy_ > 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1097 | explicit_policy_ -= 1; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1098 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1099 | |
| 1100 | // (2) If policy_mapping is not 0, decrement policy_mapping by 1. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1101 | if (policy_mapping_ > 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1102 | policy_mapping_ -= 1; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1103 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1104 | |
| 1105 | // (3) If inhibit_anyPolicy is not 0, decrement inhibit_anyPolicy |
| 1106 | // by 1. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1107 | if (inhibit_any_policy_ > 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1108 | inhibit_any_policy_ -= 1; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1109 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1110 | } |
| 1111 | |
| 1112 | // RFC 5280 section 6.1.4 step i-j: |
| 1113 | ApplyPolicyConstraints(cert); |
| 1114 | |
| 1115 | // From RFC 5280 section 6.1.4 step k: |
| 1116 | // |
| 1117 | // If certificate i is a version 3 certificate, verify that the |
| 1118 | // basicConstraints extension is present and that cA is set to |
| 1119 | // TRUE. (If certificate i is a version 1 or version 2 |
| 1120 | // certificate, then the application MUST either verify that |
| 1121 | // certificate i is a CA certificate through out-of-band means |
| 1122 | // or reject the certificate. Conforming implementations may |
| 1123 | // choose to reject all version 1 and version 2 intermediate |
| 1124 | // certificates.) |
| 1125 | // |
| 1126 | // This code implicitly rejects non version 3 intermediates, since they |
| 1127 | // can't contain a BasicConstraints extension. |
| 1128 | if (!cert.has_basic_constraints()) { |
| 1129 | errors->AddError(cert_errors::kMissingBasicConstraints); |
| 1130 | } else if (!cert.basic_constraints().is_ca) { |
| 1131 | errors->AddError(cert_errors::kBasicConstraintsIndicatesNotCa); |
| 1132 | } |
| 1133 | |
| 1134 | // From RFC 5280 section 6.1.4 step l: |
| 1135 | // |
| 1136 | // If the certificate was not self-issued, verify that |
| 1137 | // max_path_length is greater than zero and decrement |
| 1138 | // max_path_length by 1. |
| 1139 | if (!IsSelfIssued(cert)) { |
| 1140 | if (max_path_length_ == 0) { |
| 1141 | errors->AddError(cert_errors::kMaxPathLengthViolated); |
| 1142 | } else { |
| 1143 | --max_path_length_; |
| 1144 | } |
| 1145 | } |
| 1146 | |
| 1147 | // From RFC 5280 section 6.1.4 step m: |
| 1148 | // |
| 1149 | // If pathLenConstraint is present in the certificate and is |
| 1150 | // less than max_path_length, set max_path_length to the value |
| 1151 | // of pathLenConstraint. |
| 1152 | if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len && |
| 1153 | cert.basic_constraints().path_len < max_path_length_) { |
| 1154 | max_path_length_ = cert.basic_constraints().path_len; |
| 1155 | } |
| 1156 | |
| 1157 | // From RFC 5280 section 6.1.4 step n: |
| 1158 | // |
| 1159 | // If a key usage extension is present, verify that the |
| 1160 | // keyCertSign bit is set. |
| 1161 | if (cert.has_key_usage() && |
| 1162 | !cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { |
| 1163 | errors->AddError(cert_errors::kKeyCertSignBitNotSet); |
| 1164 | } |
| 1165 | |
| 1166 | // From RFC 5280 section 6.1.4 step o: |
| 1167 | // |
| 1168 | // Recognize and process any other critical extension present in |
| 1169 | // the certificate. Process any other recognized non-critical |
| 1170 | // extension present in the certificate that is relevant to path |
| 1171 | // processing. |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1172 | VerifyNoUnconsumedCriticalExtensions(cert, errors, |
| 1173 | delegate_->AcceptPreCertificates()); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1174 | } |
| 1175 | |
| 1176 | // Checks if the target certificate has the CA bit set. If it does, add |
| 1177 | // the appropriate error or warning to |errors|. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1178 | void VerifyTargetCertIsNotCA(const ParsedCertificate &cert, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1179 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1180 | CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1181 | if (cert.has_basic_constraints() && cert.basic_constraints().is_ca) { |
| 1182 | // In spite of RFC 5280 4.2.1.9 which says the CA properties MAY exist in |
| 1183 | // an end entity certificate, the CABF Baseline Requirements version |
| 1184 | // 1.8.4, 7.1.2.3(d) prohibit the CA bit being set in an end entity |
| 1185 | // certificate. |
| 1186 | switch (required_key_purpose) { |
| 1187 | case KeyPurpose::ANY_EKU: |
| 1188 | break; |
| 1189 | case KeyPurpose::SERVER_AUTH: |
| 1190 | case KeyPurpose::CLIENT_AUTH: |
| 1191 | errors->AddWarning(cert_errors::kTargetCertShouldNotBeCa); |
| 1192 | break; |
| 1193 | case KeyPurpose::SERVER_AUTH_STRICT: |
| 1194 | case KeyPurpose::CLIENT_AUTH_STRICT: |
| 1195 | errors->AddError(cert_errors::kTargetCertShouldNotBeCa); |
| 1196 | break; |
| 1197 | } |
| 1198 | } |
| 1199 | } |
| 1200 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1201 | void PathVerifier::WrapUp(const ParsedCertificate &cert, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1202 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1203 | const std::set<der::Input> &user_initial_policy_set, |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1204 | bool allow_precertificate, |
| 1205 | CertErrors * errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1206 | // From RFC 5280 section 6.1.5: |
| 1207 | // (a) If explicit_policy is not 0, decrement explicit_policy by 1. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1208 | if (explicit_policy_ > 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1209 | explicit_policy_ -= 1; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1210 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1211 | |
| 1212 | // (b) If a policy constraints extension is included in the |
| 1213 | // certificate and requireExplicitPolicy is present and has a |
| 1214 | // value of 0, set the explicit_policy state variable to 0. |
| 1215 | if (cert.has_policy_constraints() && |
| 1216 | cert.policy_constraints().require_explicit_policy.has_value() && |
| 1217 | cert.policy_constraints().require_explicit_policy == 0) { |
| 1218 | explicit_policy_ = 0; |
| 1219 | } |
| 1220 | |
| 1221 | // Note step c-e are omitted as the verification function does |
| 1222 | // not output the working public key. |
| 1223 | |
| 1224 | // From RFC 5280 section 6.1.5 step f: |
| 1225 | // |
| 1226 | // Recognize and process any other critical extension present in |
| 1227 | // the certificate n. Process any other recognized non-critical |
| 1228 | // extension present in certificate n that is relevant to path |
| 1229 | // processing. |
| 1230 | // |
| 1231 | // Note that this is duplicated by PrepareForNextCertificate() so as to |
| 1232 | // directly match the procedures in RFC 5280's section 6.1. |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1233 | VerifyNoUnconsumedCriticalExtensions(cert, errors, allow_precertificate); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1234 | |
| 1235 | // This calculates the intersection from RFC 5280 section 6.1.5 step g, as |
| 1236 | // well as applying the deferred recursive node that were skipped earlier in |
| 1237 | // the process. |
| 1238 | user_constrained_policy_set_ = |
| 1239 | valid_policy_graph_.GetUserConstrainedPolicySet(user_initial_policy_set); |
| 1240 | |
| 1241 | // From RFC 5280 section 6.1.5 step g: |
| 1242 | // |
| 1243 | // If either (1) the value of explicit_policy variable is greater than |
| 1244 | // zero or (2) the valid_policy_tree is not NULL, then path processing |
| 1245 | // has succeeded. |
| 1246 | if (explicit_policy_ == 0 && user_constrained_policy_set_.empty()) { |
| 1247 | errors->AddError(cert_errors::kNoValidPolicy); |
| 1248 | } |
| 1249 | |
| 1250 | // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", |
| 1251 | // however is implied by RFC 5280 section 4.2.1.9, as well as CABF Base |
| 1252 | // Requirements. |
| 1253 | VerifyTargetCertIsNotCA(cert, required_key_purpose, errors); |
| 1254 | |
| 1255 | // Check the public key for the target certificate. The public key for the |
| 1256 | // other certificates is already checked by PrepareForNextCertificate(). |
| 1257 | // Note that this step is not part of RFC 5280 6.1.5. |
| 1258 | ParseAndCheckPublicKey(cert.tbs().spki_tlv, errors); |
| 1259 | } |
| 1260 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1261 | void PathVerifier::ApplyTrustAnchorConstraints(const ParsedCertificate &cert, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1262 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1263 | CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1264 | // If certificatePolicies is present, process the policies. This matches the |
| 1265 | // handling for intermediates from RFC 5280 section 6.1.3.d (except that for |
| 1266 | // intermediates it is non-optional). It intentionally deviates from RFC 5937 |
| 1267 | // section 3.2 which says to intersect with user-initial-policy-set, since |
| 1268 | // processing as part of user-initial-policy-set has subtly different |
| 1269 | // semantics from being handled as part of the chain processing (see |
| 1270 | // https://crbug.com/1403258). |
| 1271 | if (cert.has_policy_oids()) { |
| 1272 | VerifyPolicies(cert, /*is_target_cert=*/false, errors); |
| 1273 | } |
| 1274 | |
| 1275 | // Process policyMappings, if present. This matches the handling for |
| 1276 | // intermediates from RFC 5280 section 6.1.4 step a-b. |
| 1277 | VerifyPolicyMappings(cert, errors); |
| 1278 | |
| 1279 | // Process policyConstraints and inhibitAnyPolicy. This matches the |
| 1280 | // handling for intermediates from RFC 5280 section 6.1.4 step i-j. |
| 1281 | // This intentionally deviates from RFC 5937 section 3.2 which says to |
| 1282 | // initialize the initial-any-policy-inhibit, initial-explicit-policy, and/or |
| 1283 | // initial-policy-mapping-inhibit inputs to verification. Those are all |
| 1284 | // bools, so they cannot properly represent the constraints encoded in the |
| 1285 | // policyConstraints and inhibitAnyPolicy extensions. |
| 1286 | ApplyPolicyConstraints(cert); |
| 1287 | |
| 1288 | // If keyUsage is present, verify that |cert| has correct keyUsage bits for a |
| 1289 | // CA. This matches the handling for intermediates from RFC 5280 section |
| 1290 | // 6.1.4 step n. |
| 1291 | if (cert.has_key_usage() && |
| 1292 | !cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { |
| 1293 | errors->AddError(cert_errors::kKeyCertSignBitNotSet); |
| 1294 | } |
| 1295 | |
| 1296 | // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling |
| 1297 | // done for intermediates (described in Web PKI's Baseline Requirements). |
| 1298 | VerifyExtendedKeyUsage(cert, required_key_purpose, errors, |
| 1299 | /*is_target_cert=*/false, |
| 1300 | /*is_target_cert_issuer=*/false); |
| 1301 | |
| 1302 | // The following enforcements follow from RFC 5937 (primarily section 3.2): |
| 1303 | |
| 1304 | // Initialize name constraints initial-permitted/excluded-subtrees. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1305 | if (cert.has_name_constraints()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1306 | name_constraints_list_.push_back(&cert.name_constraints()); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1307 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1308 | |
| 1309 | if (cert.has_basic_constraints()) { |
| 1310 | // Enforce CA=true if basicConstraints is present. This matches behavior of |
| 1311 | // other verifiers, and seems like a good thing to do to avoid a |
| 1312 | // certificate being used in the wrong context if it was specifically |
| 1313 | // marked as not being a CA. |
| 1314 | if (!cert.basic_constraints().is_ca) { |
| 1315 | errors->AddError(cert_errors::kBasicConstraintsIndicatesNotCa); |
| 1316 | } |
| 1317 | // From RFC 5937 section 3.2: |
| 1318 | // |
| 1319 | // If a basic constraints extension is associated with the trust |
| 1320 | // anchor and contains a pathLenConstraint value, set the |
| 1321 | // max_path_length state variable equal to the pathLenConstraint |
| 1322 | // value from the basic constraints extension. |
| 1323 | // |
| 1324 | if (cert.basic_constraints().has_path_len) { |
| 1325 | max_path_length_ = cert.basic_constraints().path_len; |
| 1326 | } |
| 1327 | } |
| 1328 | |
| 1329 | // From RFC 5937 section 2: |
| 1330 | // |
| 1331 | // Extensions may be marked critical or not critical. When trust anchor |
| 1332 | // constraints are enforced, clients MUST reject certification paths |
| 1333 | // containing a trust anchor with unrecognized critical extensions. |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1334 | VerifyNoUnconsumedCriticalExtensions(cert, errors, |
| 1335 | /*allow_precertificate=*/false); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1336 | } |
| 1337 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1338 | void PathVerifier::ProcessRootCertificate(const ParsedCertificate &cert, |
| 1339 | const CertificateTrust &trust, |
| 1340 | const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1341 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1342 | CertErrors *errors, |
| 1343 | bool *shortcircuit_chain_validation) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1344 | *shortcircuit_chain_validation = false; |
| 1345 | switch (trust.type) { |
| 1346 | case CertificateTrustType::UNSPECIFIED: |
| 1347 | case CertificateTrustType::TRUSTED_LEAF: |
| 1348 | // Doesn't chain to a trust anchor - implicitly distrusted |
| 1349 | errors->AddError(cert_errors::kCertIsNotTrustAnchor); |
| 1350 | *shortcircuit_chain_validation = true; |
| 1351 | break; |
| 1352 | case CertificateTrustType::DISTRUSTED: |
| 1353 | // Chains to an actively distrusted certificate. |
| 1354 | errors->AddError(cert_errors::kDistrustedByTrustStore); |
| 1355 | *shortcircuit_chain_validation = true; |
| 1356 | break; |
| 1357 | case CertificateTrustType::TRUSTED_ANCHOR: |
| 1358 | case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF: |
| 1359 | break; |
| 1360 | } |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1361 | if (*shortcircuit_chain_validation) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1362 | return; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1363 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1364 | |
| 1365 | if (trust.enforce_anchor_expiry) { |
| 1366 | VerifyTimeValidity(cert, time, errors); |
| 1367 | } |
| 1368 | if (trust.enforce_anchor_constraints) { |
| 1369 | if (trust.require_anchor_basic_constraints && |
| 1370 | !cert.has_basic_constraints()) { |
| 1371 | switch (cert.tbs().version) { |
| 1372 | case CertificateVersion::V1: |
| 1373 | case CertificateVersion::V2: |
| 1374 | break; |
| 1375 | case CertificateVersion::V3: |
| 1376 | errors->AddError(cert_errors::kMissingBasicConstraints); |
| 1377 | break; |
| 1378 | } |
| 1379 | } |
| 1380 | ApplyTrustAnchorConstraints(cert, required_key_purpose, errors); |
| 1381 | } |
| 1382 | |
| 1383 | // Use the certificate's SPKI and subject when verifying the next certificate. |
| 1384 | working_public_key_ = ParseAndCheckPublicKey(cert.tbs().spki_tlv, errors); |
| 1385 | working_normalized_issuer_name_ = cert.normalized_subject(); |
| 1386 | } |
| 1387 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1388 | void PathVerifier::ProcessSingleCertChain(const ParsedCertificate &cert, |
| 1389 | const CertificateTrust &trust, |
| 1390 | const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1391 | KeyPurpose required_key_purpose, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1392 | CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1393 | switch (trust.type) { |
| 1394 | case CertificateTrustType::UNSPECIFIED: |
| 1395 | case CertificateTrustType::TRUSTED_ANCHOR: |
| 1396 | // Target doesn't have a chain and isn't a directly trusted leaf - |
| 1397 | // implicitly distrusted. |
| 1398 | errors->AddError(cert_errors::kCertIsNotTrustAnchor); |
| 1399 | return; |
| 1400 | case CertificateTrustType::DISTRUSTED: |
| 1401 | // Target is directly distrusted. |
| 1402 | errors->AddError(cert_errors::kDistrustedByTrustStore); |
| 1403 | return; |
| 1404 | case CertificateTrustType::TRUSTED_LEAF: |
| 1405 | case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF: |
| 1406 | break; |
| 1407 | } |
| 1408 | |
| 1409 | // Check the public key for the target certificate regardless of whether |
| 1410 | // `require_leaf_selfsigned` is true. This matches the check in WrapUp and |
| 1411 | // fulfills the documented behavior of the IsPublicKeyAcceptable delegate. |
| 1412 | ParseAndCheckPublicKey(cert.tbs().spki_tlv, errors); |
| 1413 | |
| 1414 | if (trust.require_leaf_selfsigned) { |
| 1415 | if (!VerifyCertificateIsSelfSigned(cert, delegate_->GetVerifyCache(), |
| 1416 | errors)) { |
| 1417 | // VerifyCertificateIsSelfSigned should have added an error, but just |
| 1418 | // double check to be safe. |
| 1419 | if (!errors->ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH)) { |
| 1420 | errors->AddError(cert_errors::kInternalError); |
| 1421 | } |
| 1422 | return; |
| 1423 | } |
| 1424 | } |
| 1425 | |
| 1426 | // There is no standard for what it means to verify a directly trusted leaf |
| 1427 | // certificate, so this is basically just checking common sense things that |
| 1428 | // also mirror what we observed to be enforced with the Operating System |
| 1429 | // native verifiers. |
| 1430 | VerifyTimeValidity(cert, time, errors); |
| 1431 | VerifyExtendedKeyUsage(cert, required_key_purpose, errors, |
| 1432 | /*is_target_cert=*/true, |
| 1433 | /*is_target_cert_issuer=*/false); |
| 1434 | |
| 1435 | // Checking for unknown critical extensions matches Windows, but is stricter |
| 1436 | // than the Mac verifier. |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1437 | VerifyNoUnconsumedCriticalExtensions(cert, errors, |
| 1438 | /*allow_precertificate=*/false); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1439 | } |
| 1440 | |
| 1441 | bssl::UniquePtr<EVP_PKEY> PathVerifier::ParseAndCheckPublicKey( |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 1442 | der::Input spki, CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1443 | // Parse the public key. |
| 1444 | bssl::UniquePtr<EVP_PKEY> pkey; |
| 1445 | if (!ParsePublicKey(spki, &pkey)) { |
| 1446 | errors->AddError(cert_errors::kFailedParsingSpki); |
| 1447 | return nullptr; |
| 1448 | } |
| 1449 | |
| 1450 | // Check if the key is acceptable by the delegate. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1451 | if (!delegate_->IsPublicKeyAcceptable(pkey.get(), errors)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1452 | errors->AddError(cert_errors::kUnacceptablePublicKey); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 1453 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1454 | |
| 1455 | return pkey; |
| 1456 | } |
| 1457 | |
| 1458 | void PathVerifier::Run( |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1459 | const ParsedCertificateList &certs, const CertificateTrust &last_cert_trust, |
| 1460 | VerifyCertificateChainDelegate *delegate, const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1461 | KeyPurpose required_key_purpose, |
| 1462 | InitialExplicitPolicy initial_explicit_policy, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1463 | const std::set<der::Input> &user_initial_policy_set, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1464 | InitialPolicyMappingInhibit initial_policy_mapping_inhibit, |
| 1465 | InitialAnyPolicyInhibit initial_any_policy_inhibit, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1466 | std::set<der::Input> *user_constrained_policy_set, CertPathErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1467 | // This implementation is structured to mimic the description of certificate |
| 1468 | // path verification given by RFC 5280 section 6.1. |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 1469 | BSSL_CHECK(delegate); |
| 1470 | BSSL_CHECK(errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1471 | |
| 1472 | delegate_ = delegate; |
| 1473 | |
| 1474 | // An empty chain is necessarily invalid. |
| 1475 | if (certs.empty()) { |
| 1476 | errors->GetOtherErrors()->AddError(cert_errors::kChainIsEmpty); |
| 1477 | return; |
| 1478 | } |
| 1479 | |
| 1480 | // Verifying a trusted leaf certificate isn't a well-specified operation, so |
| 1481 | // it's handled separately from the RFC 5280 defined verification process. |
| 1482 | if (certs.size() == 1) { |
| 1483 | ProcessSingleCertChain(*certs.front(), last_cert_trust, time, |
| 1484 | required_key_purpose, errors->GetErrorsForCert(0)); |
| 1485 | return; |
| 1486 | } |
| 1487 | |
| 1488 | // RFC 5280's "n" variable is the length of the path, which does not count |
| 1489 | // the trust anchor. (Although in practice it doesn't really change behaviors |
| 1490 | // if n is used in place of n+1). |
| 1491 | const size_t n = certs.size() - 1; |
| 1492 | |
| 1493 | valid_policy_graph_.Init(); |
| 1494 | |
| 1495 | // RFC 5280 section section 6.1.2: |
| 1496 | // |
| 1497 | // If initial-explicit-policy is set, then the initial value |
| 1498 | // [of explicit_policy] is 0, otherwise the initial value is n+1. |
| 1499 | explicit_policy_ = |
| 1500 | initial_explicit_policy == InitialExplicitPolicy::kTrue ? 0 : n + 1; |
| 1501 | |
| 1502 | // RFC 5280 section section 6.1.2: |
| 1503 | // |
| 1504 | // If initial-any-policy-inhibit is set, then the initial value |
| 1505 | // [of inhibit_anyPolicy] is 0, otherwise the initial value is n+1. |
| 1506 | inhibit_any_policy_ = |
| 1507 | initial_any_policy_inhibit == InitialAnyPolicyInhibit::kTrue ? 0 : n + 1; |
| 1508 | |
| 1509 | // RFC 5280 section section 6.1.2: |
| 1510 | // |
| 1511 | // If initial-policy-mapping-inhibit is set, then the initial value |
| 1512 | // [of policy_mapping] is 0, otherwise the initial value is n+1. |
| 1513 | policy_mapping_ = |
| 1514 | initial_policy_mapping_inhibit == InitialPolicyMappingInhibit::kTrue |
| 1515 | ? 0 |
| 1516 | : n + 1; |
| 1517 | |
| 1518 | // RFC 5280 section section 6.1.2: |
| 1519 | // |
| 1520 | // max_path_length: this integer is initialized to n, ... |
| 1521 | max_path_length_ = n; |
| 1522 | |
| 1523 | // Iterate over all the certificates in the reverse direction: starting from |
| 1524 | // the root certificate and progressing towards the target certificate. |
| 1525 | // |
| 1526 | // * i=0 : Root certificate (i.e. trust anchor) |
| 1527 | // * i=1 : Certificate issued by root |
| 1528 | // * i=x : Certificate i=x is issued by certificate i=x-1 |
| 1529 | // * i=n : Target certificate. |
| 1530 | for (size_t i = 0; i < certs.size(); ++i) { |
| 1531 | const size_t index_into_certs = certs.size() - i - 1; |
| 1532 | |
| 1533 | // |is_target_cert| is true if the current certificate is the target |
| 1534 | // certificate being verified. The target certificate isn't necessarily an |
| 1535 | // end-entity certificate. |
| 1536 | const bool is_target_cert = index_into_certs == 0; |
| 1537 | const bool is_target_cert_issuer = index_into_certs == 1; |
| 1538 | const bool is_root_cert = i == 0; |
| 1539 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1540 | const ParsedCertificate &cert = *certs[index_into_certs]; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1541 | |
| 1542 | // Output errors for the current certificate into an error bucket that is |
| 1543 | // associated with that certificate. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1544 | CertErrors *cert_errors = errors->GetErrorsForCert(index_into_certs); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1545 | |
| 1546 | if (is_root_cert) { |
| 1547 | bool shortcircuit_chain_validation = false; |
| 1548 | ProcessRootCertificate(cert, last_cert_trust, time, required_key_purpose, |
| 1549 | cert_errors, &shortcircuit_chain_validation); |
| 1550 | if (shortcircuit_chain_validation) { |
| 1551 | // Chains that don't start from a trusted root should short-circuit the |
| 1552 | // rest of the verification, as accumulating more errors from untrusted |
| 1553 | // certificates would not be meaningful. |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 1554 | BSSL_CHECK(cert_errors->ContainsAnyErrorWithSeverity( |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1555 | CertError::SEVERITY_HIGH)); |
| 1556 | return; |
| 1557 | } |
| 1558 | |
| 1559 | // Don't do any other checks for root certificates. |
| 1560 | continue; |
| 1561 | } |
| 1562 | |
| 1563 | bool shortcircuit_chain_validation = false; |
| 1564 | // Per RFC 5280 section 6.1: |
| 1565 | // * Do basic processing for each certificate |
| 1566 | // * If it is the last certificate in the path (target certificate) |
| 1567 | // - Then run "Wrap up" |
| 1568 | // - Otherwise run "Prepare for Next cert" |
| 1569 | BasicCertificateProcessing(cert, is_target_cert, is_target_cert_issuer, |
| 1570 | time, required_key_purpose, cert_errors, |
| 1571 | &shortcircuit_chain_validation); |
| 1572 | if (shortcircuit_chain_validation) { |
| 1573 | // Signature errors should short-circuit the rest of the verification, as |
| 1574 | // accumulating more errors from untrusted certificates would not be |
| 1575 | // meaningful. |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 1576 | BSSL_CHECK( |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1577 | cert_errors->ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH)); |
| 1578 | return; |
| 1579 | } |
| 1580 | if (!is_target_cert) { |
| 1581 | PrepareForNextCertificate(cert, cert_errors); |
| 1582 | } else { |
Bob Beck | 324db64 | 2024-01-25 21:37:37 +0000 | [diff] [blame] | 1583 | WrapUp(cert, required_key_purpose, user_initial_policy_set, |
| 1584 | delegate->AcceptPreCertificates(), cert_errors); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1585 | } |
| 1586 | } |
| 1587 | |
| 1588 | if (user_constrained_policy_set) { |
| 1589 | *user_constrained_policy_set = user_constrained_policy_set_; |
| 1590 | } |
| 1591 | |
| 1592 | // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: |
| 1593 | // |
| 1594 | // A certificate MUST NOT appear more than once in a prospective |
| 1595 | // certification path. |
| 1596 | } |
| 1597 | |
| 1598 | } // namespace |
| 1599 | |
| 1600 | VerifyCertificateChainDelegate::~VerifyCertificateChainDelegate() = default; |
| 1601 | |
| 1602 | void VerifyCertificateChain( |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1603 | const ParsedCertificateList &certs, const CertificateTrust &last_cert_trust, |
| 1604 | VerifyCertificateChainDelegate *delegate, const der::GeneralizedTime &time, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1605 | KeyPurpose required_key_purpose, |
| 1606 | InitialExplicitPolicy initial_explicit_policy, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1607 | const std::set<der::Input> &user_initial_policy_set, |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1608 | InitialPolicyMappingInhibit initial_policy_mapping_inhibit, |
| 1609 | InitialAnyPolicyInhibit initial_any_policy_inhibit, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1610 | std::set<der::Input> *user_constrained_policy_set, CertPathErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1611 | PathVerifier verifier; |
| 1612 | verifier.Run(certs, last_cert_trust, delegate, time, required_key_purpose, |
| 1613 | initial_explicit_policy, user_initial_policy_set, |
| 1614 | initial_policy_mapping_inhibit, initial_any_policy_inhibit, |
| 1615 | user_constrained_policy_set, errors); |
| 1616 | } |
| 1617 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1618 | bool VerifyCertificateIsSelfSigned(const ParsedCertificate &cert, |
| 1619 | SignatureVerifyCache *cache, |
| 1620 | CertErrors *errors) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1621 | if (cert.normalized_subject() != cert.normalized_issuer()) { |
| 1622 | if (errors) { |
| 1623 | errors->AddError(cert_errors::kSubjectDoesNotMatchIssuer); |
| 1624 | } |
| 1625 | return false; |
| 1626 | } |
| 1627 | |
| 1628 | // Note that we do not restrict the available algorithms when determining if |
| 1629 | // something is a self-signed cert. The signature isn't very important on a |
| 1630 | // self-signed cert so just allow any supported algorithm here, to avoid |
| 1631 | // breakage. |
| 1632 | if (!cert.signature_algorithm().has_value()) { |
| 1633 | if (errors) { |
| 1634 | errors->AddError(cert_errors::kUnacceptableSignatureAlgorithm); |
| 1635 | } |
| 1636 | return false; |
| 1637 | } |
| 1638 | |
| 1639 | if (!VerifySignedData(*cert.signature_algorithm(), cert.tbs_certificate_tlv(), |
| 1640 | cert.signature_value(), cert.tbs().spki_tlv, cache)) { |
| 1641 | if (errors) { |
| 1642 | errors->AddError(cert_errors::kVerifySignedDataFailed); |
| 1643 | } |
| 1644 | return false; |
| 1645 | } |
| 1646 | |
| 1647 | return true; |
| 1648 | } |
| 1649 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 1650 | } // namespace bssl |