]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecECKey.m
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / sec / Security / SecECKey.m
1 /*
2 * Copyright (c) 2010-2015 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.m - CoreFoundation based ECDSA key object
26 */
27
28 #include "SecECKey.h"
29 #include "SecECKeyPriv.h"
30
31 #import <Foundation/Foundation.h>
32
33 #include <Security/SecKeyInternal.h>
34 #include <Security/SecItem.h>
35 #include <Security/SecBasePriv.h>
36 #include <AssertMacros.h>
37 #include <Security/SecureTransport.h> /* For error codes. */
38 #include <CoreFoundation/CFData.h> /* For error codes. */
39 #include <CoreFoundation/CFNumber.h>
40 #include <Security/SecFramework.h>
41 #include <Security/SecRandom.h>
42 #include <utilities/debugging.h>
43 #include <Security/SecItemPriv.h>
44 #include <Security/SecInternal.h>
45 #include <utilities/SecCFError.h>
46 #include <utilities/SecCFWrappers.h>
47 #include <utilities/array_size.h>
48 #include <corecrypto/ccec.h>
49 #include <corecrypto/ccsha1.h>
50 #include <corecrypto/ccsha2.h>
51 #include <corecrypto/ccrng.h>
52 #include <corecrypto/ccder_decode_eckey.h>
53
54 #define kMaximumECKeySize 521
55
56 static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) {
57 return kSecECDSAAlgorithmID;
58 }
59
60
61 /*
62 *
63 * Public Key
64 *
65 */
66
67 /* Public key static functions. */
68 static void SecECPublicKeyDestroy(SecKeyRef key) {
69 /* Zero out the public key */
70 ccec_pub_ctx_t pubkey = key->key;
71 if (ccec_ctx_cp(pubkey))
72 cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey);
73 }
74
75 static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length)
76 {
77 size_t keysize = ccec_x963_import_pub_size(encoded_length);
78 if(ccec_keysize_is_supported(keysize)) {
79 return ccec_get_cp(keysize);
80 }
81 return NULL;
82 }
83
84 static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length)
85 {
86 size_t keysize = ccec_x963_import_priv_size(encoded_length);
87 if(ccec_keysize_is_supported(keysize)) {
88 return ccec_get_cp(keysize);
89 }
90 return NULL;
91 }
92
93 static ccoid_t ccoid_secp192r1 = CC_EC_OID_SECP192R1;
94 static ccoid_t ccoid_secp256r1 = CC_EC_OID_SECP256R1;
95 static ccoid_t ccoid_secp224r1 = CC_EC_OID_SECP224R1;
96 static ccoid_t ccoid_secp384r1 = CC_EC_OID_SECP384R1;
97 static ccoid_t ccoid_secp521r1 = CC_EC_OID_SECP521R1;
98
99 static ccec_const_cp_t ccec_cp_for_oid(const unsigned char *oid)
100 {
101 if (oid!=NULL) {
102 if (ccoid_equal(oid, ccoid_secp192r1)) {
103 return ccec_cp_192();
104 } else if (ccoid_equal(oid, ccoid_secp256r1)) {
105 return ccec_cp_256();
106 } else if (ccoid_equal(oid, ccoid_secp224r1)) {
107 return ccec_cp_224();
108 } else if (ccoid_equal(oid, ccoid_secp384r1)) {
109 return ccec_cp_384();
110 } else if (ccoid_equal(oid, ccoid_secp521r1)) {
111 return ccec_cp_521();
112 }
113 }
114 return (ccec_const_cp_t){NULL};
115 }
116
117 static OSStatus SecECPublicKeyInit(SecKeyRef key,
118 const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
119 ccec_pub_ctx_t pubkey = key->key;
120 OSStatus err = errSecParam;
121
122 switch (encoding) {
123 case kSecDERKeyEncoding:
124 {
125 const SecDERKey *derKey = (const SecDERKey *)keyData;
126 if (keyDataLength != sizeof(SecDERKey)) {
127 err = errSecDecode;
128 break;
129 }
130
131 ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength);
132 require_action_quiet(cp, errOut, err = errSecDecode);
133
134 /* TODO: Parse and use real params from passed in derKey->algId.params */
135 err = (ccec_import_pub(cp, derKey->keyLength, derKey->key, pubkey)
136 ? errSecDecode : errSecSuccess);
137 break;
138 }
139 case kSecKeyEncodingBytes:
140 {
141 ccec_const_cp_t cp = getCPForPublicSize(keyDataLength);
142 require_action_quiet(cp, errOut, err = errSecDecode);
143 err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey)
144 ? errSecDecode : errSecSuccess);
145 break;
146 }
147 case kSecExtractPublicFromPrivate:
148 {
149 ccec_full_ctx_t fullKey = (ccec_full_ctx_t)keyData;
150
151 cc_size fullKeyN = ccec_ctx_n(fullKey);
152 require_quiet(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut);
153 memcpy(pubkey, fullKey, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN)));
154 err = errSecSuccess;
155 break;
156 }
157 case kSecKeyEncodingApplePkcs1:
158 default:
159 err = errSecParam;
160 break;
161 }
162
163 errOut:
164 return err;
165 }
166
167 static CFTypeRef SecECPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
168 CFArrayRef algorithms, SecKeyOperationMode mode,
169 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
170 if (operation != kSecKeyOperationTypeVerify || !CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
171 // EC public key supports only signature verification with X962 algorithm.
172 return kCFNull;
173 }
174
175 if (mode == kSecKeyOperationModePerform) {
176 bool valid = false;
177 int err = -1;
178 size_t sigLen = CFDataGetLength(in2);
179 uint8_t *sig = (uint8_t *)CFDataGetBytePtr(in2);
180 ccec_pub_ctx_t pubkey = key->key;
181
182 err = ccec_verify(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), sigLen, sig, &valid);
183 if (err != 0) {
184 SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed (ccerr %d)"), err);
185 return NULL;
186 } else if (!valid) {
187 SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed, no match"));
188 return NULL;
189 } else {
190 return kCFBooleanTrue;
191 }
192 } else {
193 // Algorithm is supported.
194 return kCFBooleanTrue;
195 }
196 }
197
198 static size_t SecECPublicKeyBlockSize(SecKeyRef key) {
199 /* Get key size in octets */
200 return ccec_ctx_size(ccec_ctx_pub(key->key));
201 }
202
203 /* Encode the public key and return it in a newly allocated CFDataRef. */
204 static CFDataRef SecECPublicKeyExport(CFAllocatorRef allocator,
205 ccec_pub_ctx_t pubkey) {
206 size_t pub_size = ccec_export_pub_size(pubkey);
207 CFMutableDataRef blob = CFDataCreateMutableWithScratch(allocator, pub_size);
208 ccec_export_pub(pubkey, CFDataGetMutableBytePtr(blob));
209 return blob;
210 }
211
212 static CFDataRef SecECPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
213 ccec_pub_ctx_t pubkey = key->key;
214 return SecECPublicKeyExport(NULL, pubkey);
215 }
216
217 static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
218 {
219 ccec_pub_ctx_t pubkey = key->key;
220
221 CFAllocatorRef allocator = CFGetAllocator(key);
222 *serailziation = SecECPublicKeyExport(allocator, pubkey);
223
224 if (NULL == *serailziation)
225 return errSecDecode;
226 else
227 return errSecSuccess;
228 }
229
230 static CFDictionaryRef SecECPublicKeyCopyAttributeDictionary(SecKeyRef key) {
231 CFDictionaryRef dict = SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeEC);
232 CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
233 CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse);
234 CFAssignRetained(dict, mutableDict);
235 return dict;
236 }
237
238 static const char *
239 getCurveName(SecKeyRef key)
240 {
241 SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
242
243 switch (curveType)
244 {
245 case kSecECCurveSecp256r1:
246 return "kSecECCurveSecp256r1";
247 break;
248 case kSecECCurveSecp384r1:
249 return "kSecECCurveSecp384r1";
250 break;
251 case kSecECCurveSecp521r1:
252 return "kSecECCurveSecp521r1";
253 default:
254 return "kSecECCurveNone";
255 }
256 }
257
258 static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key)
259 {
260 NSMutableString *strings[2];
261 const char* curve = getCurveName(key);
262
263 ccec_pub_ctx_t ecPubkey = key->key;
264 size_t len = ccec_ctx_size(ecPubkey);
265 NSMutableData *buffer = [NSMutableData dataWithLength:len];
266 for (int i = 0; i < 2; ++i) {
267 ccn_write_uint(ccec_ctx_n(ecPubkey), (i == 0) ? ccec_ctx_x(ecPubkey) : ccec_ctx_y(ecPubkey), len, buffer.mutableBytes);
268 strings[i] = [NSMutableString stringWithCapacity:len * 2];
269 for (size_t byteIndex = 0; byteIndex < len; ++byteIndex) {
270 [strings[i] appendFormat:@"%02X", ((const uint8_t *)buffer.bytes)[byteIndex]];
271 }
272 }
273
274 NSString *description = [NSString stringWithFormat:@"<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>",
275 curve, (long)SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version,
276 8 * SecKeyGetBlockSize(key), strings[1], strings[0], key];
277 return CFBridgingRetain(description);
278 }
279
280 static const struct ccec_rfc6637_curve * get_rfc6637_curve(SecKeyRef key)
281 {
282 SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
283
284 if (curveType == kSecECCurveSecp256r1) {
285 return &ccec_rfc6637_dh_curve_p256;
286 } else if (curveType == kSecECCurveSecp521r1) {
287 return &ccec_rfc6637_dh_curve_p521;
288 }
289 return NULL;
290 }
291
292 static CFDataRef SecECKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
293 {
294 ccec_pub_ctx_t pubkey = key->key;
295 int err = errSecUnimplemented;
296 const struct ccec_rfc6637_curve *curve;
297 const struct ccec_rfc6637_wrap *wrap = NULL;
298 uint8_t sym_alg = 0;
299 int32_t flags = 0;
300
301 if (type != kSecKeyWrapPublicKeyPGP) {
302 SecError(errSecUnsupportedOperation, error, CFSTR("unsupported key wrapping algorithm"));
303 return NULL;
304 }
305
306 curve = get_rfc6637_curve(key);
307 if (curve == NULL) {
308 SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
309 return NULL;
310 }
311
312 CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPSymAlg);
313 if (!isNumber(num) || !CFNumberGetValue(num, kCFNumberSInt8Type, &sym_alg)) {
314 SecError(errSecUnsupportedOperation, error, CFSTR("unknown symalg given"));
315 return NULL;
316 }
317
318 CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
319 if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
320 SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
321 return NULL;
322 }
323
324 CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
325 if (wrapAlg == NULL) {
326 SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
327 return NULL;
328 } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
329 wrap = &ccec_rfc6637_wrap_sha256_kek_aes128;
330 } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
331 wrap = &ccec_rfc6637_wrap_sha512_kek_aes256;
332 } else {
333 SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
334 return NULL;
335 }
336
337 num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
338 if (isNumber(num)) {
339 if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
340 SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
341 return NULL;
342 }
343 } else if (num) {
344 SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
345 return NULL;
346 }
347
348 CFIndex unwrappedKey_size = CFDataGetLength(unwrappedKey);
349
350 CFIndex output_size = ccec_rfc6637_wrap_key_size(pubkey, flags, unwrappedKey_size);
351 if (output_size == 0) {
352 SecError(errSecUnsupportedOperation, error, CFSTR("can't wrap that key, can't build size"));
353 return NULL;
354 }
355
356 CFMutableDataRef data = CFDataCreateMutableWithScratch(NULL, output_size);
357 require_quiet(data, errOut);
358
359 err = ccec_rfc6637_wrap_key(pubkey, CFDataGetMutableBytePtr(data), flags,
360 sym_alg, CFDataGetLength(unwrappedKey), CFDataGetBytePtr(unwrappedKey),
361 curve, wrap, CFDataGetBytePtr(fingerprint),
362 ccrng_seckey);
363 if (err) {
364 SecError(errSecUnsupportedOperation, error, CFSTR("Failed to wrap key"));
365 CFReleaseNull(data);
366 }
367
368 errOut:
369 return data;
370 }
371
372 SecKeyDescriptor kSecECPublicKeyDescriptor = {
373 .version = kSecKeyDescriptorVersion,
374 .name = "ECPublicKey",
375 .extraBytes = ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize)),
376 .init = SecECPublicKeyInit,
377 .destroy = SecECPublicKeyDestroy,
378 .blockSize = SecECPublicKeyBlockSize,
379 .copyDictionary = SecECPublicKeyCopyAttributeDictionary,
380 .copyExternalRepresentation = SecECPublicKeyCopyExternalRepresentation,
381 .describe = SecECPublicKeyCopyKeyDescription,
382 .getAlgorithmID = SecECKeyGetAlgorithmID,
383 .copyPublic = SecECPublicKeyCopyPublicOctets,
384 .copyWrapKey = SecECKeyCopyWrapKey,
385 .copyOperationResult = SecECPublicKeyCopyOperationResult,
386 };
387
388 /* Public Key API functions. */
389 SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
390 const uint8_t *keyData, CFIndex keyDataLength,
391 SecKeyEncoding encoding) {
392 return SecKeyCreate(allocator, &kSecECPublicKeyDescriptor, keyData,
393 keyDataLength, encoding);
394 }
395
396
397
398 /*
399 *
400 * Private Key
401 *
402 */
403
404 /* Private key static functions. */
405 static void SecECPrivateKeyDestroy(SecKeyRef key) {
406 /* Zero out the public key */
407 ccec_full_ctx_t fullkey = key->key;
408
409 if (ccec_ctx_cp(fullkey))
410 cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey);
411 }
412
413
414 static OSStatus SecECPrivateKeyInit(SecKeyRef key,
415 const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
416 ccec_full_ctx_t fullkey = key->key;
417 OSStatus err = errSecParam;
418
419 switch (encoding) {
420 case kSecKeyEncodingPkcs1:
421 {
422 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
423 //err = ecc_import(keyData, keyDataLength, fullkey);
424
425 /* DER != PKCS#1, but we'll go along with it */
426 const unsigned char *oid;
427 size_t n;
428 ccec_const_cp_t cp;
429
430 require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength, keyData, (ccoid_t*)&oid, &n), abort);
431 cp = ccec_cp_for_oid(oid);
432 if (cp == NULL) {
433 cp = ccec_curve_for_length_lookup(n * 8 /* bytes -> bits */,
434 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL);
435 }
436 require_action_quiet(cp != NULL, abort, err = errSecDecode);
437 ccec_ctx_init(cp, fullkey);
438
439 require_noerr_quiet(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort);
440 err = errSecSuccess;
441 break;
442 }
443 case kSecKeyEncodingBytes:
444 {
445 ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength);
446 require_quiet(cp != NULL, abort);
447
448 ccec_ctx_init(cp, fullkey);
449 size_t pubSize = ccec_export_pub_size(ccec_ctx_pub(fullkey));
450
451 require_quiet(pubSize < (size_t) keyDataLength, abort);
452 require_noerr_action_quiet(ccec_import_pub(cp, pubSize, keyData, ccec_ctx_pub(fullkey)),
453 abort,
454 err = errSecDecode);
455
456
457 keyData += pubSize;
458 keyDataLength -= pubSize;
459
460 cc_unit *k = ccec_ctx_k(fullkey);
461 require_noerr_action_quiet(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData),
462 abort,
463 err = errSecDecode);
464
465 err = errSecSuccess;
466 break;
467
468 }
469 case kSecGenerateKey:
470 {
471 CFDictionaryRef parameters = (CFDictionaryRef) keyData;
472
473 CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
474 CFIndex keyLengthInBits = getIntValue(ksize);
475
476 ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits);
477
478 if (!cp) {
479 secwarning("Invalid or missing key size in: %@", parameters);
480 return errSecKeySizeNotAllowed;
481 }
482
483 if (!ccec_generate_key_fips(cp, ccrng_seckey, fullkey))
484 err = errSecSuccess;
485 break;
486 }
487
488 default:
489 break;
490 }
491 abort:
492 return err;
493 }
494
495 static CFTypeRef SecECPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
496 CFArrayRef allAlgorithms, SecKeyOperationMode mode,
497 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
498 // Default answer is 'unsupported', unless we find out that we can support it.
499 CFTypeRef result = kCFNull;
500
501 ccec_full_ctx_t fullkey = key->key;
502 switch (operation) {
503 case kSecKeyOperationTypeSign: {
504 if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
505 if (mode == kSecKeyOperationModePerform) {
506 // Perform x962 mode of signature.
507 size_t size = ccec_sign_max_size(ccec_ctx_cp(fullkey));
508 result = CFDataCreateMutableWithScratch(NULL, size);
509 int err = ccec_sign(fullkey, CFDataGetLength(in1), CFDataGetBytePtr(in1),
510 &size, CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
511 require_action_quiet(err == 0, out, (CFReleaseNull(result),
512 SecError(errSecParam, error, CFSTR("%@: X962 signing failed (ccerr %d)"),
513 key, err)));
514 CFDataSetLength((CFMutableDataRef)result, size);
515 } else {
516 // Operation is supported.
517 result = kCFBooleanTrue;
518 }
519 }
520 break;
521 }
522 case kSecKeyOperationTypeKeyExchange:
523 if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) ||
524 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
525 if (mode == kSecKeyOperationModePerform) {
526 int err;
527 ccec_const_cp_t cp = getCPForPublicSize(CFDataGetLength(in1));
528 require_action_quiet(cp != NULL, out,
529 SecError(errSecParam, error, CFSTR("ECpriv sharedsecret: bad public key")));
530 ccec_pub_ctx_decl_cp(cp, pubkey);
531 err = ccec_import_pub(cp, CFDataGetLength(in1), CFDataGetBytePtr(in1), pubkey);
532 require_noerr_action_quiet(err, out, SecError(errSecParam, error,
533 CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err));
534 size_t size = ccec_ccn_size(cp);
535 result = CFDataCreateMutableWithScratch(NULL, size);
536 err = ccecdh_compute_shared_secret(fullkey, pubkey, &size,
537 CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
538 require_noerr_action_quiet(err, out, (CFReleaseNull(result),
539 SecError(errSecDecode, error,
540 CFSTR("ECpriv failed to compute shared secret (err %d)"), err)));
541 CFDataSetLength((CFMutableDataRef)result, size);
542 } else {
543 // Operation is supported.
544 result = kCFBooleanTrue;
545 }
546 }
547 break;
548 default:
549 break;
550 }
551
552 out:
553 return result;
554 }
555
556 static size_t SecECPrivateKeyBlockSize(SecKeyRef key) {
557 ccec_full_ctx_t fullkey = key->key;
558 /* Get key size in octets */
559 return ccec_ctx_size(fullkey);
560 }
561
562 static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
563 {
564 ccec_full_ctx_t fullkey = key->key;
565
566 CFAllocatorRef allocator = CFGetAllocator(key);
567 *serailziation = SecECPublicKeyExport(allocator, ccec_ctx_pub(fullkey));
568
569 if (NULL == *serailziation)
570 return errSecDecode;
571 else
572 return errSecSuccess;
573 }
574
575 static CFDataRef SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
576 ccec_full_ctx_t fullkey = key->key;
577 size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey));
578 size_t key_size = ccec_export_pub_size(ccec_ctx_pub(fullkey)) + prime_size;
579 CFMutableDataRef blob = CFDataCreateMutableWithScratch(NULL, key_size);
580 ccec_export_pub(ccec_ctx_pub(fullkey), CFDataGetMutableBytePtr(blob));
581 UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(ccec_ctx_pub(fullkey));
582 const cc_unit *k = ccec_ctx_k(fullkey);
583 ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest);
584 return blob;
585 }
586
587 static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) {
588 /* Export the full ec key pair. */
589 CFDataRef fullKeyBlob = SecECPrivateKeyCopyExternalRepresentation(key, NULL);
590
591 CFDictionaryRef dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob);
592 CFReleaseSafe(fullKeyBlob);
593 return dict;
594 }
595 static CFStringRef SecECPrivateKeyCopyKeyDescription(SecKeyRef key) {
596
597 const char* curve = getCurveName(key);
598
599 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"), curve, (long)SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key);
600
601 }
602
603 static CFDataRef SecECKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
604 {
605 const struct ccec_rfc6637_curve *curve;
606 const struct ccec_rfc6637_unwrap *unwrap;
607 ccec_full_ctx_t fullkey = key->key;
608 CFMutableDataRef data;
609 int res;
610 uint8_t sym_alg = 0;
611 int32_t flags = 0;
612
613 curve = get_rfc6637_curve(key);
614 if (curve == NULL) {
615 SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
616 return NULL;
617 }
618
619 CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
620 if (wrapAlg == NULL) {
621 SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
622 return NULL;
623 } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
624 unwrap = &ccec_rfc6637_unwrap_sha256_kek_aes128;
625 } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
626 unwrap = &ccec_rfc6637_unwrap_sha512_kek_aes256;
627 } else {
628 SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
629 return NULL;
630 }
631
632 CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
633 if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
634 SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
635 return NULL;
636 }
637
638 CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
639 if (isNumber(num)) {
640 if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
641 SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
642 return NULL;
643 }
644 } else if (num) {
645 SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
646 return NULL;
647 }
648
649 size_t keysize = CFDataGetLength(wrappedKey);
650 data = CFDataCreateMutableWithScratch(NULL, keysize);
651 if (data == NULL)
652 return NULL;
653
654 res = ccec_rfc6637_unwrap_key(fullkey, &keysize, CFDataGetMutableBytePtr(data),
655 flags, &sym_alg, curve, unwrap,
656 CFDataGetBytePtr(fingerprint),
657 CFDataGetLength(wrappedKey), CFDataGetBytePtr(wrappedKey));
658 if (res != 0) {
659 CFReleaseNull(data);
660 SecError(errSecUnsupportedOperation, error, CFSTR("failed to wrap key"));
661 return NULL;
662 }
663 assert(keysize <= (size_t)CFDataGetLength(data));
664 CFDataSetLength(data, keysize);
665
666 if (outParam) {
667 CFMutableDictionaryRef out = CFDictionaryCreateMutableForCFTypes(NULL);
668 if (out) {
669 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &sym_alg);
670 if (num) {
671 CFDictionarySetValue(out, _kSecKeyWrapPGPSymAlg, num);
672 CFRelease(num);
673 }
674 *outParam = out;
675 }
676 }
677
678 return data;
679 }
680
681 SecKeyDescriptor kSecECPrivateKeyDescriptor = {
682 .version = kSecKeyDescriptorVersion,
683 .name = "ECPrivateKey",
684 .extraBytes = ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize)),
685
686 .init = SecECPrivateKeyInit,
687 .destroy = SecECPrivateKeyDestroy,
688 .blockSize = SecECPrivateKeyBlockSize,
689 .copyDictionary = SecECPrivateKeyCopyAttributeDictionary,
690 .describe = SecECPrivateKeyCopyKeyDescription,
691 .getAlgorithmID = SecECKeyGetAlgorithmID,
692 .copyPublic = SecECPrivateKeyCopyPublicOctets,
693 .copyExternalRepresentation = SecECPrivateKeyCopyExternalRepresentation,
694 .copyWrapKey = SecECKeyCopyWrapKey,
695 .copyUnwrapKey = SecECKeyCopyUnwrapKey,
696 .copyOperationResult = SecECPrivateKeyCopyOperationResult,
697 };
698
699 /* Private Key API functions. */
700 SecKeyRef SecKeyCreateECPrivateKey(CFAllocatorRef allocator,
701 const uint8_t *keyData, CFIndex keyDataLength,
702 SecKeyEncoding encoding) {
703 return SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor, keyData,
704 keyDataLength, encoding);
705 }
706
707
708 OSStatus SecECKeyGeneratePair(CFDictionaryRef parameters,
709 SecKeyRef *publicKey, SecKeyRef *privateKey) {
710 OSStatus status = errSecParam;
711
712 CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */
713 SecKeyRef pubKey = NULL;
714
715 SecKeyRef privKey = SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor,
716 (const void*) parameters, 0, kSecGenerateKey);
717
718 require_quiet(privKey, errOut);
719
720 /* Create SecKeyRef's from the pkcs1 encoded keys. */
721 pubKey = SecKeyCreate(allocator, &kSecECPublicKeyDescriptor,
722 privKey->key, 0, kSecExtractPublicFromPrivate);
723
724 require_quiet(pubKey, errOut);
725
726 if (publicKey) {
727 *publicKey = pubKey;
728 pubKey = NULL;
729 }
730 if (privateKey) {
731 *privateKey = privKey;
732 privKey = NULL;
733 }
734
735 status = errSecSuccess;
736
737 errOut:
738 CFReleaseSafe(pubKey);
739 CFReleaseSafe(privKey);
740
741 return status;
742 }
743
744
745 /* It's debatable whether this belongs here or in the ssl code since the
746 curve values come from a tls related rfc4492. */
747 SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) {
748 SecECNamedCurve result = kSecECCurveNone;
749 CFDictionaryRef attributes = NULL;
750 require_quiet(SecKeyGetAlgorithmId(key) == kSecECDSAAlgorithmID, out);
751 require_quiet(attributes = SecKeyCopyAttributes(key), out);
752 CFTypeRef bitsRef = CFDictionaryGetValue(attributes, kSecAttrKeySizeInBits);
753 CFIndex bits = 0;
754 require_quiet(bitsRef != NULL && CFGetTypeID(bitsRef) == CFNumberGetTypeID() &&
755 CFNumberGetValue(bitsRef, kCFNumberCFIndexType, &bits), out);
756 switch (bits) {
757 #if 0
758 case 192:
759 result = kSecECCurveSecp192r1;
760 break;
761 case 224:
762 result = kSecECCurveSecp224r1;
763 break;
764 #endif
765 case 256:
766 result = kSecECCurveSecp256r1;
767 break;
768 case 384:
769 result = kSecECCurveSecp384r1;
770 break;
771 case 521:
772 result = kSecECCurveSecp521r1;
773 break;
774 }
775
776 out:
777 CFReleaseSafe(attributes);
778 return result;
779 }
780
781 CFDataRef SecECKeyCopyPublicBits(SecKeyRef key) {
782 CFDataRef bytes = NULL;
783 SecKeyCopyPublicBytes(key, &bytes);
784 return bytes;
785 }
786
787 /* Vile accessors that get us the pub or priv key to use temporarily */
788
789 bool SecECDoWithFullKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_full_ctx_t private)) {
790 if (key->key_class == &kSecECPrivateKeyDescriptor) {
791 action(key->key);
792 } else {
793 return SecError(errSecParam, error, CFSTR("Not an EC Full Key object, sorry can't do."));
794 }
795
796 return true;
797 }
798
799 bool SecECDoWithPubKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_pub_ctx_t public)) {
800 if (key->key_class == &kSecECPublicKeyDescriptor) {
801 action(key->key);
802 } else {
803 return SecError(errSecParam, error, CFSTR("Not an EC Public Key object, sorry can't do."));
804 }
805
806 return true;
807 }
808