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

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

Issue 1934001: Simplify the Windows <keygen> implementation by making better use of CryptoAP... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Fixing nits Created 10 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/utf_string_conversions.h" 22 #include "base/utf_string_conversions.h"
22 23
23 namespace net { 24 namespace net {
24 25
25 // TODO(rsleevi): The following encoding functions are adapted from
26 // base/crypto/rsa_private_key.h and can/should probably be refactored.
27 static const uint8 kSequenceTag = 0x30;
28
29 void PrependLength(size_t size, std::list<BYTE>* data) {
30 // The high bit is used to indicate whether additional octets are needed to
31 // represent the length.
32 if (size < 0x80) {
33 data->push_front(static_cast<BYTE>(size));
34 } else {
35 uint8 num_bytes = 0;
36 while (size > 0) {
37 data->push_front(static_cast<BYTE>(size & 0xFF));
38 size >>= 8;
39 num_bytes++;
40 }
41 CHECK_LE(num_bytes, 4);
42 data->push_front(0x80 | num_bytes);
43 }
44 }
45
46 void PrependTypeHeaderAndLength(uint8 type, uint32 length,
47 std::vector<BYTE>* output) {
48 std::list<BYTE> type_and_length;
49
50 PrependLength(length, &type_and_length);
51 type_and_length.push_front(type);
52
53 output->insert(output->begin(), type_and_length.begin(),
54 type_and_length.end());
55 }
56
57 bool EncodeAndAppendType(LPCSTR type, const void* to_encode, 26 bool EncodeAndAppendType(LPCSTR type, const void* to_encode,
58 std::vector<BYTE>* output) { 27 std::vector<BYTE>* output) {
59 BOOL ok; 28 BOOL ok;
60 DWORD size = 0; 29 DWORD size = 0;
61 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode, NULL, &size); 30 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode, NULL, &size);
62 DCHECK(ok); 31 DCHECK(ok);
63 if (!ok) 32 if (!ok)
64 return false; 33 return false;
65 34
66 std::vector<BYTE>::size_type old_size = output->size(); 35 std::vector<BYTE>::size_type old_size = output->size();
67 output->resize(old_size + size); 36 output->resize(old_size + size);
68 37
69 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode, 38 ok = CryptEncodeObject(X509_ASN_ENCODING, type, to_encode,
70 &(*output)[old_size], &size); 39 &(*output)[old_size], &size);
71 DCHECK(ok); 40 DCHECK(ok);
72 if (!ok) 41 if (!ok)
73 return false; 42 return false;
74 43
75 // Sometimes the initial call to CryptEncodeObject gave a generous estimate 44 // Sometimes the initial call to CryptEncodeObject gave a generous estimate
76 // of the size, so shrink back to what was actually used. 45 // of the size, so shrink back to what was actually used.
77 output->resize(old_size + size); 46 output->resize(old_size + size);
78 47
79 return true; 48 return true;
80 } 49 }
81 50
82 // Appends a DER IA5String containing |challenge| to |output|. 51 // Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing
83 // Returns true if encoding was successful. 52 // key in |prov| to |output|. Returns true if encoding was successful.
84 bool EncodeChallenge(const std::string& challenge, std::vector<BYTE>* output) { 53 bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) {
85 CERT_NAME_VALUE challenge_nv;
86 challenge_nv.dwValueType = CERT_RDN_IA5_STRING;
87 challenge_nv.Value.pbData = const_cast<BYTE*>(
88 reinterpret_cast<const BYTE*>(challenge.data()));
89 challenge_nv.Value.cbData = challenge.size();
90
91 return EncodeAndAppendType(X509_ANY_STRING, &challenge_nv, output);
92 }
93
94 // Appends a DER SubjectPublicKeyInfo structure for the signing key in |prov|
95 // to |output|.
96 // Returns true if encoding was successful.
97 bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) {
98 BOOL ok; 54 BOOL ok;
99 DWORD size = 0; 55 DWORD size = 0;
100 56
101 // From the private key stored in HCRYPTPROV, obtain the public key, stored 57 // From the private key stored in HCRYPTPROV, obtain the public key, stored
102 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are 58 // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are
103 // supported. 59 // supported.
104 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 60 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
105 szOID_RSA_RSA, 0, NULL, NULL, &size); 61 szOID_RSA_RSA, 0, NULL, NULL, &size);
106 DCHECK(ok); 62 DCHECK(ok);
107 if (!ok) 63 if (!ok)
108 return false; 64 return false;
109 65
110 std::vector<BYTE> public_key_info(size); 66 output->resize(size);
67
111 PCERT_PUBLIC_KEY_INFO public_key_casted = 68 PCERT_PUBLIC_KEY_INFO public_key_casted =
112 reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&public_key_info[0]); 69 reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]);
113 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 70 ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
114 szOID_RSA_RSA, 0, NULL, public_key_casted, 71 szOID_RSA_RSA, 0, NULL, public_key_casted,
115 &size); 72 &size);
116 DCHECK(ok); 73 DCHECK(ok);
117 if (!ok) 74 if (!ok)
118 return false; 75 return false;
119 76
120 public_key_info.resize(size); 77 output->resize(size);
78
79 return true;
80 }
81
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;
121 89
122 return EncodeAndAppendType(X509_PUBLIC_KEY_INFO, &public_key_info[0], 90 return EncodeAndAppendType(X509_PUBLIC_KEY_INFO, &public_key_info[0],
123 output); 91 output);
124 } 92 }
125 93
126 // Generates an ASN.1 DER representation of the PublicKeyAndChallenge structure
127 // from the signing key of |prov| and the specified |challenge| and appends it
128 // to |output|.
129 // True if the the encoding was successfully generated.
130 bool GetPublicKeyAndChallenge(HCRYPTPROV prov, const std::string& challenge,
131 std::vector<BYTE>* output) {
132 if (!EncodeSubjectPublicKeyInfo(prov, output) ||
133 !EncodeChallenge(challenge, output)) {
134 return false;
135 }
136
137 PrependTypeHeaderAndLength(kSequenceTag, output->size(), output);
138 return true;
139 }
140
141 // Generates a DER encoded SignedPublicKeyAndChallenge structure from the 94 // Generates a DER encoded SignedPublicKeyAndChallenge structure from the
142 // signing key of |prov| and the specified |challenge| string and appends it 95 // signing key of |prov| and the specified ASCII |challenge| string and
143 // to |output|. 96 // appends it to |output|.
144 // True if the encoding was successfully generated. 97 // True if the encoding was successfully generated.
145 bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov, 98 bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov,
146 const std::string& challenge, 99 const std::string& challenge,
147 std::string* output) { 100 std::string* output) {
148 std::vector<BYTE> pkac; 101 std::wstring wide_challenge = ASCIIToWide(challenge);
149 if (!GetPublicKeyAndChallenge(prov, challenge, &pkac)) 102 std::vector<BYTE> spki;
103
104 if (!GetSubjectPublicKeyInfo(prov, &spki))
150 return false; 105 return false;
151 106
152 std::vector<BYTE> signature; 107 CERT_KEYGEN_REQUEST_INFO request;
108 request.dwVersion = CERT_KEYGEN_REQUEST_V1;
109 request.SubjectPublicKeyInfo =
110 *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]);
111 request.pwszChallengeString = const_cast<wchar_t*>(wide_challenge.c_str());
112
113 CRYPT_ALGORITHM_IDENTIFIER sig_alg;
114 memset(&sig_alg, 0, sizeof(sig_alg));
115 sig_alg.pszObjId = szOID_RSA_MD5RSA;
116
117 BOOL ok;
118 DWORD size = 0;
153 std::vector<BYTE> signed_pkac; 119 std::vector<BYTE> signed_pkac;
154 DWORD size = 0; 120 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
155 BOOL ok; 121 X509_KEYGEN_REQUEST_TO_BE_SIGNED,
156 122 &request, &sig_alg, NULL,
157 // While the MSDN documentation states that CERT_SIGNED_CONTENT_INFO should 123 NULL, &size);
158 // be an X.509 certificate type, for encoding this is not necessary. The
159 // result of encoding this structure will be a DER-encoded structure with
160 // the ASN.1 equivalent of
161 // ::= SEQUENCE {
162 // ToBeSigned IMPLICIT OCTET STRING,
163 // SignatureAlgorithm AlgorithmIdentifier,
164 // Signature BIT STRING
165 // }
166 //
167 // This happens to be the same naive type as an SPKAC, so this works.
168 CERT_SIGNED_CONTENT_INFO info;
169 info.ToBeSigned.cbData = pkac.size();
170 info.ToBeSigned.pbData = &pkac[0];
171 info.SignatureAlgorithm.pszObjId = szOID_RSA_MD5RSA;
172 info.SignatureAlgorithm.Parameters.cbData = 0;
173 info.SignatureAlgorithm.Parameters.pbData = NULL;
174
175 ok = CryptSignCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
176 info.ToBeSigned.pbData, info.ToBeSigned.cbData,
177 &info.SignatureAlgorithm, NULL, NULL, &size);
178 DCHECK(ok); 124 DCHECK(ok);
179 if (!ok) 125 if (!ok)
180 return false; 126 return false;
181 127
182 signature.resize(size); 128 signed_pkac.resize(size);
183 info.Signature.cbData = signature.size(); 129 ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
184 info.Signature.pbData = &signature[0]; 130 X509_KEYGEN_REQUEST_TO_BE_SIGNED,
185 info.Signature.cUnusedBits = 0; 131 &request, &sig_alg, NULL,
186 132 &signed_pkac[0], &size);
187 ok = CryptSignCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
188 info.ToBeSigned.pbData, info.ToBeSigned.cbData,
189 &info.SignatureAlgorithm, NULL,
190 info.Signature.pbData, &info.Signature.cbData);
191 DCHECK(ok); 133 DCHECK(ok);
192 if (!ok || !EncodeAndAppendType(X509_CERT, &info, &signed_pkac)) 134 if (!ok)
193 return false; 135 return false;
194 136
195 output->assign(reinterpret_cast<char*>(&signed_pkac[0]), 137 output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size);
196 signed_pkac.size());
197
198 return true; 138 return true;
199 } 139 }
200 140
201 // Generates a unique name for the container which will store the key that is 141 // Generates a unique name for the container which will store the key that is
202 // generated. The traditional Windows approach is to use a GUID here. 142 // generated. The traditional Windows approach is to use a GUID here.
203 std::wstring GetNewKeyContainerId() { 143 std::wstring GetNewKeyContainerId() {
204 RPC_STATUS status = RPC_S_OK; 144 RPC_STATUS status = RPC_S_OK;
205 std::wstring result; 145 std::wstring result;
206 146
207 UUID id = { 0 }; 147 UUID id = { 0 };
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 // Fully destroys any of the keys that were created and releases prov. 299 // Fully destroys any of the keys that were created and releases prov.
360 CryptAcquireContext(&prov, new_key_id.c_str(), NULL, PROV_RSA_FULL, 300 CryptAcquireContext(&prov, new_key_id.c_str(), NULL, PROV_RSA_FULL,
361 CRYPT_SILENT | CRYPT_DELETEKEYSET); 301 CRYPT_SILENT | CRYPT_DELETEKEYSET);
362 } 302 }
363 } 303 }
364 304
365 return result; 305 return result;
366 } 306 }
367 307
368 } // namespace net 308 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698