2 * Copyright (c) 2010,2011 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
30 #include <Security/SecKeyInternal.h>
31 #include <Security/SecItem.h>
32 #include <Security/SecBasePriv.h>
33 #include <AssertMacros.h>
34 #include <Security/SecureTransport.h> /* For error codes. */
35 #include <CoreFoundation/CFData.h> /* For error codes. */
37 #include <sys/types.h>
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 <corecrypto/ccec.h>
46 #include <corecrypto/ccsha1.h>
47 #include <corecrypto/ccsha2.h>
48 #include <corecrypto/ccrng.h>
49 #include <corecrypto/ccder_decode_eckey.h>
51 #define kMaximumECKeySize 521
53 static CFIndex
SecECKeyGetAlgorithmID(SecKeyRef key
) {
54 return kSecECDSAAlgorithmID
;
64 /* Public key static functions. */
65 static void SecECPublicKeyDestroy(SecKeyRef key
) {
66 /* Zero out the public key */
67 ccec_pub_ctx_t pubkey
;
68 pubkey
.pub
= key
->key
;
69 if (ccec_ctx_cp(pubkey
).zp
)
70 cc_zero(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey
))), pubkey
.pub
);
73 static ccec_const_cp_t
getCPForPublicSize(CFIndex encoded_length
)
75 size_t keysize
= ccec_x963_import_pub_size(encoded_length
);
76 if(ccec_keysize_is_supported(keysize
)) {
77 return ccec_get_cp(keysize
);
79 ccec_const_cp_t nullCP
= { .zp
= NULL
};
83 static ccec_const_cp_t
getCPForPrivateSize(CFIndex encoded_length
)
85 size_t keysize
= ccec_x963_import_priv_size(encoded_length
);
86 if(ccec_keysize_is_supported(keysize
)) {
87 return ccec_get_cp(keysize
);
89 ccec_const_cp_t nullCP
= { .zp
= NULL
};
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
;
99 static ccec_const_cp_t
ccec_cp_for_oid(ccoid_t oid
)
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();
114 return (ccec_const_cp_t
){NULL
};
117 static OSStatus
SecECPublicKeyInit(SecKeyRef key
,
118 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
119 ccec_pub_ctx_t pubkey
;
120 pubkey
.pub
= 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
);
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
);
139 case kSecKeyEncodingBytes
:
141 ccec_const_cp_t cp
= getCPForPublicSize(keyDataLength
);
142 err
= (ccec_import_pub(cp
, keyDataLength
, keyData
, pubkey
)
143 ? errSecDecode
: errSecSuccess
);
146 case kSecExtractPublicFromPrivate
:
148 ccec_full_ctx_t fullKey
;
149 fullKey
._full
= (ccec_full_ctx
*) keyData
;
151 cc_size fullKeyN
= ccec_ctx_n(fullKey
);
152 require(fullKeyN
<= ccn_nof(kMaximumECKeySize
), errOut
);
153 memcpy(pubkey
._pub
, fullKey
.pub
, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN
)));
157 case kSecKeyEncodingApplePkcs1
:
167 static OSStatus
SecECPublicKeyRawVerify(SecKeyRef key
, SecPadding padding
,
168 const uint8_t *signedData
, size_t signedDataLen
,
169 const uint8_t *sig
, size_t sigLen
) {
170 int err
= errSSLCrypto
; // TODO: Should be errSecNotSigner;
171 ccec_pub_ctx_t pubkey
;
172 pubkey
.pub
= key
->key
;
175 if (ccec_verify(pubkey
, signedDataLen
, signedData
, sigLen
, sig
, &valid
))
176 err
= errSSLCrypto
; // TODO: This seems weird. Shouldn't be SSL error
183 static OSStatus
SecECPublicKeyRawEncrypt(SecKeyRef key
, SecPadding padding
,
184 const uint8_t *plainText
, size_t plainTextLen
,
185 uint8_t *cipherText
, size_t *cipherTextLen
) {
186 ccec_pub_ctx_t pubkey
;
187 pubkey
.pub
= key
->key
;
188 int err
= errSecUnimplemented
;
191 require_noerr(err
= ccec_wrap_key(pubkey
, &ccsha256_di
,
192 plainTextLen
, plainText
, cipherText
), errOut
);
199 static size_t SecECPublicKeyBlockSize(SecKeyRef key
) {
200 /* Get key size in octets */
201 ccec_pub_ctx_t pubkey
;
202 pubkey
.pub
= key
->key
;
203 return ccec_ctx_size(pubkey
);
206 /* Encode the public key and return it in a newly allocated CFDataRef. */
207 static CFDataRef
SecECPublicKeyExport(CFAllocatorRef allocator
,
208 ccec_pub_ctx_t pubkey
) {
209 size_t pub_size
= ccec_export_pub_size(pubkey
);
210 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, pub_size
);
212 CFDataSetLength(blob
, pub_size
);
213 ccec_export_pub(pubkey
, CFDataGetMutableBytePtr(blob
));
219 static OSStatus
SecECPublicKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
221 ccec_pub_ctx_t pubkey
;
222 pubkey
.pub
= key
->key
;
224 CFAllocatorRef allocator
= CFGetAllocator(key
);
225 *serailziation
= SecECPublicKeyExport(allocator
, pubkey
);
227 if (NULL
== *serailziation
)
230 return errSecSuccess
;
233 static CFDictionaryRef
SecECPublicKeyCopyAttributeDictionary(SecKeyRef key
) {
234 return SecKeyGeneratePublicAttributeDictionary(key
, kSecAttrKeyTypeEC
);
237 static CFStringRef
SecECPublicKeyCopyKeyDescription(SecKeyRef key
)
239 ccec_pub_ctx_t ecPubkey
;
240 CFStringRef keyDescription
= NULL
;
241 size_t xlen
, ylen
, ix
;
242 CFMutableStringRef xString
= NULL
;
243 CFMutableStringRef yString
= NULL
;
245 ecPubkey
.pub
= key
->key
;
248 long curveType
= (long)SecECKeyGetNamedCurve(key
);
254 curve
= "kSecECCurveSecp256r1";
257 curve
= "kSecECCurveSecp384r1";
260 curve
= "kSecECCurveSecp521r1";
263 curve
= "kSecECCurveNone";
266 curve
= "kSecECCurveNone";
270 uint8_t *xunit
= (uint8_t*)ccec_ctx_x(ecPubkey
);
271 require_quiet( NULL
!= xunit
, fail
);
272 xlen
= (size_t)strlen((char*)xunit
);
275 xString
= CFStringCreateMutable(kCFAllocatorDefault
, xlen
* 2);
276 require_quiet( NULL
!= xString
, fail
);
278 for (ix
= 0; ix
< xlen
; ++ix
)
280 CFStringAppendFormat(xString
, NULL
, CFSTR("%02X"), xunit
[ix
]);
283 uint8_t *yunit
= (uint8_t*)ccec_ctx_y(ecPubkey
);
284 require_quiet( NULL
!= yunit
, fail
);
285 ylen
= (size_t)strlen((char*)yunit
);
287 yString
= CFStringCreateMutable(kCFAllocatorDefault
, ylen
*2);
288 require_quiet( NULL
!= yString
, fail
);
290 for(ix
= 0; ix
< ylen
; ++ix
)
292 CFStringAppendFormat(yString
, NULL
, CFSTR("%02X"), yunit
[ix
]);
295 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
);
298 CFReleaseSafe(xString
);
299 CFReleaseSafe(yString
);
301 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
);
303 return keyDescription
;
306 SecKeyDescriptor kSecECPublicKeyDescriptor
= {
307 kSecKeyDescriptorVersion
,
309 ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
311 SecECPublicKeyDestroy
,
312 NULL
, /* SecKeyRawSignMethod */
313 SecECPublicKeyRawVerify
,
314 SecECPublicKeyRawEncrypt
,
315 NULL
, /* SecKeyDecryptMethod */
316 NULL
, /* SecKeyComputeMethod */
317 SecECPublicKeyBlockSize
,
318 SecECPublicKeyCopyAttributeDictionary
,
319 SecECPublicKeyCopyKeyDescription
,
320 SecECKeyGetAlgorithmID
,
321 SecECPublicKeyCopyPublicOctets
,
324 /* Public Key API functions. */
325 SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
326 const uint8_t *keyData
, CFIndex keyDataLength
,
327 SecKeyEncoding encoding
) {
328 return SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
, keyData
,
329 keyDataLength
, encoding
);
340 /* Private key static functions. */
341 static void SecECPrivateKeyDestroy(SecKeyRef key
) {
342 /* Zero out the public key */
343 ccec_full_ctx_t fullkey
;
344 fullkey
.hdr
= key
->key
;
345 if (ccec_ctx_cp(fullkey
).zp
)
346 cc_zero(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey
))), fullkey
.hdr
);
350 static OSStatus
SecECPrivateKeyInit(SecKeyRef key
,
351 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
352 ccec_full_ctx_t fullkey
;
353 fullkey
.hdr
= key
->key
;
354 OSStatus err
= errSecParam
;
357 case kSecKeyEncodingPkcs1
:
359 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
360 //err = ecc_import(keyData, keyDataLength, fullkey);
362 /* DER != PKCS#1, but we'll go along with it */
367 require_noerr(ccec_der_import_priv_keytype(keyDataLength
, keyData
, &oid
, &n
), abort
);
368 cp
= ccec_cp_for_oid(oid
);
370 cp
= ccec_curve_for_length_lookup(n
* 8 /* bytes -> bits */,
371 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL
);
373 require_action(cp
.zp
!= NULL
, abort
, err
= errSecDecode
);
374 ccec_ctx_init(cp
, fullkey
);
376 require_noerr(ccec_der_import_priv(cp
, keyDataLength
, keyData
, fullkey
), abort
);
380 case kSecKeyEncodingBytes
:
382 ccec_const_cp_t cp
= getCPForPrivateSize(keyDataLength
);
383 require(cp
.zp
!= NULL
, abort
);
385 ccec_ctx_init(cp
, fullkey
);
386 size_t pubSize
= ccec_export_pub_size(fullkey
);
388 require(pubSize
< (size_t) keyDataLength
, abort
);
389 require_noerr_action(ccec_import_pub(cp
, pubSize
, keyData
, fullkey
),
395 keyDataLength
-= pubSize
;
397 cc_unit
*k
= ccec_ctx_k(fullkey
);
398 require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey
), k
, keyDataLength
, keyData
),
406 case kSecGenerateKey
:
408 CFDictionaryRef parameters
= (CFDictionaryRef
) keyData
;
410 CFTypeRef ksize
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
411 CFIndex keyLengthInBits
= getIntValue(ksize
);
413 ccec_const_cp_t cp
= ccec_get_cp(keyLengthInBits
);
416 secwarning("Invalid or missing key size in: %@", parameters
);
417 return errSecKeySizeNotAllowed
;
420 if (!ccec_generate_key(cp
, ccrng_seckey
, fullkey
))
432 static OSStatus
SecECPrivateKeyRawSign(SecKeyRef key
, SecPadding padding
,
433 const uint8_t *dataToSign
, size_t dataToSignLen
,
434 uint8_t *sig
, size_t *sigLen
) {
435 ccec_full_ctx_t fullkey
;
436 fullkey
.hdr
= key
->key
;
440 require_noerr(err
= ccec_sign(fullkey
, dataToSignLen
, dataToSign
,
441 sigLen
, sig
, ccrng_seckey
), errOut
);
448 static const struct ccdigest_info
*
449 ccdigest_lookup_by_oid(unsigned long oid_size
, const void *oid
) {
450 static const struct ccdigest_info
*dis
[] = {
458 for (i
= 0; i
< array_size(dis
); ++i
) {
459 if (oid_size
== dis
[i
]->oid_size
&& !memcmp(dis
[i
]->oid
, oid
, oid_size
))
466 static OSStatus
SecECPrivateKeyRawDecrypt(SecKeyRef key
, SecPadding padding
,
467 const uint8_t *cipherText
, size_t cipherTextLen
,
468 uint8_t *plainText
, size_t *plainTextLen
) {
469 ccec_full_ctx_t fullkey
;
470 fullkey
.hdr
= key
->key
;
471 int err
= errSecUnimplemented
;
474 err
= ccec_unwrap_key(fullkey
, ccrng_seckey
, ccdigest_lookup_by_oid
,
475 cipherTextLen
, cipherText
, plainTextLen
, plainText
);
481 static size_t SecECPrivateKeyBlockSize(SecKeyRef key
) {
482 ccec_full_ctx_t fullkey
;
483 fullkey
.hdr
= key
->key
;
484 /* Get key size in octets */
485 return ccec_ctx_size(fullkey
);
488 static OSStatus
SecECPrivateKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
490 ccec_full_ctx_t fullkey
;
491 fullkey
.hdr
= key
->key
;
493 CFAllocatorRef allocator
= CFGetAllocator(key
);
494 *serailziation
= SecECPublicKeyExport(allocator
, fullkey
);
496 if (NULL
== *serailziation
)
499 return errSecSuccess
;
502 static CFDataRef
SecECPPrivateKeyExport(CFAllocatorRef allocator
,
503 ccec_full_ctx_t fullkey
) {
504 size_t prime_size
= ccec_cp_prime_size(ccec_ctx_cp(fullkey
));
505 size_t key_size
= ccec_export_pub_size(fullkey
) + prime_size
;
506 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, key_size
);
508 CFDataSetLength(blob
, key_size
);
509 ccec_export_pub(fullkey
, CFDataGetMutableBytePtr(blob
));
510 UInt8
*dest
= CFDataGetMutableBytePtr(blob
) + ccec_export_pub_size(fullkey
);
511 const cc_unit
*k
= ccec_ctx_k(fullkey
);
512 ccn_write_uint_padded(ccec_ctx_n(fullkey
), k
, prime_size
, dest
);
519 static CFDictionaryRef
SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key
) {
520 CFDictionaryRef dict
= NULL
;
521 CFAllocatorRef allocator
= CFGetAllocator(key
);
523 ccec_full_ctx_t fullkey
;
524 fullkey
.hdr
= key
->key
;
526 CFDataRef fullKeyBlob
= NULL
;
528 /* Export the full ec key pair. */
529 require(fullKeyBlob
= SecECPPrivateKeyExport(allocator
, fullkey
), errOut
);
531 dict
= SecKeyGeneratePrivateAttributeDictionary(key
, kSecAttrKeyTypeEC
, fullKeyBlob
);
534 CFReleaseSafe(fullKeyBlob
);
538 static CFStringRef
SecECPrivateKeyCopyKeyDescription(SecKeyRef key
) {
541 long curveType
= (long)SecECKeyGetNamedCurve(key
);
547 curve
= "kSecECCurveSecp256r1";
550 curve
= "kSecECCurveSecp384r1";
553 curve
= "kSecECCurveSecp521r1";
556 curve
= "kSecECCurveNone";
559 curve
= "kSecECCurveNone";
563 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
);
567 SecKeyDescriptor kSecECPrivateKeyDescriptor
= {
568 kSecKeyDescriptorVersion
,
570 ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
572 SecECPrivateKeyDestroy
,
573 SecECPrivateKeyRawSign
,
574 NULL
, /* SecKeyRawVerifyMethod */
575 NULL
, /* SecKeyEncryptMethod */
576 SecECPrivateKeyRawDecrypt
,
577 NULL
, /* SecKeyComputeMethod */
578 SecECPrivateKeyBlockSize
,
579 SecECPrivateKeyCopyAttributeDictionary
,
580 SecECPrivateKeyCopyKeyDescription
,
581 SecECKeyGetAlgorithmID
,
582 SecECPrivateKeyCopyPublicOctets
,
585 /* Private Key API functions. */
586 SecKeyRef
SecKeyCreateECPrivateKey(CFAllocatorRef allocator
,
587 const uint8_t *keyData
, CFIndex keyDataLength
,
588 SecKeyEncoding encoding
) {
589 return SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
, keyData
,
590 keyDataLength
, encoding
);
594 OSStatus
SecECKeyGeneratePair(CFDictionaryRef parameters
,
595 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
596 OSStatus status
= errSecParam
;
598 CFAllocatorRef allocator
= NULL
; /* @@@ get from parameters. */
599 SecKeyRef pubKey
= NULL
;
601 SecKeyRef privKey
= SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
,
602 (const void*) parameters
, 0, kSecGenerateKey
);
604 require(privKey
, errOut
);
606 /* Create SecKeyRef's from the pkcs1 encoded keys. */
607 pubKey
= SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
,
608 privKey
->key
, 0, kSecExtractPublicFromPrivate
);
610 require(pubKey
, errOut
);
617 *privateKey
= privKey
;
621 status
= errSecSuccess
;
624 CFReleaseSafe(pubKey
);
625 CFReleaseSafe(privKey
);
631 /* It's debatable whether this belongs here or in the ssl code since the
632 curve values come from a tls related rfc4492. */
633 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
) {
634 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
635 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
636 return kSecECCurveNone
;
638 ccec_pub_ctx_t pubkey
;
639 pubkey
.pub
= key
->key
;
640 switch (ccec_ctx_size(pubkey
)) {
643 return kSecECCurveSecp192r1
;
645 return kSecECCurveSecp224r1
;
648 return kSecECCurveSecp256r1
;
650 return kSecECCurveSecp384r1
;
652 return kSecECCurveSecp521r1
;
654 return kSecECCurveNone
;
657 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
) {
658 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
659 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
662 ccec_pub_ctx_t pubkey
;
663 pubkey
.pub
= key
->key
;
664 return SecECPublicKeyExport(CFGetAllocator(key
), pubkey
);