OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/strings/string_piece.h" | 20 #include "base/strings/string_piece.h" |
21 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
22 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
23 #include "crypto/capi_util.h" | 23 #include "crypto/capi_util.h" |
24 #include "crypto/scoped_capi_types.h" | 24 #include "crypto/scoped_capi_types.h" |
25 | 25 |
26 | |
27 namespace net { | 26 namespace net { |
28 | 27 |
29 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing | 28 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing |
30 // key in |prov| to |output|. Returns true if encoding was successful. | 29 // key in |prov| to |output|. Returns true if encoding was successful. |
31 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { | 30 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { |
32 BOOL ok; | 31 BOOL ok; |
33 DWORD size = 0; | 32 DWORD size = 0; |
34 | 33 |
35 // From the private key stored in HCRYPTPROV, obtain the public key, stored | 34 // From the private key stored in HCRYPTPROV, obtain the public key, stored |
36 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are | 35 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are |
37 // supported. | 36 // supported. |
38 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, | 37 ok = CryptExportPublicKeyInfoEx(prov, |
39 szOID_RSA_RSA, 0, NULL, NULL, &size); | 38 AT_KEYEXCHANGE, |
| 39 X509_ASN_ENCODING, |
| 40 szOID_RSA_RSA, |
| 41 0, |
| 42 NULL, |
| 43 NULL, |
| 44 &size); |
40 DCHECK(ok); | 45 DCHECK(ok); |
41 if (!ok) | 46 if (!ok) |
42 return false; | 47 return false; |
43 | 48 |
44 output->resize(size); | 49 output->resize(size); |
45 | 50 |
46 PCERT_PUBLIC_KEY_INFO public_key_casted = | 51 PCERT_PUBLIC_KEY_INFO public_key_casted = |
47 reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]); | 52 reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]); |
48 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, | 53 ok = CryptExportPublicKeyInfoEx(prov, |
49 szOID_RSA_RSA, 0, NULL, public_key_casted, | 54 AT_KEYEXCHANGE, |
| 55 X509_ASN_ENCODING, |
| 56 szOID_RSA_RSA, |
| 57 0, |
| 58 NULL, |
| 59 public_key_casted, |
50 &size); | 60 &size); |
51 DCHECK(ok); | 61 DCHECK(ok); |
52 if (!ok) | 62 if (!ok) |
53 return false; | 63 return false; |
54 | 64 |
55 output->resize(size); | 65 output->resize(size); |
56 | 66 |
57 return true; | 67 return true; |
58 } | 68 } |
59 | 69 |
(...skipping 20 matching lines...) Expand all Loading... |
80 *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]); | 90 *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]); |
81 pkac.pwszChallengeString = const_cast<wchar_t*>(wide_challenge.c_str()); | 91 pkac.pwszChallengeString = const_cast<wchar_t*>(wide_challenge.c_str()); |
82 | 92 |
83 CRYPT_ALGORITHM_IDENTIFIER sig_alg; | 93 CRYPT_ALGORITHM_IDENTIFIER sig_alg; |
84 memset(&sig_alg, 0, sizeof(sig_alg)); | 94 memset(&sig_alg, 0, sizeof(sig_alg)); |
85 sig_alg.pszObjId = szOID_RSA_MD5RSA; | 95 sig_alg.pszObjId = szOID_RSA_MD5RSA; |
86 | 96 |
87 BOOL ok; | 97 BOOL ok; |
88 DWORD size = 0; | 98 DWORD size = 0; |
89 std::vector<BYTE> signed_pkac; | 99 std::vector<BYTE> signed_pkac; |
90 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, | 100 ok = CryptSignAndEncodeCertificate(prov, |
| 101 AT_KEYEXCHANGE, |
| 102 X509_ASN_ENCODING, |
91 X509_KEYGEN_REQUEST_TO_BE_SIGNED, | 103 X509_KEYGEN_REQUEST_TO_BE_SIGNED, |
92 &pkac, &sig_alg, NULL, | 104 &pkac, |
93 NULL, &size); | 105 &sig_alg, |
| 106 NULL, |
| 107 NULL, |
| 108 &size); |
94 DCHECK(ok); | 109 DCHECK(ok); |
95 if (!ok) | 110 if (!ok) |
96 return false; | 111 return false; |
97 | 112 |
98 signed_pkac.resize(size); | 113 signed_pkac.resize(size); |
99 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, | 114 ok = CryptSignAndEncodeCertificate(prov, |
| 115 AT_KEYEXCHANGE, |
| 116 X509_ASN_ENCODING, |
100 X509_KEYGEN_REQUEST_TO_BE_SIGNED, | 117 X509_KEYGEN_REQUEST_TO_BE_SIGNED, |
101 &pkac, &sig_alg, NULL, | 118 &pkac, |
102 &signed_pkac[0], &size); | 119 &sig_alg, |
| 120 NULL, |
| 121 &signed_pkac[0], |
| 122 &size); |
103 DCHECK(ok); | 123 DCHECK(ok); |
104 if (!ok) | 124 if (!ok) |
105 return false; | 125 return false; |
106 | 126 |
107 output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size); | 127 output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size); |
108 return true; | 128 return true; |
109 } | 129 } |
110 | 130 |
111 // Generates a unique name for the container which will store the key that is | 131 // Generates a unique name for the container which will store the key that is |
112 // generated. The traditional Windows approach is to use a GUID here. | 132 // generated. The traditional Windows approach is to use a GUID here. |
113 std::wstring GetNewKeyContainerId() { | 133 std::wstring GetNewKeyContainerId() { |
114 RPC_STATUS status = RPC_S_OK; | 134 RPC_STATUS status = RPC_S_OK; |
115 std::wstring result; | 135 std::wstring result; |
116 | 136 |
117 UUID id = { 0 }; | 137 UUID id = {0}; |
118 status = UuidCreateSequential(&id); | 138 status = UuidCreateSequential(&id); |
119 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) | 139 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) |
120 return result; | 140 return result; |
121 | 141 |
122 RPC_WSTR rpc_string = NULL; | 142 RPC_WSTR rpc_string = NULL; |
123 status = UuidToString(&id, &rpc_string); | 143 status = UuidToString(&id, &rpc_string); |
124 if (status != RPC_S_OK) | 144 if (status != RPC_S_OK) |
125 return result; | 145 return result; |
126 | 146 |
127 // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++, | 147 // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++, |
128 // so the type cast is necessary. | 148 // so the type cast is necessary. |
129 result.assign(reinterpret_cast<wchar_t*>(rpc_string)); | 149 result.assign(reinterpret_cast<wchar_t*>(rpc_string)); |
130 RpcStringFree(&rpc_string); | 150 RpcStringFree(&rpc_string); |
131 | 151 |
132 return result; | 152 return result; |
133 } | 153 } |
134 | 154 |
135 // This is a helper struct designed to optionally delete a key after releasing | 155 // This is a helper struct designed to optionally delete a key after releasing |
136 // the associated provider. | 156 // the associated provider. |
137 struct KeyContainer { | 157 struct KeyContainer { |
138 public: | 158 public: |
139 explicit KeyContainer(bool delete_keyset) | 159 explicit KeyContainer(bool delete_keyset) : delete_keyset_(delete_keyset) {} |
140 : delete_keyset_(delete_keyset) {} | |
141 | 160 |
142 ~KeyContainer() { | 161 ~KeyContainer() { |
143 if (provider_) { | 162 if (provider_) { |
144 provider_.reset(); | 163 provider_.reset(); |
145 if (delete_keyset_ && !key_id_.empty()) { | 164 if (delete_keyset_ && !key_id_.empty()) { |
146 HCRYPTPROV provider; | 165 HCRYPTPROV provider; |
147 crypto::CryptAcquireContextLocked(&provider, key_id_.c_str(), NULL, | 166 crypto::CryptAcquireContextLocked(&provider, |
148 PROV_RSA_FULL, CRYPT_SILENT | CRYPT_DELETEKEYSET); | 167 key_id_.c_str(), |
| 168 NULL, |
| 169 PROV_RSA_FULL, |
| 170 CRYPT_SILENT | CRYPT_DELETEKEYSET); |
149 } | 171 } |
150 } | 172 } |
151 } | 173 } |
152 | 174 |
153 crypto::ScopedHCRYPTPROV provider_; | 175 crypto::ScopedHCRYPTPROV provider_; |
154 std::wstring key_id_; | 176 std::wstring key_id_; |
155 | 177 |
156 private: | 178 private: |
157 bool delete_keyset_; | 179 bool delete_keyset_; |
158 }; | 180 }; |
(...skipping 12 matching lines...) Expand all Loading... |
171 // creating their own keys, they should ensure unique naming schemes to | 193 // creating their own keys, they should ensure unique naming schemes to |
172 // prevent overlap with any other applications or consumers of CSPs, and | 194 // prevent overlap with any other applications or consumers of CSPs, and |
173 // *should not* store new keys within the default, NULL key container. | 195 // *should not* store new keys within the default, NULL key container. |
174 key_container.key_id_ = GetNewKeyContainerId(); | 196 key_container.key_id_ = GetNewKeyContainerId(); |
175 if (key_container.key_id_.empty()) | 197 if (key_container.key_id_.empty()) |
176 return std::string(); | 198 return std::string(); |
177 | 199 |
178 // Only create new key containers, so that existing key containers are not | 200 // Only create new key containers, so that existing key containers are not |
179 // overwritten. | 201 // overwritten. |
180 if (crypto::CryptAcquireContextLocked(key_container.provider_.receive(), | 202 if (crypto::CryptAcquireContextLocked(key_container.provider_.receive(), |
181 key_container.key_id_.c_str(), NULL, PROV_RSA_FULL, | 203 key_container.key_id_.c_str(), |
182 CRYPT_SILENT | CRYPT_NEWKEYSET)) | 204 NULL, |
| 205 PROV_RSA_FULL, |
| 206 CRYPT_SILENT | CRYPT_NEWKEYSET)) |
183 break; | 207 break; |
184 | 208 |
185 if (GetLastError() != NTE_BAD_KEYSET) { | 209 if (GetLastError() != NTE_BAD_KEYSET) { |
186 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " | 210 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " |
187 "context: " << GetLastError(); | 211 "context: " << GetLastError(); |
188 return std::string(); | 212 return std::string(); |
189 } | 213 } |
190 } | 214 } |
191 if (attempt == kMaxAttempts) { | 215 if (attempt == kMaxAttempts) { |
192 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " | 216 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " |
193 "context: Max retries exceeded"; | 217 "context: Max retries exceeded"; |
194 return std::string(); | 218 return std::string(); |
195 } | 219 } |
196 | 220 |
197 { | 221 { |
198 crypto::ScopedHCRYPTKEY key; | 222 crypto::ScopedHCRYPTKEY key; |
199 if (!CryptGenKey(key_container.provider_, CALG_RSA_KEYX, | 223 if (!CryptGenKey(key_container.provider_, |
200 (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE, key.receive())) { | 224 CALG_RSA_KEYX, |
| 225 (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE, |
| 226 key.receive())) { |
201 LOG(ERROR) << "Keygen failed: Couldn't generate an RSA key"; | 227 LOG(ERROR) << "Keygen failed: Couldn't generate an RSA key"; |
202 return std::string(); | 228 return std::string(); |
203 } | 229 } |
204 | 230 |
205 std::string spkac; | 231 std::string spkac; |
206 if (!GetSignedPublicKeyAndChallenge(key_container.provider_, challenge_, | 232 if (!GetSignedPublicKeyAndChallenge( |
207 &spkac)) { | 233 key_container.provider_, challenge_, &spkac)) { |
208 LOG(ERROR) << "Keygen failed: Couldn't generate the signed public key " | 234 LOG(ERROR) << "Keygen failed: Couldn't generate the signed public key " |
209 "and challenge"; | 235 "and challenge"; |
210 return std::string(); | 236 return std::string(); |
211 } | 237 } |
212 | 238 |
213 std::string result; | 239 std::string result; |
214 base::Base64Encode(spkac, &result); | 240 base::Base64Encode(spkac, &result); |
215 | 241 |
216 VLOG(1) << "Keygen succeeded"; | 242 VLOG(1) << "Keygen succeeded"; |
217 return result; | 243 return result; |
218 } | 244 } |
219 } | 245 } |
220 | 246 |
221 } // namespace net | 247 } // namespace net |
OLD | NEW |