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 |