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 |
(...skipping 11 matching lines...) Expand all Loading... |
22 namespace { | 22 namespace { |
23 | 23 |
24 // Callback required by Windows API function CertFindChainInStore(). In addition | 24 // Callback required by Windows API function CertFindChainInStore(). In addition |
25 // to filtering by extended/enhanced key usage, we do not show expired | 25 // to filtering by extended/enhanced key usage, we do not show expired |
26 // certificates and require digital signature usage in the key usage extension. | 26 // certificates and require digital signature usage in the key usage extension. |
27 // | 27 // |
28 // This matches our behavior on Mac OS X and that of NSS. It also matches the | 28 // This matches our behavior on Mac OS X and that of NSS. It also matches the |
29 // default behavior of IE8. See http://support.microsoft.com/kb/890326 and | 29 // default behavior of IE8. See http://support.microsoft.com/kb/890326 and |
30 // http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certifica | 30 // http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certifica |
31 // tes-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx | 31 // tes-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx |
32 static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context, | 32 static BOOL WINAPI |
33 void* find_arg) { | 33 ClientCertFindCallback(PCCERT_CONTEXT cert_context, void* find_arg) { |
34 // Verify the certificate key usage is appropriate or not specified. | 34 // Verify the certificate key usage is appropriate or not specified. |
35 BYTE key_usage; | 35 BYTE key_usage; |
36 if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo, | 36 if (CertGetIntendedKeyUsage( |
37 &key_usage, 1)) { | 37 X509_ASN_ENCODING, cert_context->pCertInfo, &key_usage, 1)) { |
38 if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE)) | 38 if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE)) |
39 return FALSE; | 39 return FALSE; |
40 } else { | 40 } else { |
41 DWORD err = GetLastError(); | 41 DWORD err = GetLastError(); |
42 // If |err| is non-zero, it's an actual error. Otherwise the extension | 42 // If |err| is non-zero, it's an actual error. Otherwise the extension |
43 // just isn't present, and we treat it as if everything was allowed. | 43 // just isn't present, and we treat it as if everything was allowed. |
44 if (err) { | 44 if (err) { |
45 DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err; | 45 DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err; |
46 return FALSE; | 46 return FALSE; |
47 } | 47 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 if (GetLastError() != CRYPT_E_NOT_FOUND) | 102 if (GetLastError() != CRYPT_E_NOT_FOUND) |
103 DPLOG(ERROR) << "CertFindChainInStore failed: "; | 103 DPLOG(ERROR) << "CertFindChainInStore failed: "; |
104 break; | 104 break; |
105 } | 105 } |
106 | 106 |
107 // Get the leaf certificate. | 107 // Get the leaf certificate. |
108 PCCERT_CONTEXT cert_context = | 108 PCCERT_CONTEXT cert_context = |
109 chain_context->rgpChain[0]->rgpElement[0]->pCertContext; | 109 chain_context->rgpChain[0]->rgpElement[0]->pCertContext; |
110 // Copy the certificate, so that it is valid after |cert_store| is closed. | 110 // Copy the certificate, so that it is valid after |cert_store| is closed. |
111 PCCERT_CONTEXT cert_context2 = NULL; | 111 PCCERT_CONTEXT cert_context2 = NULL; |
112 BOOL ok = CertAddCertificateContextToStore(NULL, cert_context, | 112 BOOL ok = CertAddCertificateContextToStore( |
113 CERT_STORE_ADD_USE_EXISTING, | 113 NULL, cert_context, CERT_STORE_ADD_USE_EXISTING, &cert_context2); |
114 &cert_context2); | |
115 if (!ok) { | 114 if (!ok) { |
116 NOTREACHED(); | 115 NOTREACHED(); |
117 continue; | 116 continue; |
118 } | 117 } |
119 | 118 |
120 // Grab the intermediates, if any. | 119 // Grab the intermediates, if any. |
121 X509Certificate::OSCertHandles intermediates; | 120 X509Certificate::OSCertHandles intermediates; |
122 for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) { | 121 for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) { |
123 PCCERT_CONTEXT chain_intermediate = | 122 PCCERT_CONTEXT chain_intermediate = |
124 chain_context->rgpChain[0]->rgpElement[i]->pCertContext; | 123 chain_context->rgpChain[0]->rgpElement[i]->pCertContext; |
125 PCCERT_CONTEXT copied_intermediate = NULL; | 124 PCCERT_CONTEXT copied_intermediate = NULL; |
126 ok = CertAddCertificateContextToStore(NULL, chain_intermediate, | 125 ok = CertAddCertificateContextToStore(NULL, |
| 126 chain_intermediate, |
127 CERT_STORE_ADD_USE_EXISTING, | 127 CERT_STORE_ADD_USE_EXISTING, |
128 &copied_intermediate); | 128 &copied_intermediate); |
129 if (ok) | 129 if (ok) |
130 intermediates.push_back(copied_intermediate); | 130 intermediates.push_back(copied_intermediate); |
131 } | 131 } |
132 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | 132 scoped_refptr<X509Certificate> cert = |
133 cert_context2, intermediates); | 133 X509Certificate::CreateFromHandle(cert_context2, intermediates); |
134 selected_certs->push_back(cert); | 134 selected_certs->push_back(cert); |
135 CertFreeCertificateContext(cert_context2); | 135 CertFreeCertificateContext(cert_context2); |
136 for (size_t i = 0; i < intermediates.size(); ++i) | 136 for (size_t i = 0; i < intermediates.size(); ++i) |
137 CertFreeCertificateContext(intermediates[i]); | 137 CertFreeCertificateContext(intermediates[i]); |
138 } | 138 } |
139 | 139 |
140 std::sort(selected_certs->begin(), selected_certs->end(), | 140 std::sort(selected_certs->begin(), |
| 141 selected_certs->end(), |
141 x509_util::ClientCertSorter()); | 142 x509_util::ClientCertSorter()); |
142 } | 143 } |
143 | 144 |
144 } // namespace | 145 } // namespace |
145 | 146 |
146 ClientCertStoreWin::ClientCertStoreWin() {} | 147 ClientCertStoreWin::ClientCertStoreWin() { |
| 148 } |
147 | 149 |
148 ClientCertStoreWin::~ClientCertStoreWin() {} | 150 ClientCertStoreWin::~ClientCertStoreWin() { |
| 151 } |
149 | 152 |
150 void ClientCertStoreWin::GetClientCerts(const SSLCertRequestInfo& request, | 153 void ClientCertStoreWin::GetClientCerts(const SSLCertRequestInfo& request, |
151 CertificateList* selected_certs, | 154 CertificateList* selected_certs, |
152 const base::Closure& callback) { | 155 const base::Closure& callback) { |
153 // Client certificates of the user are in the "MY" system certificate store. | 156 // Client certificates of the user are in the "MY" system certificate store. |
154 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY"); | 157 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY"); |
155 if (!my_cert_store) { | 158 if (!my_cert_store) { |
156 PLOG(ERROR) << "Could not open the \"MY\" system certificate store: "; | 159 PLOG(ERROR) << "Could not open the \"MY\" system certificate store: "; |
157 selected_certs->clear(); | 160 selected_certs->clear(); |
158 callback.Run(); | 161 callback.Run(); |
159 return; | 162 return; |
160 } | 163 } |
161 | 164 |
162 GetClientCertsImpl(my_cert_store, request, selected_certs); | 165 GetClientCertsImpl(my_cert_store, request, selected_certs); |
163 if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG)) | 166 if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG)) |
164 PLOG(ERROR) << "Could not close the \"MY\" system certificate store: "; | 167 PLOG(ERROR) << "Could not close the \"MY\" system certificate store: "; |
165 callback.Run(); | 168 callback.Run(); |
166 } | 169 } |
167 | 170 |
168 bool ClientCertStoreWin::SelectClientCertsForTesting( | 171 bool ClientCertStoreWin::SelectClientCertsForTesting( |
169 const CertificateList& input_certs, | 172 const CertificateList& input_certs, |
170 const SSLCertRequestInfo& request, | 173 const SSLCertRequestInfo& request, |
171 CertificateList* selected_certs) { | 174 CertificateList* selected_certs) { |
172 typedef crypto::ScopedCAPIHandle< | 175 typedef crypto::ScopedCAPIHandle< |
173 HCERTSTORE, | 176 HCERTSTORE, |
174 crypto::CAPIDestroyerWithFlags<HCERTSTORE, | 177 crypto::CAPIDestroyerWithFlags<HCERTSTORE, CertCloseStore, 0> > |
175 CertCloseStore, 0> > ScopedHCERTSTORE; | 178 ScopedHCERTSTORE; |
176 | 179 |
177 ScopedHCERTSTORE test_store(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, | 180 ScopedHCERTSTORE test_store( |
178 NULL)); | 181 CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL)); |
179 if (!test_store) | 182 if (!test_store) |
180 return false; | 183 return false; |
181 | 184 |
182 // Add available certificates to the test store. | 185 // Add available certificates to the test store. |
183 for (size_t i = 0; i < input_certs.size(); ++i) { | 186 for (size_t i = 0; i < input_certs.size(); ++i) { |
184 // Add the certificate to the test store. | 187 // Add the certificate to the test store. |
185 PCCERT_CONTEXT cert = NULL; | 188 PCCERT_CONTEXT cert = NULL; |
186 if (!CertAddCertificateContextToStore(test_store, | 189 if (!CertAddCertificateContextToStore(test_store, |
187 input_certs[i]->os_cert_handle(), | 190 input_certs[i]->os_cert_handle(), |
188 CERT_STORE_ADD_NEW, &cert)) { | 191 CERT_STORE_ADD_NEW, |
| 192 &cert)) { |
189 return false; | 193 return false; |
190 } | 194 } |
191 // Add dummy private key data to the certificate - otherwise the certificate | 195 // Add dummy private key data to the certificate - otherwise the certificate |
192 // would be discarded by the filtering routines. | 196 // would be discarded by the filtering routines. |
193 CRYPT_KEY_PROV_INFO private_key_data; | 197 CRYPT_KEY_PROV_INFO private_key_data; |
194 memset(&private_key_data, 0, sizeof(private_key_data)); | 198 memset(&private_key_data, 0, sizeof(private_key_data)); |
195 if (!CertSetCertificateContextProperty(cert, | 199 if (!CertSetCertificateContextProperty( |
196 CERT_KEY_PROV_INFO_PROP_ID, | 200 cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &private_key_data)) { |
197 0, &private_key_data)) { | |
198 return false; | 201 return false; |
199 } | 202 } |
200 // Decrement the reference count of the certificate (since we requested a | 203 // Decrement the reference count of the certificate (since we requested a |
201 // copy). | 204 // copy). |
202 if (!CertFreeCertificateContext(cert)) | 205 if (!CertFreeCertificateContext(cert)) |
203 return false; | 206 return false; |
204 } | 207 } |
205 | 208 |
206 GetClientCertsImpl(test_store.get(), request, selected_certs); | 209 GetClientCertsImpl(test_store.get(), request, selected_certs); |
207 return true; | 210 return true; |
208 } | 211 } |
209 | 212 |
210 } // namespace net | 213 } // namespace net |
OLD | NEW |