OLD | NEW |
| (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 <cryptohi.h> | |
8 #include <keyhi.h> | |
9 #include <pk11pub.h> | |
10 | |
11 #include <iostream> | |
12 #include <list> | |
13 | |
14 #include "base/logging.h" | |
15 #include "base/nss_init.h" | |
16 #include "base/scoped_ptr.h" | |
17 #include "base/string_util.h" | |
18 | |
19 // TODO(rafaelw): Consider refactoring common functions and definitions from | |
20 // rsa_private_key_win.cc or using NSS's ASN.1 encoder. | |
21 namespace { | |
22 | |
23 // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8. | |
24 const uint8 kRsaAlgorithmIdentifier[] = { | |
25 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, | |
26 0x05, 0x00 | |
27 }; | |
28 | |
29 // ASN.1 tags for some types we use. | |
30 const uint8 kSequenceTag = 0x30; | |
31 const uint8 kIntegerTag = 0x02; | |
32 const uint8 kNullTag = 0x05; | |
33 const uint8 kOctetStringTag = 0x04; | |
34 | |
35 static void PrependBytesInOrder(uint8* val, int start, int num_bytes, | |
36 std::list<uint8>* data) { | |
37 while(num_bytes > start) { | |
38 --num_bytes; | |
39 data->push_front(val[num_bytes]); | |
40 } | |
41 } | |
42 | |
43 // Helper to prepend an ASN.1 length field. | |
44 static void PrependLength(size_t size, std::list<uint8>* data) { | |
45 // The high bit is used to indicate whether additional octets are needed to | |
46 // represent the length. | |
47 if (size < 0x80) { | |
48 data->push_front(static_cast<uint8>(size)); | |
49 } else { | |
50 uint8 num_bytes = 0; | |
51 while (size > 0) { | |
52 data->push_front(static_cast<uint8>(size & 0xFF)); | |
53 size >>= 8; | |
54 num_bytes++; | |
55 } | |
56 CHECK(num_bytes <= 4); | |
57 data->push_front(0x80 | num_bytes); | |
58 } | |
59 } | |
60 | |
61 // Helper to prepend an ASN.1 type header. | |
62 static void PrependTypeHeaderAndLength(uint8 type, uint32 length, | |
63 std::list<uint8>* output) { | |
64 PrependLength(length, output); | |
65 output->push_front(type); | |
66 } | |
67 | |
68 // Helper to prepend an ASN.1 integer. | |
69 static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) { | |
70 // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes | |
71 // from the most-significant end of the integer. | |
72 int start = 0; | |
73 while (start < (num_bytes - 1) && val[start] == 0x00) | |
74 start++; | |
75 | |
76 PrependBytesInOrder(val, start, num_bytes, data); | |
77 | |
78 // ASN.1 integers are signed. To encode a positive integer whose sign bit | |
79 // (the most significant bit) would otherwise be set and make the number | |
80 // negative, ASN.1 requires a leading null byte to force the integer to be | |
81 // positive. | |
82 if ((val[start] & 0x80) != 0) { | |
83 data->push_front(0x00); | |
84 num_bytes++; | |
85 } | |
86 | |
87 PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); | |
88 } | |
89 | |
90 static bool ReadAttributeAndPrependInteger(SECKEYPrivateKey* key, | |
91 CK_ATTRIBUTE_TYPE type, | |
92 std::list<uint8>* output) { | |
93 SECItem item; | |
94 SECStatus rv; | |
95 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); | |
96 if (rv != SECSuccess) { | |
97 NOTREACHED(); | |
98 return false; | |
99 } | |
100 | |
101 PrependInteger(item.data, item.len, output); | |
102 SECITEM_FreeItem(&item, PR_FALSE); | |
103 return true; | |
104 } | |
105 | |
106 } // namespace | |
107 | |
108 | |
109 namespace base { | |
110 | |
111 // static | |
112 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { | |
113 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); | |
114 | |
115 PK11SlotInfo *slot = PK11_GetInternalSlot(); | |
116 if (!slot) | |
117 return NULL; | |
118 | |
119 PK11RSAGenParams param; | |
120 param.keySizeInBits = num_bits; | |
121 param.pe = 65537L; | |
122 result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, | |
123 &result->public_key_, PR_FALSE, PR_FALSE, NULL); | |
124 PK11_FreeSlot(slot); | |
125 if (!result->key_) | |
126 return NULL; | |
127 | |
128 return result.release(); | |
129 } | |
130 | |
131 // static | |
132 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( | |
133 const std::vector<uint8>& input) { | |
134 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); | |
135 | |
136 PK11SlotInfo *slot = PK11_GetInternalSlot(); | |
137 if (!slot) | |
138 return NULL; | |
139 | |
140 SECItem der_private_key_info; | |
141 der_private_key_info.data = const_cast<unsigned char*>(&input.front()); | |
142 der_private_key_info.len = input.size(); | |
143 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, | |
144 &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE, | |
145 KU_DIGITAL_SIGNATURE, &result->key_, NULL); | |
146 PK11_FreeSlot(slot); | |
147 if (rv != SECSuccess) { | |
148 NOTREACHED(); | |
149 return NULL; | |
150 } | |
151 | |
152 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_); | |
153 if (!result->public_key_) { | |
154 NOTREACHED(); | |
155 return NULL; | |
156 } | |
157 | |
158 return result.release(); | |
159 } | |
160 | |
161 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { | |
162 EnsureNSSInit(); | |
163 } | |
164 | |
165 RSAPrivateKey::~RSAPrivateKey() { | |
166 if (key_) | |
167 SECKEY_DestroyPrivateKey(key_); | |
168 if (public_key_) | |
169 SECKEY_DestroyPublicKey(public_key_); | |
170 } | |
171 | |
172 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { | |
173 std::list<uint8> content; | |
174 | |
175 // Version (always zero) | |
176 uint8 version = 0; | |
177 | |
178 // Manually read the component attributes of the private key and build up the | |
179 // output in reverse order to prevent having to do copies to figure out the | |
180 // length. | |
181 if (!ReadAttributeAndPrependInteger(key_, CKA_COEFFICIENT, &content) || | |
182 !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_2, &content) || | |
183 !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_1, &content) || | |
184 !ReadAttributeAndPrependInteger(key_, CKA_PRIME_2, &content) || | |
185 !ReadAttributeAndPrependInteger(key_, CKA_PRIME_1, &content) || | |
186 !ReadAttributeAndPrependInteger(key_, CKA_PRIVATE_EXPONENT, &content) || | |
187 !ReadAttributeAndPrependInteger(key_, CKA_PUBLIC_EXPONENT, &content) || | |
188 !ReadAttributeAndPrependInteger(key_, CKA_MODULUS, &content)) { | |
189 NOTREACHED(); | |
190 return false; | |
191 } | |
192 PrependInteger(&version, 1, &content); | |
193 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); | |
194 PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content); | |
195 | |
196 // RSA algorithm OID | |
197 for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) | |
198 content.push_front(kRsaAlgorithmIdentifier[i - 1]); | |
199 | |
200 PrependInteger(&version, 1, &content); | |
201 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); | |
202 | |
203 // Copy everying into the output. | |
204 output->reserve(content.size()); | |
205 for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) | |
206 output->push_back(*i); | |
207 | |
208 return true; | |
209 } | |
210 | |
211 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { | |
212 SECItem* der_pubkey = PK11_DEREncodePublicKey(public_key_); | |
213 if (!der_pubkey) { | |
214 NOTREACHED(); | |
215 return false; | |
216 } | |
217 | |
218 for (size_t i = 0; i < der_pubkey->len; ++i) | |
219 output->push_back(der_pubkey->data[i]); | |
220 | |
221 SECITEM_FreeItem(der_pubkey, PR_TRUE); | |
222 return true; | |
223 } | |
224 | |
225 } // namespace base | |
OLD | NEW |