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 <utilities/array_size.h>
49 #include <corecrypto/ccec.h>
50 #include <corecrypto/ccsha1.h>
51 #include <corecrypto/ccsha2.h>
52 #include <corecrypto/ccrng.h>
53 #include <corecrypto/ccder_decode_eckey.h>
55 #define kMaximumECKeySize 521
57 static CFIndex
SecECKeyGetAlgorithmID(SecKeyRef key
) {
58 return kSecECDSAAlgorithmID
;
68 /* Public key static functions. */
69 static void SecECPublicKeyDestroy(SecKeyRef key
) {
70 /* Zero out the public key */
71 ccec_pub_ctx_t pubkey
= key
->key
;
72 if (ccec_ctx_cp(pubkey
))
73 cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey
))), pubkey
);
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
);
85 static ccec_const_cp_t
getCPForPrivateSize(CFIndex encoded_length
)
87 size_t keysize
= ccec_x963_import_priv_size(encoded_length
);
88 if(ccec_keysize_is_supported(keysize
)) {
89 return ccec_get_cp(keysize
);
94 static ccoid_t ccoid_secp192r1
= CC_EC_OID_SECP192R1
;
95 static ccoid_t ccoid_secp256r1
= CC_EC_OID_SECP256R1
;
96 static ccoid_t ccoid_secp224r1
= CC_EC_OID_SECP224R1
;
97 static ccoid_t ccoid_secp384r1
= CC_EC_OID_SECP384R1
;
98 static ccoid_t ccoid_secp521r1
= CC_EC_OID_SECP521R1
;
100 static ccec_const_cp_t
ccec_cp_for_oid(const unsigned char *oid
)
103 if (ccoid_equal(oid
, ccoid_secp192r1
)) {
104 return ccec_cp_192();
105 } else if (ccoid_equal(oid
, ccoid_secp256r1
)) {
106 return ccec_cp_256();
107 } else if (ccoid_equal(oid
, ccoid_secp224r1
)) {
108 return ccec_cp_224();
109 } else if (ccoid_equal(oid
, ccoid_secp384r1
)) {
110 return ccec_cp_384();
111 } else if (ccoid_equal(oid
, ccoid_secp521r1
)) {
112 return ccec_cp_521();
115 return (ccec_const_cp_t
){NULL
};
118 static OSStatus
SecECPublicKeyInit(SecKeyRef key
,
119 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
120 ccec_pub_ctx_t pubkey
= key
->key
;
121 OSStatus err
= errSecParam
;
124 case kSecDERKeyEncoding
:
126 const SecDERKey
*derKey
= (const SecDERKey
*)keyData
;
127 if (keyDataLength
!= sizeof(SecDERKey
)) {
132 ccec_const_cp_t cp
= getCPForPublicSize(derKey
->keyLength
);
133 require_action_quiet(cp
, errOut
, err
= errSecDecode
);
135 /* TODO: Parse and use real params from passed in derKey->algId.params */
136 err
= (ccec_import_pub(cp
, derKey
->keyLength
, derKey
->key
, pubkey
)
137 ? errSecDecode
: errSecSuccess
);
140 case kSecKeyEncodingBytes
:
142 ccec_const_cp_t cp
= getCPForPublicSize(keyDataLength
);
143 require_action_quiet(cp
, errOut
, err
= errSecDecode
);
144 err
= (ccec_import_pub(cp
, keyDataLength
, keyData
, pubkey
)
145 ? errSecDecode
: errSecSuccess
);
148 case kSecExtractPublicFromPrivate
:
150 ccec_full_ctx_t fullKey
= (ccec_full_ctx_t
)keyData
;
152 cc_size fullKeyN
= ccec_ctx_n(fullKey
);
153 require_quiet(fullKeyN
<= ccn_nof(kMaximumECKeySize
), errOut
);
154 memcpy(pubkey
, fullKey
, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN
)));
158 case kSecKeyEncodingApplePkcs1
:
168 static CFTypeRef
SecECPublicKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
169 CFArrayRef algorithms
, SecKeyOperationMode mode
,
170 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
171 if (operation
!= kSecKeyOperationTypeVerify
) {
172 // EC public key supports only signature verification.
176 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
) || CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
177 if (mode
== kSecKeyOperationModePerform
) {
180 size_t sigLen
= CFDataGetLength(in2
);
181 uint8_t *sig
= (uint8_t *)CFDataGetBytePtr(in2
);
182 ccec_pub_ctx_t pubkey
= key
->key
;
184 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
185 err
= ccec_verify(pubkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
), sigLen
, sig
, &valid
);
187 if (ccec_signature_r_s_size(pubkey
) * 2 != sigLen
) {
188 SecError(errSecParam
, error
, CFSTR("bad signature size, got %d, expecting %d bytes"),
189 (int)sigLen
, (int)ccec_signature_r_s_size(pubkey
) * 2);
192 err
= ccec_verify_composite(pubkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
193 sig
, sig
+ (sigLen
>> 1), &valid
);
197 SecError(errSecVerifyFailed
, error
, CFSTR("EC signature verification failed (ccerr %d)"), err
);
200 SecError(errSecVerifyFailed
, error
, CFSTR("EC signature verification failed, no match"));
203 return kCFBooleanTrue
;
206 // Algorithm is supported.
207 return kCFBooleanTrue
;
210 // Other algorithms are unsupported.
215 static size_t SecECPublicKeyBlockSize(SecKeyRef key
) {
216 /* Get key size in octets */
217 return ccec_ctx_size(ccec_ctx_pub(key
->key
));
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
= CFDataCreateMutableWithScratch(allocator
, pub_size
);
225 ccec_export_pub(pubkey
, CFDataGetMutableBytePtr(blob
));
229 static CFDataRef
SecECPublicKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
230 ccec_pub_ctx_t pubkey
= key
->key
;
231 return SecECPublicKeyExport(NULL
, pubkey
);
234 static OSStatus
SecECPublicKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
236 ccec_pub_ctx_t pubkey
= 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 CFDictionaryRef dict
= SecKeyGeneratePublicAttributeDictionary(key
, kSecAttrKeyTypeEC
);
249 CFMutableDictionaryRef mutableDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
250 CFDictionarySetValue(mutableDict
, kSecAttrCanDerive
, kCFBooleanFalse
);
251 CFAssignRetained(dict
, mutableDict
);
256 getCurveName(SecKeyRef key
)
258 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
262 case kSecECCurveSecp256r1
:
263 return "kSecECCurveSecp256r1";
265 case kSecECCurveSecp384r1
:
266 return "kSecECCurveSecp384r1";
268 case kSecECCurveSecp521r1
:
269 return "kSecECCurveSecp521r1";
271 return "kSecECCurveNone";
275 static CFStringRef
SecECPublicKeyCopyKeyDescription(SecKeyRef key
)
277 CFStringRef keyDescription
= NULL
;
278 CFMutableStringRef strings
[2] = { NULL
, };
279 const char* curve
= getCurveName(key
);
281 ccec_pub_ctx_t ecPubkey
= key
->key
;
282 size_t len
= ccec_ctx_size(ecPubkey
);
284 for (int i
= 0; i
< 2; ++i
) {
285 ccn_write_uint(ccec_ctx_n(ecPubkey
), (i
== 0) ? ccec_ctx_x(ecPubkey
) : ccec_ctx_y(ecPubkey
), len
, buffer
);
286 require_quiet(strings
[i
] = CFStringCreateMutable(kCFAllocatorDefault
, len
* 2), fail
);
287 for (size_t byteIndex
= 0; byteIndex
< len
; ++byteIndex
) {
288 CFStringAppendFormat(strings
[i
], NULL
, CFSTR("%02X"), buffer
[byteIndex
]);
292 keyDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
293 CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>"),
294 curve
, (long)SecKeyGetAlgorithmId(key
), key
->key_class
->name
, key
->key_class
->version
,
295 8 * SecKeyGetBlockSize(key
), strings
[1], strings
[0], key
);
298 CFReleaseSafe(strings
[0]);
299 CFReleaseSafe(strings
[1]);
301 keyDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
302 CFSTR("<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"),
303 curve
,(long)SecKeyGetAlgorithmId(key
), key
->key_class
->name
, key
->key_class
->version
,
304 8 * SecKeyGetBlockSize(key
), key
);
306 return keyDescription
;
309 static const struct ccec_rfc6637_curve
* get_rfc6637_curve(SecKeyRef key
)
311 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
313 if (curveType
== kSecECCurveSecp256r1
) {
314 return &ccec_rfc6637_dh_curve_p256
;
315 } else if (curveType
== kSecECCurveSecp521r1
) {
316 return &ccec_rfc6637_dh_curve_p521
;
321 static CFDataRef
SecECKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
323 ccec_pub_ctx_t pubkey
= key
->key
;
324 int err
= errSecUnimplemented
;
325 const struct ccec_rfc6637_curve
*curve
;
326 const struct ccec_rfc6637_wrap
*wrap
= NULL
;
330 if (type
!= kSecKeyWrapPublicKeyPGP
) {
331 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported key wrapping algorithm"));
335 curve
= get_rfc6637_curve(key
);
337 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
341 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPSymAlg
);
342 if (!isNumber(num
) || !CFNumberGetValue(num
, kCFNumberSInt8Type
, &sym_alg
)) {
343 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown symalg given"));
347 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
348 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
349 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
353 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
354 if (wrapAlg
== NULL
) {
355 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
357 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
358 wrap
= &ccec_rfc6637_wrap_sha256_kek_aes128
;
359 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
360 wrap
= &ccec_rfc6637_wrap_sha512_kek_aes256
;
362 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
366 num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
368 if (!CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
369 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
373 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
377 CFIndex unwrappedKey_size
= CFDataGetLength(unwrappedKey
);
379 CFIndex output_size
= ccec_rfc6637_wrap_key_size(pubkey
, flags
, unwrappedKey_size
);
380 if (output_size
== 0) {
381 SecError(errSecUnsupportedOperation
, error
, CFSTR("can't wrap that key, can't build size"));
385 CFMutableDataRef data
= CFDataCreateMutableWithScratch(NULL
, output_size
);
386 require_quiet(data
, errOut
);
388 err
= ccec_rfc6637_wrap_key(pubkey
, CFDataGetMutableBytePtr(data
), flags
,
389 sym_alg
, CFDataGetLength(unwrappedKey
), CFDataGetBytePtr(unwrappedKey
),
390 curve
, wrap
, CFDataGetBytePtr(fingerprint
),
393 SecError(errSecUnsupportedOperation
, error
, CFSTR("Failed to wrap key"));
401 SecKeyDescriptor kSecECPublicKeyDescriptor
= {
402 .version
= kSecKeyDescriptorVersion
,
403 .name
= "ECPublicKey",
404 .extraBytes
= ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
)),
405 .init
= SecECPublicKeyInit
,
406 .destroy
= SecECPublicKeyDestroy
,
407 .blockSize
= SecECPublicKeyBlockSize
,
408 .copyDictionary
= SecECPublicKeyCopyAttributeDictionary
,
409 .copyExternalRepresentation
= SecECPublicKeyCopyExternalRepresentation
,
410 .describe
= SecECPublicKeyCopyKeyDescription
,
411 .getAlgorithmID
= SecECKeyGetAlgorithmID
,
412 .copyPublic
= SecECPublicKeyCopyPublicOctets
,
413 .copyWrapKey
= SecECKeyCopyWrapKey
,
414 .copyOperationResult
= SecECPublicKeyCopyOperationResult
,
417 /* Public Key API functions. */
418 SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
419 const uint8_t *keyData
, CFIndex keyDataLength
,
420 SecKeyEncoding encoding
) {
421 return SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
, keyData
,
422 keyDataLength
, encoding
);
433 /* Private key static functions. */
434 static void SecECPrivateKeyDestroy(SecKeyRef key
) {
435 /* Zero out the public key */
436 ccec_full_ctx_t fullkey
= key
->key
;
438 if (ccec_ctx_cp(fullkey
))
439 cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey
))), fullkey
);
443 static OSStatus
SecECPrivateKeyInit(SecKeyRef key
,
444 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
445 ccec_full_ctx_t fullkey
= key
->key
;
446 OSStatus err
= errSecParam
;
449 case kSecKeyEncodingPkcs1
:
451 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
452 //err = ecc_import(keyData, keyDataLength, fullkey);
454 /* DER != PKCS#1, but we'll go along with it */
455 const unsigned char *oid
;
459 require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength
, keyData
, (ccoid_t
*)&oid
, &n
), abort
);
460 cp
= ccec_cp_for_oid(oid
);
462 cp
= ccec_curve_for_length_lookup(n
* 8 /* bytes -> bits */,
463 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL
);
465 require_action_quiet(cp
!= NULL
, abort
, err
= errSecDecode
);
466 ccec_ctx_init(cp
, fullkey
);
468 require_noerr_quiet(ccec_der_import_priv(cp
, keyDataLength
, keyData
, fullkey
), abort
);
472 case kSecKeyEncodingBytes
:
474 ccec_const_cp_t cp
= getCPForPrivateSize(keyDataLength
);
475 require_quiet(cp
!= NULL
, abort
);
477 ccec_ctx_init(cp
, fullkey
);
478 size_t pubSize
= ccec_export_pub_size(ccec_ctx_pub(fullkey
));
480 require(pubSize
< (size_t) keyDataLength
, abort
);
481 require_noerr_action_quiet(ccec_import_pub(cp
, pubSize
, keyData
, ccec_ctx_pub(fullkey
)),
487 keyDataLength
-= pubSize
;
489 cc_unit
*k
= ccec_ctx_k(fullkey
);
490 require_noerr_action_quiet(ccn_read_uint(ccec_ctx_n(fullkey
), k
, keyDataLength
, keyData
),
498 case kSecGenerateKey
:
500 CFDictionaryRef parameters
= (CFDictionaryRef
) keyData
;
502 CFTypeRef ksize
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
503 CFIndex keyLengthInBits
= getIntValue(ksize
);
505 ccec_const_cp_t cp
= ccec_get_cp(keyLengthInBits
);
508 secwarning("Invalid or missing key size in: %@", parameters
);
509 return errSecKeySizeNotAllowed
;
512 if (!ccec_generate_key_fips(cp
, ccrng_seckey
, fullkey
))
524 static CFTypeRef
SecECPrivateKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
525 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
526 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
527 // Default answer is 'unsupported', unless we find out that we can support it.
528 CFTypeRef result
= kCFNull
;
530 ccec_full_ctx_t fullkey
= key
->key
;
532 case kSecKeyOperationTypeSign
: {
533 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
534 if (mode
== kSecKeyOperationModePerform
) {
535 // Perform r/s mode of signature.
536 cc_size r_s_size
= ccec_signature_r_s_size(ccec_ctx_public(fullkey
));
537 result
= CFDataCreateMutableWithScratch(NULL
, r_s_size
<< 1);
538 uint8_t *signatureBuffer
= CFDataGetMutableBytePtr((CFMutableDataRef
)result
);
539 int err
= ccec_sign_composite(fullkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
540 signatureBuffer
, signatureBuffer
+ r_s_size
, ccrng_seckey
);
541 require_action_quiet(err
== 0, out
, (CFReleaseNull(result
),
542 SecError(errSecParam
, error
, CFSTR("%@: RFC4754 signing failed (ccerr %d)"),
545 // Operation is supported.
546 result
= kCFBooleanTrue
;
548 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
549 if (mode
== kSecKeyOperationModePerform
) {
550 // Perform x962 mode of signature.
551 size_t size
= ccec_sign_max_size(ccec_ctx_cp(fullkey
));
552 result
= CFDataCreateMutableWithScratch(NULL
, size
);
553 int err
= ccec_sign(fullkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
554 &size
, CFDataGetMutableBytePtr((CFMutableDataRef
)result
), ccrng_seckey
);
555 require_action_quiet(err
== 0, out
, (CFReleaseNull(result
),
556 SecError(errSecParam
, error
, CFSTR("%@: X962 signing failed (ccerr %d)"),
558 CFDataSetLength((CFMutableDataRef
)result
, size
);
560 // Operation is supported.
561 result
= kCFBooleanTrue
;
566 case kSecKeyOperationTypeKeyExchange
:
567 if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
568 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
569 if (mode
== kSecKeyOperationModePerform
) {
571 ccec_const_cp_t cp
= getCPForPublicSize(CFDataGetLength(in1
));
572 require_action_quiet(cp
!= NULL
, out
,
573 SecError(errSecParam
, error
, CFSTR("ECpriv sharedsecret: bad public key")));
574 ccec_pub_ctx_decl_cp(cp
, pubkey
);
575 err
= ccec_import_pub(cp
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
), pubkey
);
576 require_noerr_action_quiet(err
, out
, SecError(errSecParam
, error
,
577 CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err
));
578 size_t size
= ccec_ccn_size(cp
);
579 result
= CFDataCreateMutableWithScratch(NULL
, size
);
580 err
= ccecdh_compute_shared_secret(fullkey
, pubkey
, &size
,
581 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), ccrng_seckey
);
582 require_noerr_action_quiet(err
, out
, (CFReleaseNull(result
),
583 SecError(errSecDecode
, error
,
584 CFSTR("ECpriv failed to compute shared secret (err %d)"), err
)));
585 CFDataSetLength((CFMutableDataRef
)result
, size
);
587 // Operation is supported.
588 result
= kCFBooleanTrue
;
600 static size_t SecECPrivateKeyBlockSize(SecKeyRef key
) {
601 ccec_full_ctx_t fullkey
= key
->key
;
602 /* Get key size in octets */
603 return ccec_ctx_size(fullkey
);
606 static OSStatus
SecECPrivateKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
608 ccec_full_ctx_t fullkey
= key
->key
;
610 CFAllocatorRef allocator
= CFGetAllocator(key
);
611 *serailziation
= SecECPublicKeyExport(allocator
, ccec_ctx_pub(fullkey
));
613 if (NULL
== *serailziation
)
616 return errSecSuccess
;
619 static CFDataRef
SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
620 ccec_full_ctx_t fullkey
= key
->key
;
621 size_t prime_size
= ccec_cp_prime_size(ccec_ctx_cp(fullkey
));
622 size_t key_size
= ccec_export_pub_size(ccec_ctx_pub(fullkey
)) + prime_size
;
623 CFMutableDataRef blob
= CFDataCreateMutableWithScratch(NULL
, key_size
);
624 ccec_export_pub(ccec_ctx_pub(fullkey
), CFDataGetMutableBytePtr(blob
));
625 UInt8
*dest
= CFDataGetMutableBytePtr(blob
) + ccec_export_pub_size(ccec_ctx_pub(fullkey
));
626 const cc_unit
*k
= ccec_ctx_k(fullkey
);
627 ccn_write_uint_padded(ccec_ctx_n(fullkey
), k
, prime_size
, dest
);
631 static CFDictionaryRef
SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key
) {
632 /* Export the full ec key pair. */
633 CFDataRef fullKeyBlob
= SecECPrivateKeyCopyExternalRepresentation(key
, NULL
);
635 CFDictionaryRef dict
= SecKeyGeneratePrivateAttributeDictionary(key
, kSecAttrKeyTypeEC
, fullKeyBlob
);
636 CFReleaseSafe(fullKeyBlob
);
639 static CFStringRef
SecECPrivateKeyCopyKeyDescription(SecKeyRef key
) {
641 const char* curve
= getCurveName(key
);
643 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
);
647 static CFDataRef
SecECKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
649 const struct ccec_rfc6637_curve
*curve
;
650 const struct ccec_rfc6637_unwrap
*unwrap
;
651 ccec_full_ctx_t fullkey
= key
->key
;
652 CFMutableDataRef data
;
657 curve
= get_rfc6637_curve(key
);
659 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
663 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
664 if (wrapAlg
== NULL
) {
665 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
667 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
668 unwrap
= &ccec_rfc6637_unwrap_sha256_kek_aes128
;
669 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
670 unwrap
= &ccec_rfc6637_unwrap_sha512_kek_aes256
;
672 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
676 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
677 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
678 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
682 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
684 if (!CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
685 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
689 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
693 size_t keysize
= CFDataGetLength(wrappedKey
);
694 data
= CFDataCreateMutableWithScratch(NULL
, keysize
);
698 res
= ccec_rfc6637_unwrap_key(fullkey
, &keysize
, CFDataGetMutableBytePtr(data
),
699 flags
, &sym_alg
, curve
, unwrap
,
700 CFDataGetBytePtr(fingerprint
),
701 CFDataGetLength(wrappedKey
), CFDataGetBytePtr(wrappedKey
));
704 SecError(errSecUnsupportedOperation
, error
, CFSTR("failed to wrap key"));
707 assert(keysize
<= (size_t)CFDataGetLength(data
));
708 CFDataSetLength(data
, keysize
);
711 CFMutableDictionaryRef out
= CFDictionaryCreateMutableForCFTypes(NULL
);
713 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &sym_alg
);
715 CFDictionarySetValue(out
, _kSecKeyWrapPGPSymAlg
, num
);
725 SecKeyDescriptor kSecECPrivateKeyDescriptor
= {
726 .version
= kSecKeyDescriptorVersion
,
727 .name
= "ECPrivateKey",
728 .extraBytes
= ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize
)),
730 .init
= SecECPrivateKeyInit
,
731 .destroy
= SecECPrivateKeyDestroy
,
732 .blockSize
= SecECPrivateKeyBlockSize
,
733 .copyDictionary
= SecECPrivateKeyCopyAttributeDictionary
,
734 .describe
= SecECPrivateKeyCopyKeyDescription
,
735 .getAlgorithmID
= SecECKeyGetAlgorithmID
,
736 .copyPublic
= SecECPrivateKeyCopyPublicOctets
,
737 .copyExternalRepresentation
= SecECPrivateKeyCopyExternalRepresentation
,
738 .copyWrapKey
= SecECKeyCopyWrapKey
,
739 .copyUnwrapKey
= SecECKeyCopyUnwrapKey
,
740 .copyOperationResult
= SecECPrivateKeyCopyOperationResult
,
743 /* Private Key API functions. */
744 SecKeyRef
SecKeyCreateECPrivateKey(CFAllocatorRef allocator
,
745 const uint8_t *keyData
, CFIndex keyDataLength
,
746 SecKeyEncoding encoding
) {
747 return SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
, keyData
,
748 keyDataLength
, encoding
);
752 OSStatus
SecECKeyGeneratePair(CFDictionaryRef parameters
,
753 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
754 OSStatus status
= errSecParam
;
756 CFAllocatorRef allocator
= NULL
; /* @@@ get from parameters. */
757 SecKeyRef pubKey
= NULL
;
759 SecKeyRef privKey
= SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
,
760 (const void*) parameters
, 0, kSecGenerateKey
);
762 require(privKey
, errOut
);
764 /* Create SecKeyRef's from the pkcs1 encoded keys. */
765 pubKey
= SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
,
766 privKey
->key
, 0, kSecExtractPublicFromPrivate
);
768 require(pubKey
, errOut
);
775 *privateKey
= privKey
;
779 status
= errSecSuccess
;
782 CFReleaseSafe(pubKey
);
783 CFReleaseSafe(privKey
);
789 /* It's debatable whether this belongs here or in the ssl code since the
790 curve values come from a tls related rfc4492. */
791 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
) {
792 SecECNamedCurve result
= kSecECCurveNone
;
793 CFDictionaryRef attributes
= NULL
;
794 require_quiet(SecKeyGetAlgorithmId(key
) == kSecECDSAAlgorithmID
, out
);
795 require_quiet(attributes
= SecKeyCopyAttributes(key
), out
);
796 CFTypeRef bitsRef
= CFDictionaryGetValue(attributes
, kSecAttrKeySizeInBits
);
798 require_quiet(bitsRef
!= NULL
&& CFGetTypeID(bitsRef
) == CFNumberGetTypeID() &&
799 CFNumberGetValue(bitsRef
, kCFNumberCFIndexType
, &bits
), out
);
803 result
= kSecECCurveSecp192r1
;
806 result
= kSecECCurveSecp224r1
;
810 result
= kSecECCurveSecp256r1
;
813 result
= kSecECCurveSecp384r1
;
816 result
= kSecECCurveSecp521r1
;
821 CFReleaseSafe(attributes
);
825 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
) {
826 CFDataRef bytes
= NULL
;
827 SecKeyCopyPublicBytes(key
, &bytes
);
831 /* Vile accessors that get us the pub or priv key to use temporarily */
833 bool SecECDoWithFullKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_full_ctx_t
private)) {
834 if (key
->key_class
== &kSecECPrivateKeyDescriptor
) {
837 return SecError(errSecParam
, error
, CFSTR("Not an EC Full Key object, sorry can't do."));
843 bool SecECDoWithPubKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_pub_ctx_t
public)) {
844 if (key
->key_class
== &kSecECPublicKeyDescriptor
) {
847 return SecError(errSecParam
, error
, CFSTR("Not an EC Public Key object, sorry can't do."));