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

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

Issue 2536993002: Remove support for the keygen tag (Closed)
Patch Set: Rebased Created 3 years, 12 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
« no previous file with comments | « net/base/keygen_handler_unittest.cc ('k') | net/base/net_error_list.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) 2011 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/keygen_handler.h"
6
7 #include <windows.h>
8 #include <rpc.h>
9
10 #include <list>
11 #include <string>
12 #include <vector>
13
14 #include "base/base64.h"
15 #include "base/logging.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "crypto/capi_util.h"
20 #include "crypto/scoped_capi_types.h"
21 #include "crypto/wincrypt_shim.h"
22
23 namespace net {
24
25 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing
26 // key in |prov| to |output|. Returns true if encoding was successful.
27 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) {
28 BOOL ok;
29 DWORD size = 0;
30
31 // From the private key stored in HCRYPTPROV, obtain the public key, stored
32 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are
33 // supported.
34 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
35 const_cast<char*>(szOID_RSA_RSA), 0, NULL,
36 NULL, &size);
37 DCHECK(ok);
38 if (!ok)
39 return false;
40
41 output->resize(size);
42
43 PCERT_PUBLIC_KEY_INFO public_key_casted =
44 reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]);
45 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
46 const_cast<char*>(szOID_RSA_RSA), 0, NULL,
47 public_key_casted, &size);
48 DCHECK(ok);
49 if (!ok)
50 return false;
51
52 output->resize(size);
53
54 return true;
55 }
56
57 // Generates a DER encoded SignedPublicKeyAndChallenge structure from the
58 // signing key of |prov| and the specified ASCII |challenge| string and
59 // appends it to |output|.
60 // True if the encoding was successfully generated.
61 bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov,
62 const std::string& challenge,
63 std::string* output) {
64 base::string16 challenge16 = base::ASCIIToUTF16(challenge);
65 std::vector<BYTE> spki;
66
67 if (!GetSubjectPublicKeyInfo(prov, &spki))
68 return false;
69
70 // PublicKeyAndChallenge ::= SEQUENCE {
71 // spki SubjectPublicKeyInfo,
72 // challenge IA5STRING
73 // }
74 CERT_KEYGEN_REQUEST_INFO pkac;
75 pkac.dwVersion = CERT_KEYGEN_REQUEST_V1;
76 pkac.SubjectPublicKeyInfo =
77 *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]);
78 pkac.pwszChallengeString = const_cast<base::char16*>(challenge16.c_str());
79
80 CRYPT_ALGORITHM_IDENTIFIER sig_alg;
81 memset(&sig_alg, 0, sizeof(sig_alg));
82 sig_alg.pszObjId = const_cast<char*>(szOID_RSA_MD5RSA);
83
84 BOOL ok;
85 DWORD size = 0;
86 std::vector<BYTE> signed_pkac;
87 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
88 X509_KEYGEN_REQUEST_TO_BE_SIGNED,
89 &pkac, &sig_alg, NULL,
90 NULL, &size);
91 DCHECK(ok);
92 if (!ok)
93 return false;
94
95 signed_pkac.resize(size);
96 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
97 X509_KEYGEN_REQUEST_TO_BE_SIGNED,
98 &pkac, &sig_alg, NULL,
99 &signed_pkac[0], &size);
100 DCHECK(ok);
101 if (!ok)
102 return false;
103
104 output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size);
105 return true;
106 }
107
108 // Generates a unique name for the container which will store the key that is
109 // generated. The traditional Windows approach is to use a GUID here.
110 std::wstring GetNewKeyContainerId() {
111 RPC_STATUS status = RPC_S_OK;
112 std::wstring result;
113
114 UUID id = { 0 };
115 status = UuidCreateSequential(&id);
116 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY)
117 return result;
118
119 RPC_WSTR rpc_string = NULL;
120 status = UuidToString(&id, &rpc_string);
121 if (status != RPC_S_OK)
122 return result;
123
124 // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++,
125 // so the type cast is necessary.
126 result.assign(reinterpret_cast<wchar_t*>(rpc_string));
127 RpcStringFree(&rpc_string);
128
129 return result;
130 }
131
132 // This is a helper struct designed to optionally delete a key after releasing
133 // the associated provider.
134 struct KeyContainer {
135 public:
136 explicit KeyContainer(bool delete_keyset)
137 : delete_keyset_(delete_keyset) {}
138
139 ~KeyContainer() {
140 if (provider_) {
141 provider_.reset();
142 if (delete_keyset_ && !key_id_.empty()) {
143 HCRYPTPROV provider;
144 crypto::CryptAcquireContextLocked(&provider, key_id_.c_str(), NULL,
145 PROV_RSA_FULL, CRYPT_SILENT | CRYPT_DELETEKEYSET);
146 }
147 }
148 }
149
150 crypto::ScopedHCRYPTPROV provider_;
151 std::wstring key_id_;
152
153 private:
154 bool delete_keyset_;
155 };
156
157 std::string KeygenHandler::GenKeyAndSignChallenge() {
158 KeyContainer key_container(!stores_key_);
159
160 // TODO(rsleevi): Have the user choose which provider they should use, which
161 // needs to be filtered by those providers which can provide the key type
162 // requested or the key size requested. This is especially important for
163 // generating certificates that will be stored on smart cards.
164 const int kMaxAttempts = 5;
165 int attempt;
166 for (attempt = 0; attempt < kMaxAttempts; ++attempt) {
167 // Per MSDN documentation for CryptAcquireContext, if applications will be
168 // creating their own keys, they should ensure unique naming schemes to
169 // prevent overlap with any other applications or consumers of CSPs, and
170 // *should not* store new keys within the default, NULL key container.
171 key_container.key_id_ = GetNewKeyContainerId();
172 if (key_container.key_id_.empty())
173 return std::string();
174
175 // Only create new key containers, so that existing key containers are not
176 // overwritten.
177 if (crypto::CryptAcquireContextLocked(key_container.provider_.receive(),
178 key_container.key_id_.c_str(), NULL, PROV_RSA_FULL,
179 CRYPT_SILENT | CRYPT_NEWKEYSET))
180 break;
181
182 if (GetLastError() != static_cast<DWORD>(NTE_BAD_KEYSET)) {
183 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider "
184 "context: " << GetLastError();
185 return std::string();
186 }
187 }
188 if (attempt == kMaxAttempts) {
189 LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider "
190 "context: Max retries exceeded";
191 return std::string();
192 }
193
194 {
195 crypto::ScopedHCRYPTKEY key;
196 if (!CryptGenKey(key_container.provider_, CALG_RSA_KEYX,
197 (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE, key.receive())) {
198 LOG(ERROR) << "Keygen failed: Couldn't generate an RSA key";
199 return std::string();
200 }
201
202 std::string spkac;
203 if (!GetSignedPublicKeyAndChallenge(key_container.provider_, challenge_,
204 &spkac)) {
205 LOG(ERROR) << "Keygen failed: Couldn't generate the signed public key "
206 "and challenge";
207 return std::string();
208 }
209
210 std::string result;
211 base::Base64Encode(spkac, &result);
212
213 VLOG(1) << "Keygen succeeded";
214 return result;
215 }
216 }
217
218 } // namespace net
OLDNEW
« no previous file with comments | « net/base/keygen_handler_unittest.cc ('k') | net/base/net_error_list.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698