Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(562)

Side by Side Diff: net/cert/internal/verify_certificate_chain.cc

Issue 2225493003: Don't treat trust anchors as certificates during path building. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address moar feedback Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv; 96 const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv;
97 97
98 // Ensure that the two DER-encoded signature algorithms are byte-for-byte 98 // Ensure that the two DER-encoded signature algorithms are byte-for-byte
99 // equal, but make a compatibility concession for RSA with SHA1. 99 // equal, but make a compatibility concession for RSA with SHA1.
100 return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) && 100 return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) &&
101 IsRsaWithSha1SignatureAlgorithm(alg2_tlv)); 101 IsRsaWithSha1SignatureAlgorithm(alg2_tlv));
102 } 102 }
103 103
104 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate 104 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate
105 // Processing" procedure. 105 // Processing" procedure.
106 //
107 // |skip_issuer_checks| controls whether the function will skip:
108 // - Checking that |cert|'s signature using |working_spki|
109 // - Checkinging that |cert|'s issuer matches |working_normalized_issuer_name|
110 // This should be set to true only when verifying a trusted root certificate.
111 WARN_UNUSED_RESULT bool BasicCertificateProcessing( 106 WARN_UNUSED_RESULT bool BasicCertificateProcessing(
112 const ParsedCertificate& cert, 107 const ParsedCertificate& cert,
113 bool is_target_cert, 108 bool is_target_cert,
114 bool skip_issuer_checks,
115 const SignaturePolicy* signature_policy, 109 const SignaturePolicy* signature_policy,
116 const der::GeneralizedTime& time, 110 const der::GeneralizedTime& time,
117 const der::Input& working_spki, 111 const der::Input& working_spki,
118 const der::Input& working_normalized_issuer_name, 112 const der::Input& working_normalized_issuer_name,
119 const std::vector<const NameConstraints*>& name_constraints_list) { 113 const std::vector<const NameConstraints*>& name_constraints_list) {
120 // Check that the signature algorithms in Certificate vs TBSCertificate 114 // Check that the signature algorithms in Certificate vs TBSCertificate
121 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by 115 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by
122 // sections 4.1.1.2 and 4.1.2.3. 116 // sections 4.1.1.2 and 4.1.2.3.
123 if (!VerifySignatureAlgorithmsMatch(cert)) 117 if (!VerifySignatureAlgorithmsMatch(cert))
124 return false; 118 return false;
125 119
126 // Verify the digital signature using the previous certificate's key (RFC 120 // Verify the digital signature using the previous certificate's key (RFC
127 // 5280 section 6.1.3 step a.1). 121 // 5280 section 6.1.3 step a.1).
128 if (!skip_issuer_checks) { 122 if (!cert.has_valid_supported_signature_algorithm() ||
129 if (!cert.has_valid_supported_signature_algorithm() || 123 !VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(),
130 !VerifySignedData(cert.signature_algorithm(), 124 cert.signature_value(), working_spki,
131 cert.tbs_certificate_tlv(), cert.signature_value(), 125 signature_policy)) {
132 working_spki, signature_policy)) { 126 return false;
133 return false;
134 }
135 } 127 }
136 128
137 // Check the time range for the certificate's validity, ensuring it is valid 129 // Check the time range for the certificate's validity, ensuring it is valid
138 // at |time|. 130 // at |time|.
139 // (RFC 5280 section 6.1.3 step a.2) 131 // (RFC 5280 section 6.1.3 step a.2)
140 if (!VerifyTimeValidity(cert, time)) 132 if (!VerifyTimeValidity(cert, time))
141 return false; 133 return false;
142 134
143 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3) 135 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3)
144 136
145 // Verify the certificate's issuer name matches the issuing certificate's 137 // Verify the certificate's issuer name matches the issuing certificate's
146 // subject name. (RFC 5280 section 6.1.3 step a.4) 138 // subject name. (RFC 5280 section 6.1.3 step a.4)
147 if (!skip_issuer_checks) { 139 if (cert.normalized_issuer() != working_normalized_issuer_name)
148 if (cert.normalized_issuer() != working_normalized_issuer_name) 140 return false;
149 return false;
150 }
151 141
152 // Name constraints (RFC 5280 section 6.1.3 step b & c) 142 // Name constraints (RFC 5280 section 6.1.3 step b & c)
153 // If certificate i is self-issued and it is not the final certificate in the 143 // If certificate i is self-issued and it is not the final certificate in the
154 // path, skip this step for certificate i. 144 // path, skip this step for certificate i.
155 if (!name_constraints_list.empty() && 145 if (!name_constraints_list.empty() &&
156 (!IsSelfIssued(cert) || is_target_cert)) { 146 (!IsSelfIssued(cert) || is_target_cert)) {
157 for (const NameConstraints* nc : name_constraints_list) { 147 for (const NameConstraints* nc : name_constraints_list) {
158 if (!nc->IsPermittedCert(cert.normalized_subject(), 148 if (!nc->IsPermittedCert(cert.normalized_subject(),
159 cert.subject_alt_names())) { 149 cert.subject_alt_names())) {
160 return false; 150 return false;
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 if (!VerifyTargetCertHasConsistentCaBits(cert)) 320 if (!VerifyTargetCertHasConsistentCaBits(cert))
331 return false; 321 return false;
332 322
333 return true; 323 return true;
334 } 324 }
335 325
336 } // namespace 326 } // namespace
337 327
338 // This implementation is structured to mimic the description of certificate 328 // This implementation is structured to mimic the description of certificate
339 // path verification given by RFC 5280 section 6.1. 329 // path verification given by RFC 5280 section 6.1.
340 // 330 bool VerifyCertificateChain(const ParsedCertificateList& certs,
341 // Unlike RFC 5280, the trust anchor is specified as the root certificate in 331 const TrustAnchor* trust_anchor,
342 // the chain. This root certificate is assumed to be trusted, and neither its 332 const SignaturePolicy* signature_policy,
343 // signature nor issuer name are verified. (It needn't be self-signed). 333 const der::GeneralizedTime& time) {
344 bool VerifyCertificateChainAssumingTrustedRoot(
345 const ParsedCertificateList& certs,
346 // The trust store is only used for assertions.
347 const TrustStore& trust_store,
348 const SignaturePolicy* signature_policy,
349 const der::GeneralizedTime& time) {
350 // An empty chain is necessarily invalid. 334 // An empty chain is necessarily invalid.
351 if (certs.empty()) 335 if (certs.empty())
352 return false; 336 return false;
353 337
354 // IMPORTANT: the assumption being made is that the root certificate in 338 // TODO(crbug.com/635200): Support anchor constraints.
355 // the given path is the trust anchor (and has already been verified as
356 // such).
357 DCHECK(trust_store.IsTrustedCertificate(certs.back().get()));
358 339
359 // Will contain a NameConstraints for each previous cert in the chain which 340 // Will contain a NameConstraints for each previous cert in the chain which
360 // had nameConstraints. This corresponds to the permitted_subtrees and 341 // had nameConstraints. This corresponds to the permitted_subtrees and
361 // excluded_subtrees state variables from RFC 5280. 342 // excluded_subtrees state variables from RFC 5280.
362 std::vector<const NameConstraints*> name_constraints_list; 343 std::vector<const NameConstraints*> name_constraints_list;
363 344
364 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: 345 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280:
365 // * working_public_key 346 // * working_public_key
366 // * working_public_key_algorithm 347 // * working_public_key_algorithm
367 // * working_public_key_parameters 348 // * working_public_key_parameters
368 // 349 //
369 // They are combined for simplicity since the signature verification takes an 350 // They are combined for simplicity since the signature verification takes an
370 // SPKI, and the parameter inheritence is not applicable for the supported 351 // SPKI, and the parameter inheritence is not applicable for the supported
371 // key types. 352 // key types.
372 // 353 //
373 // An approximate explanation of |working_spki| is this description from RFC 354 // An approximate explanation of |working_spki| is this description from RFC
374 // 5280 section 6.1.2: 355 // 5280 section 6.1.2:
375 // 356 //
376 // working_public_key: the public key used to verify the 357 // working_public_key: the public key used to verify the
377 // signature of a certificate. 358 // signature of a certificate.
378 der::Input working_spki; 359 der::Input working_spki = trust_anchor->spki();
379 360
380 // |working_normalized_issuer_name| is the normalized value of the 361 // |working_normalized_issuer_name| is the normalized value of the
381 // working_issuer_name variable in RFC 5280 section 6.1.2: 362 // working_issuer_name variable in RFC 5280 section 6.1.2:
382 // 363 //
383 // working_issuer_name: the issuer distinguished name expected 364 // working_issuer_name: the issuer distinguished name expected
384 // in the next certificate in the chain. 365 // in the next certificate in the chain.
385 der::Input working_normalized_issuer_name; 366 der::Input working_normalized_issuer_name =
367 trust_anchor->normalized_subject();
386 368
387 // |max_path_length| corresponds with the same named variable in RFC 5280 369 // |max_path_length| corresponds with the same named variable in RFC 5280
388 // section 6.1.2: 370 // section 6.1.2:
389 // 371 //
390 // max_path_length: this integer is initialized to n, is 372 // max_path_length: this integer is initialized to n, is
391 // decremented for each non-self-issued certificate in the path, 373 // decremented for each non-self-issued certificate in the path,
392 // and may be reduced to the value in the path length constraint 374 // and may be reduced to the value in the path length constraint
393 // field within the basic constraints extension of a CA 375 // field within the basic constraints extension of a CA
394 // certificate. 376 // certificate.
395 size_t max_path_length = certs.size(); 377 size_t max_path_length = certs.size();
396 378
397 // Iterate over all the certificates in the reverse direction: starting from 379 // Iterate over all the certificates in the reverse direction: starting from
398 // the trust anchor and progressing towards the target certificate. 380 // the certificate signed by trust anchor and progressing towards the target
381 // certificate.
399 // 382 //
400 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. 383 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based.
401 // 384 //
402 // * i=0 : Trust anchor. 385 // * i=0 : Certificated signed by trust anchor.
403 // * i=N-1 : Target certificate. 386 // * i=N-1 : Target certificate.
404 for (size_t i = 0; i < certs.size(); ++i) { 387 for (size_t i = 0; i < certs.size(); ++i) {
405 const size_t index_into_certs = certs.size() - i - 1; 388 const size_t index_into_certs = certs.size() - i - 1;
406 389
407 // |is_target_cert| is true if the current certificate is the target 390 // |is_target_cert| is true if the current certificate is the target
408 // certificate being verified. The target certificate isn't necessarily an 391 // certificate being verified. The target certificate isn't necessarily an
409 // end-entity certificate. 392 // end-entity certificate.
410 const bool is_target_cert = index_into_certs == 0; 393 const bool is_target_cert = index_into_certs == 0;
411 394
412 // |is_trust_anchor| is true if the current certificate is the trust
413 // anchor. This certificate is implicitly trusted.
414 const bool is_trust_anchor = i == 0;
415
416 const ParsedCertificate& cert = *certs[index_into_certs]; 395 const ParsedCertificate& cert = *certs[index_into_certs];
417 396
418 // Per RFC 5280 section 6.1: 397 // Per RFC 5280 section 6.1:
419 // * Do basic processing for each certificate 398 // * Do basic processing for each certificate
420 // * If it is the last certificate in the path (target certificate) 399 // * If it is the last certificate in the path (target certificate)
421 // - Then run "Wrap up" 400 // - Then run "Wrap up"
422 // - Otherwise run "Prepare for Next cert" 401 // - Otherwise run "Prepare for Next cert"
423 if (!BasicCertificateProcessing(cert, is_target_cert, is_trust_anchor, 402 if (!BasicCertificateProcessing(
424 signature_policy, time, working_spki, 403 cert, is_target_cert, signature_policy, time, working_spki,
425 working_normalized_issuer_name, 404 working_normalized_issuer_name, name_constraints_list)) {
426 name_constraints_list)) {
427 return false; 405 return false;
428 } 406 }
429 if (!is_target_cert) { 407 if (!is_target_cert) {
430 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, 408 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki,
431 &working_normalized_issuer_name, 409 &working_normalized_issuer_name,
432 &name_constraints_list)) { 410 &name_constraints_list)) {
433 return false; 411 return false;
434 } 412 }
435 } else { 413 } else {
436 if (!WrapUp(cert)) 414 if (!WrapUp(cert))
437 return false; 415 return false;
438 } 416 }
439 } 417 }
440 418
441 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: 419 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1:
442 // 420 //
443 // A certificate MUST NOT appear more than once in a prospective 421 // A certificate MUST NOT appear more than once in a prospective
444 // certification path. 422 // certification path.
445 423
446 return true; 424 return true;
447 } 425 }
448 426
449 } // namespace net 427 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/internal/verify_certificate_chain.h ('k') | net/cert/internal/verify_certificate_chain_pkits_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698