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

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

Issue 242136: Refactor ASN1 parsing/serializationg (Closed)
Patch Set: more cr changes Created 11 years, 2 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.h ('k') | base/crypto/rsa_private_key_mac.cc » ('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 <iostream>
8 #include <list>
9
10 #include "base/logging.h"
11 #include "base/scoped_ptr.h"
12 #include "base/string_util.h"
13
14 // This file manually encodes and decodes RSA private keys using PrivateKeyInfo
15 // from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are:
16 //
17 // PrivateKeyInfo ::= SEQUENCE {
18 // version Version,
19 // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
20 // privateKey PrivateKey,
21 // attributes [0] IMPLICIT Attributes OPTIONAL
22 // }
23 //
24 // RSAPrivateKey ::= SEQUENCE {
25 // version Version,
26 // modulus INTEGER,
27 // publicExponent INTEGER,
28 // privateExponent INTEGER,
29 // prime1 INTEGER,
30 // prime2 INTEGER,
31 // exponent1 INTEGER,
32 // exponent2 INTEGER,
33 // coefficient INTEGER
34 // }
35
36 namespace {
37 // Helper for error handling during key import.
38 #define READ_ASSERT(truth) \
39 if (!(truth)) { \
40 NOTREACHED(); \
41 return false; \
42 }
43 } // namespace
44
45 namespace base {
46
47 const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = {
48 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
49 0x05, 0x00
50 };
51
52 void PrivateKeyInfoCodec::PrependBytes(uint8* val,
53 int start,
54 int num_bytes,
55 std::list<uint8>* data) {
56 while(num_bytes > 0) {
57 --num_bytes;
58 data->push_front(val[start + num_bytes]);
59 }
60 }
61
62 void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8>* data) {
63 // The high bit is used to indicate whether additional octets are needed to
64 // represent the length.
65 if (size < 0x80) {
66 data->push_front(static_cast<uint8>(size));
67 } else {
68 uint8 num_bytes = 0;
69 while (size > 0) {
70 data->push_front(static_cast<uint8>(size & 0xFF));
71 size >>= 8;
72 num_bytes++;
73 }
74 CHECK(num_bytes <= 4);
75 data->push_front(0x80 | num_bytes);
76 }
77 }
78
79 void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type,
80 uint32 length,
81 std::list<uint8>* output) {
82 PrependLength(length, output);
83 output->push_front(type);
84 }
85
86 void PrivateKeyInfoCodec::PrependBitString(uint8* val,
87 int num_bytes,
88 std::list<uint8>* output) {
89 // Start with the data.
90 PrependBytes(val, 0, num_bytes, output);
91 // Zero unused bits.
92 output->push_front(0);
93 // Add the length.
94 PrependLength(num_bytes + 1, output);
95 // Finally, add the bit string tag.
96 output->push_front((uint8) kBitStringTag);
97 }
98
99 bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) {
100 READ_ASSERT(*pos < end);
101 int length = 0;
102
103 // If the MSB is not set, the length is just the byte itself.
104 if (!(**pos & 0x80)) {
105 length = **pos;
106 (*pos)++;
107 } else {
108 // Otherwise, the lower 7 indicate the length of the length.
109 int length_of_length = **pos & 0x7F;
110 READ_ASSERT(length_of_length <= 4);
111 (*pos)++;
112 READ_ASSERT(*pos + length_of_length < end);
113
114 length = 0;
115 for (int i = 0; i < length_of_length; ++i) {
116 length <<= 8;
117 length |= **pos;
118 (*pos)++;
119 }
120 }
121
122 READ_ASSERT(*pos + length <= end);
123 if (result) *result = length;
124 return true;
125 }
126
127 bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos,
128 uint8* end,
129 uint8 expected_tag,
130 uint32* length) {
131 READ_ASSERT(*pos < end);
132 READ_ASSERT(**pos == expected_tag);
133 (*pos)++;
134
135 return ReadLength(pos, end, length);
136 }
137
138 bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) {
139 return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
140 }
141
142 bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
143 READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
144 READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
145 sizeof(kRsaAlgorithmIdentifier)) == 0);
146 (*pos) += sizeof(kRsaAlgorithmIdentifier);
147 return true;
148 }
149
150 bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) {
151 uint32 length = 0;
152 if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
153 return false;
154
155 // The version should be zero.
156 for (uint32 i = 0; i < length; ++i) {
157 READ_ASSERT(**pos == 0x00);
158 (*pos)++;
159 }
160
161 return true;
162 }
163
164 bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) {
165 std::list<uint8> content;
166
167 // Version (always zero)
168 uint8 version = 0;
169
170 PrependInteger(coefficient_, &content);
171 PrependInteger(exponent2_, &content);
172 PrependInteger(exponent1_, &content);
173 PrependInteger(prime2_, &content);
174 PrependInteger(prime1_, &content);
175 PrependInteger(private_exponent_, &content);
176 PrependInteger(public_exponent_, &content);
177 PrependInteger(modulus_, &content);
178 PrependInteger(&version, 1, &content);
179 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
180 PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content);
181
182 // RSA algorithm OID
183 for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i)
184 content.push_front(kRsaAlgorithmIdentifier[i - 1]);
185
186 PrependInteger(&version, 1, &content);
187 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
188
189 // Copy everying into the output.
190 output->reserve(content.size());
191 for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
192 output->push_back(*i);
193
194 return true;
195 }
196
197 bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) {
198 // Create a sequence with the modulus (n) and public exponent (e).
199 std::list<uint8> content;
200 PrependInteger(&public_exponent_[0],
201 static_cast<int>(public_exponent_.size()),
202 &content);
203 PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content);
204 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
205
206 // Copy the sequence with n and e into a buffer.
207 std::vector<uint8> bit_string;
208 for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
209 bit_string.push_back(*i);
210 content.clear();
211 // Add the sequence as the contents of a bit string.
212 PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()),
213 &content);
214
215 // Add the RSA algorithm OID.
216 for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i)
217 content.push_front(kRsaAlgorithmIdentifier[i - 1]);
218
219 // Finally, wrap everything in a sequence.
220 PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
221
222 // Copy everything into the output.
223 output->reserve(content.size());
224 for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
225 output->push_back(*i);
226
227 return true;
228 }
229
230 bool PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) {
231 if (input.empty()) {
232 return false;
233 }
234
235 // Parse the private key info up to the public key values, ignoring
236 // the subsequent private key values.
237 uint8* src = const_cast<uint8*>(&input.front());
238 uint8* end = src + input.size();
239 if (!ReadSequence(&src, end) ||
240 !ReadVersion(&src, end) ||
241 !ReadAlgorithmIdentifier(&src, end) ||
242 !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) ||
243 !ReadSequence(&src, end) ||
244 !ReadVersion(&src, end) ||
245 !ReadInteger(&src, end, &modulus_))
246 return false;
247
248 int mod_size = modulus_.size();
249 READ_ASSERT(mod_size % 2 == 0);
250 int primes_size = mod_size / 2;
251
252 if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) ||
253 !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) ||
254 !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) ||
255 !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) ||
256 !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) ||
257 !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) ||
258 !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_))
259 return false;
260
261 READ_ASSERT(src == end);
262
263
264 return true;
265 }
266
267 void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8>& in,
268 std::list<uint8>* out) {
269 uint8* ptr = const_cast<uint8*>(&in.front());
270 PrependIntegerImpl(ptr, in.size(), out, big_endian_);
271 }
272
273 // Helper to prepend an ASN.1 integer.
274 void PrivateKeyInfoCodec::PrependInteger(uint8* val,
275 int num_bytes,
276 std::list<uint8>* data) {
277 PrependIntegerImpl(val, num_bytes, data, big_endian_);
278 }
279
280 void PrivateKeyInfoCodec::PrependIntegerImpl(uint8* val,
281 int num_bytes,
282 std::list<uint8>* data,
283 bool big_endian) {
284 // Reverse input if little-endian.
285 std::vector<uint8> tmp;
286 if (!big_endian) {
287 tmp.assign(val, val + num_bytes);
288 reverse(tmp.begin(), tmp.end());
289 val = &tmp.front();
290 }
291
292 // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes
293 // from the most-significant end of the integer.
294 int start = 0;
295 while (start < (num_bytes - 1) && val[start] == 0x00) {
296 start++;
297 num_bytes--;
298 }
299 PrependBytes(val, start, num_bytes, data);
300
301 // ASN.1 integers are signed. To encode a positive integer whose sign bit
302 // (the most significant bit) would otherwise be set and make the number
303 // negative, ASN.1 requires a leading null byte to force the integer to be
304 // positive.
305 uint8 front = data->front();
306 if ((front & 0x80) != 0) {
307 data->push_front(0x00);
308 num_bytes++;
309 }
310
311 PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data);
312 }
313
314 bool PrivateKeyInfoCodec::ReadInteger(uint8** pos,
315 uint8* end,
316 std::vector<uint8>* out) {
317 return ReadIntegerImpl(pos, end, out, big_endian_);
318 }
319
320 bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos,
321 uint8* end,
322 std::vector<uint8>* out,
323 bool big_endian) {
324 uint32 length = 0;
325 if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length)
326 return false;
327
328 // The first byte can be zero to force positiveness. We can ignore this.
329 if (**pos == 0x00) {
330 ++(*pos);
331 --length;
332 }
333
334 if (length)
335 out->insert(out->end(), *pos, (*pos) + length);
336
337 (*pos) += length;
338
339 // Reverse output if little-endian.
340 if (!big_endian)
341 reverse(out->begin(), out->end());
342 return true;
343 }
344
345 bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos,
346 uint8* end,
347 size_t expected_size,
348 std::vector<uint8>* out) {
349 std::vector<uint8> temp;
350 if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian
351 return false;
352
353 int pad = expected_size - temp.size();
354 int index = 0;
355 if (out->size() == expected_size + 1) {
356 READ_ASSERT(out->front() == 0x00);
357 pad++;
358 index++;
359 } else {
360 READ_ASSERT(out->size() <= expected_size);
361 }
362
363 while(pad) {
364 out->push_back(0x00);
365 pad--;
366 }
367 out->insert(out->end(), temp.begin(), temp.end());
368
369 // Reverse output if little-endian.
370 if (!big_endian_)
371 reverse(out->begin(), out->end());
372 return true;
373 }
374
375 } // namespace base
OLDNEW
« no previous file with comments | « base/crypto/rsa_private_key.h ('k') | base/crypto/rsa_private_key_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698