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

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

Issue 12680003: net: split net/ssl out of net/base (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 9 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
« no previous file with comments | « net/base/client_cert_store_impl_unittest.cc ('k') | net/base/default_server_bound_cert_store.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/client_cert_store_impl.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #define SECURITY_WIN32 // Needs to be defined before including security.h
11 #include <windows.h>
12 #include <wincrypt.h>
13 #include <security.h>
14
15 #include "base/logging.h"
16 #include "crypto/scoped_capi_types.h"
17 #include "net/base/x509_util.h"
18
19 namespace net {
20
21 namespace {
22
23 // Callback required by Windows API function CertFindChainInStore(). In addition
24 // to filtering by extended/enhanced key usage, we do not show expired
25 // certificates and require digital signature usage in the key usage extension.
26 //
27 // 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
29 // 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
31 static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context,
32 void* find_arg) {
33 // Verify the certificate key usage is appropriate or not specified.
34 BYTE key_usage;
35 if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo,
36 &key_usage, 1)) {
37 if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE))
38 return FALSE;
39 } else {
40 DWORD err = GetLastError();
41 // If |err| is non-zero, it's an actual error. Otherwise the extension
42 // just isn't present, and we treat it as if everything was allowed.
43 if (err) {
44 DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err;
45 return FALSE;
46 }
47 }
48
49 // Verify the current time is within the certificate's validity period.
50 if (CertVerifyTimeValidity(NULL, cert_context->pCertInfo) != 0)
51 return FALSE;
52
53 // Verify private key metadata is associated with this certificate.
54 // TODO(ppi): Is this really needed? Isn't it equivalent to leaving
55 // CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG not set in |find_flags| argument of
56 // CertFindChainInStore()?
57 DWORD size = 0;
58 if (!CertGetCertificateContextProperty(
59 cert_context, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) {
60 return FALSE;
61 }
62
63 return TRUE;
64 }
65
66 bool GetClientCertsImpl(HCERTSTORE cert_store,
67 const SSLCertRequestInfo& request,
68 CertificateList* selected_certs) {
69 selected_certs->clear();
70
71 const size_t auth_count = request.cert_authorities.size();
72 std::vector<CERT_NAME_BLOB> issuers(auth_count);
73 for (size_t i = 0; i < auth_count; ++i) {
74 issuers[i].cbData = static_cast<DWORD>(request.cert_authorities[i].size());
75 issuers[i].pbData = reinterpret_cast<BYTE*>(
76 const_cast<char*>(request.cert_authorities[i].data()));
77 }
78
79 // Enumerate the client certificates.
80 CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para;
81 memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para));
82 find_by_issuer_para.cbSize = sizeof(find_by_issuer_para);
83 find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
84 find_by_issuer_para.cIssuer = static_cast<DWORD>(auth_count);
85 find_by_issuer_para.rgIssuer =
86 reinterpret_cast<CERT_NAME_BLOB*>(issuers.data());
87 find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
88
89 PCCERT_CHAIN_CONTEXT chain_context = NULL;
90 DWORD find_flags = CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG |
91 CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG;
92 for (;;) {
93 // Find a certificate chain.
94 chain_context = CertFindChainInStore(cert_store,
95 X509_ASN_ENCODING,
96 find_flags,
97 CERT_CHAIN_FIND_BY_ISSUER,
98 &find_by_issuer_para,
99 chain_context);
100 if (!chain_context) {
101 if (GetLastError() != CRYPT_E_NOT_FOUND)
102 DPLOG(ERROR) << "CertFindChainInStore failed: ";
103 break;
104 }
105
106 // Get the leaf certificate.
107 PCCERT_CONTEXT cert_context =
108 chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
109 // Copy the certificate, so that it is valid after |cert_store| is closed.
110 PCCERT_CONTEXT cert_context2 = NULL;
111 BOOL ok = CertAddCertificateContextToStore(NULL, cert_context,
112 CERT_STORE_ADD_USE_EXISTING,
113 &cert_context2);
114 if (!ok) {
115 NOTREACHED();
116 continue;
117 }
118
119 // Grab the intermediates, if any.
120 X509Certificate::OSCertHandles intermediates;
121 for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) {
122 PCCERT_CONTEXT chain_intermediate =
123 chain_context->rgpChain[0]->rgpElement[i]->pCertContext;
124 PCCERT_CONTEXT copied_intermediate = NULL;
125 ok = CertAddCertificateContextToStore(NULL, chain_intermediate,
126 CERT_STORE_ADD_USE_EXISTING,
127 &copied_intermediate);
128 if (ok)
129 intermediates.push_back(copied_intermediate);
130 }
131 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
132 cert_context2, intermediates);
133 selected_certs->push_back(cert);
134 CertFreeCertificateContext(cert_context2);
135 for (size_t i = 0; i < intermediates.size(); ++i)
136 CertFreeCertificateContext(intermediates[i]);
137 }
138
139 std::sort(selected_certs->begin(), selected_certs->end(),
140 x509_util::ClientCertSorter());
141 return true;
142 }
143
144 } // namespace
145
146 bool ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
147 CertificateList* selected_certs) {
148 // Client certificates of the user are in the "MY" system certificate store.
149 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY");
150 if (!my_cert_store) {
151 PLOG(ERROR) << "Could not open the \"MY\" system certificate store: ";
152 return false;
153 }
154
155 bool rv = GetClientCertsImpl(my_cert_store, request, selected_certs);
156 if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG)) {
157 PLOG(ERROR) << "Could not close the \"MY\" system certificate store: ";
158 return false;
159 }
160 return rv;
161 }
162
163 bool ClientCertStoreImpl::SelectClientCerts(const CertificateList& input_certs,
164 const SSLCertRequestInfo& request,
165 CertificateList* selected_certs) {
166 typedef crypto::ScopedCAPIHandle<
167 HCERTSTORE,
168 crypto::CAPIDestroyerWithFlags<HCERTSTORE,
169 CertCloseStore, 0> > ScopedHCERTSTORE;
170
171 ScopedHCERTSTORE test_store(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0,
172 NULL));
173 if (!test_store)
174 return false;
175
176 // Add available certificates to the test store.
177 for (size_t i = 0; i < input_certs.size(); ++i) {
178 // Add the certificate to the test store.
179 PCCERT_CONTEXT cert = NULL;
180 if (!CertAddCertificateContextToStore(test_store,
181 input_certs[i]->os_cert_handle(),
182 CERT_STORE_ADD_NEW, &cert)) {
183 return false;
184 }
185 // Add dummy private key data to the certificate - otherwise the certificate
186 // would be discarded by the filtering routines.
187 CRYPT_KEY_PROV_INFO private_key_data;
188 memset(&private_key_data, 0, sizeof(private_key_data));
189 if (!CertSetCertificateContextProperty(cert,
190 CERT_KEY_PROV_INFO_PROP_ID,
191 0, &private_key_data)) {
192 return false;
193 }
194 // Decrement the reference count of the certificate (since we requested a
195 // copy).
196 if (!CertFreeCertificateContext(cert))
197 return false;
198 }
199
200 bool rv = GetClientCertsImpl(test_store.get(), request, selected_certs);
201 return rv;
202 }
203
204 } // namespace net
OLDNEW
« no previous file with comments | « net/base/client_cert_store_impl_unittest.cc ('k') | net/base/default_server_bound_cert_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698