2 * Copyright (c) 2010-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecECKey.c - CoreFoundation based rsa key object
29 #include "SecECKeyPriv.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. */
38 #include <sys/types.h>
40 #include <CoreFoundation/CFNumber.h>
41 #include <Security/SecFramework.h>
42 #include <Security/SecRandom.h>
43 #include <utilities/debugging.h>
44 #include "SecItemPriv.h"
45 #include <Security/SecInternal.h>
46 #include <utilities/SecCFError.h>
47 #include <utilities/SecCFWrappers.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>
54 #define kMaximumECKeySize 521
56 static CFIndex
SecECKeyGetAlgorithmID(SecKeyRef key
) {
57 return kSecECDSAAlgorithmID
;
67 /* Public key static functions. */
68 static void SecECPublicKeyDestroy(SecKeyRef key
) {
69 /* Zero out the public key */
70 ccec_pub_ctx_t pubkey
;
71 pubkey
.pub
= key
->key
;
72 if (ccec_ctx_cp(pubkey
).zp
)
73 cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey
))), pubkey
.pub
);
76 static ccec_const_cp_t
getCPForPublicSize(CFIndex encoded_length
)
78 size_t keysize
= ccec_x963_import_pub_size(encoded_length
);
79 if(ccec_keysize_is_supported(keysize
)) {
80 return ccec_get_cp(keysize
);
82 ccec_const_cp_t nullCP
= { .zp
= NULL
};
86 static ccec_const_cp_t
getCPForPrivateSize(CFIndex encoded_length
)
88 size_t keysize
= ccec_x963_import_priv_size(encoded_length
);
89 if(ccec_keysize_is_supported(keysize
)) {
90 return ccec_get_cp(keysize
);
92 ccec_const_cp_t nullCP
= { .zp
= NULL
};
96 static ccoid_t ccoid_secp192r1
= CC_EC_OID_SECP192R1
;
97 static ccoid_t ccoid_secp256r1
= CC_EC_OID_SECP256R1
;
98 static ccoid_t ccoid_secp224r1
= CC_EC_OID_SECP224R1
;
99 static ccoid_t ccoid_secp384r1
= CC_EC_OID_SECP384R1
;
100 static ccoid_t ccoid_secp521r1
= CC_EC_OID_SECP521R1
;
102 static ccec_const_cp_t
ccec_cp_for_oid(ccoid_t oid
)
105 if (ccoid_equal(oid
, ccoid_secp192r1
)) {
106 return ccec_cp_192();
107 } else if (ccoid_equal(oid
, ccoid_secp256r1
)) {
108 return ccec_cp_256();
109 } else if (ccoid_equal(oid
, ccoid_secp224r1
)) {
110 return ccec_cp_224();
111 } else if (ccoid_equal(oid
, ccoid_secp384r1
)) {
112 return ccec_cp_384();
113 } else if (ccoid_equal(oid
, ccoid_secp521r1
)) {
114 return ccec_cp_521();
117 return (ccec_const_cp_t
){NULL
};
120 static OSStatus
SecECPublicKeyInit(SecKeyRef key
,
121 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
122 ccec_pub_ctx_t pubkey
;
123 pubkey
.pub
= key
->key
;
124 OSStatus err
= errSecParam
;
127 case kSecDERKeyEncoding
:
129 const SecDERKey
*derKey
= (const SecDERKey
*)keyData
;
130 if (keyDataLength
!= sizeof(SecDERKey
)) {
135 ccec_const_cp_t cp
= getCPForPublicSize(derKey
->keyLength
);
136 require_action(cp
.zp
, errOut
, err
= errSecDecode
);
138 /* TODO: Parse and use real params from passed in derKey->algId.params */
139 err
= (ccec_import_pub(cp
, derKey
->keyLength
, derKey
->key
, pubkey
)
140 ? errSecDecode
: errSecSuccess
);
143 case kSecKeyEncodingBytes
:
145 ccec_const_cp_t cp
= getCPForPublicSize(keyDataLength
);
146 require_action(cp
.zp
, errOut
, err
= errSecDecode
);
147 err
= (ccec_import_pub(cp
, keyDataLength
, keyData
, pubkey
)
148 ? errSecDecode
: errSecSuccess
);
151 case kSecExtractPublicFromPrivate
:
153 ccec_full_ctx_t fullKey
;
154 fullKey
._full
= (ccec_full_ctx
*) keyData
;
156 cc_size fullKeyN
= ccec_ctx_n(fullKey
);
157 require(fullKeyN
<= ccn_nof(kMaximumECKeySize
), errOut
);
158 memcpy(pubkey
._pub
, fullKey
.pub
, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN
)));
162 case kSecKeyEncodingApplePkcs1
:
172 static OSStatus
SecECPublicKeyRawVerify(SecKeyRef key
, SecPadding padding
,
173 const uint8_t *signedData
, size_t signedDataLen
,
174 const uint8_t *sig
, size_t sigLen
) {
175 int err
= errSecInternalComponent
;
176 ccec_pub_ctx_t pubkey
;
177 pubkey
.pub
= key
->key
;
180 // Perform verification
181 if (padding
==kSecPaddingSigRaw
) {
182 require_action_quiet(ccec_signature_r_s_size(pubkey
.fullt
)*2==sigLen
, errOut
, err
= errSecParam
);
183 err
=ccec_verify_composite(pubkey
, signedDataLen
, signedData
, (uint8_t*)sig
, (uint8_t*)sig
+(sigLen
>>1),&valid
);
186 // kSecPaddingSigDERx962 or default
187 err
=ccec_verify(pubkey
, signedDataLen
, signedData
, sigLen
, sig
, &valid
);
191 err
=(!err
&& valid
?errSecSuccess
:errSSLCrypto
); // TODO: Should be errSecNotSigner;
197 static OSStatus
SecECPublicKeyRawEncrypt(SecKeyRef key
, SecPadding padding
,
198 const uint8_t *plainText
, size_t plainTextLen
,
199 uint8_t *cipherText
, size_t *cipherTextLen
) {
200 ccec_pub_ctx_t pubkey
;
201 pubkey
.pub
= key
->key
;
202 int err
= errSecUnimplemented
;
205 require_noerr(err
= ccec_wrap_key(pubkey
, &ccsha256_di
,
206 plainTextLen
, plainText
, cipherText
), errOut
);
213 static size_t SecECPublicKeyBlockSize(SecKeyRef key
) {
214 /* Get key size in octets */
215 ccec_pub_ctx_t pubkey
;
216 pubkey
.pub
= key
->key
;
217 return ccec_ctx_size(pubkey
);
220 /* Encode the public key and return it in a newly allocated CFDataRef. */
221 static CFDataRef
SecECPublicKeyExport(CFAllocatorRef allocator
,
222 ccec_pub_ctx_t pubkey
) {
223 size_t pub_size
= ccec_export_pub_size(pubkey
);
224 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, pub_size
);
226 CFDataSetLength(blob
, pub_size
);
227 ccec_export_pub(pubkey
, CFDataGetMutableBytePtr(blob
));
233 static OSStatus
SecECPublicKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
235 ccec_pub_ctx_t pubkey
;
236 pubkey
.pub
= key
->key
;
238 CFAllocatorRef allocator
= CFGetAllocator(key
);
239 *serailziation
= SecECPublicKeyExport(allocator
, pubkey
);
241 if (NULL
== *serailziation
)
244 return errSecSuccess
;
247 static CFDictionaryRef
SecECPublicKeyCopyAttributeDictionary(SecKeyRef key
) {
248 return SecKeyGeneratePublicAttributeDictionary(key
, kSecAttrKeyTypeEC
);
252 getCurveName(SecKeyRef key
)
254 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
258 case kSecECCurveSecp256r1
:
259 return "kSecECCurveSecp256r1";
261 case kSecECCurveSecp384r1
:
262 return "kSecECCurveSecp384r1";
264 case kSecECCurveSecp521r1
:
265 return "kSecECCurveSecp521r1";
267 return "kSecECCurveNone";
271 static CFStringRef
SecECPublicKeyCopyKeyDescription(SecKeyRef key
)
273 ccec_pub_ctx_t ecPubkey
;
274 CFStringRef keyDescription
= NULL
;
275 size_t xlen
, ylen
, ix
;
276 CFMutableStringRef xString
= NULL
;
277 CFMutableStringRef yString
= NULL
;
279 ecPubkey
.pub
= key
->key
;
281 const char* curve
= getCurveName(key
);
283 uint8_t *xunit
= (uint8_t*)ccec_ctx_x(ecPubkey
);
284 require_quiet( NULL
!= xunit
, fail
);
285 xlen
= (size_t)strlen((char*)xunit
);
288 xString
= CFStringCreateMutable(kCFAllocatorDefault
, xlen
* 2);
289 require_quiet( NULL
!= xString
, fail
);
291 for (ix
= 0; ix
< xlen
; ++ix
)
293 CFStringAppendFormat(xString
, NULL
, CFSTR("%02X"), xunit
[ix
]);
296 uint8_t *yunit
= (uint8_t*)ccec_ctx_y(ecPubkey
);
297 require_quiet( NULL
!= yunit
, fail
);
298 ylen
= (size_t)strlen((char*)yunit
);
300 yString
= CFStringCreateMutable(kCFAllocatorDefault
, ylen
*2);
301 require_quiet( NULL
!= yString
, fail
);
303 for(ix
= 0; ix
< ylen
; ++ix
)
305 CFStringAppendFormat(yString
, NULL
, CFSTR("%02X"), yunit
[ix
]);
308 keyDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>"), curve
, (long)SecKeyGetAlgorithmId(key
), key
->key_class
->name
, key
->key_class
->version
, (8*SecKeyGetBlockSize(key
)), yString
, xString
, key
);
311 CFReleaseSafe(xString
);
312 CFReleaseSafe(yString
);
314 keyDescription
= 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
);
316 return keyDescription
;
319 static const struct ccec_rfc6637_curve
* get_rfc6637_curve(SecKeyRef key
)
321 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
323 if (curveType
== kSecECCurveSecp256r1
) {
324 return &ccec_rfc6637_dh_curve_p256
;
325 } else if (curveType
== kSecECCurveSecp521r1
) {
326 return &ccec_rfc6637_dh_curve_p521
;
331 static CFDataRef
SecECKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
333 ccec_pub_ctx_t pubkey
;
334 int err
= errSecUnimplemented
;
335 const struct ccec_rfc6637_curve
*curve
;
336 const struct ccec_rfc6637_wrap
*wrap
= NULL
;
340 pubkey
.pub
= key
->key
;
342 if (type
!= kSecKeyWrapPublicKeyPGP
) {
343 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported key wrapping algorithm"));
347 curve
= get_rfc6637_curve(key
);
349 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
353 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPSymAlg
);
354 if (!isNumber(num
) || !CFNumberGetValue(num
, kCFNumberSInt8Type
, &sym_alg
)) {
355 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown symalg given"));
359 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
360 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
361 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
365 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
366 if (wrapAlg
== NULL
) {
367 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
369 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
370 wrap
= &ccec_rfc6637_wrap_sha256_kek_aes128
;
371 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
372 wrap
= &ccec_rfc6637_wrap_sha512_kek_aes256
;
374 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
378 num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
380 if (!CFNumberGetValue(num
, kCFNumberLongType
, &flags
)) {
381 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
385 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
389 CFIndex unwrappedKey_size
= CFDataGetLength(unwrappedKey
);
391 CFIndex output_size
= ccec_rfc6637_wrap_key_size(pubkey
, flags
, unwrappedKey_size
);
392 if (output_size
== 0) {
393 SecError(errSecUnsupportedOperation
, error
, CFSTR("can't wrap that key, can't build size"));
397 CFMutableDataRef data
= CFDataCreateMutableWithScratch(NULL
, output_size
);
398 require(data
, errOut
);
400 err
= ccec_rfc6637_wrap_key(pubkey
, CFDataGetMutableBytePtr(data
), flags
,
401 sym_alg
, CFDataGetLength(unwrappedKey
), CFDataGetBytePtr(unwrappedKey
),
402 curve
, wrap
, CFDataGetBytePtr(fingerprint
),
405 SecError(errSecUnsupportedOperation
, error
, CFSTR("Failed to wrap key"));
414 SecKeyDescriptor kSecECPublicKeyDescriptor
= {
415 kSecKeyDescriptorVersion
,
417 ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
419 SecECPublicKeyDestroy
,
420 NULL
, /* SecKeyRawSignMethod */
421 SecECPublicKeyRawVerify
,
422 SecECPublicKeyRawEncrypt
,
423 NULL
, /* SecKeyDecryptMethod */
424 NULL
, /* SecKeyComputeMethod */
425 SecECPublicKeyBlockSize
,
426 SecECPublicKeyCopyAttributeDictionary
,
427 SecECPublicKeyCopyKeyDescription
,
428 SecECKeyGetAlgorithmID
,
429 SecECPublicKeyCopyPublicOctets
,
431 NULL
, /* SecKeyCopyUnwrapKey */
434 /* Public Key API functions. */
435 SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
436 const uint8_t *keyData
, CFIndex keyDataLength
,
437 SecKeyEncoding encoding
) {
438 return SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
, keyData
,
439 keyDataLength
, encoding
);
450 /* Private key static functions. */
451 static void SecECPrivateKeyDestroy(SecKeyRef key
) {
452 /* Zero out the public key */
453 ccec_full_ctx_t fullkey
;
454 fullkey
.hdr
= key
->key
;
455 if (ccec_ctx_cp(fullkey
).zp
)
456 cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey
))), fullkey
.hdr
);
460 static OSStatus
SecECPrivateKeyInit(SecKeyRef key
,
461 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
462 ccec_full_ctx_t fullkey
;
463 fullkey
.hdr
= key
->key
;
464 OSStatus err
= errSecParam
;
467 case kSecKeyEncodingPkcs1
:
469 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
470 //err = ecc_import(keyData, keyDataLength, fullkey);
472 /* DER != PKCS#1, but we'll go along with it */
477 require_noerr(ccec_der_import_priv_keytype(keyDataLength
, keyData
, &oid
, &n
), abort
);
478 cp
= ccec_cp_for_oid(oid
);
480 cp
= ccec_curve_for_length_lookup(n
* 8 /* bytes -> bits */,
481 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL
);
483 require_action(cp
.zp
!= NULL
, abort
, err
= errSecDecode
);
484 ccec_ctx_init(cp
, fullkey
);
486 require_noerr(ccec_der_import_priv(cp
, keyDataLength
, keyData
, fullkey
), abort
);
490 case kSecKeyEncodingBytes
:
492 ccec_const_cp_t cp
= getCPForPrivateSize(keyDataLength
);
493 require(cp
.zp
!= NULL
, abort
);
495 ccec_ctx_init(cp
, fullkey
);
496 size_t pubSize
= ccec_export_pub_size(fullkey
);
498 require(pubSize
< (size_t) keyDataLength
, abort
);
499 require_noerr_action(ccec_import_pub(cp
, pubSize
, keyData
, fullkey
),
505 keyDataLength
-= pubSize
;
507 cc_unit
*k
= ccec_ctx_k(fullkey
);
508 require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey
), k
, keyDataLength
, keyData
),
516 case kSecGenerateKey
:
518 CFDictionaryRef parameters
= (CFDictionaryRef
) keyData
;
520 CFTypeRef ksize
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
521 CFIndex keyLengthInBits
= getIntValue(ksize
);
523 ccec_const_cp_t cp
= ccec_get_cp(keyLengthInBits
);
526 secwarning("Invalid or missing key size in: %@", parameters
);
527 return errSecKeySizeNotAllowed
;
530 if (!ccec_generate_key_fips(cp
, ccrng_seckey
, fullkey
))
542 static OSStatus
SecECPrivateKeyRawSign(SecKeyRef key
, SecPadding padding
,
543 const uint8_t *dataToSign
, size_t dataToSignLen
,
544 uint8_t *sig
, size_t *sigLen
) {
545 ccec_full_ctx_t fullkey
= {};
546 fullkey
.hdr
= key
->key
;
548 require_action_quiet(sigLen
, errOut
, err
= errSecParam
);
551 if (padding
==kSecPaddingSigRaw
) {
552 // kSecPaddingSigRaw: {r,s} raw byte in big endian, concatenated.
553 cc_size r_s_size
=ccec_signature_r_s_size(fullkey
);
554 require_action_quiet(*sigLen
>=(r_s_size
<<1), errOut
, err
= errSecParam
);
555 require_noerr(err
= ccec_sign_composite(fullkey
, dataToSignLen
, dataToSign
,
556 sig
, sig
+r_s_size
, ccrng_seckey
), errOut
);
557 *sigLen
=(r_s_size
<<1);
560 // kSecPaddingSigDERx962 or default
561 require_noerr(err
= ccec_sign(fullkey
, dataToSignLen
, dataToSign
,
562 sigLen
, sig
, ccrng_seckey
), errOut
);
569 static const struct ccdigest_info
*
570 ccdigest_lookup_by_oid(unsigned long oid_size
, const void *oid
) {
571 static const struct ccdigest_info
*dis
[] = {
579 for (i
= 0; i
< array_size(dis
); ++i
) {
580 if (oid_size
== dis
[i
]->oid_size
&& !memcmp(dis
[i
]->oid
, oid
, oid_size
))
587 static OSStatus
SecECPrivateKeyRawDecrypt(SecKeyRef key
, SecPadding padding
,
588 const uint8_t *cipherText
, size_t cipherTextLen
,
589 uint8_t *plainText
, size_t *plainTextLen
) {
590 ccec_full_ctx_t fullkey
;
591 fullkey
.hdr
= key
->key
;
592 int err
= errSecUnimplemented
;
595 err
= ccec_unwrap_key(fullkey
, ccrng_seckey
, ccdigest_lookup_by_oid
,
596 cipherTextLen
, cipherText
, plainTextLen
, plainText
);
602 static size_t SecECPrivateKeyBlockSize(SecKeyRef key
) {
603 ccec_full_ctx_t fullkey
;
604 fullkey
.hdr
= key
->key
;
605 /* Get key size in octets */
606 return ccec_ctx_size(fullkey
);
609 static OSStatus
SecECPrivateKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
611 ccec_full_ctx_t fullkey
;
612 fullkey
.hdr
= key
->key
;
614 CFAllocatorRef allocator
= CFGetAllocator(key
);
615 *serailziation
= SecECPublicKeyExport(allocator
, fullkey
);
617 if (NULL
== *serailziation
)
620 return errSecSuccess
;
623 static CFDataRef
SecECPPrivateKeyExport(CFAllocatorRef allocator
,
624 ccec_full_ctx_t fullkey
) {
625 size_t prime_size
= ccec_cp_prime_size(ccec_ctx_cp(fullkey
));
626 size_t key_size
= ccec_export_pub_size(fullkey
) + prime_size
;
627 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, key_size
);
629 CFDataSetLength(blob
, key_size
);
630 ccec_export_pub(fullkey
, CFDataGetMutableBytePtr(blob
));
631 UInt8
*dest
= CFDataGetMutableBytePtr(blob
) + ccec_export_pub_size(fullkey
);
632 const cc_unit
*k
= ccec_ctx_k(fullkey
);
633 ccn_write_uint_padded(ccec_ctx_n(fullkey
), k
, prime_size
, dest
);
640 static CFDictionaryRef
SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key
) {
641 CFDictionaryRef dict
= NULL
;
642 CFAllocatorRef allocator
= CFGetAllocator(key
);
644 ccec_full_ctx_t fullkey
;
645 fullkey
.hdr
= key
->key
;
647 CFDataRef fullKeyBlob
= NULL
;
649 /* Export the full ec key pair. */
650 require(fullKeyBlob
= SecECPPrivateKeyExport(allocator
, fullkey
), errOut
);
652 dict
= SecKeyGeneratePrivateAttributeDictionary(key
, kSecAttrKeyTypeEC
, fullKeyBlob
);
655 CFReleaseSafe(fullKeyBlob
);
659 static CFStringRef
SecECPrivateKeyCopyKeyDescription(SecKeyRef key
) {
661 const char* curve
= getCurveName(key
);
663 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
);
667 static CFDataRef
SecECKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
669 const struct ccec_rfc6637_curve
*curve
;
670 const struct ccec_rfc6637_unwrap
*unwrap
;
671 ccec_full_ctx_t fullkey
;
672 CFMutableDataRef data
;
675 unsigned long flags
= 0;
677 fullkey
.hdr
= key
->key
;
679 curve
= get_rfc6637_curve(key
);
681 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
685 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
686 if (wrapAlg
== NULL
) {
687 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
689 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
690 unwrap
= &ccec_rfc6637_unwrap_sha256_kek_aes128
;
691 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
692 unwrap
= &ccec_rfc6637_unwrap_sha512_kek_aes256
;
694 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
698 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
699 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
700 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
704 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
706 if (!CFNumberGetValue(num
, kCFNumberSInt32Type
, &num
)) {
707 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
711 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
715 size_t keysize
= CFDataGetLength(wrappedKey
);
716 data
= CFDataCreateMutableWithScratch(NULL
, keysize
);
720 res
= ccec_rfc6637_unwrap_key(fullkey
, &keysize
, CFDataGetMutableBytePtr(data
),
721 flags
, &sym_alg
, curve
, unwrap
,
722 CFDataGetBytePtr(fingerprint
),
723 CFDataGetLength(wrappedKey
), CFDataGetBytePtr(wrappedKey
));
726 SecError(errSecUnsupportedOperation
, error
, CFSTR("failed to wrap key"));
729 assert(keysize
<= (size_t)CFDataGetLength(data
));
730 CFDataSetLength(data
, keysize
);
733 CFMutableDictionaryRef out
= CFDictionaryCreateMutableForCFTypes(NULL
);
735 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &sym_alg
);
737 CFDictionarySetValue(out
, _kSecKeyWrapPGPSymAlg
, num
);
748 SecKeyDescriptor kSecECPrivateKeyDescriptor
= {
749 kSecKeyDescriptorVersion
,
751 ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
753 SecECPrivateKeyDestroy
,
754 SecECPrivateKeyRawSign
,
755 NULL
, /* SecKeyRawVerifyMethod */
756 NULL
, /* SecKeyEncryptMethod */
757 SecECPrivateKeyRawDecrypt
,
758 NULL
, /* SecKeyComputeMethod */
759 SecECPrivateKeyBlockSize
,
760 SecECPrivateKeyCopyAttributeDictionary
,
761 SecECPrivateKeyCopyKeyDescription
,
762 SecECKeyGetAlgorithmID
,
763 SecECPrivateKeyCopyPublicOctets
,
765 SecECKeyCopyUnwrapKey
,
768 /* Private Key API functions. */
769 SecKeyRef
SecKeyCreateECPrivateKey(CFAllocatorRef allocator
,
770 const uint8_t *keyData
, CFIndex keyDataLength
,
771 SecKeyEncoding encoding
) {
772 return SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
, keyData
,
773 keyDataLength
, encoding
);
777 OSStatus
SecECKeyGeneratePair(CFDictionaryRef parameters
,
778 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
779 OSStatus status
= errSecParam
;
781 CFAllocatorRef allocator
= NULL
; /* @@@ get from parameters. */
782 SecKeyRef pubKey
= NULL
;
784 SecKeyRef privKey
= SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
,
785 (const void*) parameters
, 0, kSecGenerateKey
);
787 require(privKey
, errOut
);
789 /* Create SecKeyRef's from the pkcs1 encoded keys. */
790 pubKey
= SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
,
791 privKey
->key
, 0, kSecExtractPublicFromPrivate
);
793 require(pubKey
, errOut
);
800 *privateKey
= privKey
;
804 status
= errSecSuccess
;
807 CFReleaseSafe(pubKey
);
808 CFReleaseSafe(privKey
);
814 /* It's debatable whether this belongs here or in the ssl code since the
815 curve values come from a tls related rfc4492. */
816 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
) {
817 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
818 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
819 return kSecECCurveNone
;
821 ccec_pub_ctx_t pubkey
;
822 pubkey
.pub
= key
->key
;
823 switch (ccec_ctx_size(pubkey
)) {
826 return kSecECCurveSecp192r1
;
828 return kSecECCurveSecp224r1
;
831 return kSecECCurveSecp256r1
;
833 return kSecECCurveSecp384r1
;
835 return kSecECCurveSecp521r1
;
837 return kSecECCurveNone
;
840 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
) {
841 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
842 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
845 ccec_pub_ctx_t pubkey
;
846 pubkey
.pub
= key
->key
;
847 return SecECPublicKeyExport(CFGetAllocator(key
), pubkey
);
850 /* Vile accessors that get us the pub or priv key to use temporarily */
852 bool SecECDoWithFullKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_full_ctx_t
private)) {
853 if (key
->key_class
== &kSecECPrivateKeyDescriptor
) {
856 return SecError(errSecParam
, error
, CFSTR("Not an EC Full Key object, sorry can't do."));
862 bool SecECDoWithPubKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_pub_ctx_t
public)) {
863 if (key
->key_class
== &kSecECPublicKeyDescriptor
) {
866 return SecError(errSecParam
, error
, CFSTR("Not an EC Public Key object, sorry can't do."));