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/name_constraints.h" | 10 #include "net/cert/internal/name_constraints.h" |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 } | 159 } |
| 160 | 160 |
| 161 // This function corresponds to RFC 5280 section 6.1.4's "Preparation for | 161 // 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. | 162 // Certificate i+1" procedure. |cert| is expected to be an intermediate. |
| 163 WARN_UNUSED_RESULT bool PrepareForNextCertificate( | 163 WARN_UNUSED_RESULT bool PrepareForNextCertificate( |
| 164 const ParsedCertificate& cert, | 164 const ParsedCertificate& cert, |
| 165 size_t* max_path_length_ptr, | 165 size_t* max_path_length_ptr, |
| 166 der::Input* working_spki, | 166 der::Input* working_spki, |
| 167 der::Input* working_normalized_issuer_name, | 167 der::Input* working_normalized_issuer_name, |
| 168 std::vector<const NameConstraints*>* name_constraints_list) { | 168 std::vector<const NameConstraints*>* name_constraints_list) { |
| 169 // TODO(eroman): Steps a-b are omitted, as policy constraints are not yet | 169 // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not |
| 170 // implemented. | 170 // yet implemented. |
| 171 | 171 |
| 172 // From RFC 5280 section 6.1.4 step c: | 172 // From RFC 5280 section 6.1.4 step c: |
| 173 // | 173 // |
| 174 // Assign the certificate subject name to working_normalized_issuer_name. | 174 // Assign the certificate subject name to working_normalized_issuer_name. |
| 175 *working_normalized_issuer_name = cert.normalized_subject(); | 175 *working_normalized_issuer_name = cert.normalized_subject(); |
| 176 | 176 |
| 177 // From RFC 5280 section 6.1.4 step d: | 177 // From RFC 5280 section 6.1.4 step d: |
| 178 // | 178 // |
| 179 // Assign the certificate subjectPublicKey to working_public_key. | 179 // Assign the certificate subjectPublicKey to working_public_key. |
| 180 *working_spki = cert.tbs().spki_tlv; | 180 *working_spki = cert.tbs().spki_tlv; |
| 181 | 181 |
| 182 // Note that steps e and f are omitted as they are handled by | 182 // Note that steps e and f are omitted as they are handled by |
| 183 // the assignment to |working_spki| above. See the definition | 183 // the assignment to |working_spki| above. See the definition |
| 184 // of |working_spki|. | 184 // of |working_spki|. |
| 185 | 185 |
| 186 // From RFC 5280 section 6.1.4 step g: | 186 // From RFC 5280 section 6.1.4 step g: |
| 187 if (cert.has_name_constraints()) | 187 if (cert.has_name_constraints()) |
| 188 name_constraints_list->push_back(&cert.name_constraints()); | 188 name_constraints_list->push_back(&cert.name_constraints()); |
| 189 | 189 |
| 190 // TODO(eroman): Steps h-j are omitted as policy constraints are not yet | 190 // TODO(eroman): Steps h-j are omitted as policy |
| 191 // implemented. | 191 // constraints/mappings/inhibitAnyPolicy are not yet implemented. |
| 192 | 192 |
| 193 // From RFC 5280 section 6.1.4 step k: | 193 // From RFC 5280 section 6.1.4 step k: |
| 194 // | 194 // |
| 195 // If certificate i is a version 3 certificate, verify that the | 195 // If certificate i is a version 3 certificate, verify that the |
| 196 // basicConstraints extension is present and that cA is set to | 196 // basicConstraints extension is present and that cA is set to |
| 197 // TRUE. (If certificate i is a version 1 or version 2 | 197 // TRUE. (If certificate i is a version 1 or version 2 |
| 198 // certificate, then the application MUST either verify that | 198 // certificate, then the application MUST either verify that |
| 199 // certificate i is a CA certificate through out-of-band means | 199 // certificate i is a CA certificate through out-of-band means |
| 200 // or reject the certificate. Conforming implementations may | 200 // or reject the certificate. Conforming implementations may |
| 201 // choose to reject all version 1 and version 2 intermediate | 201 // choose to reject all version 1 and version 2 intermediate |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 (!cert.has_key_usage() || | 287 (!cert.has_key_usage() || |
| 288 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | 288 cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); |
| 289 } | 289 } |
| 290 | 290 |
| 291 return true; | 291 return true; |
| 292 } | 292 } |
| 293 | 293 |
| 294 // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". | 294 // 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). | 295 // It does processing for the final certificate (the target cert). |
| 296 WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) { | 296 WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) { |
| 297 // TODO(eroman): Steps a-b are omitted as policy constraints are not yet | 297 // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not |
| 298 // implemented. | 298 // yet implemented. |
| 299 | 299 |
| 300 // Note step c-e are omitted the verification function does | 300 // Note step c-e are omitted the verification function does |
| 301 // not output the working public key. | 301 // not output the working public key. |
| 302 | 302 |
| 303 // From RFC 5280 section 6.1.5 step f: | 303 // From RFC 5280 section 6.1.5 step f: |
| 304 // | 304 // |
| 305 // Recognize and process any other critical extension present in | 305 // Recognize and process any other critical extension present in |
| 306 // the certificate n. Process any other recognized non-critical | 306 // the certificate n. Process any other recognized non-critical |
| 307 // extension present in certificate n that is relevant to path | 307 // extension present in certificate n that is relevant to path |
| 308 // processing. | 308 // processing. |
| 309 // | 309 // |
| 310 // Note that this is duplicated by PrepareForNextCertificate() so as to | 310 // Note that this is duplicated by PrepareForNextCertificate() so as to |
| 311 // directly match the procedures in RFC 5280's section 6.1. | 311 // directly match the procedures in RFC 5280's section 6.1. |
| 312 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | 312 if (!VerifyNoUnconsumedCriticalExtensions(cert)) |
| 313 return false; | 313 return false; |
| 314 | 314 |
| 315 // TODO(eroman): Step g is omitted, as policy constraints are not yet | 315 // TODO(eroman): Step g is omitted, as policy constraints are not yet |
| 316 // implemented. | 316 // implemented. |
| 317 | 317 |
| 318 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", | 318 // 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. | 319 // however is implied by RFC 5280 section 4.2.1.9. |
| 320 if (!VerifyTargetCertHasConsistentCaBits(cert)) | 320 if (!VerifyTargetCertHasConsistentCaBits(cert)) |
| 321 return false; | 321 return false; |
| 322 | 322 |
| 323 return true; | 323 return true; |
| 324 } | 324 } |
| 325 | 325 |
| 326 // Initializes the path validation algorithm given anchor constraints. This | |
| 327 // follows the description in RFC 5937 | |
| 328 WARN_UNUSED_RESULT bool ProcessTrustAnchorConstraints( | |
| 329 const TrustAnchor& trust_anchor, | |
| 330 size_t* max_path_length_ptr, | |
| 331 std::vector<const NameConstraints*>* name_constraints_list) { | |
| 332 // In RFC 5937 the enforcement of anchor constraints is governed by the input | |
| 333 // enforceTrustAnchorConstraints to path validation. In our implementation | |
| 334 // this is always on, and enforcement is controlled solely by whether or not | |
| 335 // the trust anchor specified constraints. | |
| 336 if (!trust_anchor.enforces_constraints()) | |
| 337 return true; | |
| 338 | |
| 339 // Anchor constraints are encoded via the attached certificate. | |
| 340 const ParsedCertificate& cert = *trust_anchor.cert(); | |
| 341 | |
| 342 // The following enforcements follow from RFC 5937 (primarily section 3.2): | |
| 343 | |
| 344 // Initialize name constraints initial-permitted/excluded-subtrees. | |
| 345 if (cert.has_name_constraints()) | |
| 346 name_constraints_list->push_back(&cert.name_constraints()); | |
|
eroman
2016/08/16 00:03:01
I don't yet have a test for this -- will probably
| |
| 347 | |
| 348 // TODO(eroman): Initialize user-initial-policy-set based on anchor | |
| 349 // constraints. | |
| 350 | |
| 351 // TODO(eroman): Initialize inhibit any policy based on anchor constraints. | |
| 352 | |
| 353 // TODO(eroman): Initialize require explicit policy based on anchor | |
| 354 // constraints. | |
| 355 | |
| 356 // TODO(eroman): Initialize inhibit policy mapping based on anchor | |
| 357 // constraints. | |
| 358 | |
| 359 // From RFC 5937 section 3.2: | |
| 360 // | |
| 361 // If a basic constraints extension is associated with the trust | |
| 362 // anchor and contains a pathLenConstraint value, set the | |
| 363 // max_path_length state variable equal to the pathLenConstraint | |
| 364 // value from the basic constraints extension. | |
| 365 // | |
| 366 // NOTE: RFC 5937 does not say to enforce the CA=true part of basic | |
| 367 // constraints. | |
| 368 if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len) | |
| 369 *max_path_length_ptr = cert.basic_constraints().path_len; | |
| 370 | |
| 371 // From RFC 5937 section 2: | |
| 372 // | |
| 373 // Extensions may be marked critical or not critical. When trust anchor | |
| 374 // constraints are enforced, clients MUST reject certification paths | |
| 375 // containing a trust anchor with unrecognized critical extensions. | |
| 376 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | |
| 377 return false; | |
| 378 | |
| 379 return true; | |
| 380 } | |
| 381 | |
| 326 } // namespace | 382 } // namespace |
| 327 | 383 |
| 328 // This implementation is structured to mimic the description of certificate | 384 // This implementation is structured to mimic the description of certificate |
| 329 // path verification given by RFC 5280 section 6.1. | 385 // path verification given by RFC 5280 section 6.1. |
| 330 bool VerifyCertificateChain(const ParsedCertificateList& certs, | 386 bool VerifyCertificateChain(const ParsedCertificateList& certs, |
| 331 const TrustAnchor* trust_anchor, | 387 const TrustAnchor* trust_anchor, |
| 332 const SignaturePolicy* signature_policy, | 388 const SignaturePolicy* signature_policy, |
| 333 const der::GeneralizedTime& time) { | 389 const der::GeneralizedTime& time) { |
| 334 // An empty chain is necessarily invalid. | 390 // An empty chain is necessarily invalid. |
| 335 if (certs.empty()) | 391 if (certs.empty()) |
| 336 return false; | 392 return false; |
| 337 | 393 |
| 338 // TODO(crbug.com/635200): Support anchor constraints. | |
| 339 | |
| 340 // Will contain a NameConstraints for each previous cert in the chain which | 394 // Will contain a NameConstraints for each previous cert in the chain which |
| 341 // had nameConstraints. This corresponds to the permitted_subtrees and | 395 // had nameConstraints. This corresponds to the permitted_subtrees and |
| 342 // excluded_subtrees state variables from RFC 5280. | 396 // excluded_subtrees state variables from RFC 5280. |
| 343 std::vector<const NameConstraints*> name_constraints_list; | 397 std::vector<const NameConstraints*> name_constraints_list; |
| 344 | 398 |
| 345 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: | 399 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: |
| 346 // * working_public_key | 400 // * working_public_key |
| 347 // * working_public_key_algorithm | 401 // * working_public_key_algorithm |
| 348 // * working_public_key_parameters | 402 // * working_public_key_parameters |
| 349 // | 403 // |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 369 // |max_path_length| corresponds with the same named variable in RFC 5280 | 423 // |max_path_length| corresponds with the same named variable in RFC 5280 |
| 370 // section 6.1.2: | 424 // section 6.1.2: |
| 371 // | 425 // |
| 372 // max_path_length: this integer is initialized to n, is | 426 // max_path_length: this integer is initialized to n, is |
| 373 // decremented for each non-self-issued certificate in the path, | 427 // decremented for each non-self-issued certificate in the path, |
| 374 // and may be reduced to the value in the path length constraint | 428 // and may be reduced to the value in the path length constraint |
| 375 // field within the basic constraints extension of a CA | 429 // field within the basic constraints extension of a CA |
| 376 // certificate. | 430 // certificate. |
| 377 size_t max_path_length = certs.size(); | 431 size_t max_path_length = certs.size(); |
| 378 | 432 |
| 433 // Apply any trust anchor constraints per RFC 5937. | |
| 434 if (!ProcessTrustAnchorConstraints(*trust_anchor, &max_path_length, | |
| 435 &name_constraints_list)) { | |
| 436 return false; | |
| 437 } | |
| 438 | |
| 379 // Iterate over all the certificates in the reverse direction: starting from | 439 // Iterate over all the certificates in the reverse direction: starting from |
| 380 // the certificate signed by trust anchor and progressing towards the target | 440 // the certificate signed by trust anchor and progressing towards the target |
| 381 // certificate. | 441 // certificate. |
| 382 // | 442 // |
| 383 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. | 443 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. |
| 384 // | 444 // |
| 385 // * i=0 : Certificated signed by trust anchor. | 445 // * i=0 : Certificated signed by trust anchor. |
| 386 // * i=N-1 : Target certificate. | 446 // * i=N-1 : Target certificate. |
| 387 for (size_t i = 0; i < certs.size(); ++i) { | 447 for (size_t i = 0; i < certs.size(); ++i) { |
| 388 const size_t index_into_certs = certs.size() - i - 1; | 448 const size_t index_into_certs = certs.size() - i - 1; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 418 | 478 |
| 419 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: | 479 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: |
| 420 // | 480 // |
| 421 // A certificate MUST NOT appear more than once in a prospective | 481 // A certificate MUST NOT appear more than once in a prospective |
| 422 // certification path. | 482 // certification path. |
| 423 | 483 |
| 424 return true; | 484 return true; |
| 425 } | 485 } |
| 426 | 486 |
| 427 } // namespace net | 487 } // namespace net |
| OLD | NEW |