OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/base/keygen_handler.h" | 5 #include "net/base/keygen_handler.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <wincrypt.h> | 8 #include <wincrypt.h> |
9 #pragma comment(lib, "crypt32.lib") | 9 #pragma comment(lib, "crypt32.lib") |
10 #include <rpc.h> | 10 #include <rpc.h> |
11 #pragma comment(lib, "rpcrt4.lib") | 11 #pragma comment(lib, "rpcrt4.lib") |
12 | 12 |
13 #include <list> | 13 #include <list> |
14 #include <string> | 14 #include <string> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "base/base64.h" | 17 #include "base/base64.h" |
18 #include "base/basictypes.h" | 18 #include "base/basictypes.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/string_piece.h" | 20 #include "base/string_piece.h" |
21 #include "base/string_util.h" | 21 #include "base/string_util.h" |
22 #include "base/utf_string_conversions.h" | 22 #include "base/utf_string_conversions.h" |
23 | 23 |
24 namespace net { | 24 namespace net { |
25 | 25 |
26 bool EncodeAndAppendType(LPCSTR type, const void* to_encode, | |
27 std::vector<BYTE>* output) { | |
28 BOOL ok; | |
29 DWORD size = 0; | |
30 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode, NULL, &size); | |
31 DCHECK(ok); | |
32 if (!ok) | |
33 return false; | |
34 | |
35 std::vector<BYTE>::size_type old_size = output->size(); | |
36 output->resize(old_size + size); | |
37 | |
38 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode, | |
39 &(*output)[old_size], &size); | |
40 DCHECK(ok); | |
41 if (!ok) | |
42 return false; | |
43 | |
44 // Sometimes the initial call to CryptEncodeObject gave a generous estimate | |
45 // of the size, so shrink back to what was actually used. | |
46 output->resize(old_size + size); | |
47 | |
48 return true; | |
49 } | |
50 | |
51 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing | 26 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing |
52 // key in |prov| to |output|. Returns true if encoding was successful. | 27 // key in |prov| to |output|. Returns true if encoding was successful. |
53 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { | 28 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { |
54 BOOL ok; | 29 BOOL ok; |
55 DWORD size = 0; | 30 DWORD size = 0; |
56 | 31 |
57 // From the private key stored in HCRYPTPROV, obtain the public key, stored | 32 // From the private key stored in HCRYPTPROV, obtain the public key, stored |
58 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are | 33 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are |
59 // supported. | 34 // supported. |
60 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, | 35 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, |
(...skipping 11 matching lines...) Expand all Loading... |
72 &size); | 47 &size); |
73 DCHECK(ok); | 48 DCHECK(ok); |
74 if (!ok) | 49 if (!ok) |
75 return false; | 50 return false; |
76 | 51 |
77 output->resize(size); | 52 output->resize(size); |
78 | 53 |
79 return true; | 54 return true; |
80 } | 55 } |
81 | 56 |
82 // Appends a DER SubjectPublicKeyInfo structure for the signing key in |prov| | |
83 // to |output|. | |
84 // Returns true if encoding was successful. | |
85 bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { | |
86 std::vector<BYTE> public_key_info; | |
87 if (!GetSubjectPublicKeyInfo(prov, &public_key_info)) | |
88 return false; | |
89 | |
90 return EncodeAndAppendType(X509_PUBLIC_KEY_INFO, &public_key_info[0], | |
91 output); | |
92 } | |
93 | |
94 // Generates a DER encoded SignedPublicKeyAndChallenge structure from the | 57 // Generates a DER encoded SignedPublicKeyAndChallenge structure from the |
95 // signing key of |prov| and the specified ASCII |challenge| string and | 58 // signing key of |prov| and the specified ASCII |challenge| string and |
96 // appends it to |output|. | 59 // appends it to |output|. |
97 // True if the encoding was successfully generated. | 60 // True if the encoding was successfully generated. |
98 bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov, | 61 bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov, |
99 const std::string& challenge, | 62 const std::string& challenge, |
100 std::string* output) { | 63 std::string* output) { |
101 std::wstring wide_challenge = ASCIIToWide(challenge); | 64 std::wstring wide_challenge = ASCIIToWide(challenge); |
102 std::vector<BYTE> spki; | 65 std::vector<BYTE> spki; |
103 | 66 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 return result; | 122 return result; |
160 | 123 |
161 // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++, | 124 // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++, |
162 // so the type cast is necessary. | 125 // so the type cast is necessary. |
163 result.assign(reinterpret_cast<wchar_t*>(rpc_string)); | 126 result.assign(reinterpret_cast<wchar_t*>(rpc_string)); |
164 RpcStringFree(&rpc_string); | 127 RpcStringFree(&rpc_string); |
165 | 128 |
166 return result; | 129 return result; |
167 } | 130 } |
168 | 131 |
169 void StoreKeyLocationInCache(HCRYPTPROV prov) { | |
170 BOOL ok; | |
171 DWORD size = 0; | |
172 | |
173 // Though it is known the container and provider name, as they are supplied | |
174 // during GenKeyAndSignChallenge, explicitly resolving them via | |
175 // CryptGetProvParam ensures that any defaults (such as provider name being | |
176 // NULL) or any CSP modifications to the container name are properly | |
177 // reflected. | |
178 | |
179 // Find the container name. Though the MSDN documentation states it will | |
180 // return the exact same value as supplied when the provider was aquired, it | |
181 // also notes the return type will be CHAR, /not/ WCHAR. | |
182 ok = CryptGetProvParam(prov, PP_CONTAINER, NULL, &size, 0); | |
183 if (!ok) | |
184 return; | |
185 | |
186 std::vector<BYTE> buffer(size); | |
187 ok = CryptGetProvParam(prov, PP_CONTAINER, &buffer[0], &size, 0); | |
188 if (!ok) | |
189 return; | |
190 | |
191 KeygenHandler::KeyLocation key_location; | |
192 UTF8ToWide(reinterpret_cast<char*>(&buffer[0]), size, | |
193 &key_location.container_name); | |
194 | |
195 // Get the provider name. This will always resolve, even if NULL (indicating | |
196 // the default provider) was supplied to the CryptAcquireContext. | |
197 size = 0; | |
198 ok = CryptGetProvParam(prov, PP_NAME, NULL, &size, 0); | |
199 if (!ok) | |
200 return; | |
201 | |
202 buffer.resize(size); | |
203 ok = CryptGetProvParam(prov, PP_NAME, &buffer[0], &size, 0); | |
204 if (!ok) | |
205 return; | |
206 | |
207 UTF8ToWide(reinterpret_cast<char*>(&buffer[0]), size, | |
208 &key_location.provider_name); | |
209 | |
210 std::vector<BYTE> public_key_info; | |
211 if (!EncodeSubjectPublicKeyInfo(prov, &public_key_info)) | |
212 return; | |
213 | |
214 KeygenHandler::Cache* cache = KeygenHandler::Cache::GetInstance(); | |
215 cache->Insert(std::string(public_key_info.begin(), public_key_info.end()), | |
216 key_location); | |
217 } | |
218 | |
219 bool KeygenHandler::KeyLocation::Equals( | |
220 const KeygenHandler::KeyLocation& location) const { | |
221 return container_name == location.container_name && | |
222 provider_name == location.provider_name; | |
223 } | |
224 | |
225 std::string KeygenHandler::GenKeyAndSignChallenge() { | 132 std::string KeygenHandler::GenKeyAndSignChallenge() { |
226 std::string result; | 133 std::string result; |
227 | 134 |
228 bool is_success = true; | 135 bool is_success = true; |
229 HCRYPTPROV prov = NULL; | 136 HCRYPTPROV prov = NULL; |
230 HCRYPTKEY key = NULL; | 137 HCRYPTKEY key = NULL; |
231 DWORD flags = (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE; | 138 DWORD flags = (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE; |
232 std::string spkac; | 139 std::string spkac; |
233 | 140 |
234 std::wstring new_key_id; | 141 std::wstring new_key_id; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 is_success = false; | 181 is_success = false; |
275 goto failure; | 182 goto failure; |
276 } | 183 } |
277 | 184 |
278 if (!base::Base64Encode(spkac, &result)) { | 185 if (!base::Base64Encode(spkac, &result)) { |
279 LOG(ERROR) << "Couldn't convert signed key into base64"; | 186 LOG(ERROR) << "Couldn't convert signed key into base64"; |
280 is_success = false; | 187 is_success = false; |
281 goto failure; | 188 goto failure; |
282 } | 189 } |
283 | 190 |
284 StoreKeyLocationInCache(prov); | |
285 | |
286 failure: | 191 failure: |
287 if (!is_success) { | 192 if (!is_success) { |
288 LOG(ERROR) << "SSL Keygen failed"; | 193 LOG(ERROR) << "SSL Keygen failed"; |
289 } else { | 194 } else { |
290 LOG(INFO) << "SSL Key succeeded"; | 195 LOG(INFO) << "SSL Key succeeded"; |
291 } | 196 } |
292 if (key) { | 197 if (key) { |
293 // Securely destroys the handle, but leaves the underlying key alone. The | 198 // Securely destroys the handle, but leaves the underlying key alone. The |
294 // key can be obtained again by resolving the key location. If | 199 // key can be obtained again by resolving the key location. If |
295 // |stores_key_| is false, the underlying key will be destroyed below. | 200 // |stores_key_| is false, the underlying key will be destroyed below. |
296 CryptDestroyKey(key); | 201 CryptDestroyKey(key); |
297 } | 202 } |
298 | 203 |
299 if (prov) { | 204 if (prov) { |
300 CryptReleaseContext(prov, 0); | 205 CryptReleaseContext(prov, 0); |
301 prov = NULL; | 206 prov = NULL; |
302 if (!stores_key_) { | 207 if (!stores_key_) { |
303 // Fully destroys any of the keys that were created and releases prov. | 208 // Fully destroys any of the keys that were created and releases prov. |
304 CryptAcquireContext(&prov, new_key_id.c_str(), NULL, PROV_RSA_FULL, | 209 CryptAcquireContext(&prov, new_key_id.c_str(), NULL, PROV_RSA_FULL, |
305 CRYPT_SILENT | CRYPT_DELETEKEYSET); | 210 CRYPT_SILENT | CRYPT_DELETEKEYSET); |
306 } | 211 } |
307 } | 212 } |
308 | 213 |
309 return result; | 214 return result; |
310 } | 215 } |
311 | 216 |
312 } // namespace net | 217 } // namespace net |
OLD | NEW |