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