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.m - CoreFoundation based ECDSA key object
 
  29 #include "SecECKeyPriv.h"
 
  31 #import <Foundation/Foundation.h>
 
  33 #include <Security/SecKeyInternal.h>
 
  34 #include <Security/SecItem.h>
 
  35 #include <Security/SecBasePriv.h>
 
  36 #include <AssertMacros.h>
 
  37 #include <Security/SecureTransport.h> /* For error codes. */
 
  38 #include <CoreFoundation/CFData.h> /* For error codes. */
 
  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 <utilities/SecCFError.h>
 
  46 #include <utilities/SecCFWrappers.h>
 
  47 #include <utilities/array_size.h>
 
  48 #include <corecrypto/ccec.h>
 
  49 #include <corecrypto/ccsha1.h>
 
  50 #include <corecrypto/ccsha2.h>
 
  51 #include <corecrypto/ccrng.h>
 
  52 #include <corecrypto/ccder_decode_eckey.h>
 
  54 #define kMaximumECKeySize 521
 
  56 static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) {
 
  57     return kSecECDSAAlgorithmID;
 
  67 /* Public key static functions. */
 
  68 static void SecECPublicKeyDestroy(SecKeyRef key) {
 
  69     /* Zero out the public key */
 
  70     ccec_pub_ctx_t pubkey = key->key;
 
  71     if (ccec_ctx_cp(pubkey))
 
  72         cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey);
 
  75 static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length)
 
  77     size_t keysize = ccec_x963_import_pub_size(encoded_length);
 
  78     if(ccec_keysize_is_supported(keysize)) {
 
  79         return ccec_get_cp(keysize);
 
  84 static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length)
 
  86     size_t keysize = ccec_x963_import_priv_size(encoded_length);
 
  87     if(ccec_keysize_is_supported(keysize)) {
 
  88         return ccec_get_cp(keysize);
 
  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(const unsigned char *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 = key->key;
 
 120     OSStatus err = errSecParam;
 
 123     case kSecDERKeyEncoding:
 
 125         const SecDERKey *derKey = (const SecDERKey *)keyData;
 
 126         if (keyDataLength != sizeof(SecDERKey)) {
 
 131         ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength);
 
 132         require_action_quiet(cp, errOut, err = errSecDecode);
 
 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         require_action_quiet(cp, errOut, err = errSecDecode);
 
 143         err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey)
 
 144                ? errSecDecode : errSecSuccess);
 
 147     case kSecExtractPublicFromPrivate:
 
 149         ccec_full_ctx_t fullKey = (ccec_full_ctx_t)keyData;
 
 151         cc_size fullKeyN = ccec_ctx_n(fullKey);
 
 152         require_quiet(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut);
 
 153         memcpy(pubkey, fullKey, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN)));
 
 157     case kSecKeyEncodingApplePkcs1:
 
 167 static CFTypeRef SecECPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
 
 168                                                    CFArrayRef algorithms, SecKeyOperationMode mode,
 
 169                                                    CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
 
 170     if (operation != kSecKeyOperationTypeVerify) {
 
 171         // EC public key supports only signature verification.
 
 175     if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754) || CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
 
 176         if (mode == kSecKeyOperationModePerform) {
 
 179             size_t sigLen = CFDataGetLength(in2);
 
 180             uint8_t *sig = (uint8_t *)CFDataGetBytePtr(in2);
 
 181             ccec_pub_ctx_t pubkey = key->key;
 
 183             if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
 
 184                 err = ccec_verify(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), sigLen, sig, &valid);
 
 186                 if (ccec_signature_r_s_size(pubkey) * 2 != sigLen) {
 
 187                     SecError(errSecParam, error, CFSTR("bad signature size, got %d, expecting %d bytes"),
 
 188                              (int)sigLen, (int)ccec_signature_r_s_size(pubkey) * 2);
 
 191                 err = ccec_verify_composite(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1),
 
 192                                             sig, sig + (sigLen >> 1), &valid);
 
 196                 SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed (ccerr %d)"), err);
 
 199                 SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed, no match"));
 
 202                 return kCFBooleanTrue;
 
 205             // Algorithm is supported.
 
 206             return kCFBooleanTrue;
 
 209         // Other algorithms are unsupported.
 
 214 static size_t SecECPublicKeyBlockSize(SecKeyRef key) {
 
 215     /* Get key size in octets */
 
 216     return ccec_ctx_size(ccec_ctx_pub(key->key));
 
 219 /* Encode the public key and return it in a newly allocated CFDataRef. */
 
 220 static CFDataRef SecECPublicKeyExport(CFAllocatorRef allocator,
 
 221         ccec_pub_ctx_t pubkey) {
 
 222     size_t pub_size = ccec_export_pub_size(pubkey);
 
 223         CFMutableDataRef blob = CFDataCreateMutableWithScratch(allocator, pub_size);
 
 224     ccec_export_pub(pubkey, CFDataGetMutableBytePtr(blob));
 
 228 static CFDataRef SecECPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
 
 229     ccec_pub_ctx_t pubkey = key->key;
 
 230     return SecECPublicKeyExport(NULL, pubkey);
 
 233 static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
 
 235     ccec_pub_ctx_t pubkey = key->key;
 
 237         CFAllocatorRef allocator = CFGetAllocator(key);
 
 238     *serailziation = SecECPublicKeyExport(allocator, pubkey);
 
 240     if (NULL == *serailziation)
 
 243         return errSecSuccess;
 
 246 static CFDictionaryRef SecECPublicKeyCopyAttributeDictionary(SecKeyRef key) {
 
 247     CFDictionaryRef dict = SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeEC);
 
 248     CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
 
 249     CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse);
 
 250     CFAssignRetained(dict, mutableDict);
 
 255 getCurveName(SecKeyRef key)
 
 257     SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
 
 261         case kSecECCurveSecp256r1:
 
 262             return "kSecECCurveSecp256r1";
 
 264         case kSecECCurveSecp384r1:
 
 265             return "kSecECCurveSecp384r1";
 
 267         case kSecECCurveSecp521r1:
 
 268             return "kSecECCurveSecp521r1";
 
 270             return "kSecECCurveNone";
 
 274 static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key)
 
 276     NSMutableString *strings[2];
 
 277     const char* curve = getCurveName(key);
 
 279     ccec_pub_ctx_t ecPubkey = key->key;
 
 280     size_t len = ccec_ctx_size(ecPubkey);
 
 281     NSMutableData *buffer = [NSMutableData dataWithLength:len];
 
 282     for (int i = 0; i < 2; ++i) {
 
 283         ccn_write_uint(ccec_ctx_n(ecPubkey), (i == 0) ? ccec_ctx_x(ecPubkey) : ccec_ctx_y(ecPubkey), len, buffer.mutableBytes);
 
 284         strings[i] = [NSMutableString stringWithCapacity:len * 2];
 
 285         for (size_t byteIndex = 0; byteIndex < len; ++byteIndex) {
 
 286             [strings[i] appendFormat:@"%02X", ((const uint8_t *)buffer.bytes)[byteIndex]];
 
 290     NSString *description = [NSString stringWithFormat:@"<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>",
 
 291                              curve, (long)SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version,
 
 292                              8 * SecKeyGetBlockSize(key), strings[1], strings[0], key];
 
 293     return CFBridgingRetain(description);
 
 296 static const struct ccec_rfc6637_curve * get_rfc6637_curve(SecKeyRef key)
 
 298     SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
 
 300     if (curveType == kSecECCurveSecp256r1) {
 
 301         return &ccec_rfc6637_dh_curve_p256;
 
 302     } else if (curveType == kSecECCurveSecp521r1) {
 
 303         return &ccec_rfc6637_dh_curve_p521;
 
 308 static CFDataRef SecECKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
 
 310     ccec_pub_ctx_t pubkey = key->key;
 
 311     int err = errSecUnimplemented;
 
 312     const struct ccec_rfc6637_curve *curve;
 
 313     const struct ccec_rfc6637_wrap *wrap = NULL;
 
 317     if (type != kSecKeyWrapPublicKeyPGP) {
 
 318         SecError(errSecUnsupportedOperation, error, CFSTR("unsupported key wrapping algorithm"));
 
 322     curve = get_rfc6637_curve(key);
 
 324         SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
 
 328     CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPSymAlg);
 
 329     if (!isNumber(num) || !CFNumberGetValue(num, kCFNumberSInt8Type, &sym_alg)) {
 
 330         SecError(errSecUnsupportedOperation, error, CFSTR("unknown symalg given"));
 
 334     CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
 
 335     if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
 
 336         SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
 
 340     CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
 
 341     if (wrapAlg == NULL) {
 
 342         SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
 
 344     } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
 
 345         wrap = &ccec_rfc6637_wrap_sha256_kek_aes128;
 
 346     } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
 
 347         wrap = &ccec_rfc6637_wrap_sha512_kek_aes256;
 
 349         SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
 
 353     num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
 
 355         if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
 
 356             SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
 
 360         SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
 
 364     CFIndex unwrappedKey_size = CFDataGetLength(unwrappedKey);
 
 366     CFIndex output_size = ccec_rfc6637_wrap_key_size(pubkey, flags, unwrappedKey_size);
 
 367     if (output_size == 0) {
 
 368         SecError(errSecUnsupportedOperation, error, CFSTR("can't wrap that key, can't build size"));
 
 372     CFMutableDataRef data = CFDataCreateMutableWithScratch(NULL, output_size);
 
 373     require_quiet(data, errOut);
 
 375     err = ccec_rfc6637_wrap_key(pubkey, CFDataGetMutableBytePtr(data), flags,
 
 376                                 sym_alg, CFDataGetLength(unwrappedKey), CFDataGetBytePtr(unwrappedKey),
 
 377                                 curve, wrap, CFDataGetBytePtr(fingerprint),
 
 380         SecError(errSecUnsupportedOperation, error, CFSTR("Failed to wrap key"));
 
 388 SecKeyDescriptor kSecECPublicKeyDescriptor = {
 
 389     .version = kSecKeyDescriptorVersion,
 
 390     .name = "ECPublicKey",
 
 391     .extraBytes = ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize)),
 
 392     .init = SecECPublicKeyInit,
 
 393     .destroy = SecECPublicKeyDestroy,
 
 394     .blockSize = SecECPublicKeyBlockSize,
 
 395     .copyDictionary = SecECPublicKeyCopyAttributeDictionary,
 
 396     .copyExternalRepresentation = SecECPublicKeyCopyExternalRepresentation,
 
 397     .describe = SecECPublicKeyCopyKeyDescription,
 
 398     .getAlgorithmID = SecECKeyGetAlgorithmID,
 
 399     .copyPublic = SecECPublicKeyCopyPublicOctets,
 
 400     .copyWrapKey = SecECKeyCopyWrapKey,
 
 401     .copyOperationResult = SecECPublicKeyCopyOperationResult,
 
 404 /* Public Key API functions. */
 
 405 SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
 
 406     const uint8_t *keyData, CFIndex keyDataLength,
 
 407     SecKeyEncoding encoding) {
 
 408     return SecKeyCreate(allocator, &kSecECPublicKeyDescriptor, keyData,
 
 409                         keyDataLength, encoding);
 
 420 /* Private key static functions. */
 
 421 static void SecECPrivateKeyDestroy(SecKeyRef key) {
 
 422     /* Zero out the public key */
 
 423     ccec_full_ctx_t fullkey = key->key;
 
 425     if (ccec_ctx_cp(fullkey))
 
 426         cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey);
 
 430 static OSStatus SecECPrivateKeyInit(SecKeyRef key,
 
 431     const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
 
 432     ccec_full_ctx_t fullkey = key->key;
 
 433     OSStatus err = errSecParam;
 
 436     case kSecKeyEncodingPkcs1:
 
 438         /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
 
 439         //err = ecc_import(keyData, keyDataLength, fullkey);
 
 441         /* DER != PKCS#1, but we'll go along with it */
 
 442         const unsigned char *oid;
 
 446         require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength, keyData, (ccoid_t*)&oid, &n), abort);
 
 447         cp = ccec_cp_for_oid(oid);
 
 449             cp = ccec_curve_for_length_lookup(n * 8 /* bytes -> bits */,
 
 450                 ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL);
 
 452         require_action_quiet(cp != NULL, abort, err = errSecDecode);
 
 453         ccec_ctx_init(cp, fullkey);
 
 455         require_noerr_quiet(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort);
 
 459     case kSecKeyEncodingBytes:
 
 461         ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength);
 
 462         require_quiet(cp != NULL, abort);
 
 464         ccec_ctx_init(cp, fullkey);
 
 465         size_t pubSize = ccec_export_pub_size(ccec_ctx_pub(fullkey));
 
 467         require_quiet(pubSize < (size_t) keyDataLength, abort);
 
 468         require_noerr_action_quiet(ccec_import_pub(cp, pubSize, keyData, ccec_ctx_pub(fullkey)),
 
 474         keyDataLength -= pubSize;
 
 476         cc_unit *k = ccec_ctx_k(fullkey);
 
 477         require_noerr_action_quiet(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData),
 
 485     case kSecGenerateKey:
 
 487         CFDictionaryRef parameters = (CFDictionaryRef) keyData;
 
 489         CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
 
 490         CFIndex keyLengthInBits = getIntValue(ksize);
 
 492         ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits);
 
 495             secwarning("Invalid or missing key size in: %@", parameters);
 
 496             return errSecKeySizeNotAllowed;
 
 499         if (!ccec_generate_key_fips(cp, ccrng_seckey, fullkey))
 
 511 static CFTypeRef SecECPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
 
 512                                                     CFArrayRef allAlgorithms, SecKeyOperationMode mode,
 
 513                                                     CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
 
 514     // Default answer is 'unsupported', unless we find out that we can support it.
 
 515     CFTypeRef result = kCFNull;
 
 517     ccec_full_ctx_t fullkey = key->key;
 
 519         case kSecKeyOperationTypeSign: {
 
 520             if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) {
 
 521                 if (mode == kSecKeyOperationModePerform) {
 
 522                     // Perform r/s mode of signature.
 
 523                     cc_size r_s_size = ccec_signature_r_s_size(ccec_ctx_public(fullkey));
 
 524                     result = CFDataCreateMutableWithScratch(NULL, r_s_size << 1);
 
 525                     uint8_t *signatureBuffer = CFDataGetMutableBytePtr((CFMutableDataRef)result);
 
 526                     int err = ccec_sign_composite(fullkey, CFDataGetLength(in1), CFDataGetBytePtr(in1),
 
 527                                                   signatureBuffer, signatureBuffer + r_s_size, ccrng_seckey);
 
 528                     require_action_quiet(err == 0, out, (CFReleaseNull(result),
 
 529                                                          SecError(errSecParam, error, CFSTR("%@: RFC4754 signing failed (ccerr %d)"),
 
 532                     // Operation is supported.
 
 533                     result = kCFBooleanTrue;
 
 535             } else if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
 
 536                 if (mode == kSecKeyOperationModePerform) {
 
 537                     // Perform x962 mode of signature.
 
 538                     size_t size = ccec_sign_max_size(ccec_ctx_cp(fullkey));
 
 539                     result = CFDataCreateMutableWithScratch(NULL, size);
 
 540                     int err = ccec_sign(fullkey, CFDataGetLength(in1), CFDataGetBytePtr(in1),
 
 541                                         &size, CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
 
 542                     require_action_quiet(err == 0, out, (CFReleaseNull(result),
 
 543                                                          SecError(errSecParam, error, CFSTR("%@: X962 signing failed (ccerr %d)"),
 
 545                     CFDataSetLength((CFMutableDataRef)result, size);
 
 547                     // Operation is supported.
 
 548                     result = kCFBooleanTrue;
 
 553         case kSecKeyOperationTypeKeyExchange:
 
 554             if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) ||
 
 555                 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
 
 556                 if (mode == kSecKeyOperationModePerform) {
 
 558                     ccec_const_cp_t cp = getCPForPublicSize(CFDataGetLength(in1));
 
 559                     require_action_quiet(cp != NULL, out,
 
 560                                          SecError(errSecParam, error, CFSTR("ECpriv sharedsecret: bad public key")));
 
 561                     ccec_pub_ctx_decl_cp(cp, pubkey);
 
 562                     err = ccec_import_pub(cp, CFDataGetLength(in1), CFDataGetBytePtr(in1), pubkey);
 
 563                     require_noerr_action_quiet(err, out, SecError(errSecParam, error,
 
 564                                                                   CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err));
 
 565                     size_t size = ccec_ccn_size(cp);
 
 566                     result = CFDataCreateMutableWithScratch(NULL, size);
 
 567                     err = ccecdh_compute_shared_secret(fullkey, pubkey, &size,
 
 568                                                        CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
 
 569                     require_noerr_action_quiet(err, out, (CFReleaseNull(result),
 
 570                                                           SecError(errSecDecode, error,
 
 571                                                                    CFSTR("ECpriv failed to compute shared secret (err %d)"), err)));
 
 572                     CFDataSetLength((CFMutableDataRef)result, size);
 
 574                     // Operation is supported.
 
 575                     result = kCFBooleanTrue;
 
 587 static size_t SecECPrivateKeyBlockSize(SecKeyRef key) {
 
 588     ccec_full_ctx_t fullkey = key->key;
 
 589     /* Get key size in octets */
 
 590     return ccec_ctx_size(fullkey);
 
 593 static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
 
 595     ccec_full_ctx_t fullkey = key->key;
 
 597         CFAllocatorRef allocator = CFGetAllocator(key);
 
 598     *serailziation = SecECPublicKeyExport(allocator, ccec_ctx_pub(fullkey));
 
 600     if (NULL == *serailziation)
 
 603         return errSecSuccess;
 
 606 static CFDataRef SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
 
 607     ccec_full_ctx_t fullkey = key->key;
 
 608     size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey));
 
 609     size_t key_size = ccec_export_pub_size(ccec_ctx_pub(fullkey)) + prime_size;
 
 610     CFMutableDataRef blob = CFDataCreateMutableWithScratch(NULL, key_size);
 
 611     ccec_export_pub(ccec_ctx_pub(fullkey), CFDataGetMutableBytePtr(blob));
 
 612     UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(ccec_ctx_pub(fullkey));
 
 613     const cc_unit *k = ccec_ctx_k(fullkey);
 
 614     ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest);
 
 618 static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) {
 
 619     /* Export the full ec key pair. */
 
 620     CFDataRef fullKeyBlob = SecECPrivateKeyCopyExternalRepresentation(key, NULL);
 
 622     CFDictionaryRef dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob);
 
 623         CFReleaseSafe(fullKeyBlob);
 
 626 static CFStringRef SecECPrivateKeyCopyKeyDescription(SecKeyRef key) {
 
 628     const char* curve = getCurveName(key);
 
 630         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);
 
 634 static CFDataRef SecECKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
 
 636     const struct ccec_rfc6637_curve *curve;
 
 637     const struct ccec_rfc6637_unwrap *unwrap;
 
 638     ccec_full_ctx_t fullkey = key->key;
 
 639     CFMutableDataRef data;
 
 644     curve = get_rfc6637_curve(key);
 
 646         SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
 
 650     CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
 
 651     if (wrapAlg == NULL) {
 
 652         SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
 
 654     } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
 
 655         unwrap = &ccec_rfc6637_unwrap_sha256_kek_aes128;
 
 656     } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
 
 657         unwrap = &ccec_rfc6637_unwrap_sha512_kek_aes256;
 
 659         SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
 
 663     CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
 
 664     if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
 
 665         SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
 
 669     CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
 
 671         if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
 
 672             SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
 
 676         SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
 
 680     size_t keysize = CFDataGetLength(wrappedKey);
 
 681     data = CFDataCreateMutableWithScratch(NULL, keysize);
 
 685     res = ccec_rfc6637_unwrap_key(fullkey, &keysize, CFDataGetMutableBytePtr(data),
 
 686                                   flags, &sym_alg, curve, unwrap,
 
 687                                   CFDataGetBytePtr(fingerprint),
 
 688                                   CFDataGetLength(wrappedKey), CFDataGetBytePtr(wrappedKey));
 
 691         SecError(errSecUnsupportedOperation, error, CFSTR("failed to wrap key"));
 
 694     assert(keysize <= (size_t)CFDataGetLength(data));
 
 695     CFDataSetLength(data, keysize);
 
 698         CFMutableDictionaryRef out =  CFDictionaryCreateMutableForCFTypes(NULL);
 
 700             CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &sym_alg);
 
 702                 CFDictionarySetValue(out, _kSecKeyWrapPGPSymAlg, num);
 
 712 SecKeyDescriptor kSecECPrivateKeyDescriptor = {
 
 713     .version = kSecKeyDescriptorVersion,
 
 714     .name = "ECPrivateKey",
 
 715     .extraBytes = ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize)),
 
 717     .init = SecECPrivateKeyInit,
 
 718     .destroy = SecECPrivateKeyDestroy,
 
 719     .blockSize = SecECPrivateKeyBlockSize,
 
 720     .copyDictionary = SecECPrivateKeyCopyAttributeDictionary,
 
 721     .describe = SecECPrivateKeyCopyKeyDescription,
 
 722     .getAlgorithmID = SecECKeyGetAlgorithmID,
 
 723     .copyPublic = SecECPrivateKeyCopyPublicOctets,
 
 724     .copyExternalRepresentation = SecECPrivateKeyCopyExternalRepresentation,
 
 725     .copyWrapKey = SecECKeyCopyWrapKey,
 
 726     .copyUnwrapKey = SecECKeyCopyUnwrapKey,
 
 727     .copyOperationResult = SecECPrivateKeyCopyOperationResult,
 
 730 /* Private Key API functions. */
 
 731 SecKeyRef SecKeyCreateECPrivateKey(CFAllocatorRef allocator,
 
 732     const uint8_t *keyData, CFIndex keyDataLength,
 
 733     SecKeyEncoding encoding) {
 
 734     return SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor, keyData,
 
 735         keyDataLength, encoding);
 
 739 OSStatus SecECKeyGeneratePair(CFDictionaryRef parameters,
 
 740                               SecKeyRef *publicKey, SecKeyRef *privateKey) {
 
 741     OSStatus status = errSecParam;
 
 743     CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */
 
 744     SecKeyRef pubKey = NULL;
 
 746     SecKeyRef privKey = SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor,
 
 747                                      (const void*) parameters, 0, kSecGenerateKey);
 
 749     require_quiet(privKey, errOut);
 
 751     /* Create SecKeyRef's from the pkcs1 encoded keys. */
 
 752     pubKey = SecKeyCreate(allocator, &kSecECPublicKeyDescriptor,
 
 753                           privKey->key, 0, kSecExtractPublicFromPrivate);
 
 755     require_quiet(pubKey, errOut);
 
 762         *privateKey = privKey;
 
 766     status = errSecSuccess;
 
 769     CFReleaseSafe(pubKey);
 
 770     CFReleaseSafe(privKey);
 
 776 /* It's debatable whether this belongs here or in the ssl code since the
 
 777    curve values come from a tls related rfc4492. */
 
 778 SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) {
 
 779     SecECNamedCurve result = kSecECCurveNone;
 
 780     CFDictionaryRef attributes = NULL;
 
 781     require_quiet(SecKeyGetAlgorithmId(key) == kSecECDSAAlgorithmID, out);
 
 782     require_quiet(attributes = SecKeyCopyAttributes(key), out);
 
 783     CFTypeRef bitsRef = CFDictionaryGetValue(attributes, kSecAttrKeySizeInBits);
 
 785     require_quiet(bitsRef != NULL && CFGetTypeID(bitsRef) == CFNumberGetTypeID() &&
 
 786                   CFNumberGetValue(bitsRef, kCFNumberCFIndexType, &bits), out);
 
 790             result = kSecECCurveSecp192r1;
 
 793             result = kSecECCurveSecp224r1;
 
 797             result = kSecECCurveSecp256r1;
 
 800             result = kSecECCurveSecp384r1;
 
 803             result = kSecECCurveSecp521r1;
 
 808     CFReleaseSafe(attributes);
 
 812 CFDataRef SecECKeyCopyPublicBits(SecKeyRef key) {
 
 813     CFDataRef bytes = NULL;
 
 814     SecKeyCopyPublicBytes(key, &bytes);
 
 818 /* Vile accessors that get us the pub or priv key to use temporarily */
 
 820 bool SecECDoWithFullKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_full_ctx_t private)) {
 
 821     if (key->key_class == &kSecECPrivateKeyDescriptor) {
 
 824         return SecError(errSecParam, error, CFSTR("Not an EC Full Key object, sorry can't do."));
 
 830 bool SecECDoWithPubKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_pub_ctx_t public)) {
 
 831     if (key->key_class == &kSecECPublicKeyDescriptor) {
 
 834         return SecError(errSecParam, error, CFSTR("Not an EC Public Key object, sorry can't do."));