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

Side by Side Diff: net/base/x509_certificate_win.cc

Issue 7324039: Ensure X509Certificate::OSCertHandles are safe to be used on both UI and IO threads on Win (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review feedback Created 9 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/base/x509_certificate.h" 5 #include "net/base/x509_certificate.h"
6 6
7 #include "base/lazy_instance.h" 7 #include "base/lazy_instance.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/pickle.h" 9 #include "base/pickle.h"
10 #include "base/sha1.h" 10 #include "base/sha1.h"
11 #include "base/string_tokenizer.h" 11 #include "base/string_tokenizer.h"
12 #include "base/string_util.h" 12 #include "base/string_util.h"
13 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
14 #include "crypto/rsa_private_key.h" 14 #include "crypto/rsa_private_key.h"
15 #include "crypto/scoped_capi_types.h" 15 #include "crypto/scoped_capi_types.h"
16 #include "net/base/asn1_util.h" 16 #include "net/base/asn1_util.h"
17 #include "net/base/cert_status_flags.h" 17 #include "net/base/cert_status_flags.h"
18 #include "net/base/cert_verify_result.h" 18 #include "net/base/cert_verify_result.h"
19 #include "net/base/ev_root_ca_metadata.h" 19 #include "net/base/ev_root_ca_metadata.h"
20 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
21 #include "net/base/scoped_cert_chain_context.h"
22 #include "net/base/test_root_certs.h" 21 #include "net/base/test_root_certs.h"
23 #include "net/base/x509_certificate_known_roots_win.h" 22 #include "net/base/x509_certificate_known_roots_win.h"
24 23
25 #pragma comment(lib, "crypt32.lib") 24 #pragma comment(lib, "crypt32.lib")
26 25
27 using base::Time; 26 using base::Time;
28 27
29 namespace net { 28 namespace net {
30 29
31 namespace { 30 namespace {
32 31
33 typedef crypto::ScopedCAPIHandle<
34 HCERTSTORE,
35 crypto::CAPIDestroyerWithFlags<HCERTSTORE,
36 CertCloseStore, 0> > ScopedHCERTSTORE;
37
38 struct FreeChainEngineFunctor { 32 struct FreeChainEngineFunctor {
39 void operator()(HCERTCHAINENGINE engine) const { 33 void operator()(HCERTCHAINENGINE engine) const {
40 if (engine) 34 if (engine)
41 CertFreeCertificateChainEngine(engine); 35 CertFreeCertificateChainEngine(engine);
42 } 36 }
43 }; 37 };
44 38
39 struct FreeCertContextFunctor {
40 void operator()(PCCERT_CONTEXT context) const {
41 if (context)
42 CertFreeCertificateContext(context);
43 }
44 };
45
46 struct FreeCertChainContextFunctor {
47 void operator()(PCCERT_CHAIN_CONTEXT chain_context) const {
48 if (context)
49 CertFreeCertificateChain(context);
50 }
51 };
52
53 typedef crypto::ScopedCAPIHandle<
54 HCERTSTORE,
55 crypto::CAPIDestroyerWithFlags<HCERTSTORE,
56 CertCloseStore, 0> > ScopedHCERTSTORE;
57
45 typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor> 58 typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor>
46 ScopedHCERTCHAINENGINE; 59 ScopedHCERTCHAINENGINE;
47 60
61 typedef scoped_ptr_malloc<const CERT_CONTEXT,
62 FreeCertContextFunctor> ScopedCertContext;
63
64 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT,
65 FreeCertChainContextFunctor> ScopedCertChainContext;
66
wtc 2011/10/04 18:00:52 Nit: delete one blank line.
67
48 //----------------------------------------------------------------------------- 68 //-----------------------------------------------------------------------------
49 69
50 // TODO(wtc): This is a copy of the MapSecurityError function in 70 // TODO(wtc): This is a copy of the MapSecurityError function in
51 // ssl_client_socket_win.cc. Another function that maps Windows error codes 71 // ssl_client_socket_win.cc. Another function that maps Windows error codes
52 // to our network error codes is WinInetUtil::OSErrorToNetError. We should 72 // to our network error codes is WinInetUtil::OSErrorToNetError. We should
53 // eliminate the code duplication. 73 // eliminate the code duplication.
54 int MapSecurityError(SECURITY_STATUS err) { 74 int MapSecurityError(SECURITY_STATUS err) {
55 // There are numerous security error codes, but these are the ones we thus 75 // There are numerous security error codes, but these are the ones we thus
56 // far find interesting. 76 // far find interesting.
57 switch (err) { 77 switch (err) {
(...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 717
698 static base::LazyInstance<GlobalCertStore, 718 static base::LazyInstance<GlobalCertStore,
699 base::LeakyLazyInstanceTraits<GlobalCertStore> > 719 base::LeakyLazyInstanceTraits<GlobalCertStore> >
700 g_cert_store(base::LINKER_INITIALIZED); 720 g_cert_store(base::LINKER_INITIALIZED);
701 721
702 // static 722 // static
703 HCERTSTORE X509Certificate::cert_store() { 723 HCERTSTORE X509Certificate::cert_store() {
704 return g_cert_store.Get().cert_store(); 724 return g_cert_store.Get().cert_store();
705 } 725 }
706 726
727 X509Certificate::OSCertListHandle
728 X509Certificate::CreateOSCertListHandle() const {
729 // Create an in-memory certificate store to hold |cert_handle_| and any
730 // associated intermediate certificates. The store will be referenced in the
731 // returned OSCertListHandle, and will not be freed until the
732 // OSCertListHandle is freed.
733 OSCertListHandle cert_list = NULL;
734 DWORD flags = CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG;
735 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0,
736 NULL, flags, NULL);
737
738 if (store) {
739 // NOTE: This preserves all of the properties of |cert_handle_| except for
740 // CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two
741 // properties that hold access to already-opened private keys. If a handle
742 // has already been unlocked (eg: PIN prompt), then the first time that
743 // the identity is used for client auth, it may prompt the user again.
744 BOOL ok = CertAddCertificateContextToStore(store, cert_handle_,
745 CERT_STORE_ADD_ALWAYS,
746 &cert_list);
747 if (ok && cert_list) {
748 for (size_t i = 0; ok && i < intermediate_ca_certs_.size(); ++i) {
749 ok = CertAddCertificateContextToStore(store, intermediate_ca_certs_[i],
750 CERT_STORE_ADD_ALWAYS, NULL);
751 }
752 }
753
754 // If |cert_list| points to a valid certificate, this will not actually
755 // close and free |store| until |cert_list| is freed.
756 CertCloseStore(store, 0);
757
758 if (!ok) {
759 FreeOSCertListHandle(cert_list);
760 return NULL;
761 }
762 }
763
764 return cert_list;
765 }
766
707 int X509Certificate::VerifyInternal(const std::string& hostname, 767 int X509Certificate::VerifyInternal(const std::string& hostname,
708 int flags, 768 int flags,
709 CertVerifyResult* verify_result) const { 769 CertVerifyResult* verify_result) const {
710 if (!cert_handle_) 770 if (!cert_handle_)
711 return ERR_UNEXPECTED; 771 return ERR_UNEXPECTED;
712 772
713 // Build and validate certificate chain. 773 // Build and validate certificate chain.
714 CERT_CHAIN_PARA chain_para; 774 CERT_CHAIN_PARA chain_para;
715 memset(&chain_para, 0, sizeof(chain_para)); 775 memset(&chain_para, 0, sizeof(chain_para));
716 chain_para.cbSize = sizeof(chain_para); 776 chain_para.cbSize = sizeof(chain_para);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 // corresponds to HCCE_CURRENT_USER and is is initialized as needed by 823 // corresponds to HCCE_CURRENT_USER and is is initialized as needed by
764 // crypt32. However, when testing, it is necessary to create a new 824 // crypt32. However, when testing, it is necessary to create a new
765 // HCERTCHAINENGINE and use that instead. This is because each 825 // HCERTCHAINENGINE and use that instead. This is because each
766 // HCERTCHAINENGINE maintains a cache of information about certificates 826 // HCERTCHAINENGINE maintains a cache of information about certificates
767 // encountered, and each test run may modify the trust status of a 827 // encountered, and each test run may modify the trust status of a
768 // certificate. 828 // certificate.
769 ScopedHCERTCHAINENGINE chain_engine(NULL); 829 ScopedHCERTCHAINENGINE chain_engine(NULL);
770 if (TestRootCerts::HasInstance()) 830 if (TestRootCerts::HasInstance())
771 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine()); 831 chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine());
772 832
833 ScopedPCCERT_CONTEXT cert_list(CreateOSCertListHandle());
wtc 2011/10/04 18:00:52 I don't see where the ScopedPCCERT_CONTEXT type is
773 PCCERT_CHAIN_CONTEXT chain_context; 834 PCCERT_CHAIN_CONTEXT chain_context;
774 // IE passes a non-NULL pTime argument that specifies the current system 835 // IE passes a non-NULL pTime argument that specifies the current system
775 // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the 836 // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
776 // chain_flags argument. 837 // chain_flags argument.
777 if (!CertGetCertificateChain( 838 if (!CertGetCertificateChain(
778 chain_engine, 839 chain_engine,
779 cert_handle_, 840 cert_list,
780 NULL, // current system time 841 NULL, // current system time
781 cert_handle_->hCertStore, 842 cert_list->hCertStore,
782 &chain_para, 843 &chain_para,
783 chain_flags, 844 chain_flags,
784 NULL, // reserved 845 NULL, // reserved
785 &chain_context)) { 846 &chain_context)) {
786 return MapSecurityError(GetLastError()); 847 return MapSecurityError(GetLastError());
787 } 848 }
849
788 if (chain_context->TrustStatus.dwErrorStatus & 850 if (chain_context->TrustStatus.dwErrorStatus &
789 CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { 851 CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
790 ev_policy_oid = NULL; 852 ev_policy_oid = NULL;
791 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0; 853 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0;
792 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL; 854 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL;
793 CertFreeCertificateChain(chain_context); 855 CertFreeCertificateChain(chain_context);
794 if (!CertGetCertificateChain( 856 if (!CertGetCertificateChain(
795 chain_engine, 857 chain_engine,
796 cert_handle_, 858 cert_list,
797 NULL, // current system time 859 NULL, // current system time
798 cert_handle_->hCertStore, 860 cert_list->hCertStore,
799 &chain_para, 861 &chain_para,
800 chain_flags, 862 chain_flags,
801 NULL, // reserved 863 NULL, // reserved
802 &chain_context)) { 864 &chain_context)) {
803 return MapSecurityError(GetLastError()); 865 return MapSecurityError(GetLastError());
804 } 866 }
805 } 867 }
868
806 ScopedCertChainContext scoped_chain_context(chain_context); 869 ScopedCertChainContext scoped_chain_context(chain_context);
807 870
808 GetCertChainInfo(chain_context, verify_result); 871 GetCertChainInfo(chain_context, verify_result);
809 verify_result->cert_status |= MapCertChainErrorStatusToCertStatus( 872 verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
810 chain_context->TrustStatus.dwErrorStatus); 873 chain_context->TrustStatus.dwErrorStatus);
811 874
812 // Treat certificates signed using broken signature algorithms as invalid. 875 // Treat certificates signed using broken signature algorithms as invalid.
813 if (verify_result->has_md4) 876 if (verify_result->has_md4)
814 verify_result->cert_status |= CERT_STATUS_INVALID; 877 verify_result->cert_status |= CERT_STATUS_INVALID;
815 878
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 OSCertHandle cert_handle) { 1067 OSCertHandle cert_handle) {
1005 return CertDuplicateCertificateContext(cert_handle); 1068 return CertDuplicateCertificateContext(cert_handle);
1006 } 1069 }
1007 1070
1008 // static 1071 // static
1009 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { 1072 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
1010 CertFreeCertificateContext(cert_handle); 1073 CertFreeCertificateContext(cert_handle);
1011 } 1074 }
1012 1075
1013 // static 1076 // static
1077 void X509Certificate::FreeOSCertListHandle(OSCertListHandle cert_list) {
1078 CertFreeCertificateContext(cert_list);
1079 }
1080
1081 // static
1014 SHA1Fingerprint X509Certificate::CalculateFingerprint( 1082 SHA1Fingerprint X509Certificate::CalculateFingerprint(
1015 OSCertHandle cert) { 1083 OSCertHandle cert) {
1016 DCHECK(NULL != cert->pbCertEncoded); 1084 DCHECK(NULL != cert->pbCertEncoded);
1017 DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded); 1085 DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded);
1018 1086
1019 BOOL rv; 1087 BOOL rv;
1020 SHA1Fingerprint sha1; 1088 SHA1Fingerprint sha1;
1021 DWORD sha1_size = sizeof(sha1.data); 1089 DWORD sha1_size = sizeof(sha1.data);
1022 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, 1090 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded,
1023 cert->cbCertEncoded, sha1.data, &sha1_size); 1091 cert->cbCertEncoded, sha1.data, &sha1_size);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], 1129 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0],
1062 &length)) { 1130 &length)) {
1063 return false; 1131 return false;
1064 } 1132 }
1065 1133
1066 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), 1134 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]),
1067 length); 1135 length);
1068 } 1136 }
1069 1137
1070 } // namespace net 1138 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698