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

Side by Side Diff: net/ssl/client_cert_store_win.cc

Issue 2898573002: Refactor client cert private key handling. (Closed)
Patch Set: removed no longer needed forward declaration Created 3 years, 6 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/ssl/client_cert_store_win.h ('k') | net/ssl/client_cert_store_win_unittest.cc » ('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 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
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
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
OLDNEW
« no previous file with comments | « net/ssl/client_cert_store_win.h ('k') | net/ssl/client_cert_store_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698