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 <security_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>
50 #define kMaximumECKeySize 521
52 static CFIndex
SecECKeyGetAlgorithmID(SecKeyRef key
) {
53 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
getCPForBits(size_t bits
)
88 ccec_const_cp_t nullCP
= { .zp
= NULL
};
93 static ccec_const_cp_t
getCPForPublicSize(CFIndex publicLength
)
96 switch (publicLength
) {
114 ccec_const_cp_t nullCP
= { .zp
= NULL
};
121 static ccec_const_cp_t
getCPForPrivateSize(CFIndex publicLength
)
124 switch (publicLength
) {
142 ccec_const_cp_t nullCP
= { .zp
= NULL
};
149 static OSStatus
SecECPublicKeyInit(SecKeyRef key
,
150 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
151 ccec_pub_ctx_t pubkey
;
152 pubkey
.pub
= key
->key
;
153 OSStatus err
= errSecParam
;
156 case kSecDERKeyEncoding
:
158 const SecDERKey
*derKey
= (const SecDERKey
*)keyData
;
159 if (keyDataLength
!= sizeof(SecDERKey
)) {
164 ccec_const_cp_t cp
= getCPForPublicSize(derKey
->keyLength
);
166 /* TODO: Parse and use real params from passed in derKey->algId.params */
167 err
= (ccec_import_pub(cp
, derKey
->keyLength
, derKey
->key
, pubkey
)
168 ? errSecDecode
: errSecSuccess
);
171 case kSecKeyEncodingBytes
:
173 ccec_const_cp_t cp
= getCPForPublicSize(keyDataLength
);
174 err
= (ccec_import_pub(cp
, keyDataLength
, keyData
, pubkey
)
175 ? errSecDecode
: errSecSuccess
);
178 case kSecExtractPublicFromPrivate
:
180 ccec_full_ctx_t fullKey
;
181 fullKey
._full
= (ccec_full_ctx
*) keyData
;
183 cc_size fullKeyN
= ccec_ctx_n(fullKey
);
184 require(fullKeyN
<= ccn_nof(kMaximumECKeySize
), errOut
);
185 memcpy(pubkey
._pub
, fullKey
.pub
, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN
)));
189 case kSecKeyEncodingApplePkcs1
:
199 static OSStatus
SecECPublicKeyRawVerify(SecKeyRef key
, SecPadding padding
,
200 const uint8_t *signedData
, size_t signedDataLen
,
201 const uint8_t *sig
, size_t sigLen
) {
202 int err
= errSSLCrypto
; // TODO: Should be errSecNotSigner;
203 ccec_pub_ctx_t pubkey
;
204 pubkey
.pub
= key
->key
;
207 if (ccec_verify(pubkey
, signedDataLen
, signedData
, sigLen
, sig
, &valid
))
208 err
= errSSLCrypto
; // TODO: This seems weird. Shouldn't be SSL error
215 static OSStatus
SecECPublicKeyRawEncrypt(SecKeyRef key
, SecPadding padding
,
216 const uint8_t *plainText
, size_t plainTextLen
,
217 uint8_t *cipherText
, size_t *cipherTextLen
) {
218 ccec_pub_ctx_t pubkey
;
219 pubkey
.pub
= key
->key
;
220 int err
= errSecUnimplemented
;
223 require_noerr(err
= ccec_wrap_key(pubkey
, &ccsha256_di
,
224 plainTextLen
, plainText
, cipherText
), errOut
);
231 static size_t SecECPublicKeyBlockSize(SecKeyRef key
) {
232 /* Get key size in octets */
233 ccec_pub_ctx_t pubkey
;
234 pubkey
.pub
= key
->key
;
235 return ccec_ccn_size(ccec_ctx_cp(pubkey
));
238 /* Encode the public key and return it in a newly allocated CFDataRef. */
239 static CFDataRef
SecECPublicKeyExport(CFAllocatorRef allocator
,
240 ccec_pub_ctx_t pubkey
) {
241 size_t pub_size
= ccec_export_pub_size(pubkey
);
242 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, pub_size
);
244 CFDataSetLength(blob
, pub_size
);
245 ccec_export_pub(pubkey
, CFDataGetMutableBytePtr(blob
));
251 static OSStatus
SecECPublicKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
253 ccec_pub_ctx_t pubkey
;
254 pubkey
.pub
= key
->key
;
256 CFAllocatorRef allocator
= CFGetAllocator(key
);
257 *serailziation
= SecECPublicKeyExport(allocator
, pubkey
);
259 if (NULL
== *serailziation
)
262 return errSecSuccess
;
265 static CFDictionaryRef
SecECPublicKeyCopyAttributeDictionary(SecKeyRef key
) {
266 return SecKeyGeneratePublicAttributeDictionary(key
, kSecAttrKeyTypeEC
);
269 SecKeyDescriptor kSecECPublicKeyDescriptor
= {
270 kSecKeyDescriptorVersion
,
272 ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
274 SecECPublicKeyDestroy
,
275 NULL
, /* SecKeyRawSignMethod */
276 SecECPublicKeyRawVerify
,
277 SecECPublicKeyRawEncrypt
,
278 NULL
, /* SecKeyDecryptMethod */
279 NULL
, /* SecKeyComputeMethod */
280 SecECPublicKeyBlockSize
,
281 SecECPublicKeyCopyAttributeDictionary
,
282 SecECKeyGetAlgorithmID
,
283 SecECPublicKeyCopyPublicOctets
,
286 /* Public Key API functions. */
287 SecKeyRef
SecKeyCreateECPublicKey(CFAllocatorRef allocator
,
288 const uint8_t *keyData
, CFIndex keyDataLength
,
289 SecKeyEncoding encoding
) {
290 return SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
, keyData
,
291 keyDataLength
, encoding
);
302 /* Private key static functions. */
303 static void SecECPrivateKeyDestroy(SecKeyRef key
) {
304 /* Zero out the public key */
305 ccec_full_ctx_t fullkey
;
306 fullkey
.hdr
= key
->key
;
307 if (ccec_ctx_cp(fullkey
).zp
)
308 cc_zero(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey
))), fullkey
.hdr
);
312 static OSStatus
SecECPrivateKeyInit(SecKeyRef key
,
313 const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
314 ccec_full_ctx_t fullkey
;
315 fullkey
.hdr
= key
->key
;
316 OSStatus err
= errSecParam
;
319 case kSecKeyEncodingPkcs1
:
320 /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
321 //err = ecc_import(keyData, keyDataLength, fullkey);
323 case kSecKeyEncodingBytes
:
325 ccec_const_cp_t cp
= getCPForPrivateSize(keyDataLength
);
326 require(cp
.zp
!= NULL
, abort
);
328 ccec_ctx_init(cp
, fullkey
);
329 size_t pubSize
= ccec_export_pub_size(fullkey
);
331 require(pubSize
< (size_t) keyDataLength
, abort
);
332 require_noerr_action(ccec_import_pub(cp
, pubSize
, keyData
, fullkey
),
338 keyDataLength
-= pubSize
;
340 cc_unit
*k
= ccec_ctx_k(fullkey
);
341 require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey
), k
, keyDataLength
, keyData
),
349 case kSecGenerateKey
:
351 CFDictionaryRef parameters
= (CFDictionaryRef
) keyData
;
353 CFTypeRef ksize
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
354 CFIndex keyLengthInBits
= getIntValue(ksize
);
356 ccec_const_cp_t cp
= getCPForBits(keyLengthInBits
);
359 secwarning("Invalid or missing key size in: %@", parameters
);
360 return errSecKeySizeNotAllowed
;
363 if (!ccec_generate_key(cp
, ccrng_seckey
, fullkey
))
375 static OSStatus
SecECPrivateKeyRawSign(SecKeyRef key
, SecPadding padding
,
376 const uint8_t *dataToSign
, size_t dataToSignLen
,
377 uint8_t *sig
, size_t *sigLen
) {
378 ccec_full_ctx_t fullkey
;
379 fullkey
.hdr
= key
->key
;
383 require_noerr(err
= ccec_sign(fullkey
, dataToSignLen
, dataToSign
,
384 sigLen
, sig
, ccrng_seckey
), errOut
);
391 static const struct ccdigest_info
*
392 ccdigest_lookup_by_oid(unsigned long oid_size
, const void *oid
) {
393 static const struct ccdigest_info
*dis
[] = {
401 for (i
= 0; i
< sizeof(dis
) / sizeof(*dis
); ++i
) {
402 if (oid_size
== dis
[i
]->oid_size
&& !memcmp(dis
[i
]->oid
, oid
, oid_size
))
409 static OSStatus
SecECPrivateKeyRawDecrypt(SecKeyRef key
, SecPadding padding
,
410 const uint8_t *cipherText
, size_t cipherTextLen
,
411 uint8_t *plainText
, size_t *plainTextLen
) {
412 ccec_full_ctx_t fullkey
;
413 fullkey
.hdr
= key
->key
;
414 int err
= errSecUnimplemented
;
417 err
= ccec_unwrap_key(fullkey
, ccrng_seckey
, ccdigest_lookup_by_oid
,
418 cipherTextLen
, cipherText
, plainTextLen
, plainText
);
424 static size_t SecECPrivateKeyBlockSize(SecKeyRef key
) {
425 ccec_full_ctx_t fullkey
;
426 fullkey
.hdr
= key
->key
;
427 /* Get key size in octets */
428 return ccec_ccn_size(ccec_ctx_cp(fullkey
));
431 static OSStatus
SecECPrivateKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*serailziation
)
433 ccec_full_ctx_t fullkey
;
434 fullkey
.hdr
= key
->key
;
436 CFAllocatorRef allocator
= CFGetAllocator(key
);
437 *serailziation
= SecECPublicKeyExport(allocator
, fullkey
);
439 if (NULL
== *serailziation
)
442 return errSecSuccess
;
445 static CFDataRef
SecECPPrivateKeyExport(CFAllocatorRef allocator
,
446 ccec_full_ctx_t fullkey
) {
447 size_t prime_size
= ccec_cp_prime_size(ccec_ctx_cp(fullkey
));
448 size_t key_size
= ccec_export_pub_size(fullkey
) + prime_size
;
449 CFMutableDataRef blob
= CFDataCreateMutable(allocator
, key_size
);
451 CFDataSetLength(blob
, key_size
);
452 ccec_export_pub(fullkey
, CFDataGetMutableBytePtr(blob
));
453 UInt8
*dest
= CFDataGetMutableBytePtr(blob
) + ccec_export_pub_size(fullkey
);
454 const cc_unit
*k
= ccec_ctx_k(fullkey
);
455 ccn_write_uint_padded(ccec_ctx_n(fullkey
), k
, prime_size
, dest
);
462 static CFDictionaryRef
SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key
) {
463 CFDictionaryRef dict
= NULL
;
464 CFAllocatorRef allocator
= CFGetAllocator(key
);
466 ccec_full_ctx_t fullkey
;
467 fullkey
.hdr
= key
->key
;
469 CFDataRef fullKeyBlob
= NULL
;
471 /* Export the full ec key pair. */
472 require(fullKeyBlob
= SecECPPrivateKeyExport(allocator
, fullkey
), errOut
);
474 dict
= SecKeyGeneratePrivateAttributeDictionary(key
, kSecAttrKeyTypeEC
, fullKeyBlob
);
477 CFReleaseSafe(fullKeyBlob
);
482 SecKeyDescriptor kSecECPrivateKeyDescriptor
= {
483 kSecKeyDescriptorVersion
,
485 ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize
)), /* extraBytes */
487 SecECPrivateKeyDestroy
,
488 SecECPrivateKeyRawSign
,
489 NULL
, /* SecKeyRawVerifyMethod */
490 NULL
, /* SecKeyEncryptMethod */
491 SecECPrivateKeyRawDecrypt
,
492 NULL
, /* SecKeyComputeMethod */
493 SecECPrivateKeyBlockSize
,
494 SecECPrivateKeyCopyAttributeDictionary
,
495 SecECKeyGetAlgorithmID
,
496 SecECPrivateKeyCopyPublicOctets
,
499 /* Private Key API functions. */
500 SecKeyRef
SecKeyCreateECPrivateKey(CFAllocatorRef allocator
,
501 const uint8_t *keyData
, CFIndex keyDataLength
,
502 SecKeyEncoding encoding
) {
503 return SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
, keyData
,
504 keyDataLength
, encoding
);
508 OSStatus
SecECKeyGeneratePair(CFDictionaryRef parameters
,
509 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
510 OSStatus status
= errSecParam
;
512 CFAllocatorRef allocator
= NULL
; /* @@@ get from parameters. */
513 SecKeyRef pubKey
= NULL
;
515 SecKeyRef privKey
= SecKeyCreate(allocator
, &kSecECPrivateKeyDescriptor
,
516 (const void*) parameters
, 0, kSecGenerateKey
);
518 require(privKey
, errOut
);
520 /* Create SecKeyRef's from the pkcs1 encoded keys. */
521 pubKey
= SecKeyCreate(allocator
, &kSecECPublicKeyDescriptor
,
522 privKey
->key
, 0, kSecExtractPublicFromPrivate
);
524 require(pubKey
, errOut
);
531 *privateKey
= privKey
;
535 status
= errSecSuccess
;
538 CFReleaseSafe(pubKey
);
539 CFReleaseSafe(privKey
);
545 /* It's debatable whether this belongs here or in the ssl code since the
546 curve values come from a tls related rfc4492. */
547 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
) {
548 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
549 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
550 return kSecECCurveNone
;
552 ccec_pub_ctx_t pubkey
;
553 pubkey
.pub
= key
->key
;
554 switch (ccec_cp_prime_size(ccec_ctx_cp(pubkey
))) {
557 return kSecECCurveSecp192r1
;
559 return kSecECCurveSecp224r1
;
562 return kSecECCurveSecp256r1
;
564 return kSecECCurveSecp384r1
;
566 return kSecECCurveSecp521r1
;
568 return kSecECCurveNone
;
571 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
) {
572 if (key
->key_class
!= &kSecECPublicKeyDescriptor
&&
573 key
->key_class
!= &kSecECPrivateKeyDescriptor
)
576 ccec_pub_ctx_t pubkey
;
577 pubkey
.pub
= key
->key
;
578 return SecECPublicKeyExport(CFGetAllocator(key
), pubkey
);