]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecECKey.c
Security-55163.44.tar.gz
[apple/security.git] / sec / Security / SecECKey.c
1 /*
2 * Copyright (c) 2010,2011 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 * SecECKey.c - CoreFoundation based rsa key object
26 */
27
28 #include "SecECKey.h"
29
30 #include <Security/SecKeyInternal.h>
31 #include <Security/SecItem.h>
32 #include <Security/SecBasePriv.h>
33 #include <AssertMacros.h>
34 #include <Security/SecureTransport.h> /* For error codes. */
35 #include <CoreFoundation/CFData.h> /* For error codes. */
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <CoreFoundation/CFNumber.h>
40 #include <Security/SecFramework.h>
41 #include <Security/SecRandom.h>
42 #include <security_utilities/debugging.h>
43 #include "SecItemPriv.h"
44 #include <Security/SecInternal.h>
45 #include <corecrypto/ccec.h>
46 #include <corecrypto/ccsha1.h>
47 #include <corecrypto/ccsha2.h>
48 #include <corecrypto/ccrng.h>
49
50 #define kMaximumECKeySize 521
51
52 static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) {
53 return kSecECDSAAlgorithmID;
54 }
55
56
57
58 /*
59 *
60 * Public Key
61 *
62 */
63
64 /* Public key static functions. */
65 static void SecECPublicKeyDestroy(SecKeyRef key) {
66 /* Zero out the public key */
67 ccec_pub_ctx_t pubkey;
68 pubkey.pub = key->key;
69 if (ccec_ctx_cp(pubkey).zp)
70 cc_zero(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey.pub);
71 }
72
73 static ccec_const_cp_t getCPForBits(size_t bits)
74 {
75 switch (bits) {
76 case 192:
77 return ccec_cp_192();
78 case 224:
79 return ccec_cp_224();
80 case 256:
81 return ccec_cp_256();
82 case 384:
83 return ccec_cp_384();
84 case 521:
85 return ccec_cp_521();
86 default:
87 {
88 ccec_const_cp_t nullCP = { .zp = NULL };
89 return nullCP;
90 }
91 }
92 }
93 static ccec_const_cp_t getCPForPublicSize(CFIndex publicLength)
94 {
95 ccec_const_cp_t cp;
96 switch (publicLength) {
97 case 49:
98 cp = ccec_cp_192();
99 break;
100 case 57:
101 cp = ccec_cp_224();
102 break;
103 case 65:
104 cp = ccec_cp_256();
105 break;
106 case 97:
107 cp = ccec_cp_384();
108 break;
109 case 133:
110 cp = ccec_cp_521();
111 break;
112 default:
113 {
114 ccec_const_cp_t nullCP = { .zp = NULL };
115 return nullCP;
116 }
117 }
118 return cp;
119 }
120
121 static ccec_const_cp_t getCPForPrivateSize(CFIndex publicLength)
122 {
123 ccec_const_cp_t cp;
124 switch (publicLength) {
125 case 49 + 24:
126 cp = ccec_cp_192();
127 break;
128 case 57 + 28:
129 cp = ccec_cp_224();
130 break;
131 case 65 + 32:
132 cp = ccec_cp_256();
133 break;
134 case 97 + 48:
135 cp = ccec_cp_384();
136 break;
137 case 133 + 66:
138 cp = ccec_cp_521();
139 break;
140 default:
141 {
142 ccec_const_cp_t nullCP = { .zp = NULL };
143 return nullCP;
144 }
145 }
146 return cp;
147 }
148
149 static OSStatus SecECPublicKeyInit(SecKeyRef key,
150 const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
151 ccec_pub_ctx_t pubkey;
152 pubkey.pub = key->key;
153 OSStatus err = errSecParam;
154
155 switch (encoding) {
156 case kSecDERKeyEncoding:
157 {
158 const SecDERKey *derKey = (const SecDERKey *)keyData;
159 if (keyDataLength != sizeof(SecDERKey)) {
160 err = errSecDecode;
161 break;
162 }
163
164 ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength);
165
166 /* TODO: Parse and use real params from passed in derKey->algId.params */
167 err = (ccec_import_pub(cp, derKey->keyLength, derKey->key, pubkey)
168 ? errSecDecode : errSecSuccess);
169 break;
170 }
171 case kSecKeyEncodingBytes:
172 {
173 ccec_const_cp_t cp = getCPForPublicSize(keyDataLength);
174 err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey)
175 ? errSecDecode : errSecSuccess);
176 break;
177 }
178 case kSecExtractPublicFromPrivate:
179 {
180 ccec_full_ctx_t fullKey;
181 fullKey._full = (ccec_full_ctx *) keyData;
182
183 cc_size fullKeyN = ccec_ctx_n(fullKey);
184 require(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut);
185 memcpy(pubkey._pub, fullKey.pub, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN)));
186 err = errSecSuccess;
187 break;
188 }
189 case kSecKeyEncodingApplePkcs1:
190 default:
191 err = errSecParam;
192 break;
193 }
194
195 errOut:
196 return err;
197 }
198
199 static OSStatus SecECPublicKeyRawVerify(SecKeyRef key, SecPadding padding,
200 const uint8_t *signedData, size_t signedDataLen,
201 const uint8_t *sig, size_t sigLen) {
202 int err = errSSLCrypto; // TODO: Should be errSecNotSigner;
203 ccec_pub_ctx_t pubkey;
204 pubkey.pub = key->key;
205 bool valid = 0;
206
207 if (ccec_verify(pubkey, signedDataLen, signedData, sigLen, sig, &valid))
208 err = errSSLCrypto; // TODO: This seems weird. Shouldn't be SSL error
209 if (valid)
210 err = errSecSuccess;
211
212 return err;
213 }
214
215 static OSStatus SecECPublicKeyRawEncrypt(SecKeyRef key, SecPadding padding,
216 const uint8_t *plainText, size_t plainTextLen,
217 uint8_t *cipherText, size_t *cipherTextLen) {
218 ccec_pub_ctx_t pubkey;
219 pubkey.pub = key->key;
220 int err = errSecUnimplemented;
221
222 #if 0
223 require_noerr(err = ccec_wrap_key(pubkey, &ccsha256_di,
224 plainTextLen, plainText, cipherText), errOut);
225
226 errOut:
227 #endif
228 return err;
229 }
230
231 static size_t SecECPublicKeyBlockSize(SecKeyRef key) {
232 /* Get key size in octets */
233 ccec_pub_ctx_t pubkey;
234 pubkey.pub = key->key;
235 return ccec_ccn_size(ccec_ctx_cp(pubkey));
236 }
237
238 /* Encode the public key and return it in a newly allocated CFDataRef. */
239 static CFDataRef SecECPublicKeyExport(CFAllocatorRef allocator,
240 ccec_pub_ctx_t pubkey) {
241 size_t pub_size = ccec_export_pub_size(pubkey);
242 CFMutableDataRef blob = CFDataCreateMutable(allocator, pub_size);
243 if (blob) {
244 CFDataSetLength(blob, pub_size);
245 ccec_export_pub(pubkey, CFDataGetMutableBytePtr(blob));
246 }
247
248 return blob;
249 }
250
251 static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
252 {
253 ccec_pub_ctx_t pubkey;
254 pubkey.pub = key->key;
255
256 CFAllocatorRef allocator = CFGetAllocator(key);
257 *serailziation = SecECPublicKeyExport(allocator, pubkey);
258
259 if (NULL == *serailziation)
260 return errSecDecode;
261 else
262 return errSecSuccess;
263 }
264
265 static CFDictionaryRef SecECPublicKeyCopyAttributeDictionary(SecKeyRef key) {
266 return SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeEC);
267 }
268
269 SecKeyDescriptor kSecECPublicKeyDescriptor = {
270 kSecKeyDescriptorVersion,
271 "ECPublicKey",
272 ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize)), /* extraBytes */
273 SecECPublicKeyInit,
274 SecECPublicKeyDestroy,
275 NULL, /* SecKeyRawSignMethod */
276 SecECPublicKeyRawVerify,
277 SecECPublicKeyRawEncrypt,
278 NULL, /* SecKeyDecryptMethod */
279 NULL, /* SecKeyComputeMethod */
280 SecECPublicKeyBlockSize,
281 SecECPublicKeyCopyAttributeDictionary,
282 SecECKeyGetAlgorithmID,
283 SecECPublicKeyCopyPublicOctets,
284 };
285
286 /* Public Key API functions. */
287 SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
288 const uint8_t *keyData, CFIndex keyDataLength,
289 SecKeyEncoding encoding) {
290 return SecKeyCreate(allocator, &kSecECPublicKeyDescriptor, keyData,
291 keyDataLength, encoding);
292 }
293
294
295
296 /*
297 *
298 * Private Key
299 *
300 */
301
302 /* Private key static functions. */
303 static void SecECPrivateKeyDestroy(SecKeyRef key) {
304 /* Zero out the public key */
305 ccec_full_ctx_t fullkey;
306 fullkey.hdr = key->key;
307 if (ccec_ctx_cp(fullkey).zp)
308 cc_zero(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey.hdr);
309 }
310
311
312 static OSStatus SecECPrivateKeyInit(SecKeyRef key,
313 const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
314 ccec_full_ctx_t fullkey;
315 fullkey.hdr = key->key;
316 OSStatus err = errSecParam;
317
318 switch (encoding) {
319 case kSecKeyEncodingPkcs1:
320 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
321 //err = ecc_import(keyData, keyDataLength, fullkey);
322 break;
323 case kSecKeyEncodingBytes:
324 {
325 ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength);
326 require(cp.zp != NULL, abort);
327
328 ccec_ctx_init(cp, fullkey);
329 size_t pubSize = ccec_export_pub_size(fullkey);
330
331 require(pubSize < (size_t) keyDataLength, abort);
332 require_noerr_action(ccec_import_pub(cp, pubSize, keyData, fullkey),
333 abort,
334 err = errSecDecode);
335
336
337 keyData += pubSize;
338 keyDataLength -= pubSize;
339
340 cc_unit *k = ccec_ctx_k(fullkey);
341 require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData),
342 abort,
343 err = errSecDecode);
344
345 err = errSecSuccess;
346 break;
347
348 }
349 case kSecGenerateKey:
350 {
351 CFDictionaryRef parameters = (CFDictionaryRef) keyData;
352
353 CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
354 CFIndex keyLengthInBits = getIntValue(ksize);
355
356 ccec_const_cp_t cp = getCPForBits(keyLengthInBits);
357
358 if (!cp.zp) {
359 secwarning("Invalid or missing key size in: %@", parameters);
360 return errSecKeySizeNotAllowed;
361 }
362
363 if (!ccec_generate_key(cp, ccrng_seckey, fullkey))
364 err = errSecSuccess;
365 break;
366 }
367
368 default:
369 break;
370 }
371 abort:
372 return err;
373 }
374
375 static OSStatus SecECPrivateKeyRawSign(SecKeyRef key, SecPadding padding,
376 const uint8_t *dataToSign, size_t dataToSignLen,
377 uint8_t *sig, size_t *sigLen) {
378 ccec_full_ctx_t fullkey;
379 fullkey.hdr = key->key;
380 int err;;
381 check(sigLen);
382
383 require_noerr(err = ccec_sign(fullkey, dataToSignLen, dataToSign,
384 sigLen, sig, ccrng_seckey), errOut);
385 errOut:
386
387 return err;
388 }
389
390 #if 0
391 static const struct ccdigest_info *
392 ccdigest_lookup_by_oid(unsigned long oid_size, const void *oid) {
393 static const struct ccdigest_info *dis[] = {
394 &ccsha1_di,
395 &ccsha224_di,
396 &ccsha256_di,
397 &ccsha384_di,
398 &ccsha512_di
399 };
400 size_t i;
401 for (i = 0; i < sizeof(dis) / sizeof(*dis); ++i) {
402 if (oid_size == dis[i]->oid_size && !memcmp(dis[i]->oid, oid, oid_size))
403 return dis[i];
404 }
405 return NULL;
406 }
407 #endif
408
409 static OSStatus SecECPrivateKeyRawDecrypt(SecKeyRef key, SecPadding padding,
410 const uint8_t *cipherText, size_t cipherTextLen,
411 uint8_t *plainText, size_t *plainTextLen) {
412 ccec_full_ctx_t fullkey;
413 fullkey.hdr = key->key;
414 int err = errSecUnimplemented;
415
416 #if 0
417 err = ccec_unwrap_key(fullkey, ccrng_seckey, ccdigest_lookup_by_oid,
418 cipherTextLen, cipherText, plainTextLen, plainText);
419 #endif
420
421 return err;
422 }
423
424 static size_t SecECPrivateKeyBlockSize(SecKeyRef key) {
425 ccec_full_ctx_t fullkey;
426 fullkey.hdr = key->key;
427 /* Get key size in octets */
428 return ccec_ccn_size(ccec_ctx_cp(fullkey));
429 }
430
431 static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
432 {
433 ccec_full_ctx_t fullkey;
434 fullkey.hdr = key->key;
435
436 CFAllocatorRef allocator = CFGetAllocator(key);
437 *serailziation = SecECPublicKeyExport(allocator, fullkey);
438
439 if (NULL == *serailziation)
440 return errSecDecode;
441 else
442 return errSecSuccess;
443 }
444
445 static CFDataRef SecECPPrivateKeyExport(CFAllocatorRef allocator,
446 ccec_full_ctx_t fullkey) {
447 size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey));
448 size_t key_size = ccec_export_pub_size(fullkey) + prime_size;
449 CFMutableDataRef blob = CFDataCreateMutable(allocator, key_size);
450 if (blob) {
451 CFDataSetLength(blob, key_size);
452 ccec_export_pub(fullkey, CFDataGetMutableBytePtr(blob));
453 UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(fullkey);
454 const cc_unit *k = ccec_ctx_k(fullkey);
455 ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest);
456 }
457
458 return blob;
459 }
460
461
462 static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) {
463 CFDictionaryRef dict = NULL;
464 CFAllocatorRef allocator = CFGetAllocator(key);
465
466 ccec_full_ctx_t fullkey;
467 fullkey.hdr = key->key;
468
469 CFDataRef fullKeyBlob = NULL;
470
471 /* Export the full ec key pair. */
472 require(fullKeyBlob = SecECPPrivateKeyExport(allocator, fullkey), errOut);
473
474 dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob);
475
476 errOut:
477 CFReleaseSafe(fullKeyBlob);
478
479 return dict;
480 }
481
482 SecKeyDescriptor kSecECPrivateKeyDescriptor = {
483 kSecKeyDescriptorVersion,
484 "ECPrivateKey",
485 ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize)), /* extraBytes */
486 SecECPrivateKeyInit,
487 SecECPrivateKeyDestroy,
488 SecECPrivateKeyRawSign,
489 NULL, /* SecKeyRawVerifyMethod */
490 NULL, /* SecKeyEncryptMethod */
491 SecECPrivateKeyRawDecrypt,
492 NULL, /* SecKeyComputeMethod */
493 SecECPrivateKeyBlockSize,
494 SecECPrivateKeyCopyAttributeDictionary,
495 SecECKeyGetAlgorithmID,
496 SecECPrivateKeyCopyPublicOctets,
497 };
498
499 /* Private Key API functions. */
500 SecKeyRef SecKeyCreateECPrivateKey(CFAllocatorRef allocator,
501 const uint8_t *keyData, CFIndex keyDataLength,
502 SecKeyEncoding encoding) {
503 return SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor, keyData,
504 keyDataLength, encoding);
505 }
506
507
508 OSStatus SecECKeyGeneratePair(CFDictionaryRef parameters,
509 SecKeyRef *publicKey, SecKeyRef *privateKey) {
510 OSStatus status = errSecParam;
511
512 CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */
513 SecKeyRef pubKey = NULL;
514
515 SecKeyRef privKey = SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor,
516 (const void*) parameters, 0, kSecGenerateKey);
517
518 require(privKey, errOut);
519
520 /* Create SecKeyRef's from the pkcs1 encoded keys. */
521 pubKey = SecKeyCreate(allocator, &kSecECPublicKeyDescriptor,
522 privKey->key, 0, kSecExtractPublicFromPrivate);
523
524 require(pubKey, errOut);
525
526 if (publicKey) {
527 *publicKey = pubKey;
528 pubKey = NULL;
529 }
530 if (privateKey) {
531 *privateKey = privKey;
532 privKey = NULL;
533 }
534
535 status = errSecSuccess;
536
537 errOut:
538 CFReleaseSafe(pubKey);
539 CFReleaseSafe(privKey);
540
541 return status;
542 }
543
544
545 /* It's debatable whether this belongs here or in the ssl code since the
546 curve values come from a tls related rfc4492. */
547 SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) {
548 if (key->key_class != &kSecECPublicKeyDescriptor &&
549 key->key_class != &kSecECPrivateKeyDescriptor)
550 return kSecECCurveNone;
551
552 ccec_pub_ctx_t pubkey;
553 pubkey.pub = key->key;
554 switch (ccec_cp_prime_size(ccec_ctx_cp(pubkey))) {
555 #if 0
556 case 24:
557 return kSecECCurveSecp192r1;
558 case 28:
559 return kSecECCurveSecp224r1;
560 #endif
561 case 32:
562 return kSecECCurveSecp256r1;
563 case 48:
564 return kSecECCurveSecp384r1;
565 case 66:
566 return kSecECCurveSecp521r1;
567 }
568 return kSecECCurveNone;
569 }
570
571 CFDataRef SecECKeyCopyPublicBits(SecKeyRef key) {
572 if (key->key_class != &kSecECPublicKeyDescriptor &&
573 key->key_class != &kSecECPrivateKeyDescriptor)
574 return NULL;
575
576 ccec_pub_ctx_t pubkey;
577 pubkey.pub = key->key;
578 return SecECPublicKeyExport(CFGetAllocator(key), pubkey);
579 }