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

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

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

Powered by Google App Engine
This is Rietveld 408576698