Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/internal/verify_certificate_chain.h" | 5 #include "net/cert/internal/verify_certificate_chain.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "net/cert/internal/cert_errors.h" | |
| 10 #include "net/cert/internal/name_constraints.h" | 11 #include "net/cert/internal/name_constraints.h" |
| 11 #include "net/cert/internal/parse_certificate.h" | 12 #include "net/cert/internal/parse_certificate.h" |
| 12 #include "net/cert/internal/signature_algorithm.h" | 13 #include "net/cert/internal/signature_algorithm.h" |
| 13 #include "net/cert/internal/signature_policy.h" | 14 #include "net/cert/internal/signature_policy.h" |
| 14 #include "net/cert/internal/trust_store.h" | 15 #include "net/cert/internal/trust_store.h" |
| 15 #include "net/cert/internal/verify_signed_data.h" | 16 #include "net/cert/internal/verify_signed_data.h" |
| 16 #include "net/der/input.h" | 17 #include "net/der/input.h" |
| 17 #include "net/der/parser.h" | 18 #include "net/der/parser.h" |
| 18 | 19 |
| 19 namespace net { | 20 namespace net { |
| 20 | 21 |
| 22 using namespace verify_certificate_chain_errors; | |
| 23 | |
| 21 namespace { | 24 namespace { |
| 22 | 25 |
| 23 // Returns true if the certificate does not contain any unconsumed _critical_ | 26 // Returns true if the certificate does not contain any unconsumed _critical_ |
| 24 // extensions. | 27 // extensions. |
| 25 WARN_UNUSED_RESULT bool VerifyNoUnconsumedCriticalExtensions( | 28 WARN_UNUSED_RESULT bool VerifyNoUnconsumedCriticalExtensions( |
| 26 const ParsedCertificate& cert) { | 29 const ParsedCertificate& cert, |
| 30 CertErrors* errors) { | |
| 31 bool has_unconsumed_critical_extensions = false; | |
| 32 | |
| 27 for (const auto& entry : cert.unparsed_extensions()) { | 33 for (const auto& entry : cert.unparsed_extensions()) { |
| 28 if (entry.second.critical) | 34 if (entry.second.critical) { |
| 29 return false; | 35 has_unconsumed_critical_extensions = true; |
| 36 errors->AddWith2DerParams(kUnconsumedCriticalExtension, entry.second.oid, | |
| 37 entry.second.value); | |
| 38 } | |
| 30 } | 39 } |
| 31 return true; | 40 |
| 41 return !has_unconsumed_critical_extensions; | |
| 32 } | 42 } |
| 33 | 43 |
| 34 // Returns true if |cert| was self-issued. The definition of self-issuance | 44 // Returns true if |cert| was self-issued. The definition of self-issuance |
| 35 // comes from RFC 5280 section 6.1: | 45 // comes from RFC 5280 section 6.1: |
| 36 // | 46 // |
| 37 // A certificate is self-issued if the same DN appears in the subject | 47 // A certificate is self-issued if the same DN appears in the subject |
| 38 // and issuer fields (the two DNs are the same if they match according | 48 // and issuer fields (the two DNs are the same if they match according |
| 39 // to the rules specified in Section 7.1). In general, the issuer and | 49 // to the rules specified in Section 7.1). In general, the issuer and |
| 40 // subject of the certificates that make up a path are different for | 50 // subject of the certificates that make up a path are different for |
| 41 // each certificate. However, a CA may issue a certificate to itself to | 51 // each certificate. However, a CA may issue a certificate to itself to |
| 42 // support key rollover or changes in certificate policies. These | 52 // support key rollover or changes in certificate policies. These |
| 43 // self-issued certificates are not counted when evaluating path length | 53 // self-issued certificates are not counted when evaluating path length |
| 44 // or name constraints. | 54 // or name constraints. |
| 45 WARN_UNUSED_RESULT bool IsSelfIssued(const ParsedCertificate& cert) { | 55 WARN_UNUSED_RESULT bool IsSelfIssued(const ParsedCertificate& cert) { |
| 46 return cert.normalized_subject() == cert.normalized_issuer(); | 56 return cert.normalized_subject() == cert.normalized_issuer(); |
| 47 } | 57 } |
| 48 | 58 |
| 49 // Returns true if |cert| is valid at time |time|. | 59 // Returns true if |cert| is valid at time |time|. |
| 50 // | 60 // |
| 51 // The certificate's validity requirements are described by RFC 5280 section | 61 // The certificate's validity requirements are described by RFC 5280 section |
| 52 // 4.1.2.5: | 62 // 4.1.2.5: |
| 53 // | 63 // |
| 54 // The validity period for a certificate is the period of time from | 64 // The validity period for a certificate is the period of time from |
| 55 // notBefore through notAfter, inclusive. | 65 // notBefore through notAfter, inclusive. |
| 56 WARN_UNUSED_RESULT bool VerifyTimeValidity(const ParsedCertificate& cert, | 66 WARN_UNUSED_RESULT bool VerifyTimeValidity(const ParsedCertificate& cert, |
| 57 const der::GeneralizedTime time) { | 67 const der::GeneralizedTime time, |
| 58 return !(time < cert.tbs().validity_not_before) && | 68 CertErrors* errors) { |
| 59 !(cert.tbs().validity_not_after < time); | 69 if (time < cert.tbs().validity_not_before) { |
| 70 errors->Add(kValidityFailedNotBefore); | |
| 71 return false; | |
| 72 } | |
| 73 | |
| 74 if (cert.tbs().validity_not_after < time) { | |
| 75 errors->Add(kValidityFailedNotAfter); | |
| 76 return false; | |
| 77 } | |
| 78 | |
| 79 return true; | |
| 60 } | 80 } |
| 61 | 81 |
| 62 // Returns true if |signature_algorithm_tlv| is a valid algorithm encoding for | 82 // Returns true if |signature_algorithm_tlv| is a valid algorithm encoding for |
| 63 // RSA with SHA1. | 83 // RSA with SHA1. |
| 64 WARN_UNUSED_RESULT bool IsRsaWithSha1SignatureAlgorithm( | 84 WARN_UNUSED_RESULT bool IsRsaWithSha1SignatureAlgorithm( |
| 65 const der::Input& signature_algorithm_tlv) { | 85 const der::Input& signature_algorithm_tlv) { |
| 66 std::unique_ptr<SignatureAlgorithm> algorithm = | 86 std::unique_ptr<SignatureAlgorithm> algorithm = |
| 67 SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv); | 87 SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv); |
| 68 | 88 |
| 69 return algorithm && | 89 return algorithm && |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 84 // signature field in the sequence tbsCertificate (Section 4.1.2.3). | 104 // signature field in the sequence tbsCertificate (Section 4.1.2.3). |
| 85 // | 105 // |
| 86 // The spec is not explicit about what "the same algorithm identifier" means. | 106 // The spec is not explicit about what "the same algorithm identifier" means. |
| 87 // Our interpretation is that the two DER-encoded fields must be byte-for-byte | 107 // Our interpretation is that the two DER-encoded fields must be byte-for-byte |
| 88 // identical. | 108 // identical. |
| 89 // | 109 // |
| 90 // In practice however there are certificates which use different encodings for | 110 // In practice however there are certificates which use different encodings for |
| 91 // specifying RSA with SHA1 (different OIDs). This is special-cased for | 111 // specifying RSA with SHA1 (different OIDs). This is special-cased for |
| 92 // compatibility sake. | 112 // compatibility sake. |
| 93 WARN_UNUSED_RESULT bool VerifySignatureAlgorithmsMatch( | 113 WARN_UNUSED_RESULT bool VerifySignatureAlgorithmsMatch( |
| 94 const ParsedCertificate& cert) { | 114 const ParsedCertificate& cert, |
| 115 CertErrors* errors) { | |
| 95 const der::Input& alg1_tlv = cert.signature_algorithm_tlv(); | 116 const der::Input& alg1_tlv = cert.signature_algorithm_tlv(); |
| 96 const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv; | 117 const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv; |
| 97 | 118 |
| 98 // Ensure that the two DER-encoded signature algorithms are byte-for-byte | 119 // Ensure that the two DER-encoded signature algorithms are byte-for-byte |
| 99 // equal, but make a compatibility concession for RSA with SHA1. | 120 // equal. |
| 100 return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) && | 121 if (alg1_tlv == alg2_tlv) |
| 101 IsRsaWithSha1SignatureAlgorithm(alg2_tlv)); | 122 return true; |
| 123 | |
| 124 // But make a compatibility concession for RSA with SHA1. | |
| 125 if (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) && | |
| 126 IsRsaWithSha1SignatureAlgorithm(alg2_tlv)) { | |
| 127 errors->AddWith2DerParams(kSignatureAlgorithmsDifferentEncoding, alg1_tlv, | |
| 128 alg2_tlv); | |
| 129 return true; | |
| 130 } | |
| 131 | |
| 132 errors->AddWith2DerParams(kSignatureAlgorithmMismatch, alg1_tlv, alg2_tlv); | |
| 133 | |
| 134 return false; | |
| 102 } | 135 } |
| 103 | 136 |
| 104 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate | 137 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate |
| 105 // Processing" procedure. | 138 // Processing" procedure. |
| 106 WARN_UNUSED_RESULT bool BasicCertificateProcessing( | 139 WARN_UNUSED_RESULT bool BasicCertificateProcessing( |
| 107 const ParsedCertificate& cert, | 140 const ParsedCertificate& cert, |
| 108 bool is_target_cert, | 141 bool is_target_cert, |
| 109 const SignaturePolicy* signature_policy, | 142 const SignaturePolicy* signature_policy, |
| 110 const der::GeneralizedTime& time, | 143 const der::GeneralizedTime& time, |
| 111 const der::Input& working_spki, | 144 const der::Input& working_spki, |
| 112 const der::Input& working_normalized_issuer_name, | 145 const der::Input& working_normalized_issuer_name, |
| 113 const std::vector<const NameConstraints*>& name_constraints_list) { | 146 const std::vector<const NameConstraints*>& name_constraints_list, |
| 147 CertErrors* errors) { | |
| 114 // Check that the signature algorithms in Certificate vs TBSCertificate | 148 // Check that the signature algorithms in Certificate vs TBSCertificate |
| 115 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by | 149 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by |
| 116 // sections 4.1.1.2 and 4.1.2.3. | 150 // sections 4.1.1.2 and 4.1.2.3. |
| 117 if (!VerifySignatureAlgorithmsMatch(cert)) | 151 if (!VerifySignatureAlgorithmsMatch(cert, errors)) |
| 118 return false; | 152 return false; |
| 119 | 153 |
| 120 // Verify the digital signature using the previous certificate's key (RFC | 154 // Verify the digital signature using the previous certificate's key (RFC |
| 121 // 5280 section 6.1.3 step a.1). | 155 // 5280 section 6.1.3 step a.1). |
| 122 if (!cert.has_valid_supported_signature_algorithm() || | 156 if (!cert.has_valid_supported_signature_algorithm()) { |
| 123 !VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(), | 157 errors->AddWith1DerParam(kInvalidOrUnsupportedAlgorithm, |
| 158 cert.signature_algorithm_tlv()); | |
| 159 return false; | |
| 160 } | |
| 161 | |
| 162 if (!VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(), | |
| 124 cert.signature_value(), working_spki, | 163 cert.signature_value(), working_spki, |
| 125 signature_policy)) { | 164 signature_policy)) { |
| 165 errors->Add(kSignatureVerificationFailed); | |
| 126 return false; | 166 return false; |
| 127 } | 167 } |
| 128 | 168 |
| 129 // Check the time range for the certificate's validity, ensuring it is valid | 169 // Check the time range for the certificate's validity, ensuring it is valid |
| 130 // at |time|. | 170 // at |time|. |
| 131 // (RFC 5280 section 6.1.3 step a.2) | 171 // (RFC 5280 section 6.1.3 step a.2) |
| 132 if (!VerifyTimeValidity(cert, time)) | 172 if (!VerifyTimeValidity(cert, time, errors)) |
| 133 return false; | 173 return false; |
| 134 | 174 |
| 135 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3) | 175 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3) |
| 136 | 176 |
| 137 // Verify the certificate's issuer name matches the issuing certificate's | 177 // Verify the certificate's issuer name matches the issuing certificate's |
| 138 // subject name. (RFC 5280 section 6.1.3 step a.4) | 178 // subject name. (RFC 5280 section 6.1.3 step a.4) |
| 139 if (cert.normalized_issuer() != working_normalized_issuer_name) | 179 if (cert.normalized_issuer() != working_normalized_issuer_name) { |
| 180 errors->Add(kSubjectDoesNotMatchIssuer); | |
| 140 return false; | 181 return false; |
| 182 } | |
| 141 | 183 |
| 142 // Name constraints (RFC 5280 section 6.1.3 step b & c) | 184 // Name constraints (RFC 5280 section 6.1.3 step b & c) |
| 143 // If certificate i is self-issued and it is not the final certificate in the | 185 // If certificate i is self-issued and it is not the final certificate in the |
| 144 // path, skip this step for certificate i. | 186 // path, skip this step for certificate i. |
| 145 if (!name_constraints_list.empty() && | 187 if (!name_constraints_list.empty() && |
| 146 (!IsSelfIssued(cert) || is_target_cert)) { | 188 (!IsSelfIssued(cert) || is_target_cert)) { |
| 147 for (const NameConstraints* nc : name_constraints_list) { | 189 for (const NameConstraints* nc : name_constraints_list) { |
| 148 if (!nc->IsPermittedCert(cert.normalized_subject(), | 190 if (!nc->IsPermittedCert(cert.normalized_subject(), |
| 149 cert.subject_alt_names())) { | 191 cert.subject_alt_names())) { |
| 192 errors->Add(kNotPermitterdByNameConstraints); | |
| 150 return false; | 193 return false; |
| 151 } | 194 } |
| 152 } | 195 } |
| 153 } | 196 } |
| 154 | 197 |
| 155 // TODO(eroman): Steps d-f are omitted, as policy constraints are not yet | 198 // TODO(eroman): Steps d-f are omitted, as policy constraints are not yet |
| 156 // implemented. | 199 // implemented. |
| 157 | 200 |
| 158 return true; | 201 return true; |
| 159 } | 202 } |
| 160 | 203 |
| 161 // This function corresponds to RFC 5280 section 6.1.4's "Preparation for | 204 // This function corresponds to RFC 5280 section 6.1.4's "Preparation for |
| 162 // Certificate i+1" procedure. |cert| is expected to be an intermediate. | 205 // Certificate i+1" procedure. |cert| is expected to be an intermediate. |
| 163 WARN_UNUSED_RESULT bool PrepareForNextCertificate( | 206 WARN_UNUSED_RESULT bool PrepareForNextCertificate( |
| 164 const ParsedCertificate& cert, | 207 const ParsedCertificate& cert, |
| 165 size_t* max_path_length_ptr, | 208 size_t* max_path_length_ptr, |
| 166 der::Input* working_spki, | 209 der::Input* working_spki, |
| 167 der::Input* working_normalized_issuer_name, | 210 der::Input* working_normalized_issuer_name, |
| 168 std::vector<const NameConstraints*>* name_constraints_list) { | 211 std::vector<const NameConstraints*>* name_constraints_list, |
| 212 CertErrors* errors) { | |
| 169 // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not | 213 // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not |
| 170 // yet implemented. | 214 // yet implemented. |
| 171 | 215 |
| 172 // From RFC 5280 section 6.1.4 step c: | 216 // From RFC 5280 section 6.1.4 step c: |
| 173 // | 217 // |
| 174 // Assign the certificate subject name to working_normalized_issuer_name. | 218 // Assign the certificate subject name to working_normalized_issuer_name. |
| 175 *working_normalized_issuer_name = cert.normalized_subject(); | 219 *working_normalized_issuer_name = cert.normalized_subject(); |
| 176 | 220 |
| 177 // From RFC 5280 section 6.1.4 step d: | 221 // From RFC 5280 section 6.1.4 step d: |
| 178 // | 222 // |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 196 // basicConstraints extension is present and that cA is set to | 240 // basicConstraints extension is present and that cA is set to |
| 197 // TRUE. (If certificate i is a version 1 or version 2 | 241 // TRUE. (If certificate i is a version 1 or version 2 |
| 198 // certificate, then the application MUST either verify that | 242 // certificate, then the application MUST either verify that |
| 199 // certificate i is a CA certificate through out-of-band means | 243 // certificate i is a CA certificate through out-of-band means |
| 200 // or reject the certificate. Conforming implementations may | 244 // or reject the certificate. Conforming implementations may |
| 201 // choose to reject all version 1 and version 2 intermediate | 245 // choose to reject all version 1 and version 2 intermediate |
| 202 // certificates.) | 246 // certificates.) |
| 203 // | 247 // |
| 204 // This code implicitly rejects non version 3 intermediates, since they | 248 // This code implicitly rejects non version 3 intermediates, since they |
| 205 // can't contain a BasicConstraints extension. | 249 // can't contain a BasicConstraints extension. |
| 206 if (!cert.has_basic_constraints() || !cert.basic_constraints().is_ca) | 250 if (!cert.has_basic_constraints()) { |
| 251 errors->Add(kMissingBasicConstraints); | |
| 207 return false; | 252 return false; |
| 253 } | |
| 254 | |
| 255 if (!cert.basic_constraints().is_ca) { | |
| 256 errors->Add(kBasicConstraintsIndicatesNotCa); | |
| 257 return false; | |
| 258 } | |
| 208 | 259 |
| 209 // From RFC 5280 section 6.1.4 step l: | 260 // From RFC 5280 section 6.1.4 step l: |
| 210 // | 261 // |
| 211 // If the certificate was not self-issued, verify that | 262 // If the certificate was not self-issued, verify that |
| 212 // max_path_length is greater than zero and decrement | 263 // max_path_length is greater than zero and decrement |
| 213 // max_path_length by 1. | 264 // max_path_length by 1. |
| 214 if (!IsSelfIssued(cert)) { | 265 if (!IsSelfIssued(cert)) { |
| 215 if (*max_path_length_ptr == 0) | 266 if (*max_path_length_ptr == 0) { |
| 267 errors->Add(kMaxPathLengthViolated); | |
| 216 return false; | 268 return false; |
| 269 } | |
| 217 --(*max_path_length_ptr); | 270 --(*max_path_length_ptr); |
| 218 } | 271 } |
| 219 | 272 |
| 220 // From RFC 5280 section 6.1.4 step m: | 273 // From RFC 5280 section 6.1.4 step m: |
| 221 // | 274 // |
| 222 // If pathLenConstraint is present in the certificate and is | 275 // If pathLenConstraint is present in the certificate and is |
| 223 // less than max_path_length, set max_path_length to the value | 276 // less than max_path_length, set max_path_length to the value |
| 224 // of pathLenConstraint. | 277 // of pathLenConstraint. |
| 225 if (cert.basic_constraints().has_path_len && | 278 if (cert.basic_constraints().has_path_len && |
| 226 cert.basic_constraints().path_len < *max_path_length_ptr) { | 279 cert.basic_constraints().path_len < *max_path_length_ptr) { |
| 227 *max_path_length_ptr = cert.basic_constraints().path_len; | 280 *max_path_length_ptr = cert.basic_constraints().path_len; |
| 228 } | 281 } |
| 229 | 282 |
| 230 // From RFC 5280 section 6.1.4 step n: | 283 // From RFC 5280 section 6.1.4 step n: |
| 231 // | 284 // |
| 232 // If a key usage extension is present, verify that the | 285 // If a key usage extension is present, verify that the |
| 233 // keyCertSign bit is set. | 286 // keyCertSign bit is set. |
| 234 if (cert.has_key_usage() && | 287 if (cert.has_key_usage() && |
| 235 !cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { | 288 !cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { |
| 289 errors->Add(kKeyCertSignBitNotSet); | |
| 236 return false; | 290 return false; |
| 237 } | 291 } |
| 238 | 292 |
| 239 // From RFC 5280 section 6.1.4 step o: | 293 // From RFC 5280 section 6.1.4 step o: |
| 240 // | 294 // |
| 241 // Recognize and process any other critical extension present in | 295 // Recognize and process any other critical extension present in |
| 242 // the certificate. Process any other recognized non-critical | 296 // the certificate. Process any other recognized non-critical |
| 243 // extension present in the certificate that is relevant to path | 297 // extension present in the certificate that is relevant to path |
| 244 // processing. | 298 // processing. |
| 245 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | 299 if (!VerifyNoUnconsumedCriticalExtensions(cert, errors)) |
| 246 return false; | 300 return false; |
| 247 | 301 |
| 248 return true; | 302 return true; |
| 249 } | 303 } |
| 250 | 304 |
| 251 // Checks that if the target certificate has properties that only a CA should | 305 // Checks that if the target certificate has properties that only a CA should |
| 252 // have (keyCertSign, CA=true, pathLenConstraint), then its other properties | 306 // have (keyCertSign, CA=true, pathLenConstraint), then its other properties |
| 253 // are consistent with being a CA. | 307 // are consistent with being a CA. |
| 254 // | 308 // |
| 255 // This follows from some requirements in RFC 5280 section 4.2.1.9. In | 309 // This follows from some requirements in RFC 5280 section 4.2.1.9. In |
| 256 // particular: | 310 // particular: |
| 257 // | 311 // |
| 258 // CAs MUST NOT include the pathLenConstraint field unless the cA | 312 // CAs MUST NOT include the pathLenConstraint field unless the cA |
| 259 // boolean is asserted and the key usage extension asserts the | 313 // boolean is asserted and the key usage extension asserts the |
| 260 // keyCertSign bit. | 314 // keyCertSign bit. |
| 261 // | 315 // |
| 262 // And: | 316 // And: |
| 263 // | 317 // |
| 264 // If the cA boolean is not asserted, then the keyCertSign bit in the key | 318 // If the cA boolean is not asserted, then the keyCertSign bit in the key |
| 265 // usage extension MUST NOT be asserted. | 319 // usage extension MUST NOT be asserted. |
| 266 // | 320 // |
| 267 // TODO(eroman): Strictly speaking the first requirement is on CAs and not the | 321 // TODO(eroman): Strictly speaking the first requirement is on CAs and not the |
| 268 // certificate client, so could be skipped. | 322 // certificate client, so could be skipped. |
| 269 // | 323 // |
| 270 // TODO(eroman): I don't believe Firefox enforces the keyCertSign restriction | 324 // TODO(eroman): I don't believe Firefox enforces the keyCertSign restriction |
| 271 // for compatibility reasons. Investigate if we need to similarly relax this | 325 // for compatibility reasons. Investigate if we need to similarly relax this |
| 272 // constraint. | 326 // constraint. |
| 273 WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits( | 327 WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits( |
| 274 const ParsedCertificate& cert) { | 328 const ParsedCertificate& cert, |
| 329 CertErrors* errors) { | |
| 275 // Check if the certificate contains any property specific to CAs. | 330 // Check if the certificate contains any property specific to CAs. |
| 276 bool has_ca_property = | 331 bool has_ca_property = |
| 277 (cert.has_basic_constraints() && | 332 (cert.has_basic_constraints() && |
| 278 (cert.basic_constraints().is_ca || | 333 (cert.basic_constraints().is_ca || |
| 279 cert.basic_constraints().has_path_len)) || | 334 cert.basic_constraints().has_path_len)) || |
| 280 (cert.has_key_usage() && | 335 (cert.has_key_usage() && |
| 281 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 336 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); |
| 282 | 337 |
| 283 // If it "looks" like a CA because it has a CA-only property, then check that | 338 // If it "looks" like a CA because it has a CA-only property, then check that |
| 284 // it sets ALL the properties expected of a CA. | 339 // it sets ALL the properties expected of a CA. |
| 285 if (has_ca_property) { | 340 if (has_ca_property) { |
| 286 return cert.has_basic_constraints() && cert.basic_constraints().is_ca && | 341 bool success = cert.has_basic_constraints() && |
| 287 (!cert.has_key_usage() || | 342 cert.basic_constraints().is_ca && |
| 288 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 343 (!cert.has_key_usage() || |
| 344 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | |
| 345 if (!success) { | |
| 346 // TODO(eroman): Add DER for basic constraints and key usage. | |
| 347 errors->Add(kTargetCertInconsistentCaBits); | |
| 348 } | |
| 349 | |
| 350 return success; | |
| 289 } | 351 } |
| 290 | 352 |
| 291 return true; | 353 return true; |
| 292 } | 354 } |
| 293 | 355 |
| 294 // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". | 356 // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". |
| 295 // It does processing for the final certificate (the target cert). | 357 // It does processing for the final certificate (the target cert). |
| 296 WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) { | 358 WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert, |
| 359 CertErrors* errors) { | |
| 297 // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not | 360 // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not |
| 298 // yet implemented. | 361 // yet implemented. |
| 299 | 362 |
| 300 // Note step c-e are omitted the verification function does | 363 // Note step c-e are omitted the verification function does |
| 301 // not output the working public key. | 364 // not output the working public key. |
| 302 | 365 |
| 303 // From RFC 5280 section 6.1.5 step f: | 366 // From RFC 5280 section 6.1.5 step f: |
| 304 // | 367 // |
| 305 // Recognize and process any other critical extension present in | 368 // Recognize and process any other critical extension present in |
| 306 // the certificate n. Process any other recognized non-critical | 369 // the certificate n. Process any other recognized non-critical |
| 307 // extension present in certificate n that is relevant to path | 370 // extension present in certificate n that is relevant to path |
| 308 // processing. | 371 // processing. |
| 309 // | 372 // |
| 310 // Note that this is duplicated by PrepareForNextCertificate() so as to | 373 // Note that this is duplicated by PrepareForNextCertificate() so as to |
| 311 // directly match the procedures in RFC 5280's section 6.1. | 374 // directly match the procedures in RFC 5280's section 6.1. |
| 312 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | 375 if (!VerifyNoUnconsumedCriticalExtensions(cert, errors)) |
| 313 return false; | 376 return false; |
| 314 | 377 |
| 315 // TODO(eroman): Step g is omitted, as policy constraints are not yet | 378 // TODO(eroman): Step g is omitted, as policy constraints are not yet |
| 316 // implemented. | 379 // implemented. |
| 317 | 380 |
| 318 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", | 381 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", |
| 319 // however is implied by RFC 5280 section 4.2.1.9. | 382 // however is implied by RFC 5280 section 4.2.1.9. |
| 320 if (!VerifyTargetCertHasConsistentCaBits(cert)) | 383 if (!VerifyTargetCertHasConsistentCaBits(cert, errors)) |
| 321 return false; | 384 return false; |
| 322 | 385 |
| 323 return true; | 386 return true; |
| 324 } | 387 } |
| 325 | 388 |
| 326 // Initializes the path validation algorithm given anchor constraints. This | 389 // Initializes the path validation algorithm given anchor constraints. This |
| 327 // follows the description in RFC 5937 | 390 // follows the description in RFC 5937 |
| 328 WARN_UNUSED_RESULT bool ProcessTrustAnchorConstraints( | 391 WARN_UNUSED_RESULT bool ProcessTrustAnchorConstraints( |
| 329 const TrustAnchor& trust_anchor, | 392 const TrustAnchor& trust_anchor, |
| 330 size_t* max_path_length_ptr, | 393 size_t* max_path_length_ptr, |
| 331 std::vector<const NameConstraints*>* name_constraints_list) { | 394 std::vector<const NameConstraints*>* name_constraints_list, |
| 395 CertErrors* errors) { | |
| 396 // Set the trust anchor as the current context for any subsequent errors. | |
| 397 ScopedCertErrorsTrustAnchorContext error_context(errors, &trust_anchor); | |
| 398 | |
| 332 // In RFC 5937 the enforcement of anchor constraints is governed by the input | 399 // In RFC 5937 the enforcement of anchor constraints is governed by the input |
| 333 // enforceTrustAnchorConstraints to path validation. In our implementation | 400 // enforceTrustAnchorConstraints to path validation. In our implementation |
| 334 // this is always on, and enforcement is controlled solely by whether or not | 401 // this is always on, and enforcement is controlled solely by whether or not |
| 335 // the trust anchor specified constraints. | 402 // the trust anchor specified constraints. |
| 336 if (!trust_anchor.enforces_constraints()) | 403 if (!trust_anchor.enforces_constraints()) |
| 337 return true; | 404 return true; |
| 338 | 405 |
| 339 // Anchor constraints are encoded via the attached certificate. | 406 // Anchor constraints are encoded via the attached certificate. |
| 340 const ParsedCertificate& cert = *trust_anchor.cert(); | 407 const ParsedCertificate& cert = *trust_anchor.cert(); |
| 341 | 408 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 366 // NOTE: RFC 5937 does not say to enforce the CA=true part of basic | 433 // NOTE: RFC 5937 does not say to enforce the CA=true part of basic |
| 367 // constraints. | 434 // constraints. |
| 368 if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len) | 435 if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len) |
| 369 *max_path_length_ptr = cert.basic_constraints().path_len; | 436 *max_path_length_ptr = cert.basic_constraints().path_len; |
| 370 | 437 |
| 371 // From RFC 5937 section 2: | 438 // From RFC 5937 section 2: |
| 372 // | 439 // |
| 373 // Extensions may be marked critical or not critical. When trust anchor | 440 // Extensions may be marked critical or not critical. When trust anchor |
| 374 // constraints are enforced, clients MUST reject certification paths | 441 // constraints are enforced, clients MUST reject certification paths |
| 375 // containing a trust anchor with unrecognized critical extensions. | 442 // containing a trust anchor with unrecognized critical extensions. |
| 376 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | 443 if (!VerifyNoUnconsumedCriticalExtensions(cert, errors)) |
| 377 return false; | 444 return false; |
| 378 | 445 |
| 379 return true; | 446 return true; |
| 380 } | 447 } |
| 381 | 448 |
| 382 } // namespace | 449 } // namespace |
| 383 | 450 |
| 384 // This implementation is structured to mimic the description of certificate | 451 // This implementation is structured to mimic the description of certificate |
| 385 // path verification given by RFC 5280 section 6.1. | 452 // path verification given by RFC 5280 section 6.1. |
| 386 bool VerifyCertificateChain(const ParsedCertificateList& certs, | 453 bool VerifyCertificateChain(const ParsedCertificateList& certs, |
| 387 const TrustAnchor* trust_anchor, | 454 const TrustAnchor* trust_anchor, |
| 388 const SignaturePolicy* signature_policy, | 455 const SignaturePolicy* signature_policy, |
| 389 const der::GeneralizedTime& time) { | 456 const der::GeneralizedTime& time, |
| 457 CertErrors* errors) { | |
| 458 DCHECK(trust_anchor); | |
|
mattm
2016/08/29 22:15:11
DCHECK(errors) and signature_policy also?
eroman
2016/08/29 22:55:18
Done.
| |
| 459 | |
| 390 // An empty chain is necessarily invalid. | 460 // An empty chain is necessarily invalid. |
| 391 if (certs.empty()) | 461 if (certs.empty()) { |
| 462 errors->Add(kChainIsEmpty); | |
| 392 return false; | 463 return false; |
| 464 } | |
| 393 | 465 |
| 394 // Will contain a NameConstraints for each previous cert in the chain which | 466 // Will contain a NameConstraints for each previous cert in the chain which |
| 395 // had nameConstraints. This corresponds to the permitted_subtrees and | 467 // had nameConstraints. This corresponds to the permitted_subtrees and |
| 396 // excluded_subtrees state variables from RFC 5280. | 468 // excluded_subtrees state variables from RFC 5280. |
| 397 std::vector<const NameConstraints*> name_constraints_list; | 469 std::vector<const NameConstraints*> name_constraints_list; |
| 398 | 470 |
| 399 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: | 471 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: |
| 400 // * working_public_key | 472 // * working_public_key |
| 401 // * working_public_key_algorithm | 473 // * working_public_key_algorithm |
| 402 // * working_public_key_parameters | 474 // * working_public_key_parameters |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 425 // | 497 // |
| 426 // max_path_length: this integer is initialized to n, is | 498 // max_path_length: this integer is initialized to n, is |
| 427 // decremented for each non-self-issued certificate in the path, | 499 // decremented for each non-self-issued certificate in the path, |
| 428 // and may be reduced to the value in the path length constraint | 500 // and may be reduced to the value in the path length constraint |
| 429 // field within the basic constraints extension of a CA | 501 // field within the basic constraints extension of a CA |
| 430 // certificate. | 502 // certificate. |
| 431 size_t max_path_length = certs.size(); | 503 size_t max_path_length = certs.size(); |
| 432 | 504 |
| 433 // Apply any trust anchor constraints per RFC 5937. | 505 // Apply any trust anchor constraints per RFC 5937. |
| 434 if (!ProcessTrustAnchorConstraints(*trust_anchor, &max_path_length, | 506 if (!ProcessTrustAnchorConstraints(*trust_anchor, &max_path_length, |
| 435 &name_constraints_list)) { | 507 &name_constraints_list, errors)) { |
| 436 return false; | 508 return false; |
| 437 } | 509 } |
| 438 | 510 |
| 439 // Iterate over all the certificates in the reverse direction: starting from | 511 // Iterate over all the certificates in the reverse direction: starting from |
| 440 // the certificate signed by trust anchor and progressing towards the target | 512 // the certificate signed by trust anchor and progressing towards the target |
| 441 // certificate. | 513 // certificate. |
| 442 // | 514 // |
| 443 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. | 515 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. |
| 444 // | 516 // |
| 445 // * i=0 : Certificated signed by trust anchor. | 517 // * i=0 : Certificated signed by trust anchor. |
| 446 // * i=N-1 : Target certificate. | 518 // * i=N-1 : Target certificate. |
| 447 for (size_t i = 0; i < certs.size(); ++i) { | 519 for (size_t i = 0; i < certs.size(); ++i) { |
| 448 const size_t index_into_certs = certs.size() - i - 1; | 520 const size_t index_into_certs = certs.size() - i - 1; |
| 449 | 521 |
| 450 // |is_target_cert| is true if the current certificate is the target | 522 // |is_target_cert| is true if the current certificate is the target |
| 451 // certificate being verified. The target certificate isn't necessarily an | 523 // certificate being verified. The target certificate isn't necessarily an |
| 452 // end-entity certificate. | 524 // end-entity certificate. |
| 453 const bool is_target_cert = index_into_certs == 0; | 525 const bool is_target_cert = index_into_certs == 0; |
| 454 | 526 |
| 455 const ParsedCertificate& cert = *certs[index_into_certs]; | 527 const ParsedCertificate& cert = *certs[index_into_certs]; |
| 456 | 528 |
| 529 // Set the certificate anchor as the current context for any subsequent | |
|
mattm
2016/08/29 22:15:11
Is "anchor" here a typo?
eroman
2016/08/29 22:55:18
Yes. Fixed.
| |
| 530 // errors. | |
| 531 ScopedCertErrorsCertContext error_context(errors, &cert, i); | |
| 532 | |
| 457 // Per RFC 5280 section 6.1: | 533 // Per RFC 5280 section 6.1: |
| 458 // * Do basic processing for each certificate | 534 // * Do basic processing for each certificate |
| 459 // * If it is the last certificate in the path (target certificate) | 535 // * If it is the last certificate in the path (target certificate) |
| 460 // - Then run "Wrap up" | 536 // - Then run "Wrap up" |
| 461 // - Otherwise run "Prepare for Next cert" | 537 // - Otherwise run "Prepare for Next cert" |
| 462 if (!BasicCertificateProcessing( | 538 if (!BasicCertificateProcessing( |
| 463 cert, is_target_cert, signature_policy, time, working_spki, | 539 cert, is_target_cert, signature_policy, time, working_spki, |
| 464 working_normalized_issuer_name, name_constraints_list)) { | 540 working_normalized_issuer_name, name_constraints_list, errors)) { |
| 465 return false; | 541 return false; |
| 466 } | 542 } |
| 467 if (!is_target_cert) { | 543 if (!is_target_cert) { |
| 468 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, | 544 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, |
| 469 &working_normalized_issuer_name, | 545 &working_normalized_issuer_name, |
| 470 &name_constraints_list)) { | 546 &name_constraints_list, errors)) { |
| 471 return false; | 547 return false; |
| 472 } | 548 } |
| 473 } else { | 549 } else { |
| 474 if (!WrapUp(cert)) | 550 if (!WrapUp(cert, errors)) |
| 475 return false; | 551 return false; |
| 476 } | 552 } |
| 477 } | 553 } |
| 478 | 554 |
| 479 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: | 555 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: |
| 480 // | 556 // |
| 481 // A certificate MUST NOT appear more than once in a prospective | 557 // A certificate MUST NOT appear more than once in a prospective |
| 482 // certification path. | 558 // certification path. |
| 483 | 559 |
| 484 return true; | 560 return true; |
| 485 } | 561 } |
| 486 | 562 |
| 563 namespace verify_certificate_chain_errors { | |
| 564 | |
| 565 DEFINE_CERT_ERROR_TYPE( | |
| 566 kSignatureAlgorithmMismatch, | |
| 567 "Certificate.signatureAlgorithm != TBSCertificate.signature"); | |
| 568 DEFINE_CERT_ERROR_TYPE(kInvalidOrUnsupportedAlgorithm, | |
| 569 "Invalid or unsupported signature algorithm"); | |
| 570 DEFINE_CERT_ERROR_TYPE(kChainIsEmpty, "Chain is empty"); | |
| 571 DEFINE_CERT_ERROR_TYPE(kUnconsumedCriticalExtension, | |
| 572 "Unconsumed critical extension"); | |
| 573 DEFINE_CERT_ERROR_TYPE( | |
| 574 kTargetCertInconsistentCaBits, | |
| 575 "Target certificate looks like a CA but does not set all CA properties"); | |
| 576 DEFINE_CERT_ERROR_TYPE(kKeyCertSignBitNotSet, "keyCertSign bit is not set"); | |
| 577 DEFINE_CERT_ERROR_TYPE(kMaxPathLengthViolated, "max_path_length reached"); | |
| 578 DEFINE_CERT_ERROR_TYPE(kBasicConstraintsIndicatesNotCa, | |
| 579 "Basic Constraints indicates not a CA"); | |
| 580 DEFINE_CERT_ERROR_TYPE(kMissingBasicConstraints, | |
| 581 "Does not have Basic Constraints"); | |
| 582 DEFINE_CERT_ERROR_TYPE(kNotPermitterdByNameConstraints, | |
|
mattm
2016/08/29 22:15:11
s/Permitterd/Permitted/
eroman
2016/08/29 22:55:18
Good spot! Fixed.
| |
| 583 "Not permitted by name constraints"); | |
| 584 DEFINE_CERT_ERROR_TYPE(kSubjectDoesNotMatchIssuer, | |
| 585 "subject does not match issuer"); | |
| 586 DEFINE_CERT_ERROR_TYPE(kSignatureVerificationFailed, | |
| 587 "Signature verification failed"); | |
| 588 DEFINE_CERT_ERROR_TYPE(kValidityFailedNotAfter, "Time is after notAfter"); | |
| 589 DEFINE_CERT_ERROR_TYPE(kValidityFailedNotBefore, "Time is before notBefore"); | |
| 590 DEFINE_CERT_ERROR_TYPE(kSignatureAlgorithmsDifferentEncoding, | |
| 591 "Certificate.signatureAlgorithm is encoded differently " | |
| 592 "than TBSCertificate.signature"); | |
| 593 | |
| 594 } // verify_certificate_chain_errors | |
| 595 | |
| 487 } // namespace net | 596 } // namespace net |
| OLD | NEW |