]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | /* | |
25 | * SecRSAKey.c - CoreFoundation based rsa key object | |
26 | */ | |
27 | ||
28 | ||
29 | #include "SecRSAKey.h" | |
30 | #include "SecRSAKeyPriv.h" | |
31 | #include <Security/SecKeyInternal.h> | |
32 | #include <Security/SecItem.h> | |
33 | #include <Security/SecBasePriv.h> | |
34 | #include <AssertMacros.h> | |
35 | #include <Security/SecureTransport.h> /* For error codes. */ | |
36 | #include <CoreFoundation/CFData.h> /* For error codes. */ | |
37 | #include <fcntl.h> | |
38 | #include <sys/types.h> | |
39 | #include <unistd.h> | |
40 | #include <CoreFoundation/CFNumber.h> | |
41 | #include <Security/SecFramework.h> | |
42 | #include <Security/SecRandom.h> | |
43 | #include <security_utilities/debugging.h> | |
44 | #include "SecItemPriv.h" | |
45 | #include <Security/SecInternal.h> | |
46 | ||
47 | #include <corecrypto/ccn.h> | |
48 | #include <corecrypto/ccrsa.h> | |
49 | #include <corecrypto/ccsha1.h> | |
50 | ||
51 | #include <libDER/asn1Types.h> | |
52 | #include <libDER/DER_Keys.h> | |
53 | #include <libDER/DER_Encode.h> | |
54 | ||
55 | #include <CommonCrypto/CommonDigest.h> | |
56 | ||
57 | #include <corecrypto/ccrsa_priv.h> | |
58 | ||
59 | #include <stdint.h> | |
60 | #include <string.h> | |
61 | ||
62 | #define kMaximumRSAKeyBits 4096 | |
63 | #define kMaximumRSAKeyBytes ccn_sizeof(kMaximumRSAKeyBits) | |
64 | ||
65 | #define RSA_PKCS1_PAD_SIGN 0x01 | |
66 | #define RSA_PKCS1_PAD_ENCRYPT 0x02 | |
67 | ||
68 | static void ccn_c_dump(cc_size count, const cc_unit *s) | |
69 | { | |
70 | printf("{ "); | |
71 | cc_size ix; | |
72 | for (ix = count; ix--;) { | |
73 | printf("0x%.02x, 0x%.02x, 0x%.02x, 0x%.02x, ", | |
74 | (s[ix] >> 24) & 0xFF, | |
75 | (s[ix] >> 16) & 0xFF, | |
76 | (s[ix] >> 8 ) & 0xFF, | |
77 | (s[ix] >> 0 ) & 0xFF); | |
78 | } | |
79 | printf("};"); | |
80 | } | |
81 | ||
82 | static void ccn_cprint(cc_size count, char* prefix, const cc_unit *s) | |
83 | { | |
84 | printf("%s", prefix); | |
85 | ccn_c_dump(count, s); | |
86 | printf("\n"); | |
87 | } | |
88 | ||
89 | void ccrsa_dump_full_key(ccrsa_full_ctx_t key); // Suppress warnings | |
90 | void ccrsa_dump_full_key(ccrsa_full_ctx_t key) { | |
91 | ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); | |
92 | ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); | |
93 | ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); | |
94 | ccn_cprint(ccrsa_ctx_n(key), "uint8_t d[] = ", ccrsa_ctx_d(key)); | |
95 | ||
96 | printf("cc_size np = %lu;\n", cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); | |
97 | ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t p[] = ", | |
98 | cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); | |
99 | ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))) + 1, "uint8_t rp[] = ", | |
100 | cczp_recip(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); | |
101 | printf("cc_size nq = %lu;\n", cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); | |
102 | ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t q[] = ", | |
103 | cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); | |
104 | ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))) + 1, "uint8_t rq[] = ", | |
105 | cczp_recip(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); | |
106 | ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t dp[] = ", | |
107 | ccrsa_ctx_private_dp(ccrsa_ctx_private(key))); | |
108 | ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t dq[] = ", | |
109 | ccrsa_ctx_private_dq(ccrsa_ctx_private(key))); | |
110 | ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t qinv[] = ", | |
111 | ccrsa_ctx_private_qinv(ccrsa_ctx_private(key))); | |
112 | printf("--\n"); | |
113 | } | |
114 | ||
115 | void ccrsa_dump_public_key(ccrsa_pub_ctx_t key); // Suppress warning. | |
116 | void ccrsa_dump_public_key(ccrsa_pub_ctx_t key) { | |
117 | ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); | |
118 | ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); | |
119 | ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); | |
120 | ||
121 | printf("--\n"); | |
122 | } | |
123 | ||
124 | /* | |
125 | * | |
126 | * Public Key | |
127 | * | |
128 | */ | |
129 | ||
130 | /* Public key static functions. */ | |
131 | static void SecRSAPublicKeyDestroy(SecKeyRef key) { | |
132 | /* Zero out the public key */ | |
133 | ccrsa_pub_ctx_t pubkey; | |
134 | pubkey.pub = key->key; | |
135 | cc_zero(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey.pub); | |
136 | } | |
137 | ||
138 | #define cc_skip_zeros(size, ptr) { while (size > 0 && *ptr == 0) { ++ptr; --size; } } | |
139 | ||
140 | // | |
141 | // pubkey is initilaized with an n which is the maximum it can hold | |
142 | // We set the n to its correct value given m. | |
143 | // | |
144 | static int ccrsa_pub_init(ccrsa_pub_ctx_t pubkey, | |
145 | size_t m_size, const uint8_t* m, | |
146 | size_t e_size, const uint8_t* e) | |
147 | { | |
148 | cc_skip_zeros(m_size, m); | |
149 | ||
150 | cc_size nm = ccn_nof_size(m_size); | |
151 | if (nm > ccrsa_ctx_n(pubkey)) | |
152 | return -1; | |
153 | ||
154 | ccrsa_ctx_n(pubkey) = nm; | |
155 | ||
156 | ccn_read_uint(nm, ccrsa_ctx_m(pubkey), m_size, m); | |
157 | cczp_init(ccrsa_ctx_zm(pubkey)); | |
158 | ||
159 | return ccn_read_uint(nm, ccrsa_ctx_e(pubkey), e_size, e); | |
160 | } | |
161 | ||
162 | ||
163 | static OSStatus ccrsa_pub_decode(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) | |
164 | { | |
165 | OSStatus result = errSecParam; | |
166 | ||
167 | DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; | |
168 | DERRSAPubKeyPKCS1 decodedKey; | |
169 | ||
170 | require_noerr_action(DERParseSequence(&keyItem, | |
171 | DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs, | |
172 | &decodedKey, sizeof(decodedKey)), | |
173 | errOut, result = errSecDecode); | |
174 | ||
175 | require_noerr(ccrsa_pub_init(pubkey, | |
176 | decodedKey.modulus.length, decodedKey.modulus.data, | |
177 | decodedKey.pubExponent.length, decodedKey.pubExponent.data), | |
178 | errOut); | |
179 | ||
180 | result = errSecSuccess; | |
181 | ||
182 | errOut: | |
183 | return result; | |
184 | } | |
185 | ||
186 | static OSStatus ccrsa_pub_decode_apple(ccrsa_pub_ctx_t pubkey, size_t pkcs1_size, const uint8_t* pkcs1) | |
187 | { | |
188 | OSStatus result = errSecParam; | |
189 | ||
190 | DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; | |
191 | DERRSAPubKeyApple decodedKey; | |
192 | ||
193 | require_noerr_action(DERParseSequence(&keyItem, | |
194 | DERNumRSAPubKeyAppleItemSpecs, DERRSAPubKeyAppleItemSpecs, | |
195 | &decodedKey, sizeof(decodedKey)), | |
196 | errOut, result = errSecDecode); | |
197 | ||
198 | // We could honor the recipricol, but we don't think this is used enough to care. | |
199 | // Don't bother exploding the below function to try to handle this case, it computes. | |
200 | ||
201 | require_noerr(ccrsa_pub_init(pubkey, | |
202 | decodedKey.modulus.length, decodedKey.modulus.data, | |
203 | decodedKey.pubExponent.length, decodedKey.pubExponent.data), | |
204 | errOut); | |
205 | ||
206 | result = errSecSuccess; | |
207 | ||
208 | errOut: | |
209 | return result; | |
210 | } | |
211 | ||
212 | ||
213 | static void ccasn_encode_int(cc_size n, const cc_unit*s, size_t s_size, uint8_t **buffer) | |
214 | { | |
215 | **buffer = ASN1_INTEGER; | |
216 | *buffer += 1; | |
217 | ||
218 | DERSize itemLength = 4; | |
219 | DEREncodeLength(s_size, *buffer, &itemLength); | |
220 | *buffer += itemLength; | |
221 | ||
222 | ccn_write_int(n, s, s_size, *buffer); | |
223 | ||
224 | *buffer += s_size; | |
225 | } | |
226 | ||
227 | ||
228 | static OSStatus SecRSAPublicKeyInit(SecKeyRef key, | |
229 | const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { | |
230 | ||
231 | OSStatus result = errSecParam; | |
232 | ||
233 | ccrsa_pub_ctx_t pubkey; | |
234 | pubkey.pub = key->key; | |
235 | ||
236 | // Set maximum size for parsers | |
237 | ccrsa_ctx_n(pubkey) = ccn_nof(kMaximumRSAKeyBits); | |
238 | ||
239 | switch (encoding) { | |
240 | case kSecKeyEncodingBytes: // Octets is PKCS1 | |
241 | case kSecKeyEncodingPkcs1: | |
242 | result = ccrsa_pub_decode(pubkey, keyDataLength, keyData); | |
243 | break; | |
244 | case kSecKeyEncodingApplePkcs1: | |
245 | result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); | |
246 | break; | |
247 | case kSecKeyEncodingRSAPublicParams: | |
248 | { | |
249 | SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; | |
250 | ||
251 | require_noerr(ccrsa_pub_init(pubkey, | |
252 | params->modulusLength, params->modulus, | |
253 | params->exponentLength, params->exponent), errOut); | |
254 | ||
255 | result = errSecSuccess; | |
256 | break; | |
257 | } | |
258 | case kSecExtractPublicFromPrivate: | |
259 | { | |
260 | ccrsa_full_ctx_t fullKey; | |
261 | fullKey.full = (ccrsa_full_ctx*) keyData; | |
262 | ||
263 | cc_size fullKeyN = ccrsa_ctx_n(fullKey); | |
264 | require(fullKeyN <= ccrsa_ctx_n(pubkey), errOut); | |
265 | memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(fullKeyN))); | |
266 | result = errSecSuccess; | |
267 | break; | |
268 | } | |
269 | default: | |
270 | break; | |
271 | } | |
272 | ||
273 | errOut: | |
274 | return result; | |
275 | } | |
276 | ||
277 | static OSStatus SecRSAPublicKeyRawVerify(SecKeyRef key, SecPadding padding, | |
278 | const uint8_t *signedData, size_t signedDataLen, | |
279 | const uint8_t *sig, size_t sigLen) { | |
280 | OSStatus result = errSSLCrypto; | |
281 | ||
282 | ccrsa_pub_ctx_t pubkey; | |
283 | pubkey.pub = key->key; | |
284 | ||
285 | cc_unit s[ccrsa_ctx_n(pubkey)]; | |
286 | ||
287 | ccn_read_uint(ccrsa_ctx_n(pubkey), s, sigLen, sig); | |
288 | ccrsa_pub_crypt(pubkey, s, s); | |
289 | ccn_swap(ccrsa_ctx_n(pubkey), s); | |
290 | ||
291 | const uint8_t* sBytes = (uint8_t*) s; | |
292 | const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); | |
293 | ||
294 | switch (padding) { | |
295 | case kSecPaddingNone: | |
296 | // Skip leading zeros as long as s is bigger than signedData. | |
297 | while (((ptrdiff_t)signedDataLen < (sEnd - sBytes)) && (*sBytes == 0)) | |
298 | ++sBytes; | |
299 | break; | |
300 | ||
301 | case kSecPaddingPKCS1: | |
302 | { | |
303 | // Verify and skip PKCS1 padding: | |
304 | // | |
305 | // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData | |
306 | // | |
307 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
308 | size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; | |
309 | ||
310 | while (prefix_zeros--) | |
311 | require_quiet(*sBytes++ == 0x00, errOut); | |
312 | ||
313 | require_quiet(*sBytes++ == 0x00, errOut); | |
314 | require_quiet(*sBytes++ == RSA_PKCS1_PAD_SIGN, errOut); | |
315 | ||
316 | while (*sBytes == 0xFF) { | |
317 | require_quiet(++sBytes < sEnd, errOut); | |
318 | } | |
319 | // Required to have at least 8 0xFFs | |
320 | require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); | |
321 | ||
322 | require_quiet(*sBytes == 0x00, errOut); | |
323 | require_quiet(++sBytes < sEnd, errOut); | |
324 | break; | |
325 | } | |
326 | case kSecPaddingOAEP: | |
327 | result = errSecParam; | |
328 | goto errOut; | |
329 | ||
330 | default: | |
331 | result = errSecUnimplemented; | |
332 | goto errOut; | |
333 | } | |
334 | ||
335 | // Compare the rest. | |
336 | require_quiet((sEnd - sBytes) == (ptrdiff_t)signedDataLen, errOut); | |
337 | require_quiet(memcmp(sBytes, signedData, signedDataLen) == 0, errOut); | |
338 | ||
339 | result = errSecSuccess; | |
340 | ||
341 | errOut: | |
342 | cc_zero(ccrsa_ctx_n(pubkey), s); | |
343 | ||
344 | return result; | |
345 | } | |
346 | ||
347 | static OSStatus SecRSAPublicKeyRawEncrypt(SecKeyRef key, SecPadding padding, | |
348 | const uint8_t *plainText, size_t plainTextLen, | |
349 | uint8_t *cipherText, size_t *cipherTextLen) { | |
350 | OSStatus result = errSecParam; | |
351 | ccrsa_pub_ctx_t pubkey; | |
352 | pubkey.pub = key->key; | |
353 | ||
354 | cc_unit s[ccrsa_ctx_n(pubkey)]; | |
355 | const size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
356 | ||
357 | require(cipherTextLen, errOut); | |
358 | require(*cipherTextLen >= m_size, errOut); | |
359 | ||
360 | uint8_t* sBytes = (uint8_t*) s; | |
361 | ||
362 | switch (padding) { | |
363 | case kSecPaddingNone: | |
364 | require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(pubkey), s, plainTextLen, plainText), errOut); | |
365 | require_quiet(ccn_cmp(ccrsa_ctx_n(pubkey), s, ccrsa_ctx_m(pubkey)) < 0, errOut); | |
366 | break; | |
367 | ||
368 | case kSecPaddingPKCS1: | |
369 | { | |
370 | // Create PKCS1 padding: | |
371 | // | |
372 | // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData | |
373 | // | |
374 | const int kMinimumPadding = 1 + 1 + 8 + 1; | |
375 | ||
376 | require_quiet(plainTextLen < m_size - kMinimumPadding, errOut); | |
377 | ||
378 | size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; | |
379 | ||
380 | while (prefix_zeros--) | |
381 | *sBytes++ = 0x00; | |
382 | ||
383 | size_t pad_size = m_size - plainTextLen; | |
384 | ||
385 | *sBytes++ = 0x00; | |
386 | *sBytes++ = RSA_PKCS1_PAD_ENCRYPT; | |
387 | ||
388 | ccrng_generate(ccrng_seckey, pad_size - 3, sBytes); | |
389 | // Remove zeroes from the random pad | |
390 | ||
391 | const uint8_t* sEndOfPad = sBytes + (pad_size - 3); | |
392 | while (sBytes < sEndOfPad) | |
393 | { | |
394 | if (*sBytes == 0x00) | |
395 | *sBytes = 0xFF; // Michael said 0xFF was good enough. | |
396 | ||
397 | ++sBytes; | |
398 | } | |
399 | ||
400 | *sBytes++ = 0x00; | |
401 | ||
402 | memcpy(sBytes, plainText, plainTextLen); | |
403 | ||
404 | ccn_swap(ccrsa_ctx_n(pubkey), s); | |
405 | break; | |
406 | } | |
407 | case kSecPaddingOAEP: | |
408 | { | |
409 | const struct ccdigest_info* di = ccsha1_di(); | |
410 | ||
411 | const size_t encodingOverhead = 2 + 2 * di->output_size; | |
412 | ||
413 | require_action(m_size > encodingOverhead, errOut, result = errSecParam); | |
414 | require_action_quiet(plainTextLen < m_size - encodingOverhead, errOut, result = errSSLCrypto); | |
415 | ||
416 | require_noerr_action(ccrsa_oaep_encode(di, | |
417 | ccrng_seckey, | |
418 | m_size, s, | |
419 | plainTextLen, plainText), errOut, result = errSecInternal); | |
420 | break; | |
421 | } | |
422 | default: | |
423 | goto errOut; | |
424 | } | |
425 | ||
426 | ||
427 | ccrsa_pub_crypt(pubkey, s, s); | |
428 | ||
429 | ccn_write_uint_padded(ccrsa_ctx_n(pubkey), s, m_size, cipherText); | |
430 | *cipherTextLen = m_size; | |
431 | ||
432 | result = errSecSuccess; | |
433 | ||
434 | errOut: | |
435 | ccn_zero(ccrsa_ctx_n(pubkey), s); | |
436 | return result; | |
437 | } | |
438 | ||
439 | static OSStatus SecRSAPublicKeyRawDecrypt(SecKeyRef key, SecPadding padding, | |
440 | const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { | |
441 | OSStatus result = errSSLCrypto; | |
442 | ||
443 | ccrsa_pub_ctx_t pubkey; | |
444 | pubkey.pub = key->key; | |
445 | ||
446 | cc_unit s[ccrsa_ctx_n(pubkey)]; | |
447 | ||
448 | require_action_quiet(cipherText != NULL, errOut, result = errSecParam); | |
449 | require_action_quiet(plainText != NULL, errOut, result = errSecParam); | |
450 | require_action_quiet(plainTextLen != NULL, errOut, result = errSecParam); | |
451 | ||
452 | ccn_read_uint(ccrsa_ctx_n(pubkey), s, cipherTextLen, cipherText); | |
453 | ccrsa_pub_crypt(pubkey, s, s); | |
454 | ccn_swap(ccrsa_ctx_n(pubkey), s); | |
455 | ||
456 | const uint8_t* sBytes = (uint8_t*) s; | |
457 | const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); | |
458 | ||
459 | switch (padding) { | |
460 | case kSecPaddingNone: | |
461 | // Skip leading zeros | |
462 | // We return the bytes for a number and | |
463 | // trim leading zeroes | |
464 | while (sBytes < sEnd && *sBytes == 0x00) | |
465 | ++sBytes; | |
466 | break; | |
467 | ||
468 | case kSecPaddingPKCS1: | |
469 | { | |
470 | // Verify and skip PKCS1 padding: | |
471 | // | |
472 | // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData | |
473 | // | |
474 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
475 | size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; | |
476 | ||
477 | while (prefix_zeros--) | |
478 | require_quiet(*sBytes++ == 0x00, errOut); | |
479 | ||
480 | require_quiet(*sBytes++ == 0x00, errOut); | |
481 | require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); | |
482 | ||
483 | while (*sBytes != 0x00) { | |
484 | require_quiet(++sBytes < sEnd, errOut); | |
485 | } | |
486 | // Required to have at least 8 0xFFs | |
487 | require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); | |
488 | ||
489 | require_quiet(*sBytes == 0x00, errOut); | |
490 | require_quiet(++sBytes < sEnd, errOut); | |
491 | ||
492 | break; | |
493 | } | |
494 | case kSecPaddingOAEP: | |
495 | result = errSecParam; | |
496 | default: | |
497 | goto errOut; | |
498 | } | |
499 | ||
500 | // Return the rest. | |
501 | require_action((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut, result = errSecParam); | |
502 | ||
503 | *plainTextLen = sEnd - sBytes; | |
504 | memcpy(plainText, sBytes, *plainTextLen); | |
505 | ||
506 | result = errSecSuccess; | |
507 | ||
508 | errOut: | |
509 | ccn_zero(ccrsa_ctx_n(pubkey), s); | |
510 | ||
511 | return result; | |
512 | } | |
513 | ||
514 | static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { | |
515 | ccrsa_pub_ctx_t pubkey; | |
516 | pubkey.pub = key->key; | |
517 | ||
518 | return ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
519 | } | |
520 | ||
521 | ||
522 | static CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ctx_t pubkey) | |
523 | { | |
524 | size_t m_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
525 | size_t e_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); | |
526 | ||
527 | const size_t seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + | |
528 | DERLengthOfItem(ASN1_INTEGER, e_size); | |
529 | ||
530 | const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); | |
531 | ||
532 | CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); | |
533 | ||
534 | if (pkcs1 == NULL) | |
535 | return NULL; | |
536 | ||
537 | CFDataSetLength(pkcs1, result_size); | |
538 | ||
539 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); | |
540 | ||
541 | *bytes++ = ASN1_CONSTR_SEQUENCE; | |
542 | ||
543 | DERSize itemLength = 4; | |
544 | DEREncodeLength(seq_size, bytes, &itemLength); | |
545 | bytes += itemLength; | |
546 | ||
547 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, &bytes); | |
548 | ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, &bytes); | |
549 | ||
550 | return pkcs1; | |
551 | } | |
552 | ||
553 | static OSStatus SecRSAPublicKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
554 | { | |
555 | ccrsa_pub_ctx_t pubkey; | |
556 | pubkey.pub = key->key; | |
557 | ||
558 | CFAllocatorRef allocator = CFGetAllocator(key); | |
559 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, pubkey); | |
560 | ||
561 | if (NULL == *serialized) | |
562 | return errSecDecode; | |
563 | else | |
564 | return errSecSuccess; | |
565 | } | |
566 | ||
567 | static CFDictionaryRef SecRSAPublicKeyCopyAttributeDictionary(SecKeyRef key) { | |
568 | return SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeRSA); | |
569 | } | |
570 | ||
571 | SecKeyDescriptor kSecRSAPublicKeyDescriptor = { | |
572 | kSecKeyDescriptorVersion, | |
573 | "RSAPublicKey", | |
574 | ccrsa_pub_ctx_size(kMaximumRSAKeyBytes), /* extraBytes */ | |
575 | SecRSAPublicKeyInit, | |
576 | SecRSAPublicKeyDestroy, | |
577 | NULL, /* SecKeyRawSignMethod */ | |
578 | SecRSAPublicKeyRawVerify, | |
579 | SecRSAPublicKeyRawEncrypt, | |
580 | SecRSAPublicKeyRawDecrypt, | |
581 | NULL, /* SecKeyComputeMethod */ | |
582 | SecRSAPublicKeyBlockSize, | |
583 | SecRSAPublicKeyCopyAttributeDictionary, | |
584 | NULL, | |
585 | SecRSAPublicKeyCopyPublicSerialization, | |
586 | }; | |
587 | ||
588 | /* Public Key API functions. */ | |
589 | SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, | |
590 | const uint8_t *keyData, CFIndex keyDataLength, | |
591 | SecKeyEncoding encoding) { | |
592 | return SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, keyData, | |
593 | keyDataLength, encoding); | |
594 | } | |
595 | ||
596 | CFDataRef SecKeyCopyModulus(SecKeyRef key) { | |
597 | ccrsa_pub_ctx_t pubkey; | |
598 | pubkey.pub = key->key; | |
599 | ||
600 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); | |
601 | ||
602 | CFAllocatorRef allocator = CFGetAllocator(key); | |
603 | CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); | |
604 | ||
605 | if (modulusData == NULL) | |
606 | return NULL; | |
607 | ||
608 | CFDataSetLength(modulusData, m_size); | |
609 | ||
610 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); | |
611 | ||
612 | return modulusData; | |
613 | } | |
614 | ||
615 | CFDataRef SecKeyCopyExponent(SecKeyRef key) { | |
616 | ccrsa_pub_ctx_t pubkey; | |
617 | pubkey.pub = key->key; | |
618 | ||
619 | size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); | |
620 | ||
621 | CFAllocatorRef allocator = CFGetAllocator(key); | |
622 | CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); | |
623 | ||
624 | if (exponentData == NULL) | |
625 | return NULL; | |
626 | ||
627 | CFDataSetLength(exponentData, e_size); | |
628 | ||
629 | ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); | |
630 | ||
631 | return exponentData; | |
632 | } | |
633 | ||
634 | ||
635 | /* | |
636 | * | |
637 | * Private Key | |
638 | * | |
639 | */ | |
640 | ||
641 | /* Private key static functions. */ | |
642 | static void SecRSAPrivateKeyDestroy(SecKeyRef key) { | |
643 | /* Zero out the public key */ | |
644 | ccrsa_full_ctx_t fullkey; | |
645 | fullkey.full = key->key; | |
646 | cc_zero(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); | |
647 | } | |
648 | ||
649 | static int ccrsa_priv_init(ccrsa_priv_ctx_t privkey, | |
650 | size_t p_size, const uint8_t* p, | |
651 | size_t q_size, const uint8_t* q, | |
652 | size_t dp_size, const uint8_t* dp, | |
653 | size_t dq_size, const uint8_t* dq, | |
654 | size_t qinv_size, const uint8_t* qinv) | |
655 | { | |
656 | int result = -1; | |
657 | ||
658 | const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); | |
659 | cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); | |
660 | ||
661 | if (ccn_read_uint(np, CCZP_PRIME(ccrsa_ctx_private_zp(privkey)), p_size, p)) | |
662 | goto errOut; | |
663 | cczp_init(ccrsa_ctx_private_zp(privkey)); | |
664 | if (ccn_read_uint(np, ccrsa_ctx_private_dp(privkey), dp_size, dp)) | |
665 | goto errOut; | |
666 | if (ccn_read_uint(np, ccrsa_ctx_private_qinv(privkey), qinv_size, qinv)) | |
667 | goto errOut; | |
668 | ||
669 | if (ccn_read_uint(nq, CCZP_PRIME(ccrsa_ctx_private_zq(privkey)), q_size, q)) | |
670 | goto errOut; | |
671 | ||
672 | nq = ccn_n(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); | |
673 | CCZP_N(ccrsa_ctx_private_zq(privkey)) = nq; | |
674 | ||
675 | cczp_init(ccrsa_ctx_private_zq(privkey)); | |
676 | if (ccn_read_uint(nq, ccrsa_ctx_private_dq(privkey), dq_size, dq)) | |
677 | goto errOut; | |
678 | ||
679 | result = 0; | |
680 | ||
681 | errOut: | |
682 | return result; | |
683 | } | |
684 | ||
685 | ||
686 | static OSStatus ccrsa_full_decode(ccrsa_full_ctx_t fullkey, size_t pkcs1_size, const uint8_t* pkcs1) | |
687 | { | |
688 | OSStatus result = errSecParam; | |
689 | ||
690 | DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; | |
691 | DERRSAKeyPair decodedKey; | |
692 | ||
693 | require_noerr_action(DERParseSequence(&keyItem, | |
694 | DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs, | |
695 | &decodedKey, sizeof(decodedKey)), | |
696 | errOut, result = errSecDecode); | |
697 | ||
698 | require_noerr(ccrsa_pub_init(fullkey, | |
699 | decodedKey.n.length, decodedKey.n.data, | |
700 | decodedKey.e.length, decodedKey.e.data), | |
701 | errOut); | |
702 | ccn_read_uint(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), | |
703 | decodedKey.d.length, decodedKey.d.data); | |
704 | { | |
705 | ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); | |
706 | CCZP_N(ccrsa_ctx_private_zp(privkey)) = ccn_nof((ccn_bitsof_n(ccrsa_ctx_n(fullkey)) / 2) + 1); | |
707 | CCZP_N(ccrsa_ctx_private_zq(privkey)) = cczp_n(ccrsa_ctx_private_zp(privkey)); | |
708 | ||
709 | // TODO: Actually remember decodedKey.d. | |
710 | ||
711 | require_noerr(ccrsa_priv_init(privkey, | |
712 | decodedKey.p.length, decodedKey.p.data, | |
713 | decodedKey.q.length, decodedKey.q.data, | |
714 | decodedKey.dp.length, decodedKey.dp.data, | |
715 | decodedKey.dq.length, decodedKey.dq.data, | |
716 | decodedKey.qInv.length, decodedKey.qInv.data), | |
717 | errOut); | |
718 | } | |
719 | ||
720 | result = errSecSuccess; | |
721 | ||
722 | errOut: | |
723 | return result; | |
724 | } | |
725 | ||
726 | static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, | |
727 | const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { | |
728 | OSStatus result = errSecParam; | |
729 | ||
730 | ccrsa_full_ctx_t fullkey; | |
731 | fullkey.full = key->key; | |
732 | ||
733 | // Set maximum size for parsers | |
734 | ccrsa_ctx_n(fullkey) = ccn_nof(kMaximumRSAKeyBits); | |
735 | ||
736 | switch (encoding) { | |
737 | case kSecKeyEncodingBytes: // Octets is PKCS1 | |
738 | case kSecKeyEncodingPkcs1: | |
739 | result = ccrsa_full_decode(fullkey, keyDataLength, keyData); | |
740 | break; | |
741 | case kSecGenerateKey: | |
742 | { | |
743 | CFDictionaryRef parameters = (CFDictionaryRef) keyData; | |
744 | ||
745 | CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); | |
746 | CFIndex keyLengthInBits = getIntValue(ksize); | |
747 | ||
748 | if (keyLengthInBits < 256 || keyLengthInBits > kMaximumRSAKeyBits) { | |
749 | secwarning("Invalid or missing key size in: %@", parameters); | |
750 | return errSecKeySizeNotAllowed; | |
751 | } | |
752 | ||
753 | /* TODO: Add support for kSecPublicExponent parameter. */ | |
754 | static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 | |
755 | if (!ccrsa_generate_key(keyLengthInBits, fullkey.full, sizeof(e), e, ccrng_seckey)) | |
756 | result = errSecSuccess; | |
757 | break; | |
758 | } | |
759 | default: | |
760 | break; | |
761 | } | |
762 | ||
763 | return result; | |
764 | } | |
765 | ||
766 | static OSStatus SecRSAPrivateKeyRawSign(SecKeyRef key, SecPadding padding, | |
767 | const uint8_t *dataToSign, size_t dataToSignLen, | |
768 | uint8_t *sig, size_t *sigLen) { | |
769 | ||
770 | OSStatus result = errSecParam; | |
771 | ||
772 | ccrsa_full_ctx_t fullkey; | |
773 | fullkey.full = key->key; | |
774 | ||
775 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); | |
776 | cc_unit s[ccrsa_ctx_n(fullkey)]; | |
777 | ||
778 | uint8_t* sBytes = (uint8_t*) s; | |
779 | ||
780 | require(sigLen, errOut); | |
781 | require(*sigLen >= m_size, errOut); | |
782 | ||
783 | switch (padding) { | |
784 | case kSecPaddingNone: | |
785 | require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(fullkey), s, dataToSignLen, dataToSign), errOut); | |
786 | require_quiet(ccn_cmp(ccrsa_ctx_n(fullkey), s, ccrsa_ctx_m(fullkey)) < 0, errOut); | |
787 | break; | |
788 | ||
789 | case kSecPaddingPKCS1: | |
790 | { | |
791 | // Create PKCS1 padding: | |
792 | // | |
793 | // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData | |
794 | // | |
795 | const int kMinimumPadding = 1 + 1 + 8 + 1; | |
796 | ||
797 | require(dataToSignLen < m_size - kMinimumPadding, errOut); | |
798 | ||
799 | size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; | |
800 | ||
801 | while (prefix_zeros--) | |
802 | *sBytes++ = 0x00; | |
803 | ||
804 | size_t pad_size = m_size - dataToSignLen; | |
805 | ||
806 | *sBytes++ = 0x00; | |
807 | *sBytes++ = RSA_PKCS1_PAD_SIGN; | |
808 | ||
809 | size_t ff_size; | |
810 | for(ff_size = pad_size - 3; ff_size > 0; --ff_size) | |
811 | *sBytes++ = 0xFF; | |
812 | ||
813 | *sBytes++ = 0x00; | |
814 | ||
815 | // Get the user data into s looking like a ccn. | |
816 | memcpy(sBytes, dataToSign, dataToSignLen); | |
817 | ccn_swap(ccrsa_ctx_n(fullkey), s); | |
818 | ||
819 | break; | |
820 | } | |
821 | case kSecPaddingOAEP: | |
822 | result = errSecParam; | |
823 | default: | |
824 | goto errOut; | |
825 | } | |
826 | ||
827 | ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); | |
828 | ||
829 | // Pad with leading zeros to fit in modulus size | |
830 | ccn_write_uint_padded(ccrsa_ctx_n(fullkey), s, m_size, sig); | |
831 | *sigLen = m_size; | |
832 | ||
833 | result = errSecSuccess; | |
834 | ||
835 | errOut: | |
836 | ccn_zero(ccrsa_ctx_n(fullkey), s); | |
837 | return result; | |
838 | } | |
839 | ||
840 | static OSStatus SecRSAPrivateKeyRawDecrypt(SecKeyRef key, SecPadding padding, | |
841 | const uint8_t *cipherText, size_t cipherTextLen, | |
842 | uint8_t *plainText, size_t *plainTextLen) { | |
843 | OSStatus result = errSSLCrypto; | |
844 | ||
845 | ccrsa_full_ctx_t fullkey; | |
846 | fullkey.full = key->key; | |
847 | ||
848 | size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); | |
849 | ||
850 | cc_unit s[ccrsa_ctx_n(fullkey)]; | |
851 | uint8_t recoveredData[ccn_sizeof_n(ccrsa_ctx_n(fullkey))]; | |
852 | ||
853 | ccn_read_uint(ccrsa_ctx_n(fullkey), s, cipherTextLen, cipherText); | |
854 | ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); | |
855 | ||
856 | const uint8_t* sBytes = (uint8_t*) s; | |
857 | const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(fullkey)); | |
858 | ||
859 | require(plainTextLen, errOut); | |
860 | ||
861 | switch (padding) { | |
862 | case kSecPaddingNone: | |
863 | ccn_swap(ccrsa_ctx_n(fullkey), s); | |
864 | // Skip Zeros since our contract is to do so. | |
865 | while (sBytes < sEnd && *sBytes == 0x00) | |
866 | ++sBytes; | |
867 | break; | |
868 | ||
869 | case kSecPaddingPKCS1: | |
870 | { | |
871 | ccn_swap(ccrsa_ctx_n(fullkey), s); | |
872 | // Verify and skip PKCS1 padding: | |
873 | // | |
874 | // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData | |
875 | // | |
876 | ||
877 | size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; | |
878 | ||
879 | while (prefix_zeros--) | |
880 | require_quiet(*sBytes++ == 0x00, errOut); | |
881 | ||
882 | require_quiet(*sBytes++ == 0x00, errOut); | |
883 | require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); | |
884 | ||
885 | while (*sBytes != 0x00) { | |
886 | require_quiet(++sBytes < sEnd, errOut); | |
887 | } | |
888 | // Required to have at least 8 non-zeros | |
889 | require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); | |
890 | ||
891 | require_quiet(*sBytes == 0x00, errOut); | |
892 | require_quiet(++sBytes < sEnd, errOut); | |
893 | break; | |
894 | } | |
895 | case kSecPaddingOAEP: | |
896 | { | |
897 | size_t length = sizeof(recoveredData); | |
898 | ||
899 | require_noerr_quiet(ccrsa_oaep_decode(ccsha1_di(), | |
900 | ccn_write_uint_size(ccrsa_ctx_n(fullkey),ccrsa_ctx_m(fullkey)), s, | |
901 | &length, recoveredData), errOut); | |
902 | ||
903 | sBytes = recoveredData; | |
904 | sEnd = recoveredData + length; | |
905 | break; | |
906 | } | |
907 | default: | |
908 | goto errOut; | |
909 | } | |
910 | ||
911 | require((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut); | |
912 | *plainTextLen = sEnd - sBytes; | |
913 | memcpy(plainText, sBytes, *plainTextLen); | |
914 | ||
915 | result = errSecSuccess; | |
916 | ||
917 | errOut: | |
918 | bzero(recoveredData, sizeof(recoveredData)); | |
919 | ccn_zero(ccrsa_ctx_n(fullkey), s); | |
920 | ||
921 | return result; | |
922 | } | |
923 | ||
924 | static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { | |
925 | ccrsa_full_ctx_t fullkey; | |
926 | fullkey.full = key->key; | |
927 | ||
928 | return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); | |
929 | } | |
930 | ||
931 | static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey) | |
932 | { | |
933 | ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); | |
934 | ||
935 | const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); | |
936 | const cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); | |
937 | ||
938 | size_t m_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); | |
939 | size_t e_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey)); | |
940 | size_t d_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey)); | |
941 | ||
942 | size_t p_size = ccn_write_int_size(np, cczp_prime(ccrsa_ctx_private_zp(privkey))); | |
943 | size_t q_size = ccn_write_int_size(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); | |
944 | ||
945 | size_t dp_size = ccn_write_int_size(np, ccrsa_ctx_private_dp(privkey)); | |
946 | size_t dq_size = ccn_write_int_size(nq, ccrsa_ctx_private_dq(privkey)); | |
947 | ||
948 | size_t qinv_size = ccn_write_int_size(np, ccrsa_ctx_private_qinv(privkey)); | |
949 | ||
950 | const size_t seq_size = 3 + | |
951 | DERLengthOfItem(ASN1_INTEGER, m_size) + | |
952 | DERLengthOfItem(ASN1_INTEGER, e_size) + | |
953 | DERLengthOfItem(ASN1_INTEGER, d_size) + | |
954 | DERLengthOfItem(ASN1_INTEGER, p_size) + | |
955 | DERLengthOfItem(ASN1_INTEGER, q_size) + | |
956 | DERLengthOfItem(ASN1_INTEGER, dp_size) + | |
957 | DERLengthOfItem(ASN1_INTEGER, dq_size) + | |
958 | DERLengthOfItem(ASN1_INTEGER, qinv_size); | |
959 | ||
960 | const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); | |
961 | ||
962 | CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); | |
963 | ||
964 | if (pkcs1 == NULL) | |
965 | return NULL; | |
966 | ||
967 | CFDataSetLength(pkcs1, result_size); | |
968 | ||
969 | uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); | |
970 | ||
971 | *bytes++ = ASN1_CONSTR_SEQUENCE; | |
972 | ||
973 | DERSize itemLength = 4; | |
974 | DEREncodeLength(seq_size, bytes, &itemLength); | |
975 | bytes += itemLength; | |
976 | ||
977 | *bytes++ = ASN1_INTEGER; | |
978 | *bytes++ = 0x01; | |
979 | *bytes++ = 0x00; | |
980 | ||
981 | ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey), m_size, &bytes); | |
982 | ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey), e_size, &bytes); | |
983 | ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), d_size, &bytes); | |
984 | ||
985 | ccasn_encode_int(np, cczp_prime(ccrsa_ctx_private_zp(privkey)), p_size, &bytes); | |
986 | ccasn_encode_int(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)), q_size, &bytes); | |
987 | ccasn_encode_int(np, ccrsa_ctx_private_dp(privkey), dp_size, &bytes); | |
988 | ccasn_encode_int(nq, ccrsa_ctx_private_dq(privkey), dq_size, &bytes); | |
989 | ccasn_encode_int(np, ccrsa_ctx_private_qinv(privkey), qinv_size, &bytes); | |
990 | ||
991 | return pkcs1; | |
992 | } | |
993 | ||
994 | static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) | |
995 | { | |
996 | ccrsa_full_ctx_t fullkey; | |
997 | fullkey.full = key->key; | |
998 | ||
999 | CFAllocatorRef allocator = CFGetAllocator(key); | |
1000 | return SecRSAPrivateKeyCreatePKCS1(allocator, fullkey); | |
1001 | } | |
1002 | ||
1003 | static OSStatus SecRSAPrivateKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) | |
1004 | { | |
1005 | ccrsa_full_ctx_t fullkey; | |
1006 | fullkey.full = key->key; | |
1007 | ||
1008 | CFAllocatorRef allocator = CFGetAllocator(key); | |
1009 | *serialized = SecRSAPublicKeyCreatePKCS1(allocator, fullkey); | |
1010 | ||
1011 | if (NULL == *serialized) | |
1012 | return errSecDecode; | |
1013 | else | |
1014 | return errSecSuccess; | |
1015 | } | |
1016 | ||
1017 | ||
1018 | static CFDictionaryRef SecRSAPrivateKeyCopyAttributeDictionary(SecKeyRef key) { | |
1019 | CFDictionaryRef dict = NULL; | |
1020 | CFDataRef fullKeyBlob = NULL; | |
1021 | ||
1022 | /* PKCS1 encode the key pair. */ | |
1023 | fullKeyBlob = SecRSAPrivateKeyCopyPKCS1(key); | |
1024 | require(fullKeyBlob, errOut); | |
1025 | ||
1026 | dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeRSA, fullKeyBlob); | |
1027 | ||
1028 | errOut: | |
1029 | CFReleaseSafe(fullKeyBlob); | |
1030 | ||
1031 | return dict; | |
1032 | } | |
1033 | ||
1034 | SecKeyDescriptor kSecRSAPrivateKeyDescriptor = { | |
1035 | kSecKeyDescriptorVersion, | |
1036 | "RSAPrivateKey", | |
1037 | ccrsa_full_ctx_size(kMaximumRSAKeyBytes), /* extraBytes */ | |
1038 | SecRSAPrivateKeyInit, | |
1039 | SecRSAPrivateKeyDestroy, | |
1040 | SecRSAPrivateKeyRawSign, | |
1041 | NULL, /* SecKeyRawVerifyMethod */ | |
1042 | NULL, /* SecKeyEncryptMethod */ | |
1043 | SecRSAPrivateKeyRawDecrypt, | |
1044 | NULL, /* SecKeyComputeMethod */ | |
1045 | SecRSAPrivateKeyBlockSize, | |
1046 | SecRSAPrivateKeyCopyAttributeDictionary, | |
1047 | NULL, | |
1048 | SecRSAPrivateKeyCopyPublicSerialization, | |
1049 | }; | |
1050 | ||
1051 | /* Private Key API functions. */ | |
1052 | SecKeyRef SecKeyCreateRSAPrivateKey(CFAllocatorRef allocator, | |
1053 | const uint8_t *keyData, CFIndex keyDataLength, | |
1054 | SecKeyEncoding encoding) { | |
1055 | return SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, keyData, | |
1056 | keyDataLength, encoding); | |
1057 | } | |
1058 | ||
1059 | ||
1060 | OSStatus SecRSAKeyGeneratePair(CFDictionaryRef parameters, | |
1061 | SecKeyRef *rsaPublicKey, SecKeyRef *rsaPrivateKey) { | |
1062 | OSStatus status = errSecParam; | |
1063 | ||
1064 | CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */ | |
1065 | ||
1066 | SecKeyRef pubKey = NULL; | |
1067 | SecKeyRef privKey = SecKeyCreate(allocator, &kSecRSAPrivateKeyDescriptor, | |
1068 | (const void*) parameters, 0, kSecGenerateKey); | |
1069 | ||
1070 | require(privKey, errOut); | |
1071 | ||
1072 | /* Create SecKeyRef's from the pkcs1 encoded keys. */ | |
1073 | pubKey = SecKeyCreate(allocator, &kSecRSAPublicKeyDescriptor, | |
1074 | privKey->key, 0, kSecExtractPublicFromPrivate); | |
1075 | ||
1076 | require(pubKey, errOut); | |
1077 | ||
1078 | if (rsaPublicKey) { | |
1079 | *rsaPublicKey = pubKey; | |
1080 | pubKey = NULL; | |
1081 | } | |
1082 | if (rsaPrivateKey) { | |
1083 | *rsaPrivateKey = privKey; | |
1084 | privKey = NULL; | |
1085 | } | |
1086 | ||
1087 | status = errSecSuccess; | |
1088 | ||
1089 | errOut: | |
1090 | CFReleaseSafe(pubKey); | |
1091 | CFReleaseSafe(privKey); | |
1092 | ||
1093 | return status; | |
1094 | } |