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

Side by Side Diff: net/cert/cert_verify_proc_win.cc

Issue 1557133002: Perform CRLSet evaluation during Path Building on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Test fixes Created 4 years, 10 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
« no previous file with comments | « net/cert/cert_verify_proc_unittest.cc ('k') | net/data/ssl/certificates/multi-root-A-by-B.pem » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/cert_verify_proc_win.h" 5 #include "net/cert/cert_verify_proc_win.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/sha1.h" 11 #include "base/sha1.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread_local.h"
14 #include "crypto/capi_util.h" 15 #include "crypto/capi_util.h"
15 #include "crypto/scoped_capi_types.h" 16 #include "crypto/scoped_capi_types.h"
16 #include "crypto/sha2.h" 17 #include "crypto/sha2.h"
17 #include "net/base/net_errors.h" 18 #include "net/base/net_errors.h"
18 #include "net/cert/asn1_util.h" 19 #include "net/cert/asn1_util.h"
19 #include "net/cert/cert_status_flags.h" 20 #include "net/cert/cert_status_flags.h"
20 #include "net/cert/cert_verifier.h" 21 #include "net/cert/cert_verifier.h"
21 #include "net/cert/cert_verify_result.h" 22 #include "net/cert/cert_verify_result.h"
22 #include "net/cert/crl_set.h" 23 #include "net/cert/crl_set.h"
23 #include "net/cert/ev_root_ca_metadata.h" 24 #include "net/cert/ev_root_ca_metadata.h"
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 extension->Value.pbData, 379 extension->Value.pbData,
379 extension->Value.cbData, 380 extension->Value.cbData,
380 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, 381 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
381 &decode_para, 382 &decode_para,
382 &policies_info, 383 &policies_info,
383 &policies_info_size); 384 &policies_info_size);
384 if (rv) 385 if (rv)
385 output->reset(policies_info); 386 output->reset(policies_info);
386 } 387 }
387 388
389 // Computes the SHA-256 hash of the SPKI of |cert| and stores it in |hash|,
390 // returning true. If an error occurs, returns false and leaves |hash|
391 // unmodified.
392 bool HashSPKI(PCCERT_CONTEXT cert, std::string* hash) {
393 base::StringPiece der_bytes(
394 reinterpret_cast<const char*>(cert->pbCertEncoded), cert->cbCertEncoded);
395
396 base::StringPiece spki;
397 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki))
398 return false;
399
400 *hash = crypto::SHA256HashString(spki);
401 return true;
402 }
403
388 enum CRLSetResult { 404 enum CRLSetResult {
405 // Indicates an error happened while attempting to determine CRLSet status.
406 // For example, if the certificate's SPKI could not be extracted.
407 kCRLSetError,
408
409 // Indicates there is no fresh information about the certificate, or if the
410 // CRLSet has expired.
411 // In the case of certificate chains, this is only returned if the leaf
412 // certificate is not covered by the CRLSet; this is because some
413 // intermediates are fully covered, but after filtering, the issuer's CRL
414 // is empty and thus omitted from the CRLSet. Since online checking is
415 // performed for EV certificates when this status is returned, this would
416 // result in needless online lookups for certificates known not-revoked.
417 kCRLSetUnknown,
418
419 // Indicates that the certificate (or a certificate in the chain) has been
420 // revoked.
421 kCRLSetRevoked,
422
423 // The certificate (or certificate chain) has no revocations.
389 kCRLSetOk, 424 kCRLSetOk,
390 kCRLSetUnknown,
391 kCRLSetRevoked,
392 }; 425 };
393 426
394 // CheckRevocationWithCRLSet attempts to check each element of |chain| 427 // Determines if |subject_cert| is revoked within |crl_set|,
428 // storing the SubjectPublicKeyInfo hash of |subject_cert| in
429 // |*previous_hash|.
430 //
431 // CRLSets store revocations by both SPKI and by the tuple of Issuer SPKI
432 // Hash & Serial. While |subject_cert| contains enough information to check
433 // for SPKI revocations, to determine the issuer's SPKI, either |issuer_cert|
434 // must be supplied, or the hash of the issuer's SPKI provided in
435 // |*previous_hash|. If |issuer_cert| is omitted, and |*previous_hash| is empty,
436 // only SPKI checks are performed.
437 //
438 // To avoid recomputing SPKI hashes, the hash of |subject_cert| is stored in
439 // |*previous_hash|. This allows chaining revocation checking, by starting
440 // at the root and iterating to the leaf, supplying |previous_hash| each time.
441 //
442 // In the event of a parsing error, |*previous_hash| is cleared, to prevent the
443 // wrong Issuer&Serial tuple from being used.
444 CRLSetResult CheckRevocationWithCRLSet(CRLSet* crl_set,
445 PCCERT_CONTEXT subject_cert,
446 PCCERT_CONTEXT issuer_cert,
447 std::string* previous_hash) {
448 DCHECK(crl_set);
449 DCHECK(subject_cert);
450
451 // Check to see if |subject_cert|'s SPKI is revoked. The actual revocation
452 // is handled by the SHA-256 hash of the SPKI, so compute that.
453 std::string subject_hash;
454 if (!HashSPKI(subject_cert, &subject_hash)) {
455 NOTREACHED(); // Indicates Windows accepted something irrecoverably bad.
456 previous_hash->clear();
457 return kCRLSetError;
458 }
459
460 CRLSet::Result result = crl_set->CheckSPKI(subject_hash);
461 if (result == CRLSet::REVOKED)
462 return kCRLSetRevoked;
463
464 // If no issuer cert is provided, nor a hash of the issuer's SPKI, no
465 // further checks can be done.
466 if (!issuer_cert && previous_hash->empty()) {
467 previous_hash->swap(subject_hash);
468 return kCRLSetUnknown;
469 }
470
471 // Compute the subject's serial.
472 const CRYPT_INTEGER_BLOB* serial_blob =
473 &subject_cert->pCertInfo->SerialNumber;
474 scoped_ptr<uint8_t[]> serial_bytes(new uint8_t[serial_blob->cbData]);
475 // The bytes of the serial number are stored little-endian.
476 // Note: While MSDN implies that bytes are stripped from this serial,
477 // they are not - only CertCompareIntegerBlob actually removes bytes.
478 for (DWORD j = 0; j < serial_blob->cbData; j++)
479 serial_bytes[j] = serial_blob->pbData[serial_blob->cbData - j - 1];
480 base::StringPiece serial(reinterpret_cast<const char*>(serial_bytes.get()),
481 serial_blob->cbData);
482
483 // Compute the issuer's hash. If it was provided (via previous_hash),
484 // use that; otherwise, compute it based on |issuer_cert|.
485 std::string issuer_hash_local;
486 std::string* issuer_hash = previous_hash;
487 if (issuer_hash->empty()) {
488 if (!HashSPKI(issuer_cert, &issuer_hash_local)) {
489 NOTREACHED(); // Indicates Windows accepted something irrecoverably bad.
490 previous_hash->clear();
491 return kCRLSetError;
492 }
493 issuer_hash = &issuer_hash_local;
494 }
495
496 // Look up by serial & issuer SPKI.
497 result = crl_set->CheckSerial(serial, *issuer_hash);
498 if (result == CRLSet::REVOKED)
499 return kCRLSetRevoked;
500
501 previous_hash->swap(subject_hash);
502 if (result == CRLSet::GOOD)
503 return kCRLSetOk;
504 if (result == CRLSet::UNKNOWN)
505 return kCRLSetUnknown;
506
507 NOTREACHED();
508 return kCRLSetError;
509 }
510
511 // CheckChainRevocationWithCRLSet attempts to check each element of |chain|
395 // against |crl_set|. It returns: 512 // against |crl_set|. It returns:
396 // kCRLSetRevoked: if any element of the chain is known to have been revoked. 513 // kCRLSetRevoked: if any element of the chain is known to have been revoked.
397 // kCRLSetUnknown: if there is no fresh information about the leaf 514 // kCRLSetUnknown: if there is no fresh information about the leaf
398 // certificate in the chain or if the CRLSet has expired. 515 // certificate in the chain or if the CRLSet has expired.
399 // 516 //
400 // Only the leaf certificate is considered for coverage because some 517 // Only the leaf certificate is considered for coverage because some
401 // intermediates have CRLs with no revocations (after filtering) and 518 // intermediates have CRLs with no revocations (after filtering) and
402 // those CRLs are pruned from the CRLSet at generation time. This means 519 // those CRLs are pruned from the CRLSet at generation time. This means
403 // that some EV sites would otherwise take the hit of an OCSP lookup for 520 // that some EV sites would otherwise take the hit of an OCSP lookup for
404 // no reason. 521 // no reason.
405 // kCRLSetOk: otherwise. 522 // kCRLSetOk: otherwise.
406 CRLSetResult CheckRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain, 523 CRLSetResult CheckChainRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain,
407 CRLSet* crl_set) { 524 CRLSet* crl_set) {
408 if (chain->cChain == 0) 525 if (chain->cChain == 0 || chain->rgpChain[0]->cElement == 0)
409 return kCRLSetOk; 526 return kCRLSetOk;
410 527
411 const PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0]; 528 PCERT_CHAIN_ELEMENT* elements = chain->rgpChain[0]->rgpElement;
412 const PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; 529 DWORD num_elements = chain->rgpChain[0]->cElement;
413 530
414 const int num_elements = first_chain->cElement; 531 bool had_error = false;
415 if (num_elements == 0) 532 CRLSetResult result = kCRLSetError;
416 return kCRLSetOk;
417
418 // error is set to true if any errors are found. It causes such chains to be
419 // considered as not covered.
420 bool error = false;
421 // last_covered is set to the coverage state of the previous certificate. The
422 // certificates are iterated over backwards thus, after the iteration,
423 // |last_covered| contains the coverage state of the leaf certificate.
424 bool last_covered = false;
425
426 // We iterate from the root certificate down to the leaf, keeping track of
427 // the issuer's SPKI at each step.
428 std::string issuer_spki_hash; 533 std::string issuer_spki_hash;
429 for (int i = num_elements - 1; i >= 0; i--) { 534 for (DWORD i = 0; i < num_elements; ++i) {
430 PCCERT_CONTEXT cert = element[i]->pCertContext; 535 PCCERT_CONTEXT subject = elements[num_elements - i - 1]->pCertContext;
431 536 result =
432 base::StringPiece der_bytes( 537 CheckRevocationWithCRLSet(crl_set, subject, nullptr, &issuer_spki_hash);
433 reinterpret_cast<const char*>(cert->pbCertEncoded), 538 if (result == kCRLSetRevoked)
434 cert->cbCertEncoded); 539 return result;
435 540 if (result == kCRLSetError)
436 base::StringPiece spki; 541 had_error = true;
437 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) {
438 NOTREACHED();
439 error = true;
440 continue;
441 }
442
443 const std::string spki_hash = crypto::SHA256HashString(spki);
444
445 const CRYPT_INTEGER_BLOB* serial_blob = &cert->pCertInfo->SerialNumber;
446 scoped_ptr<uint8_t[]> serial_bytes(new uint8_t[serial_blob->cbData]);
447 // The bytes of the serial number are stored little-endian.
448 for (unsigned j = 0; j < serial_blob->cbData; j++)
449 serial_bytes[j] = serial_blob->pbData[serial_blob->cbData - j - 1];
450 base::StringPiece serial(reinterpret_cast<const char*>(serial_bytes.get()),
451 serial_blob->cbData);
452
453 CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
454
455 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
456 result = crl_set->CheckSerial(serial, issuer_spki_hash);
457
458 issuer_spki_hash = spki_hash;
459
460 switch (result) {
461 case CRLSet::REVOKED:
462 return kCRLSetRevoked;
463 case CRLSet::UNKNOWN:
464 last_covered = false;
465 continue;
466 case CRLSet::GOOD:
467 last_covered = true;
468 continue;
469 default:
470 NOTREACHED();
471 error = true;
472 continue;
473 }
474 } 542 }
475 543 if (had_error || crl_set->IsExpired())
476 if (error || !last_covered || crl_set->IsExpired())
477 return kCRLSetUnknown; 544 return kCRLSetUnknown;
478 return kCRLSetOk; 545 return result;
479 } 546 }
480 547
481 void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain, 548 void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain,
482 HashValueVector* hashes) { 549 HashValueVector* hashes) {
483 if (chain->cChain == 0) 550 if (chain->cChain == 0)
484 return; 551 return;
485 552
486 PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0]; 553 PCERT_SIMPLE_CHAIN first_chain = chain->rgpChain[0];
487 PCERT_CHAIN_ELEMENT* const element = first_chain->rgpElement; 554 PCERT_CHAIN_ELEMENT* const element = first_chain->rgpElement;
488 555
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 return false; 611 return false;
545 612
546 // Look up the EV policy OID of the root CA. 613 // Look up the EV policy OID of the root CA.
547 PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; 614 PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext;
548 SHA1HashValue fingerprint = 615 SHA1HashValue fingerprint =
549 X509Certificate::CalculateFingerprint(root_cert); 616 X509Certificate::CalculateFingerprint(root_cert);
550 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); 617 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
551 return metadata->HasEVPolicyOID(fingerprint, policy_oid); 618 return metadata->HasEVPolicyOID(fingerprint, policy_oid);
552 } 619 }
553 620
621 // Custom revocation provider function that compares incoming certificates with
622 // those in CRLSets. This is called BEFORE the default CRL & OCSP handling
623 // is invoked (which is handled by the revocation provider function
624 // "CertDllVerifyRevocation" in cryptnet.dll)
625 BOOL WINAPI
626 CertDllVerifyRevocationWithCRLSet(DWORD encoding_type,
627 DWORD revocation_type,
628 DWORD num_contexts,
629 void* rgpvContext[],
630 DWORD flags,
631 PCERT_REVOCATION_PARA revocation_params,
632 PCERT_REVOCATION_STATUS revocation_status);
633
634 // Helper class that installs the CRLSet-based Revocation Provider as the
635 // default revocation provider. Because it is installed as a function address
636 // (meaning only scoped to the process, and not stored in the registry), it
637 // will be used before any registry-based providers, including Microsoft's
638 // default provider.
639 class RevocationInjector {
640 public:
641 CRLSet* GetCRLSet() { return thread_local_crlset.Get(); }
642
643 void SetCRLSet(CRLSet* crl_set) { thread_local_crlset.Set(crl_set); }
644
645 private:
646 friend struct base::DefaultLazyInstanceTraits<RevocationInjector>;
647
648 RevocationInjector() {
649 const CRYPT_OID_FUNC_ENTRY kInterceptFunction[] = {
650 {CRYPT_DEFAULT_OID, &CertDllVerifyRevocationWithCRLSet},
651 };
652 BOOL ok = CryptInstallOIDFunctionAddress(
653 NULL, X509_ASN_ENCODING, CRYPT_OID_VERIFY_REVOCATION_FUNC,
654 arraysize(kInterceptFunction), kInterceptFunction,
655 CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG);
656 DCHECK(ok);
657 }
658
659 ~RevocationInjector() {}
660
661 // As the revocation parameters passed to CertVerifyProc::VerifyInternal
662 // cannot be officially smuggled to the Revocation Provider
663 base::ThreadLocalPointer<CRLSet> thread_local_crlset;
664 };
665
666 // Leaky, as CertVerifyProc workers are themselves leaky.
667 base::LazyInstance<RevocationInjector>::Leaky g_revocation_injector =
668 LAZY_INSTANCE_INITIALIZER;
669
670 BOOL WINAPI
671 CertDllVerifyRevocationWithCRLSet(DWORD encoding_type,
672 DWORD revocation_type,
673 DWORD num_contexts,
674 void* rgpvContext[],
675 DWORD flags,
676 PCERT_REVOCATION_PARA revocation_params,
677 PCERT_REVOCATION_STATUS revocation_status) {
678 PCERT_CONTEXT* cert_contexts = reinterpret_cast<PCERT_CONTEXT*>(rgpvContext);
679 // The dummy CRLSet provider never returns that something is affirmatively
680 // *un*revoked, as this would disable other revocation providers from being
681 // checked for this certificate (much like an OCSP "Good" status would).
682 // Instead, it merely indicates that insufficient information existed to
683 // determine if the certificate was revoked (in the good case), or that a cert
684 // is affirmatively revoked in the event it appears within the CRLSet.
685 // Because of this, set up some basic bookkeeping for the results.
686 CHECK(revocation_status);
687 revocation_status->dwIndex = 0;
688 revocation_status->dwError = static_cast<DWORD>(CRYPT_E_NO_REVOCATION_CHECK);
689 revocation_status->dwReason = 0;
690
691 if (num_contexts == 0 || !cert_contexts[0]) {
692 SetLastError(static_cast<DWORD>(E_INVALIDARG));
693 return FALSE;
694 }
695
696 if ((GET_CERT_ENCODING_TYPE(encoding_type) != X509_ASN_ENCODING) ||
697 revocation_type != CERT_CONTEXT_REVOCATION_TYPE) {
698 SetLastError(static_cast<DWORD>(CRYPT_E_NO_REVOCATION_CHECK));
699 return FALSE;
700 }
701
702 // No revocation checking possible if there is no associated
703 // CRLSet.
704 CRLSet* crl_set = g_revocation_injector.Get().GetCRLSet();
705 if (!crl_set)
706 return FALSE;
707
708 // |revocation_params| is an optional structure; to make life simple and avoid
709 // the need to constantly check whether or not it was supplied, create a local
710 // copy. If the caller didn't supply anything, it will be empty; otherwise,
711 // it will be (non-owning) copies of the caller's original params.
712 CERT_REVOCATION_PARA local_params;
713 memset(&local_params, 0, sizeof(local_params));
714 if (revocation_params) {
715 DWORD bytes_to_copy = std::min(revocation_params->cbSize,
716 static_cast<DWORD>(sizeof(local_params)));
717 memcpy(&local_params, revocation_params, bytes_to_copy);
718 }
719 local_params.cbSize = sizeof(local_params);
720
721 PCERT_CONTEXT subject_cert = cert_contexts[0];
722
723 if ((flags & CERT_VERIFY_REV_CHAIN_FLAG) && num_contexts > 1) {
724 // Verifying a chain; first verify from the last certificate in the
725 // chain to the first, and then leave the last certificate (which
726 // is presumably self-issued, although it may simply be a trust
727 // anchor) as the |subject_cert| in order to scan for more
728 // revocations.
729 std::string issuer_hash;
730 PCCERT_CONTEXT issuer_cert = nullptr;
731 for (DWORD i = num_contexts; i > 0; --i) {
732 subject_cert = cert_contexts[i - 1];
733 if (!subject_cert) {
734 SetLastError(static_cast<DWORD>(E_INVALIDARG));
735 return FALSE;
736 }
737 CRLSetResult result = CheckRevocationWithCRLSet(
738 crl_set, subject_cert, issuer_cert, &issuer_hash);
739 if (result == kCRLSetRevoked) {
740 revocation_status->dwIndex = i - 1;
741 revocation_status->dwError = static_cast<DWORD>(CRYPT_E_REVOKED);
742 revocation_status->dwReason = CRL_REASON_UNSPECIFIED;
743 SetLastError(revocation_status->dwError);
744 return FALSE;
745 }
746 issuer_cert = subject_cert;
747 }
748 // Verified all certificates from the trust anchor to the leaf, and none
749 // were explicitly revoked. Now do a second pass to attempt to determine
750 // the issuer for cert_contexts[num_contexts - 1], so that the
751 // Issuer SPKI+Serial can be checked for that certificate.
752 //
753 // This code intentionally ignores the flag
754 subject_cert = cert_contexts[num_contexts - 1];
755 // Reset local_params.pIssuerCert, since it would contain the issuer
756 // for cert_contexts[0].
757 local_params.pIssuerCert = nullptr;
758 // Fixup the revocation index to point to this cert (in the event it is
759 // revoked). If it isn't revoked, this will be done undone later.
760 revocation_status->dwIndex = num_contexts - 1;
761 }
762
763 // Determine the issuer cert for the incoming cert
764 ScopedPCCERT_CONTEXT issuer_cert;
765 if (local_params.pIssuerCert &&
766 CryptVerifyCertificateSignatureEx(
767 NULL, subject_cert->dwCertEncodingType,
768 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, subject_cert,
769 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
770 const_cast<PCERT_CONTEXT>(local_params.pIssuerCert), 0, nullptr)) {
771 // Caller has already supplied the issuer cert via the revocation params;
772 // just use that.
773 issuer_cert.reset(
774 CertDuplicateCertificateContext(local_params.pIssuerCert));
775 } else if (CertCompareCertificateName(subject_cert->dwCertEncodingType,
776 &subject_cert->pCertInfo->Subject,
777 &subject_cert->pCertInfo->Issuer) &&
778 CryptVerifyCertificateSignatureEx(
779 NULL, subject_cert->dwCertEncodingType,
780 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, subject_cert,
781 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, subject_cert, 0,
782 nullptr)) {
783 // Certificate is self-signed; use it as its own issuer.
784 issuer_cert.reset(CertDuplicateCertificateContext(subject_cert));
785 } else {
786 // Scan the caller-supplied stores first, to try and find the issuer cert.
787 for (DWORD i = 0; i < local_params.cCertStore && !issuer_cert; ++i) {
788 PCCERT_CONTEXT previous_cert = nullptr;
789 for (;;) {
790 DWORD store_search_flags = CERT_STORE_SIGNATURE_FLAG;
791 previous_cert = CertGetIssuerCertificateFromStore(
792 local_params.rgCertStore[i], subject_cert, previous_cert,
793 &store_search_flags);
794 if (!previous_cert)
795 break;
796 // If a cert is found and meets the criteria, the flag will be reset to
797 // zero. Thus NOT having the bit set is equivalent to having found a
798 // matching certificate.
799 if (!(store_search_flags & CERT_STORE_SIGNATURE_FLAG)) {
800 // No need to dupe; reference is held.
801 issuer_cert.reset(previous_cert);
802 break;
803 }
804 }
805 if (issuer_cert)
806 break;
807 if (GetLastError() == CRYPT_E_SELF_SIGNED) {
808 issuer_cert.reset(CertDuplicateCertificateContext(subject_cert));
809 break;
810 }
811 }
812
813 // At this point, the Microsoft provider opens up the "CA", "Root", and
814 // "SPC" stores to search for the issuer certificate, if not found in the
815 // caller-supplied stores. It is unclear whether that is necessary here.
816 }
817
818 if (!issuer_cert) {
819 // Rather than return CRYPT_E_NO_REVOCATION_CHECK (indicating everything
820 // is fine to try the next provider), return CRYPT_E_REVOCATION_OFFLINE.
821 // This propogates up to the caller as an error while checking revocation,
822 // which is the desired intent if there are certificates that cannot
823 // be checked.
824 revocation_status->dwIndex = 0;
825 revocation_status->dwError = static_cast<DWORD>(CRYPT_E_REVOCATION_OFFLINE);
826 SetLastError(revocation_status->dwError);
827 return FALSE;
828 }
829
830 std::string unused;
831 CRLSetResult result = CheckRevocationWithCRLSet(crl_set, subject_cert,
832 issuer_cert.get(), &unused);
833 if (result == kCRLSetRevoked) {
834 revocation_status->dwError = static_cast<DWORD>(CRYPT_E_REVOKED);
835 revocation_status->dwReason = CRL_REASON_UNSPECIFIED;
836 SetLastError(revocation_status->dwError);
837 return FALSE;
838 }
839
840 // The result is ALWAYS FALSE in order to allow the next revocation provider
841 // a chance to examine. The only difference is whether or not an error is
842 // indicated via dwError (and SetLastError()).
843 // Reset the error index so that Windows does not believe this code has
844 // examined the entire chain and found no issues until the last cert (thus
845 // skipping other revocation providers).
846 revocation_status->dwIndex = 0;
847 return FALSE;
848 }
849
850 class ScopedThreadLocalCRLSet {
851 public:
852 explicit ScopedThreadLocalCRLSet(CRLSet* crl_set) {
853 g_revocation_injector.Get().SetCRLSet(crl_set);
854 }
855 ~ScopedThreadLocalCRLSet() { g_revocation_injector.Get().SetCRLSet(nullptr); }
856 };
857
554 } // namespace 858 } // namespace
555 859
556 CertVerifyProcWin::CertVerifyProcWin() {} 860 CertVerifyProcWin::CertVerifyProcWin() {}
557 861
558 CertVerifyProcWin::~CertVerifyProcWin() {} 862 CertVerifyProcWin::~CertVerifyProcWin() {}
559 863
560 bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const { 864 bool CertVerifyProcWin::SupportsAdditionalTrustAnchors() const {
561 return false; 865 return false;
562 } 866 }
563 867
564 bool CertVerifyProcWin::SupportsOCSPStapling() const { 868 bool CertVerifyProcWin::SupportsOCSPStapling() const {
565 // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be 869 // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be
566 // set on Windows XP without error. There is some overhead from the server 870 // set on Windows XP without error. There is some overhead from the server
567 // sending the OCSP response if it supports the extension, for the subset of 871 // sending the OCSP response if it supports the extension, for the subset of
568 // XP clients who will request it but be unable to use it, but this is an 872 // XP clients who will request it but be unable to use it, but this is an
569 // acceptable trade-off for simplicity of implementation. 873 // acceptable trade-off for simplicity of implementation.
570 return true; 874 return true;
571 } 875 }
572 876
573 int CertVerifyProcWin::VerifyInternal( 877 int CertVerifyProcWin::VerifyInternal(
574 X509Certificate* cert, 878 X509Certificate* cert,
575 const std::string& hostname, 879 const std::string& hostname,
576 const std::string& ocsp_response, 880 const std::string& ocsp_response,
577 int flags, 881 int flags,
578 CRLSet* crl_set, 882 CRLSet* crl_set,
579 const CertificateList& additional_trust_anchors, 883 const CertificateList& additional_trust_anchors,
580 CertVerifyResult* verify_result) { 884 CertVerifyResult* verify_result) {
885 // Ensure the Revocation Provider has been installed and configured for this
886 // CRLSet.
887 ScopedThreadLocalCRLSet thread_local_crlset(crl_set);
888
581 PCCERT_CONTEXT cert_handle = cert->os_cert_handle(); 889 PCCERT_CONTEXT cert_handle = cert->os_cert_handle();
582 if (!cert_handle) 890 if (!cert_handle)
583 return ERR_UNEXPECTED; 891 return ERR_UNEXPECTED;
584 892
585 // Build and validate certificate chain. 893 // Build and validate certificate chain.
586 CERT_CHAIN_PARA chain_para; 894 CERT_CHAIN_PARA chain_para;
587 memset(&chain_para, 0, sizeof(chain_para)); 895 memset(&chain_para, 0, sizeof(chain_para));
588 chain_para.cbSize = sizeof(chain_para); 896 chain_para.cbSize = sizeof(chain_para);
589 // ExtendedKeyUsage. 897 // ExtendedKeyUsage.
590 // We still need to request szOID_SERVER_GATED_CRYPTO and szOID_SGC_NETSCAPE 898 // We still need to request szOID_SERVER_GATED_CRYPTO and szOID_SGC_NETSCAPE
(...skipping 23 matching lines...) Expand all
614 chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND; 922 chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
615 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 1; 923 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 1;
616 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = 924 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier =
617 &ev_policy_oid; 925 &ev_policy_oid;
618 break; 926 break;
619 } 927 }
620 } 928 }
621 } 929 }
622 } 930 }
623 931
624 // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains. 932 // Revocation checking is always enabled, in order to enable CRLSets to be
625 DWORD chain_flags = CERT_CHAIN_CACHE_END_CERT | 933 // evaluated as part of a revocation provider. However, when the caller did
626 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; 934 // not explicitly request revocation checking (which is to say, online
935 // revocation checking), then only enable cached results. This disables OCSP
936 // and CRL fetching, but still allows the revocation provider to be called.
937 // Note: The root cert is also checked for revocation status, so that CRLSets
938 // will cover revoked SPKIs.
939 DWORD chain_flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
627 bool rev_checking_enabled = 940 bool rev_checking_enabled =
628 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); 941 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
629
630 if (rev_checking_enabled) { 942 if (rev_checking_enabled) {
631 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 943 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
632 } else { 944 } else {
633 chain_flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; 945 chain_flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
634 } 946 }
635 947
636 // For non-test scenarios, use the default HCERTCHAINENGINE, NULL, which 948 // By default, use the default HCERTCHAINENGINE (aka HCCE_CURRENT_USER). When
637 // corresponds to HCCE_CURRENT_USER and is is initialized as needed by 949 // running tests, use a dynamic HCERTCHAINENGINE. All of the status and cache
638 // crypt32. However, when testing, it is necessary to create a new 950 // of verified certificates and chains is tied to the HCERTCHAINENGINE. As
639 // HCERTCHAINENGINE and use that instead. This is because each 951 // each invocation may have changed the set of known roots, invalid the cache
640 // HCERTCHAINENGINE maintains a cache of information about certificates 952 // between runs.
641 // encountered, and each test run may modify the trust status of a 953 //
642 // certificate. 954 // This is not the most efficient means of doing so; it's possible to mark the
955 // Root store used by TestRootCerts as changed, via CertControlStore with the
956 // CERT_STORE_CTRL_NOTIFY_CHANGE / CERT_STORE_CTRL_RESYNC, but that's more
957 // complexity for what is test-only code.
643 ScopedHCERTCHAINENGINE chain_engine(NULL); 958 ScopedHCERTCHAINENGINE chain_engine(NULL);
644 if (TestRootCerts::HasInstance()) 959 if (TestRootCerts::HasInstance())
645 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine()); 960 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine());
646 961
647 ScopedPCCERT_CONTEXT cert_list(cert->CreateOSCertChainForCert()); 962 ScopedPCCERT_CONTEXT cert_list(cert->CreateOSCertChainForCert());
648 963
964 // Add stapled OCSP response data, which will be preferred over online checks
965 // and used when in cache-only mode.
649 if (!ocsp_response.empty()) { 966 if (!ocsp_response.empty()) {
650 // Attach the OCSP response to the chain.
651 CRYPT_DATA_BLOB ocsp_response_blob; 967 CRYPT_DATA_BLOB ocsp_response_blob;
652 ocsp_response_blob.cbData = ocsp_response.size(); 968 ocsp_response_blob.cbData = ocsp_response.size();
653 ocsp_response_blob.pbData = 969 ocsp_response_blob.pbData =
654 reinterpret_cast<BYTE*>(const_cast<char*>(ocsp_response.data())); 970 reinterpret_cast<BYTE*>(const_cast<char*>(ocsp_response.data()));
655 CertSetCertificateContextProperty( 971 CertSetCertificateContextProperty(
656 cert_list.get(), CERT_OCSP_RESPONSE_PROP_ID, 972 cert_list.get(), CERT_OCSP_RESPONSE_PROP_ID,
657 CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG, &ocsp_response_blob); 973 CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG, &ocsp_response_blob);
658 } 974 }
659 975
660 PCCERT_CHAIN_CONTEXT chain_context; 976 PCCERT_CHAIN_CONTEXT chain_context = nullptr;
661 // IE passes a non-NULL pTime argument that specifies the current system
662 // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
663 // chain_flags argument.
664 if (!CertGetCertificateChain( 977 if (!CertGetCertificateChain(
665 chain_engine, 978 chain_engine,
666 cert_list.get(), 979 cert_list.get(),
667 NULL, // current system time 980 NULL, // current system time
668 cert_list->hCertStore, 981 cert_list->hCertStore,
669 &chain_para, 982 &chain_para,
670 chain_flags, 983 chain_flags,
671 NULL, // reserved 984 NULL, // reserved
672 &chain_context)) { 985 &chain_context)) {
673 verify_result->cert_status |= CERT_STATUS_INVALID; 986 verify_result->cert_status |= CERT_STATUS_INVALID;
674 return MapSecurityError(GetLastError()); 987 return MapSecurityError(GetLastError());
675 } 988 }
676 989
990 // Perform a second check with CRLSets. Although the Revocation Provider
991 // should have prevented invalid paths from being built, the behaviour and
992 // timing of how a Revocation Provider is invoked is not well documented. This
993 // is just defense in depth.
677 CRLSetResult crl_set_result = kCRLSetUnknown; 994 CRLSetResult crl_set_result = kCRLSetUnknown;
678 if (crl_set) 995 if (crl_set)
679 crl_set_result = CheckRevocationWithCRLSet(chain_context, crl_set); 996 crl_set_result = CheckChainRevocationWithCRLSet(chain_context, crl_set);
680 997
681 if (crl_set_result == kCRLSetRevoked) { 998 if (crl_set_result == kCRLSetRevoked) {
682 verify_result->cert_status |= CERT_STATUS_REVOKED; 999 verify_result->cert_status |= CERT_STATUS_REVOKED;
683 } else if (crl_set_result == kCRLSetUnknown && 1000 } else if (crl_set_result == kCRLSetUnknown &&
684 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) && 1001 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
685 !rev_checking_enabled && 1002 !rev_checking_enabled &&
686 ev_policy_oid != NULL) { 1003 ev_policy_oid != NULL) {
687 // We don't have fresh information about this chain from the CRLSet and 1004 // We don't have fresh information about this chain from the CRLSet and
688 // it's probably an EV certificate. Retry with online revocation checking. 1005 // it's probably an EV certificate. Retry with online revocation checking.
689 rev_checking_enabled = true; 1006 rev_checking_enabled = true;
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 return MapCertStatusToNetError(verify_result->cert_status); 1144 return MapCertStatusToNetError(verify_result->cert_status);
828 1145
829 if (ev_policy_oid && 1146 if (ev_policy_oid &&
830 CheckEV(chain_context, rev_checking_enabled, ev_policy_oid)) { 1147 CheckEV(chain_context, rev_checking_enabled, ev_policy_oid)) {
831 verify_result->cert_status |= CERT_STATUS_IS_EV; 1148 verify_result->cert_status |= CERT_STATUS_IS_EV;
832 } 1149 }
833 return OK; 1150 return OK;
834 } 1151 }
835 1152
836 } // namespace net 1153 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/cert_verify_proc_unittest.cc ('k') | net/data/ssl/certificates/multi-root-A-by-B.pem » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698