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

Side by Side Diff: base/crypto/rsa_private_key_win.cc

Issue 118277: Introduce SignatureCreator. (Closed)
Patch Set: Responses to feedback Created 11 years, 6 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 | « base/crypto/rsa_private_key_unittest.cc ('k') | base/crypto/signature_creator.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) 2009 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 "base/crypto/rsa_private_key.h"
6
7 #include <list>
8
9 #include "base/logging.h"
10 #include "base/scoped_ptr.h"
11
12
13 // This file manually encodes and decodes RSA private keys using PrivateKeyInfo
14 // from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are:
15 //
16 // PrivateKeyInfo ::= SEQUENCE {
17 // version Version,
18 // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
19 // privateKey PrivateKey,
20 // attributes [0] IMPLICIT Attributes OPTIONAL
21 // }
22 //
23 // RSAPrivateKey ::= SEQUENCE {
24 // version Version,
25 // modulus INTEGER,
26 // publicExponent INTEGER,
27 // privateExponent INTEGER,
28 // prime1 INTEGER,
29 // prime2 INTEGER,
30 // exponent1 INTEGER,
31 // exponent2 INTEGER,
32 // coefficient INTEGER
33 // }
34
35
36 namespace {
37
38 // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
39 const uint8 kRsaAlgorithmIdentifier[] = {
40 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
41 0x05, 0x00
42 };
43
44 // ASN.1 tags for some types we use.
45 const uint8 kSequenceTag = 0x30;
46 const uint8 kIntegerTag = 0x02;
47 const uint8 kNullTag = 0x05;
48 const uint8 kOctetStringTag = 0x04;
49
50 // Helper function to prepend an array of bytes into a list, reversing their
51 // order. This is needed because ASN.1 integers are big-endian, while CryptoAPI
52 // uses little-endian.
53 static void PrependBytesInReverseOrder(uint8* val, int num_bytes,
54 std::list<uint8>* data) {
55 for (int i = 0; i < num_bytes; ++i)
56 data->push_front(val[i]);
57 }
58
59 // Helper to prepend an ASN.1 length field.
60 static void PrependLength(size_t size, std::list<uint8>* data) {
61 // The high bit is used to indicate whether additional octets are needed to
62 // represent the length.
63 if (size < 0x80) {
64 data->push_front(static_cast<uint8>(size));
65 } else {
66 uint8 num_bytes = 0;
67 while (size > 0) {
68 data->push_front(static_cast<uint8>(size & 0xFF));
69 size >>= 8;
70 num_bytes++;
71 }
72 CHECK(num_bytes <= 4);
73 data->push_front(0x80 | num_bytes);
74 }
75 }
76
77 // Helper to prepend an ASN.1 type header.
78 static void PrependTypeHeaderAndLength(uint8 type, uint32 length,
79 std::list<uint8>* output) {
80 PrependLength(length, output);
81 output->push_front(type);
82 }
83
84 // Helper to prepend an ASN.1 integer.
85 static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) {
86 // If the MSB is set, we need an extra null byte at the front.
87 bool needs_null_byte = !(val[num_bytes - 1] & 0x80);
88 int length = needs_null_byte ? num_bytes + 1 : num_bytes;
89
90 PrependBytesInReverseOrder(val, num_bytes, data);
91
92 // Add a null byte to force the integer to be positive if necessary.
93 if (needs_null_byte)
94 data->push_front(0x00);
95
96 PrependTypeHeaderAndLength(kIntegerTag, length, data);
97 }
98
99 // Helper for error handling during key import.
100 #define READ_ASSERT(truth) \
101 if (!(truth)) { \
102 NOTREACHED(); \
103 return false; \
104 }
105
106 // Read an ASN.1 length field. This also checks that the length does not extend
107 // beyond |end|.
108 static bool ReadLength(uint8** pos, uint8* end, uint32* result) {
109 READ_ASSERT(*pos < end);
110 int length = 0;
111
112 // If the MSB is not set, the length is just the byte itself.
113 if (!(**pos & 0x80)) {
114 length = **pos;
115 (*pos)++;
116 } else {
117 // Otherwise, the lower 7 indicate the length of the length.
118 int length_of_length = **pos & 0x7F;
119 READ_ASSERT(length_of_length <= 4);
120 (*pos)++;
121 READ_ASSERT(*pos + length_of_length < end);
122
123 length = 0;
124 for (int i = 0; i < length_of_length; ++i) {
125 length <<= 8;
126 length |= **pos;
127 (*pos)++;
128 }
129 }
130
131 READ_ASSERT(*pos + length <= end);
132 if (result) *result = length;
133 return true;
134 }
135
136 // Read an ASN.1 type header and its length.
137 static bool ReadTypeHeaderAndLength(uint8** pos, uint8* end,
138 uint8 expected_tag, uint32* length) {
139 READ_ASSERT(*pos < end);
140 READ_ASSERT(**pos == expected_tag);
141 (*pos)++;
142
143 return ReadLength(pos, end, length);
144 }
145
146 // Read an ASN.1 sequence declaration. This consumes the type header and length
147 // field, but not the contents of the sequence.
148 static bool ReadSequence(uint8** pos, uint8* end) {
149 return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
150 }
151
152 // Read the RSA AlgorithmIdentifier.
153 static bool ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
154 READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
155 READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
156 sizeof(kRsaAlgorithmIdentifier)) == 0);
157 (*pos) += sizeof(kRsaAlgorithmIdentifier);
158 return true;
159 }
160
161 // Read one of the two version fields in PrivateKeyInfo.
162 static bool ReadVersion(uint8** pos, uint8* end) {
163 uint32 length = 0;
164 if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
165 return false;
166
167 // The version should be zero.
168 for (uint32 i = 0; i < length; ++i) {
169 READ_ASSERT(**pos == 0x00);
170 (*pos)++;
171 }
172
173 return true;
174 }
175
176 // Read an ASN.1 integer.
177 static bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out) {
178 uint32 length = 0;
179 if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
180 return false;
181
182 // Read the bytes out in reverse order because of endianness.
183 for (uint32 i = length - 1; i > 0; --i)
184 out->push_back(*(*pos + i));
185
186 // The last byte can be zero to force positiveness. We can ignore this.
187 if (**pos != 0x00)
188 out->push_back(**pos);
189
190 (*pos) += length;
191 return true;
192 }
193
194 } // namespace
195
196
197 namespace base {
198
199 // static
200 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
201 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
202 if (!result->InitProvider())
203 return NULL;
204
205 DWORD flags = CRYPT_EXPORTABLE;
206
207 // The size is encoded as the upper 16 bits of the flags. :: sigh ::.
208 flags |= (num_bits << 16);
209 if (!CryptGenKey(result->provider_, CALG_RSA_SIGN, flags, &result->key_))
210 return NULL;
211
212 return result.release();
213 }
214
215 // static
216 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
217 const std::vector<uint8>& input) {
218 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
219 if (!result->InitProvider())
220 return NULL;
221
222 uint8* src = const_cast<uint8*>(&input.front());
223 uint8* end = src + input.size();
224 int version = -1;
225 std::vector<uint8> modulus;
226 std::vector<uint8> public_exponent;
227 std::vector<uint8> private_exponent;
228 std::vector<uint8> prime1;
229 std::vector<uint8> prime2;
230 std::vector<uint8> exponent1;
231 std::vector<uint8> exponent2;
232 std::vector<uint8> coefficient;
233
234 if (!ReadSequence(&src, end) ||
235 !ReadVersion(&src, end) ||
236 !ReadAlgorithmIdentifier(&src, end) ||
237 !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) ||
238 !ReadSequence(&src, end) ||
239 !ReadVersion(&src, end) ||
240 !ReadInteger(&src, end, &modulus) ||
241 !ReadInteger(&src, end, &public_exponent) ||
242 !ReadInteger(&src, end, &private_exponent) ||
243 !ReadInteger(&src, end, &prime1) ||
244 !ReadInteger(&src, end, &prime2) ||
245 !ReadInteger(&src, end, &exponent1) ||
246 !ReadInteger(&src, end, &exponent2) ||
247 !ReadInteger(&src, end, &coefficient))
248 return false;
249
250 READ_ASSERT(src == end);
251
252 int blob_size = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulus.size() +
253 prime1.size() + prime2.size() +
254 exponent1.size() + exponent2.size() +
255 coefficient.size() + private_exponent.size();
256 scoped_array<BYTE> blob(new BYTE[blob_size]);
257
258 uint8* dest = blob.get();
259 PUBLICKEYSTRUC* public_key_struc = reinterpret_cast<PUBLICKEYSTRUC*>(dest);
260 public_key_struc->bType = PRIVATEKEYBLOB;
261 public_key_struc->bVersion = 0x02;
262 public_key_struc->reserved = 0;
263 public_key_struc->aiKeyAlg = CALG_RSA_SIGN;
264 dest += sizeof(PUBLICKEYSTRUC);
265
266 RSAPUBKEY* rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(dest);
267 rsa_pub_key->magic = 0x32415352;
268 rsa_pub_key->bitlen = modulus.size() * 8;
269 int public_exponent_int = 0;
270 for (size_t i = public_exponent.size(); i > 0; --i) {
271 public_exponent_int <<= 8;
272 public_exponent_int |= public_exponent[i - 1];
273 }
274 rsa_pub_key->pubexp = public_exponent_int;
275 dest += sizeof(RSAPUBKEY);
276
277 memcpy(dest, &modulus.front(), modulus.size());
278 dest += modulus.size();
279 memcpy(dest, &prime1.front(), prime1.size());
280 dest += prime1.size();
281 memcpy(dest, &prime2.front(), prime2.size());
282 dest += prime2.size();
283 memcpy(dest, &exponent1.front(), exponent1.size());
284 dest += exponent1.size();
285 memcpy(dest, &exponent2.front(), exponent2.size());
286 dest += exponent2.size();
287 memcpy(dest, &coefficient.front(), coefficient.size());
288 dest += coefficient.size();
289 memcpy(dest, &private_exponent.front(), private_exponent.size());
290 dest += private_exponent.size();
291
292 READ_ASSERT(dest == blob.get() + blob_size);
293 if (!CryptImportKey(
294 result->provider_, reinterpret_cast<uint8*>(public_key_struc), blob_size,
295 NULL, CRYPT_EXPORTABLE, &result->key_)) {
296 return NULL;
297 }
298
299 return result.release();
300 }
301
302 RSAPrivateKey::RSAPrivateKey() : provider_(NULL), key_(NULL) {}
303
304 RSAPrivateKey::~RSAPrivateKey() {
305 if (key_) {
306 if (!CryptDestroyKey(key_))
307 NOTREACHED();
308 }
309
310 if (provider_) {
311 if (!CryptReleaseContext(provider_, 0))
312 NOTREACHED();
313 }
314 }
315
316 bool RSAPrivateKey::InitProvider() {
317 return FALSE != CryptAcquireContext(&provider_, NULL, NULL,
318 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
319 }
320
321 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
322 // Export the key
323 DWORD blob_length = 0;
324 if (!CryptExportKey(key_, NULL, PRIVATEKEYBLOB, 0, NULL, &blob_length)) {
325 NOTREACHED();
326 return false;
327 }
328
329 scoped_array<uint8> blob(new uint8[blob_length]);
330 if (!CryptExportKey(key_, NULL, PRIVATEKEYBLOB, 0, blob.get(),
331 &blob_length)) {
332 NOTREACHED();
333 return false;
334 }
335
336 uint8* pos = blob.get();
337 PUBLICKEYSTRUC *publickey_struct = reinterpret_cast<PUBLICKEYSTRUC*>(pos);
338 pos += sizeof(PUBLICKEYSTRUC);
339
340 RSAPUBKEY *rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(pos);
341 pos += sizeof(RSAPUBKEY);
342
343 int mod_size = rsa_pub_key->bitlen / 8;
344 int primes_size = rsa_pub_key->bitlen / 16;
345 int exponents_size = primes_size;
346 int coefficient_size = primes_size;
347 int private_exponent_size = mod_size;
348
349 uint8* modulus = pos;
350 pos += mod_size;
351
352 uint8* prime1 = pos;
353 pos += primes_size;
354 uint8* prime2 = pos;
355 pos += primes_size;
356
357 uint8* exponent1 = pos;
358 pos += exponents_size;
359 uint8* exponent2 = pos;
360 pos += exponents_size;
361
362 uint8* coefficient = pos;
363 pos += coefficient_size;
364
365 uint8* private_exponent = pos;
366 pos += private_exponent_size;
367
368 CHECK((pos - blob_length) == reinterpret_cast<BYTE*>(publickey_struct));
369
370 std::list<uint8> content;
371
372 // Version (always zero)
373 uint8 version = 0;
374
375 // We build up the output in reverse order to prevent having to do copies to
376 // figure out the length.
377 PrependInteger(coefficient, coefficient_size, &content);
378 PrependInteger(exponent2, exponents_size, &content);
379 PrependInteger(exponent1, exponents_size, &content);
380 PrependInteger(prime2, primes_size, &content);
381 PrependInteger(prime1, primes_size, &content);
382 PrependInteger(private_exponent, private_exponent_size, &content);
383 PrependInteger(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp), 4, &content);
384 PrependInteger(modulus, mod_size, &content);
385 PrependInteger(&version, 1, &content);
386 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
387 PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content);
388
389 // RSA algorithm OID
390 for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i)
391 content.push_front(kRsaAlgorithmIdentifier[i - 1]);
392
393 PrependInteger(&version, 1, &content);
394 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
395
396 // Copy everying into the output.
397 output->reserve(content.size());
398 for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
399 output->push_back(*i);
400
401 return true;
402 }
403
404 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
405 DWORD key_info_len;
406 if (!CryptExportPublicKeyInfo(
407 provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
408 NULL, &key_info_len)) {
409 NOTREACHED();
410 return false;
411 }
412
413 scoped_array<uint8> key_info(new uint8[key_info_len]);
414 if (!CryptExportPublicKeyInfo(
415 provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
416 reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), &key_info_len)) {
417 NOTREACHED();
418 return false;
419 }
420
421 DWORD encoded_length;
422 if (!CryptEncodeObject(
423 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
424 reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), NULL,
425 &encoded_length)) {
426 NOTREACHED();
427 return false;
428 }
429
430 scoped_array<BYTE> encoded(new BYTE[encoded_length]);
431 if (!CryptEncodeObject(
432 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
433 reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), encoded.get(),
434 &encoded_length)) {
435 NOTREACHED();
436 return false;
437 }
438
439 for (size_t i = 0; i < encoded_length; ++i)
440 output->push_back(encoded[i]);
441
442 return true;
443 }
444
445 } // namespace base
OLDNEW
« no previous file with comments | « base/crypto/rsa_private_key_unittest.cc ('k') | base/crypto/signature_creator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698