| 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 |