| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/ssl/client_cert_store_win.h" | 5 #include "net/ssl/client_cert_store_win.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #define SECURITY_WIN32 // Needs to be defined before including security.h | 10 #define SECURITY_WIN32 // Needs to be defined before including security.h |
| 11 #include <windows.h> | 11 #include <windows.h> |
| 12 #include <security.h> | 12 #include <security.h> |
| 13 | 13 |
| 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" |
| 14 #include "base/callback.h" | 16 #include "base/callback.h" |
| 15 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/memory/ptr_util.h" |
| 19 #include "base/task_runner_util.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "crypto/wincrypt_shim.h" | 21 #include "crypto/wincrypt_shim.h" |
| 17 #include "net/cert/x509_util.h" | 22 #include "net/cert/x509_util.h" |
| 23 #include "net/ssl/ssl_platform_key_win.h" |
| 24 #include "net/ssl/ssl_private_key.h" |
| 18 | 25 |
| 19 namespace net { | 26 namespace net { |
| 20 | 27 |
| 21 namespace { | 28 namespace { |
| 22 | 29 |
| 30 class ClientCertIdentityWin : public ClientCertIdentity { |
| 31 public: |
| 32 // Takes ownership of |cert_context|. |
| 33 ClientCertIdentityWin( |
| 34 scoped_refptr<net::X509Certificate> cert, |
| 35 PCCERT_CONTEXT cert_context, |
| 36 scoped_refptr<base::SingleThreadTaskRunner> key_task_runner) |
| 37 : ClientCertIdentity(std::move(cert)), |
| 38 cert_context_(cert_context), |
| 39 key_task_runner_(key_task_runner) {} |
| 40 ~ClientCertIdentityWin() override { |
| 41 CertFreeCertificateContext(cert_context_); |
| 42 } |
| 43 |
| 44 void AcquirePrivateKey( |
| 45 const base::Callback<void(scoped_refptr<SSLPrivateKey>)>& |
| 46 private_key_callback) override { |
| 47 if (base::PostTaskAndReplyWithResult( |
| 48 key_task_runner_.get(), FROM_HERE, |
| 49 base::Bind(&FetchClientCertPrivateKey, |
| 50 base::Unretained(certificate()), cert_context_), |
| 51 private_key_callback)) { |
| 52 return; |
| 53 } |
| 54 // If the task could not be posted, behave as if there was no key. |
| 55 private_key_callback.Run(nullptr); |
| 56 } |
| 57 |
| 58 private: |
| 59 PCCERT_CONTEXT cert_context_; |
| 60 scoped_refptr<base::SingleThreadTaskRunner> key_task_runner_; |
| 61 }; |
| 62 |
| 23 // Callback required by Windows API function CertFindChainInStore(). In addition | 63 // Callback required by Windows API function CertFindChainInStore(). In addition |
| 24 // to filtering by extended/enhanced key usage, we do not show expired | 64 // to filtering by extended/enhanced key usage, we do not show expired |
| 25 // certificates and require digital signature usage in the key usage extension. | 65 // certificates and require digital signature usage in the key usage extension. |
| 26 // | 66 // |
| 27 // This matches our behavior on Mac OS X and that of NSS. It also matches the | 67 // This matches our behavior on Mac OS X and that of NSS. It also matches the |
| 28 // default behavior of IE8. See http://support.microsoft.com/kb/890326 and | 68 // default behavior of IE8. See http://support.microsoft.com/kb/890326 and |
| 29 // http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certifica | 69 // http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certifica |
| 30 // tes-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx | 70 // tes-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx |
| 31 static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context, | 71 static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context, |
| 32 void* find_arg) { | 72 void* find_arg) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 58 if (!CertGetCertificateContextProperty( | 98 if (!CertGetCertificateContextProperty( |
| 59 cert_context, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) { | 99 cert_context, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) { |
| 60 return FALSE; | 100 return FALSE; |
| 61 } | 101 } |
| 62 | 102 |
| 63 return TRUE; | 103 return TRUE; |
| 64 } | 104 } |
| 65 | 105 |
| 66 void GetClientCertsImpl(HCERTSTORE cert_store, | 106 void GetClientCertsImpl(HCERTSTORE cert_store, |
| 67 const SSLCertRequestInfo& request, | 107 const SSLCertRequestInfo& request, |
| 68 CertificateList* selected_certs) { | 108 ClientCertIdentityList* selected_identities) { |
| 69 selected_certs->clear(); | 109 selected_identities->clear(); |
| 110 |
| 111 scoped_refptr<base::SingleThreadTaskRunner> current_thread = |
| 112 base::ThreadTaskRunnerHandle::Get(); |
| 70 | 113 |
| 71 const size_t auth_count = request.cert_authorities.size(); | 114 const size_t auth_count = request.cert_authorities.size(); |
| 72 std::vector<CERT_NAME_BLOB> issuers(auth_count); | 115 std::vector<CERT_NAME_BLOB> issuers(auth_count); |
| 73 for (size_t i = 0; i < auth_count; ++i) { | 116 for (size_t i = 0; i < auth_count; ++i) { |
| 74 issuers[i].cbData = static_cast<DWORD>(request.cert_authorities[i].size()); | 117 issuers[i].cbData = static_cast<DWORD>(request.cert_authorities[i].size()); |
| 75 issuers[i].pbData = reinterpret_cast<BYTE*>( | 118 issuers[i].pbData = reinterpret_cast<BYTE*>( |
| 76 const_cast<char*>(request.cert_authorities[i].data())); | 119 const_cast<char*>(request.cert_authorities[i].data())); |
| 77 } | 120 } |
| 78 | 121 |
| 79 // Enumerate the client certificates. | 122 // Enumerate the client certificates. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 intermediates.pop_back(); | 185 intermediates.pop_back(); |
| 143 } | 186 } |
| 144 | 187 |
| 145 // TODO(svaldez): cert currently wraps cert_context2 which may be backed | 188 // TODO(svaldez): cert currently wraps cert_context2 which may be backed |
| 146 // by a smartcard with threading difficulties. Instead, create a fresh | 189 // by a smartcard with threading difficulties. Instead, create a fresh |
| 147 // X509Certificate with CreateFromBytes and route cert_context2 into the | 190 // X509Certificate with CreateFromBytes and route cert_context2 into the |
| 148 // SSLPrivateKey. Probably changing CertificateList to be a | 191 // SSLPrivateKey. Probably changing CertificateList to be a |
| 149 // pair<X509Certificate, SSLPrivateKeyCallback>. | 192 // pair<X509Certificate, SSLPrivateKeyCallback>. |
| 150 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | 193 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( |
| 151 cert_context2, intermediates); | 194 cert_context2, intermediates); |
| 152 if (cert) | 195 if (cert) { |
| 153 selected_certs->push_back(std::move(cert)); | 196 selected_identities->push_back(base::MakeUnique<ClientCertIdentityWin>( |
| 154 CertFreeCertificateContext(cert_context2); | 197 std::move(cert), |
| 198 cert_context2, // Takes ownership of |cert_context2|. |
| 199 current_thread)); // The key must be acquired on the same thread, as |
| 200 // the PCCERT_CONTEXT may not be thread safe. |
| 201 } |
| 155 for (size_t i = 0; i < intermediates.size(); ++i) | 202 for (size_t i = 0; i < intermediates.size(); ++i) |
| 156 CertFreeCertificateContext(intermediates[i]); | 203 CertFreeCertificateContext(intermediates[i]); |
| 157 } | 204 } |
| 158 | 205 |
| 159 std::sort(selected_certs->begin(), selected_certs->end(), | 206 std::sort(selected_identities->begin(), selected_identities->end(), |
| 160 x509_util::ClientCertSorter()); | 207 ClientCertIdentitySorter()); |
| 161 } | 208 } |
| 162 | 209 |
| 163 } // namespace | 210 } // namespace |
| 164 | 211 |
| 165 ClientCertStoreWin::ClientCertStoreWin() {} | 212 ClientCertStoreWin::ClientCertStoreWin() {} |
| 166 | 213 |
| 167 ClientCertStoreWin::ClientCertStoreWin(HCERTSTORE cert_store) { | 214 ClientCertStoreWin::ClientCertStoreWin(HCERTSTORE cert_store) { |
| 168 DCHECK(cert_store); | 215 DCHECK(cert_store); |
| 169 cert_store_.reset(cert_store); | 216 cert_store_.reset(cert_store); |
| 170 } | 217 } |
| 171 | 218 |
| 172 ClientCertStoreWin::~ClientCertStoreWin() {} | 219 ClientCertStoreWin::~ClientCertStoreWin() {} |
| 173 | 220 |
| 174 void ClientCertStoreWin::GetClientCerts( | 221 void ClientCertStoreWin::GetClientCerts( |
| 175 const SSLCertRequestInfo& request, | 222 const SSLCertRequestInfo& request, |
| 176 const ClientCertListCallback& callback) { | 223 const ClientCertListCallback& callback) { |
| 177 CertificateList selected_certs; | 224 ClientCertIdentityList selected_identities; |
| 178 if (cert_store_) { | 225 if (cert_store_) { |
| 179 // Use the existing client cert store. Note: Under some situations, | 226 // Use the existing client cert store. Note: Under some situations, |
| 180 // it's possible for this to return certificates that aren't usable | 227 // it's possible for this to return certificates that aren't usable |
| 181 // (see below). | 228 // (see below). |
| 182 GetClientCertsImpl(cert_store_, request, &selected_certs); | 229 GetClientCertsImpl(cert_store_, request, &selected_identities); |
| 183 callback.Run(std::move(selected_certs)); | 230 callback.Run(std::move(selected_identities)); |
| 184 return; | 231 return; |
| 185 } | 232 } |
| 186 | 233 |
| 187 // Always open a new instance of the "MY" store, to ensure that there | 234 // Always open a new instance of the "MY" store, to ensure that there |
| 188 // are no previously cached certificates being reused after they're | 235 // are no previously cached certificates being reused after they're |
| 189 // no longer available (some smartcard providers fail to update the "MY" | 236 // no longer available (some smartcard providers fail to update the "MY" |
| 190 // store handles and instead interpose CertOpenSystemStore). | 237 // store handles and instead interpose CertOpenSystemStore). |
| 191 ScopedHCERTSTORE my_cert_store(CertOpenSystemStore(NULL, L"MY")); | 238 ScopedHCERTSTORE my_cert_store(CertOpenSystemStore(NULL, L"MY")); |
| 192 if (!my_cert_store) { | 239 if (!my_cert_store) { |
| 193 PLOG(ERROR) << "Could not open the \"MY\" system certificate store: "; | 240 PLOG(ERROR) << "Could not open the \"MY\" system certificate store: "; |
| 194 callback.Run(CertificateList()); | 241 callback.Run(ClientCertIdentityList()); |
| 195 return; | 242 return; |
| 196 } | 243 } |
| 197 | 244 |
| 198 GetClientCertsImpl(my_cert_store, request, &selected_certs); | 245 GetClientCertsImpl(my_cert_store, request, &selected_identities); |
| 199 callback.Run(std::move(selected_certs)); | 246 callback.Run(std::move(selected_identities)); |
| 200 } | 247 } |
| 201 | 248 |
| 202 bool ClientCertStoreWin::SelectClientCertsForTesting( | 249 bool ClientCertStoreWin::SelectClientCertsForTesting( |
| 203 const CertificateList& input_certs, | 250 const CertificateList& input_certs, |
| 204 const SSLCertRequestInfo& request, | 251 const SSLCertRequestInfo& request, |
| 205 CertificateList* selected_certs) { | 252 ClientCertIdentityList* selected_identities) { |
| 206 ScopedHCERTSTORE test_store(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, | 253 ScopedHCERTSTORE test_store(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, |
| 207 NULL)); | 254 NULL)); |
| 208 if (!test_store) | 255 if (!test_store) |
| 209 return false; | 256 return false; |
| 210 | 257 |
| 211 // Add available certificates to the test store. | 258 // Add available certificates to the test store. |
| 212 for (size_t i = 0; i < input_certs.size(); ++i) { | 259 for (size_t i = 0; i < input_certs.size(); ++i) { |
| 213 // Add the certificate to the test store. | 260 // Add the certificate to the test store. |
| 214 PCCERT_CONTEXT cert = NULL; | 261 PCCERT_CONTEXT cert = NULL; |
| 215 if (!CertAddCertificateContextToStore(test_store, | 262 if (!CertAddCertificateContextToStore(test_store, |
| 216 input_certs[i]->os_cert_handle(), | 263 input_certs[i]->os_cert_handle(), |
| 217 CERT_STORE_ADD_NEW, &cert)) { | 264 CERT_STORE_ADD_NEW, &cert)) { |
| 218 return false; | 265 return false; |
| 219 } | 266 } |
| 220 // Add dummy private key data to the certificate - otherwise the certificate | 267 // Add dummy private key data to the certificate - otherwise the certificate |
| 221 // would be discarded by the filtering routines. | 268 // would be discarded by the filtering routines. |
| 222 CRYPT_KEY_PROV_INFO private_key_data; | 269 CRYPT_KEY_PROV_INFO private_key_data; |
| 223 memset(&private_key_data, 0, sizeof(private_key_data)); | 270 memset(&private_key_data, 0, sizeof(private_key_data)); |
| 224 if (!CertSetCertificateContextProperty(cert, | 271 if (!CertSetCertificateContextProperty(cert, |
| 225 CERT_KEY_PROV_INFO_PROP_ID, | 272 CERT_KEY_PROV_INFO_PROP_ID, |
| 226 0, &private_key_data)) { | 273 0, &private_key_data)) { |
| 227 return false; | 274 return false; |
| 228 } | 275 } |
| 229 // Decrement the reference count of the certificate (since we requested a | 276 // Decrement the reference count of the certificate (since we requested a |
| 230 // copy). | 277 // copy). |
| 231 if (!CertFreeCertificateContext(cert)) | 278 if (!CertFreeCertificateContext(cert)) |
| 232 return false; | 279 return false; |
| 233 } | 280 } |
| 234 | 281 |
| 235 GetClientCertsImpl(test_store.get(), request, selected_certs); | 282 GetClientCertsImpl(test_store.get(), request, selected_identities); |
| 236 return true; | 283 return true; |
| 237 } | 284 } |
| 238 | 285 |
| 239 } // namespace net | 286 } // namespace net |
| OLD | NEW |