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
;
72 pubkey
.pub
= key
->key
;
73 if (ccec_ctx_cp(pubkey
).zp
)
74 cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey
))), pubkey
.pub
);
77 static ccec_const_cp_t
getCPForPublicSize(CFIndex encoded_length
)
79 size_t keysize
= ccec_x963_import_pub_size(encoded_length
);
80 if(ccec_keysize_is_supported(keysize
)) {
81 return ccec_get_cp(keysize
);
83 ccec_const_cp_t nullCP
= { .zp
= NULL
};
87 static ccec_const_cp_t
getCPForPrivateSize(CFIndex encoded_length
)
89 size_t keysize
= ccec_x963_import_priv_size(encoded_length
);
90 if(ccec_keysize_is_supported(keysize
)) {
91 return ccec_get_cp(keysize
);
93 ccec_const_cp_t nullCP
= { .zp
= NULL
};
97 static ccoid_t ccoid_secp192r1
= CC_EC_OID_SECP192R1
;
98 static ccoid_t ccoid_secp256r1
= CC_EC_OID_SECP256R1
;
99 static ccoid_t ccoid_secp224r1
= CC_EC_OID_SECP224R1
;
100 static ccoid_t ccoid_secp384r1
= CC_EC_OID_SECP384R1
;
101 static ccoid_t ccoid_secp521r1
= CC_EC_OID_SECP521R1
;
103 static ccec_const_cp_t
ccec_cp_for_oid(const unsigned char *oid
)
106 if (ccoid_equal(oid
, ccoid_secp192r1
)) {
107 return ccec_cp_192();
108 } else if (ccoid_equal(oid
, ccoid_secp256r1
)) {
109 return ccec_cp_256();
110 } else if (ccoid_equal(oid
, ccoid_secp224r1
)) {
111 return ccec_cp_224();
112 } else if (ccoid_equal(oid
, ccoid_secp384r1
)) {
113 return ccec_cp_384();
114 } else if (ccoid_equal(oid
, ccoid_secp521r1
)) {
115 return ccec_cp_521();
118 return (ccec_const_cp_t
){NULL
};
121 static OSStatus
SecECPublicKeyInit(SecKeyRef key
,
122 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
123 ccec_pub_ctx_t pubkey
;
124 pubkey
.pub
= key
->key
;
125 OSStatus err
= errSecParam
;
128 case kSecDERKeyEncoding
:
130 const SecDERKey
*derKey
= (const SecDERKey
*)keyData
;
131 if (keyDataLength
!= sizeof(SecDERKey
)) {
136 ccec_const_cp_t cp
= getCPForPublicSize(derKey
->keyLength
);
137 require_action_quiet(cp
.zp
, errOut
, err
= errSecDecode
);
139 /* TODO: Parse and use real params from passed in derKey->algId.params */
140 err
= (ccec_import_pub(cp
, derKey
->keyLength
, derKey
->key
, pubkey
)
141 ? errSecDecode
: errSecSuccess
);
144 case kSecKeyEncodingBytes
:
146 ccec_const_cp_t cp
= getCPForPublicSize(keyDataLength
);
147 require_action_quiet(cp
.zp
, errOut
, err
= errSecDecode
);
148 err
= (ccec_import_pub(cp
, keyDataLength
, keyData
, pubkey
)
149 ? errSecDecode
: errSecSuccess
);
152 case kSecExtractPublicFromPrivate
:
154 ccec_full_ctx_t fullKey
;
155 fullKey
._full
= (ccec_full_ctx
*) keyData
;
157 cc_size fullKeyN
= ccec_ctx_n(fullKey
);
158 require_quiet(fullKeyN
<= ccn_nof(kMaximumECKeySize
), errOut
);
159 memcpy(pubkey
._pub
, fullKey
.pub
, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN
)));
163 case kSecKeyEncodingApplePkcs1
:
173 static CFTypeRef
SecECPublicKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
174 CFArrayRef algorithms
, SecKeyOperationMode mode
,
175 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
176 if (operation
!= kSecKeyOperationTypeVerify
) {
177 // EC public key supports only signature verification.
181 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
) || CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
182 if (mode
== kSecKeyOperationModePerform
) {
185 size_t sigLen
= CFDataGetLength(in2
);
186 uint8_t *sig
= (uint8_t *)CFDataGetBytePtr(in2
);
187 ccec_pub_ctx_t pubkey
= { .pub
= key
->key
};
189 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
190 err
= ccec_verify(pubkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
), sigLen
, sig
, &valid
);
192 if (ccec_signature_r_s_size(pubkey
.fullt
) * 2 != sigLen
) {
193 SecError(errSecParam
, error
, CFSTR("bad signature size, got %d, expecting %d bytes"),
194 (int)sigLen
, (int)ccec_signature_r_s_size(pubkey
.fullt
) * 2);
197 err
= ccec_verify_composite(pubkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
198 sig
, sig
+ (sigLen
>> 1), &valid
);
202 SecError(errSecVerifyFailed
, error
, CFSTR("EC signature verification failed (ccerr %d)"), err
);
205 SecError(errSecVerifyFailed
, error
, CFSTR("EC signature verification failed, no match"));
208 return kCFBooleanTrue
;
211 // Algorithm is supported.
212 return kCFBooleanTrue
;
215 // Other algorithms are unsupported.
220 static size_t SecECPublicKeyBlockSize(SecKeyRef key
) {
221 /* Get key size in octets */
222 ccec_pub_ctx_t pubkey
;
223 pubkey
.pub
= key
->key
;
224 return ccec_ctx_size(pubkey
);
227 /* Encode the public key and return it in a newly allocated CFDataRef. */
228 static CFDataRef
SecECPublicKeyExport(CFAllocatorRef allocator
,
229 ccec_pub_ctx_t pubkey
) {
230 size_t pub_size
= ccec_export_pub_size(pubkey
);
231 CFMutableDataRef blob
= CFDataCreateMutableWithScratch(allocator
, pub_size
);
232 ccec_export_pub(pubkey
, CFDataGetMutableBytePtr(blob
));
236 static CFDataRef
SecECPublicKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
237 ccec_pub_ctx_t pubkey
;
238 pubkey
.pub
= key
->key
;
239 return SecECPublicKeyExport(NULL
, pubkey
);
242 static OSStatus
SecECPublicKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
244 ccec_pub_ctx_t pubkey
;
245 pubkey
.pub
= key
->key
;
247 CFAllocatorRef allocator
= CFGetAllocator(key
);
248 *serailziation
= SecECPublicKeyExport(allocator
, pubkey
);
250 if (NULL
== *serailziation
)
253 return errSecSuccess
;
256 static CFDictionaryRef
SecECPublicKeyCopyAttributeDictionary(SecKeyRef key
) {
257 CFDictionaryRef dict
= SecKeyGeneratePublicAttributeDictionary(key
, kSecAttrKeyTypeEC
);
258 CFMutableDictionaryRef mutableDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
259 CFDictionarySetValue(mutableDict
, kSecAttrCanDerive
, kCFBooleanFalse
);
260 CFAssignRetained(dict
, mutableDict
);
265 getCurveName(SecKeyRef key
)
267 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
271 case kSecECCurveSecp256r1
:
272 return "kSecECCurveSecp256r1";
274 case kSecECCurveSecp384r1
:
275 return "kSecECCurveSecp384r1";
277 case kSecECCurveSecp521r1
:
278 return "kSecECCurveSecp521r1";
280 return "kSecECCurveNone";
284 static CFStringRef
SecECPublicKeyCopyKeyDescription(SecKeyRef key
)
286 CFStringRef keyDescription
= NULL
;
287 CFMutableStringRef strings
[2] = { NULL
, };
288 const char* curve
= getCurveName(key
);
290 ccec_pub_ctx_t ecPubkey
= { .pub
= key
->key
};
291 size_t len
= ccec_ctx_size(ecPubkey
);
293 for (int i
= 0; i
< 2; ++i
) {
294 ccn_write_uint(ccec_ctx_n(ecPubkey
), (i
== 0) ? ccec_ctx_x(ecPubkey
) : ccec_ctx_y(ecPubkey
), len
, buffer
);
295 require_quiet(strings
[i
] = CFStringCreateMutable(kCFAllocatorDefault
, len
* 2), fail
);
296 for (size_t byteIndex
= 0; byteIndex
< len
; ++byteIndex
) {
297 CFStringAppendFormat(strings
[i
], NULL
, CFSTR("%02X"), buffer
[byteIndex
]);
301 keyDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
302 CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>"),
303 curve
, (long)SecKeyGetAlgorithmId(key
), key
->key_class
->name
, key
->key_class
->version
,
304 8 * SecKeyGetBlockSize(key
), strings
[1], strings
[0], key
);
307 CFReleaseSafe(strings
[0]);
308 CFReleaseSafe(strings
[1]);
310 keyDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
311 CFSTR("<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"),
312 curve
,(long)SecKeyGetAlgorithmId(key
), key
->key_class
->name
, key
->key_class
->version
,
313 8 * SecKeyGetBlockSize(key
), key
);
315 return keyDescription
;
318 static const struct ccec_rfc6637_curve
* get_rfc6637_curve(SecKeyRef key
)
320 SecECNamedCurve curveType
= SecECKeyGetNamedCurve(key
);
322 if (curveType
== kSecECCurveSecp256r1
) {
323 return &ccec_rfc6637_dh_curve_p256
;
324 } else if (curveType
== kSecECCurveSecp521r1
) {
325 return &ccec_rfc6637_dh_curve_p521
;
330 static CFDataRef
SecECKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
332 ccec_pub_ctx_t pubkey
;
333 int err
= errSecUnimplemented
;
334 const struct ccec_rfc6637_curve
*curve
;
335 const struct ccec_rfc6637_wrap
*wrap
= NULL
;
339 pubkey
.pub
= key
->key
;
341 if (type
!= kSecKeyWrapPublicKeyPGP
) {
342 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported key wrapping algorithm"));
346 curve
= get_rfc6637_curve(key
);
348 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
352 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPSymAlg
);
353 if (!isNumber(num
) || !CFNumberGetValue(num
, kCFNumberSInt8Type
, &sym_alg
)) {
354 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown symalg given"));
358 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
359 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
360 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
364 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
365 if (wrapAlg
== NULL
) {
366 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
368 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
369 wrap
= &ccec_rfc6637_wrap_sha256_kek_aes128
;
370 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
371 wrap
= &ccec_rfc6637_wrap_sha512_kek_aes256
;
373 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
377 num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
379 if (!CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
380 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
384 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
388 CFIndex unwrappedKey_size
= CFDataGetLength(unwrappedKey
);
390 CFIndex output_size
= ccec_rfc6637_wrap_key_size(pubkey
, flags
, unwrappedKey_size
);
391 if (output_size
== 0) {
392 SecError(errSecUnsupportedOperation
, error
, CFSTR("can't wrap that key, can't build size"));
396 CFMutableDataRef data
= CFDataCreateMutableWithScratch(NULL
, output_size
);
397 require_quiet(data
, errOut
);
399 err
= ccec_rfc6637_wrap_key(pubkey
, CFDataGetMutableBytePtr(data
), flags
,
400 sym_alg
, CFDataGetLength(unwrappedKey
), CFDataGetBytePtr(unwrappedKey
),
401 curve
, wrap
, CFDataGetBytePtr(fingerprint
),
404 SecError(errSecUnsupportedOperation
, error
, CFSTR("Failed to wrap key"));
412 SecKeyDescriptor kSecECPublicKeyDescriptor
= {
413 .version
= kSecKeyDescriptorVersion
,
414 .name
= "ECPublicKey",
415 .extraBytes
= ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
)),
416 .init
= SecECPublicKeyInit
,
417 .destroy
= SecECPublicKeyDestroy
,
418 .blockSize
= SecECPublicKeyBlockSize
,
419 .copyDictionary
= SecECPublicKeyCopyAttributeDictionary
,
420 .copyExternalRepresentation
= SecECPublicKeyCopyExternalRepresentation
,
421 .describe
= SecECPublicKeyCopyKeyDescription
,
422 .getAlgorithmID
= SecECKeyGetAlgorithmID
,
423 .copyPublic
= SecECPublicKeyCopyPublicOctets
,
424 .copyWrapKey
= SecECKeyCopyWrapKey
,
425 .copyOperationResult
= SecECPublicKeyCopyOperationResult
,
428 /* Public Key API functions. */
429 SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
430 const uint8_t *keyData
, CFIndex keyDataLength
,
431 SecKeyEncoding encoding
) {
432 return SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
, keyData
,
433 keyDataLength
, encoding
);
444 /* Private key static functions. */
445 static void SecECPrivateKeyDestroy(SecKeyRef key
) {
446 /* Zero out the public key */
447 ccec_full_ctx_t fullkey
;
448 fullkey
.hdr
= key
->key
;
449 if (ccec_ctx_cp(fullkey
).zp
)
450 cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey
))), fullkey
.hdr
);
454 static OSStatus
SecECPrivateKeyInit(SecKeyRef key
,
455 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
456 ccec_full_ctx_t fullkey
;
457 fullkey
.hdr
= key
->key
;
458 OSStatus err
= errSecParam
;
461 case kSecKeyEncodingPkcs1
:
463 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
464 //err = ecc_import(keyData, keyDataLength, fullkey);
466 /* DER != PKCS#1, but we'll go along with it */
467 const unsigned char *oid
;
471 require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength
, keyData
, (ccoid_t
*)&oid
, &n
), abort
);
472 cp
= ccec_cp_for_oid(oid
);
474 cp
= ccec_curve_for_length_lookup(n
* 8 /* bytes -> bits */,
475 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL
);
477 require_action_quiet(cp
.zp
!= NULL
, abort
, err
= errSecDecode
);
478 ccec_ctx_init(cp
, fullkey
);
480 require_noerr_quiet(ccec_der_import_priv(cp
, keyDataLength
, keyData
, fullkey
), abort
);
484 case kSecKeyEncodingBytes
:
486 ccec_const_cp_t cp
= getCPForPrivateSize(keyDataLength
);
487 require_quiet(cp
.zp
!= NULL
, abort
);
489 ccec_ctx_init(cp
, fullkey
);
490 size_t pubSize
= ccec_export_pub_size(fullkey
);
492 require_quiet(pubSize
< (size_t) keyDataLength
, abort
);
493 require_noerr_action_quiet(ccec_import_pub(cp
, pubSize
, keyData
, fullkey
),
499 keyDataLength
-= pubSize
;
501 cc_unit
*k
= ccec_ctx_k(fullkey
);
502 require_noerr_action_quiet(ccn_read_uint(ccec_ctx_n(fullkey
), k
, keyDataLength
, keyData
),
510 case kSecGenerateKey
:
512 CFDictionaryRef parameters
= (CFDictionaryRef
) keyData
;
514 CFTypeRef ksize
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
515 CFIndex keyLengthInBits
= getIntValue(ksize
);
517 ccec_const_cp_t cp
= ccec_get_cp(keyLengthInBits
);
520 secwarning("Invalid or missing key size in: %@", parameters
);
521 return errSecKeySizeNotAllowed
;
524 if (!ccec_generate_key_fips(cp
, ccrng_seckey
, fullkey
))
536 static CFTypeRef
SecECPrivateKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
537 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
538 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
539 // Default answer is 'unsupported', unless we find out that we can support it.
540 CFTypeRef result
= kCFNull
;
542 ccec_full_ctx_t fullkey
= { .hdr
= key
->key
};
544 case kSecKeyOperationTypeSign
: {
545 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
546 if (mode
== kSecKeyOperationModePerform
) {
547 // Perform r/s mode of signature.
548 cc_size r_s_size
= ccec_signature_r_s_size(fullkey
);
549 result
= CFDataCreateMutableWithScratch(NULL
, r_s_size
<< 1);
550 uint8_t *signatureBuffer
= CFDataGetMutableBytePtr((CFMutableDataRef
)result
);
551 int err
= ccec_sign_composite(fullkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
552 signatureBuffer
, signatureBuffer
+ r_s_size
, ccrng_seckey
);
553 require_action_quiet(err
== 0, out
, (CFReleaseNull(result
),
554 SecError(errSecParam
, error
, CFSTR("%@: RFC4754 signing failed (ccerr %d)"),
557 // Operation is supported.
558 result
= kCFBooleanTrue
;
560 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
561 if (mode
== kSecKeyOperationModePerform
) {
562 // Perform x962 mode of signature.
563 size_t size
= ccec_sign_max_size(ccec_ctx_cp(fullkey
));
564 result
= CFDataCreateMutableWithScratch(NULL
, size
);
565 int err
= ccec_sign(fullkey
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
),
566 &size
, CFDataGetMutableBytePtr((CFMutableDataRef
)result
), ccrng_seckey
);
567 require_action_quiet(err
== 0, out
, (CFReleaseNull(result
),
568 SecError(errSecParam
, error
, CFSTR("%@: X962 signing failed (ccerr %d)"),
570 CFDataSetLength((CFMutableDataRef
)result
, size
);
572 // Operation is supported.
573 result
= kCFBooleanTrue
;
578 case kSecKeyOperationTypeKeyExchange
:
579 if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
580 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
581 if (mode
== kSecKeyOperationModePerform
) {
583 ccec_const_cp_t cp
= getCPForPublicSize(CFDataGetLength(in1
));
584 require_action_quiet(cp
.zp
!= NULL
, out
,
585 SecError(errSecParam
, error
, CFSTR("ECpriv sharedsecret: bad public key")));
586 uint8_t pubkeyBuffer
[ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
))];
587 ccec_pub_ctx_t pubkey
= { .pub
= (struct ccec_ctx_public
*)pubkeyBuffer
};
588 err
= ccec_import_pub(cp
, CFDataGetLength(in1
), CFDataGetBytePtr(in1
), pubkey
);
589 require_noerr_action_quiet(err
, out
, SecError(errSecParam
, error
,
590 CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err
));
591 size_t size
= ccec_ccn_size(cp
);
592 result
= CFDataCreateMutableWithScratch(NULL
, size
);
593 err
= ccecdh_compute_shared_secret(fullkey
, pubkey
, &size
,
594 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), ccrng_seckey
);
595 require_noerr_action_quiet(err
, out
, (CFReleaseNull(result
),
596 SecError(errSecDecode
, error
,
597 CFSTR("ECpriv failed to compute shared secret (err %d)"), err
)));
598 CFDataSetLength((CFMutableDataRef
)result
, size
);
600 // Operation is supported.
601 result
= kCFBooleanTrue
;
613 static size_t SecECPrivateKeyBlockSize(SecKeyRef key
) {
614 ccec_full_ctx_t fullkey
;
615 fullkey
.hdr
= key
->key
;
616 /* Get key size in octets */
617 return ccec_ctx_size(fullkey
);
620 static OSStatus
SecECPrivateKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
622 ccec_full_ctx_t fullkey
;
623 fullkey
.hdr
= key
->key
;
625 CFAllocatorRef allocator
= CFGetAllocator(key
);
626 *serailziation
= SecECPublicKeyExport(allocator
, fullkey
);
628 if (NULL
== *serailziation
)
631 return errSecSuccess
;
634 static CFDataRef
SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
635 ccec_full_ctx_t fullkey
;
636 fullkey
.hdr
= key
->key
;
637 size_t prime_size
= ccec_cp_prime_size(ccec_ctx_cp(fullkey
));
638 size_t key_size
= ccec_export_pub_size(fullkey
) + prime_size
;
639 CFMutableDataRef blob
= CFDataCreateMutableWithScratch(NULL
, key_size
);
640 ccec_export_pub(fullkey
, CFDataGetMutableBytePtr(blob
));
641 UInt8
*dest
= CFDataGetMutableBytePtr(blob
) + ccec_export_pub_size(fullkey
);
642 const cc_unit
*k
= ccec_ctx_k(fullkey
);
643 ccn_write_uint_padded(ccec_ctx_n(fullkey
), k
, prime_size
, dest
);
647 static CFDictionaryRef
SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key
) {
648 /* Export the full ec key pair. */
649 ccec_full_ctx_t fullkey
;
650 fullkey
.hdr
= key
->key
;
651 CFDataRef fullKeyBlob
= SecECPrivateKeyCopyExternalRepresentation(key
, NULL
);
653 CFDictionaryRef dict
= SecKeyGeneratePrivateAttributeDictionary(key
, kSecAttrKeyTypeEC
, fullKeyBlob
);
654 CFReleaseSafe(fullKeyBlob
);
657 static CFStringRef
SecECPrivateKeyCopyKeyDescription(SecKeyRef key
) {
659 const char* curve
= getCurveName(key
);
661 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
);
665 static CFDataRef
SecECKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
667 const struct ccec_rfc6637_curve
*curve
;
668 const struct ccec_rfc6637_unwrap
*unwrap
;
669 ccec_full_ctx_t fullkey
;
670 CFMutableDataRef data
;
675 fullkey
.hdr
= key
->key
;
677 curve
= get_rfc6637_curve(key
);
679 SecError(errSecUnsupportedOperation
, error
, CFSTR("unsupported curve"));
683 CFTypeRef wrapAlg
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPWrapAlg
);
684 if (wrapAlg
== NULL
) {
685 SecError(errSecUnsupportedOperation
, error
, CFSTR("no wrap alg"));
687 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
)) {
688 unwrap
= &ccec_rfc6637_unwrap_sha256_kek_aes128
;
689 } else if (CFEqual(wrapAlg
, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
)) {
690 unwrap
= &ccec_rfc6637_unwrap_sha512_kek_aes256
;
692 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown wrap alg"));
696 CFDataRef fingerprint
= CFDictionaryGetValue(parameters
, _kSecKeyWrapPGPFingerprint
);
697 if (!isData(fingerprint
) || CFDataGetLength(fingerprint
) < kSecKeyWrapPGPFingerprintMinSize
) {
698 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid fingerprint"));
702 CFNumberRef num
= CFDictionaryGetValue(parameters
, _kSecKeyWrapRFC6637Flags
);
704 if (!CFNumberGetValue(num
, kCFNumberSInt32Type
, &flags
)) {
705 SecError(errSecUnsupportedOperation
, error
, CFSTR("invalid flags: %@"), num
);
709 SecError(errSecUnsupportedOperation
, error
, CFSTR("unknown flags"));
713 size_t keysize
= CFDataGetLength(wrappedKey
);
714 data
= CFDataCreateMutableWithScratch(NULL
, keysize
);
718 res
= ccec_rfc6637_unwrap_key(fullkey
, &keysize
, CFDataGetMutableBytePtr(data
),
719 flags
, &sym_alg
, curve
, unwrap
,
720 CFDataGetBytePtr(fingerprint
),
721 CFDataGetLength(wrappedKey
), CFDataGetBytePtr(wrappedKey
));
724 SecError(errSecUnsupportedOperation
, error
, CFSTR("failed to wrap key"));
727 assert(keysize
<= (size_t)CFDataGetLength(data
));
728 CFDataSetLength(data
, keysize
);
731 CFMutableDictionaryRef out
= CFDictionaryCreateMutableForCFTypes(NULL
);
733 CFNumberRef num
= CFNumberCreate(NULL
, kCFNumberSInt8Type
, &sym_alg
);
735 CFDictionarySetValue(out
, _kSecKeyWrapPGPSymAlg
, num
);
745 SecKeyDescriptor kSecECPrivateKeyDescriptor
= {
746 .version
= kSecKeyDescriptorVersion
,
747 .name
= "ECPrivateKey",
748 .extraBytes
= ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize
)),
750 .init
= SecECPrivateKeyInit
,
751 .destroy
= SecECPrivateKeyDestroy
,
752 .blockSize
= SecECPrivateKeyBlockSize
,
753 .copyDictionary
= SecECPrivateKeyCopyAttributeDictionary
,
754 .describe
= SecECPrivateKeyCopyKeyDescription
,
755 .getAlgorithmID
= SecECKeyGetAlgorithmID
,
756 .copyPublic
= SecECPrivateKeyCopyPublicOctets
,
757 .copyExternalRepresentation
= SecECPrivateKeyCopyExternalRepresentation
,
758 .copyWrapKey
= SecECKeyCopyWrapKey
,
759 .copyUnwrapKey
= SecECKeyCopyUnwrapKey
,
760 .copyOperationResult
= SecECPrivateKeyCopyOperationResult
,
763 /* Private Key API functions. */
764 SecKeyRef
SecKeyCreateECPrivateKey(CFAllocatorRef allocator
,
765 const uint8_t *keyData
, CFIndex keyDataLength
,
766 SecKeyEncoding encoding
) {
767 return SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
, keyData
,
768 keyDataLength
, encoding
);
772 OSStatus
SecECKeyGeneratePair(CFDictionaryRef parameters
,
773 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
774 OSStatus status
= errSecParam
;
776 CFAllocatorRef allocator
= NULL
; /* @@@ get from parameters. */
777 SecKeyRef pubKey
= NULL
;
779 SecKeyRef privKey
= SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
,
780 (const void*) parameters
, 0, kSecGenerateKey
);
782 require(privKey
, errOut
);
784 /* Create SecKeyRef's from the pkcs1 encoded keys. */
785 pubKey
= SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
,
786 privKey
->key
, 0, kSecExtractPublicFromPrivate
);
788 require(pubKey
, errOut
);
795 *privateKey
= privKey
;
799 status
= errSecSuccess
;
802 CFReleaseSafe(pubKey
);
803 CFReleaseSafe(privKey
);
809 /* It's debatable whether this belongs here or in the ssl code since the
810 curve values come from a tls related rfc4492. */
811 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
) {
812 SecECNamedCurve result
= kSecECCurveNone
;
813 CFDictionaryRef attributes
= NULL
;
814 require_quiet(SecKeyGetAlgorithmId(key
) == kSecECDSAAlgorithmID
, out
);
815 require_quiet(attributes
= SecKeyCopyAttributes(key
), out
);
816 CFTypeRef bitsRef
= CFDictionaryGetValue(attributes
, kSecAttrKeySizeInBits
);
818 require_quiet(bitsRef
!= NULL
&& CFGetTypeID(bitsRef
) == CFNumberGetTypeID() &&
819 CFNumberGetValue(bitsRef
, kCFNumberCFIndexType
, &bits
), out
);
823 result
= kSecECCurveSecp192r1
;
826 result
= kSecECCurveSecp224r1
;
830 result
= kSecECCurveSecp256r1
;
833 result
= kSecECCurveSecp384r1
;
836 result
= kSecECCurveSecp521r1
;
841 CFReleaseSafe(attributes
);
845 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
) {
846 CFDataRef bytes
= NULL
;
847 SecKeyCopyPublicBytes(key
, &bytes
);
851 /* Vile accessors that get us the pub or priv key to use temporarily */
853 bool SecECDoWithFullKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_full_ctx_t
private)) {
854 if (key
->key_class
== &kSecECPrivateKeyDescriptor
) {
857 return SecError(errSecParam
, error
, CFSTR("Not an EC Full Key object, sorry can't do."));
863 bool SecECDoWithPubKey(SecKeyRef key
, CFErrorRef
* error
, void (^action
)(ccec_pub_ctx_t
public)) {
864 if (key
->key_class
== &kSecECPublicKeyDescriptor
) {
867 return SecError(errSecParam
, error
, CFSTR("Not an EC Public Key object, sorry can't do."));