1/*
2 * Copyright (c) 2010,2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * SecECKey.c - CoreFoundation based rsa key object
26 */
27
28#include "SecECKey.h"
29
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. */
36#include <fcntl.h>
37#include <sys/types.h>
38#include <unistd.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>
50
51#define kMaximumECKeySize 521
52
53static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) {
54    return kSecECDSAAlgorithmID;
55}
56
57
58/*
59 *
60 * Public Key
61 *
62 */
63
64/* Public key static functions. */
65static 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);
71}
72
73static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length)
74{
75    size_t keysize = ccec_x963_import_pub_size(encoded_length);
76    if(ccec_keysize_is_supported(keysize)) {
77        return ccec_get_cp(keysize);
78    }
79    ccec_const_cp_t nullCP = { .zp = NULL };
80    return nullCP;
81}
82
83static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length)
84{
85    size_t keysize = ccec_x963_import_priv_size(encoded_length);
86    if(ccec_keysize_is_supported(keysize)) {
87        return ccec_get_cp(keysize);
88    }
89    ccec_const_cp_t nullCP = { .zp = NULL };
90    return nullCP;
91}
92
93static ccoid_t ccoid_secp192r1 = CC_EC_OID_SECP192R1;
94static ccoid_t ccoid_secp256r1 = CC_EC_OID_SECP256R1;
95static ccoid_t ccoid_secp224r1 = CC_EC_OID_SECP224R1;
96static ccoid_t ccoid_secp384r1 = CC_EC_OID_SECP384R1;
97static ccoid_t ccoid_secp521r1 = CC_EC_OID_SECP521R1;
98
99static ccec_const_cp_t ccec_cp_for_oid(ccoid_t oid)
100{
101    if (oid.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();
112        }
113    }
114    return (ccec_const_cp_t){NULL};
115}
116
117static 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;
122
123    switch (encoding) {
124    case kSecDERKeyEncoding:
125    {
126        const SecDERKey *derKey = (const SecDERKey *)keyData;
127        if (keyDataLength != sizeof(SecDERKey)) {
128            err = errSecDecode;
129            break;
130        }
131
132        ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength);
133
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);
137        break;
138    }
139    case kSecKeyEncodingBytes:
140    {
141        ccec_const_cp_t cp = getCPForPublicSize(keyDataLength);
142        err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey)
143               ? errSecDecode : errSecSuccess);
144        break;
145    }
146    case kSecExtractPublicFromPrivate:
147    {
148        ccec_full_ctx_t fullKey;
149        fullKey._full = (ccec_full_ctx *) keyData;
150
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)));
154        err = errSecSuccess;
155        break;
156    }
157    case kSecKeyEncodingApplePkcs1:
158    default:
159        err = errSecParam;
160        break;
161    }
162
163errOut:
164    return err;
165}
166
167static 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;
173    bool valid = 0;
174
175    if (ccec_verify(pubkey, signedDataLen, signedData, sigLen, sig, &valid))
176        err = errSSLCrypto; // TODO: This seems weird. Shouldn't be SSL error
177    if (valid)
178        err = errSecSuccess;
179
180    return err;
181}
182
183static 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;
189
190#if 0
191    require_noerr(err = ccec_wrap_key(pubkey, &ccsha256_di,
192                                      plainTextLen, plainText, cipherText), errOut);
193
194errOut:
195#endif
196    return err;
197}
198
199static 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);
204}
205
206/* Encode the public key and return it in a newly allocated CFDataRef. */
207static 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);
211    if (blob) {
212        CFDataSetLength(blob, pub_size);
213        ccec_export_pub(pubkey, CFDataGetMutableBytePtr(blob));
214    }
215
216	return blob;
217}
218
219static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
220{
221    ccec_pub_ctx_t pubkey;
222    pubkey.pub = key->key;
223
224	CFAllocatorRef allocator = CFGetAllocator(key);
225    *serailziation = SecECPublicKeyExport(allocator, pubkey);
226
227    if (NULL == *serailziation)
228        return errSecDecode;
229    else
230        return errSecSuccess;
231}
232
233static CFDictionaryRef SecECPublicKeyCopyAttributeDictionary(SecKeyRef key) {
234    return SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeEC);
235}
236
237static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key)
238{
239    ccec_pub_ctx_t ecPubkey;
240    CFStringRef keyDescription = NULL;
241    size_t xlen, ylen, ix;
242    CFMutableStringRef xString = NULL;
243    CFMutableStringRef yString = NULL;
244
245    ecPubkey.pub = key->key;
246
247    //curve
248    long curveType = (long)SecECKeyGetNamedCurve(key);
249    char* curve= NULL;
250
251    switch (curveType)
252 	{
253        case 23:
254            curve = "kSecECCurveSecp256r1";
255            break;
256        case 24:
257            curve = "kSecECCurveSecp384r1";
258            break;
259        case 25:
260            curve = "kSecECCurveSecp521r1";
261            break;
262        case -1:
263            curve = "kSecECCurveNone";
264            break;
265        default:
266            curve = "kSecECCurveNone";
267            break;
268    }
269
270    uint8_t *xunit = (uint8_t*)ccec_ctx_x(ecPubkey);
271    require_quiet( NULL != xunit, fail);
272    xlen = (size_t)strlen((char*)xunit);
273
274
275    xString = CFStringCreateMutable(kCFAllocatorDefault, xlen * 2);
276    require_quiet( NULL != xString, fail);
277
278    for (ix = 0; ix < xlen; ++ix)
279    {
280		CFStringAppendFormat(xString, NULL, CFSTR("%02X"), xunit[ix]);
281    }
282
283    uint8_t *yunit = (uint8_t*)ccec_ctx_y(ecPubkey);
284    require_quiet( NULL != yunit, fail);
285    ylen = (size_t)strlen((char*)yunit);
286
287    yString = CFStringCreateMutable(kCFAllocatorDefault, ylen*2);
288    require_quiet( NULL != yString, fail);
289
290    for(ix = 0; ix < ylen; ++ix)
291    {
292        CFStringAppendFormat(yString, NULL, CFSTR("%02X"), yunit[ix]);
293    }
294
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);
296
297fail:
298	CFReleaseSafe(xString);
299	CFReleaseSafe(yString);
300	if(!keyDescription)
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);
302
303	return keyDescription;
304}
305
306SecKeyDescriptor kSecECPublicKeyDescriptor = {
307    kSecKeyDescriptorVersion,
308    "ECPublicKey",
309    ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize)), /* extraBytes */
310    SecECPublicKeyInit,
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,
322};
323
324/* Public Key API functions. */
325SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
326    const uint8_t *keyData, CFIndex keyDataLength,
327    SecKeyEncoding encoding) {
328    return SecKeyCreate(allocator, &kSecECPublicKeyDescriptor, keyData,
329        keyDataLength, encoding);
330}
331
332
333
334/*
335 *
336 * Private Key
337 *
338 */
339
340/* Private key static functions. */
341static 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);
347}
348
349
350static 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;
355
356    switch (encoding) {
357    case kSecKeyEncodingPkcs1:
358    {
359        /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
360        //err = ecc_import(keyData, keyDataLength, fullkey);
361
362        /* DER != PKCS#1, but we'll go along with it */
363        ccoid_t oid;
364        size_t n;
365        ccec_const_cp_t cp;
366
367        require_noerr(ccec_der_import_priv_keytype(keyDataLength, keyData, &oid, &n), abort);
368        cp = ccec_cp_for_oid(oid);
369        if (cp.zp == NULL) {
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);
372        }
373        require_action(cp.zp != NULL, abort, err = errSecDecode);
374        ccec_ctx_init(cp, fullkey);
375
376        require_noerr(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort);
377        err = errSecSuccess;
378        break;
379    }
380    case kSecKeyEncodingBytes:
381    {
382        ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength);
383        require(cp.zp != NULL, abort);
384
385        ccec_ctx_init(cp, fullkey);
386        size_t pubSize = ccec_export_pub_size(fullkey);
387
388        require(pubSize < (size_t) keyDataLength, abort);
389        require_noerr_action(ccec_import_pub(cp, pubSize, keyData, fullkey),
390                             abort,
391                             err = errSecDecode);
392
393
394        keyData += pubSize;
395        keyDataLength -= pubSize;
396
397        cc_unit *k = ccec_ctx_k(fullkey);
398        require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData),
399                             abort,
400                             err = errSecDecode);
401
402        err = errSecSuccess;
403        break;
404
405    }
406    case kSecGenerateKey:
407    {
408        CFDictionaryRef parameters = (CFDictionaryRef) keyData;
409
410        CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
411        CFIndex keyLengthInBits = getIntValue(ksize);
412
413        ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits);
414
415        if (!cp.zp) {
416            secwarning("Invalid or missing key size in: %@", parameters);
417            return errSecKeySizeNotAllowed;
418        }
419
420        if (!ccec_generate_key(cp, ccrng_seckey, fullkey))
421            err = errSecSuccess;
422        break;
423    }
424
425    default:
426        break;
427    }
428abort:
429    return err;
430}
431
432static 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;
437    int err;;
438    check(sigLen);
439
440    require_noerr(err = ccec_sign(fullkey, dataToSignLen, dataToSign,
441                                  sigLen, sig, ccrng_seckey), errOut);
442errOut:
443
444    return err;
445}
446
447#if 0
448static const struct ccdigest_info *
449ccdigest_lookup_by_oid(unsigned long oid_size, const void *oid) {
450    static const struct ccdigest_info *dis[] = {
451        &ccsha1_di,
452        &ccsha224_di,
453        &ccsha256_di,
454        &ccsha384_di,
455        &ccsha512_di
456    };
457    size_t i;
458    for (i = 0; i < array_size(dis); ++i) {
459        if (oid_size == dis[i]->oid_size && !memcmp(dis[i]->oid, oid, oid_size))
460            return dis[i];
461    }
462    return NULL;
463}
464#endif
465
466static 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;
472
473#if 0
474    err = ccec_unwrap_key(fullkey, ccrng_seckey, ccdigest_lookup_by_oid,
475                          cipherTextLen, cipherText, plainTextLen, plainText);
476#endif
477
478    return err;
479}
480
481static 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);
486}
487
488static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
489{
490    ccec_full_ctx_t fullkey;
491    fullkey.hdr = key->key;
492
493	CFAllocatorRef allocator = CFGetAllocator(key);
494    *serailziation = SecECPublicKeyExport(allocator, fullkey);
495
496    if (NULL == *serailziation)
497        return errSecDecode;
498    else
499        return errSecSuccess;
500}
501
502static 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);
507    if (blob) {
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);
513    }
514
515	return blob;
516}
517
518
519static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) {
520	CFDictionaryRef dict = NULL;
521	CFAllocatorRef allocator = CFGetAllocator(key);
522
523    ccec_full_ctx_t fullkey;
524    fullkey.hdr = key->key;
525
526	CFDataRef fullKeyBlob = NULL;
527
528	/* Export the full ec key pair. */
529	require(fullKeyBlob = SecECPPrivateKeyExport(allocator, fullkey), errOut);
530
531	dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob);
532
533errOut:
534	CFReleaseSafe(fullKeyBlob);
535
536	return dict;
537}
538static CFStringRef SecECPrivateKeyCopyKeyDescription(SecKeyRef key) {
539
540    //curve
541    long curveType = (long)SecECKeyGetNamedCurve(key);
542    char* curve= NULL;
543
544    switch (curveType)
545 	{
546        case 23:
547            curve = "kSecECCurveSecp256r1";
548            break;
549        case 24:
550            curve = "kSecECCurveSecp384r1";
551            break;
552        case 25:
553            curve = "kSecECCurveSecp521r1";
554            break;
555        case -1:
556            curve = "kSecECCurveNone";
557            break;
558        default:
559            curve = "kSecECCurveNone";
560            break;
561    }
562
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);
564
565}
566
567SecKeyDescriptor kSecECPrivateKeyDescriptor = {
568    kSecKeyDescriptorVersion,
569    "ECPrivateKey",
570    ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize)), /* extraBytes */
571    SecECPrivateKeyInit,
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,
583};
584
585/* Private Key API functions. */
586SecKeyRef SecKeyCreateECPrivateKey(CFAllocatorRef allocator,
587    const uint8_t *keyData, CFIndex keyDataLength,
588    SecKeyEncoding encoding) {
589    return SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor, keyData,
590        keyDataLength, encoding);
591}
592
593
594OSStatus SecECKeyGeneratePair(CFDictionaryRef parameters,
595                              SecKeyRef *publicKey, SecKeyRef *privateKey) {
596    OSStatus status = errSecParam;
597
598    CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */
599    SecKeyRef pubKey = NULL;
600
601    SecKeyRef privKey = SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor,
602                                     (const void*) parameters, 0, kSecGenerateKey);
603
604    require(privKey, errOut);
605
606    /* Create SecKeyRef's from the pkcs1 encoded keys. */
607    pubKey = SecKeyCreate(allocator, &kSecECPublicKeyDescriptor,
608                                    privKey->key, 0, kSecExtractPublicFromPrivate);
609
610    require(pubKey, errOut);
611
612    if (publicKey) {
613        *publicKey = pubKey;
614        pubKey = NULL;
615    }
616    if (privateKey) {
617        *privateKey = privKey;
618        privKey = NULL;
619    }
620
621    status = errSecSuccess;
622
623errOut:
624    CFReleaseSafe(pubKey);
625    CFReleaseSafe(privKey);
626
627    return status;
628}
629
630
631/* It's debatable whether this belongs here or in the ssl code since the
632   curve values come from a tls related rfc4492. */
633SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) {
634    if (key->key_class != &kSecECPublicKeyDescriptor &&
635        key->key_class != &kSecECPrivateKeyDescriptor)
636        return kSecECCurveNone;
637
638    ccec_pub_ctx_t pubkey;
639    pubkey.pub = key->key;
640    switch (ccec_ctx_size(pubkey)) {
641#if 0
642    case 24:
643        return kSecECCurveSecp192r1;
644    case 28:
645        return kSecECCurveSecp224r1;
646#endif
647    case 32:
648        return kSecECCurveSecp256r1;
649    case 48:
650        return kSecECCurveSecp384r1;
651    case 66:
652        return kSecECCurveSecp521r1;
653    }
654    return kSecECCurveNone;
655}
656
657CFDataRef SecECKeyCopyPublicBits(SecKeyRef key) {
658    if (key->key_class != &kSecECPublicKeyDescriptor &&
659        key->key_class != &kSecECPrivateKeyDescriptor)
660        return NULL;
661
662    ccec_pub_ctx_t pubkey;
663    pubkey.pub = key->key;
664    return SecECPublicKeyExport(CFGetAllocator(key), pubkey);
665}
666