/ OSX / sec / Security / SecECKey.m
SecECKey.m
  1  /*
  2   * Copyright (c) 2010-2015 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.m - CoreFoundation based ECDSA key object
 26   */
 27  
 28  #include "SecECKey.h"
 29  #include "SecECKeyPriv.h"
 30  
 31  #import <Foundation/Foundation.h>
 32  
 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 <Security/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>
 53  
 54  #define kMaximumECKeySize 521
 55  
 56  static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) {
 57      return kSecECDSAAlgorithmID;
 58  }
 59  
 60  
 61  /*
 62   *
 63   * Public Key
 64   *
 65   */
 66  
 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);
 73  }
 74  
 75  static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length)
 76  {
 77      size_t keysize = ccec_x963_import_pub_size(encoded_length);
 78      if(ccec_keysize_is_supported(keysize)) {
 79          return ccec_get_cp(keysize);
 80      }
 81      return NULL;
 82  }
 83  
 84  static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length)
 85  {
 86      size_t keysize = ccec_x963_import_priv_size(encoded_length);
 87      if(ccec_keysize_is_supported(keysize)) {
 88          return ccec_get_cp(keysize);
 89      }
 90      return NULL;
 91  }
 92  
 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;
 98  
 99  // <rdar://problem/66864716> OID_CERTICOM is wrong
100  static ccoid_t ccoid_libder_secp384r1 = ((unsigned char *)"\x06\x04\x2B\x84\x00\x22");
101  static ccoid_t ccoid_libder_secp521r1 = ((unsigned char *)"\x06\x04\x2B\x84\x00\x23");
102  
103  static ccec_const_cp_t ccec_cp_for_oid(const unsigned char *oid)
104  {
105      if (oid!=NULL) {
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) || ccoid_equal(oid, ccoid_libder_secp384r1)) {
113              return ccec_cp_384();
114          } else if (ccoid_equal(oid, ccoid_secp521r1) || ccoid_equal(oid, ccoid_libder_secp521r1)) {
115              return ccec_cp_521();
116          }
117      }
118      return (ccec_const_cp_t){NULL};
119  }
120  
121  static OSStatus SecECPublicKeyInit(SecKeyRef key,
122      const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
123      ccec_pub_ctx_t pubkey = key->key;
124      OSStatus err = errSecParam;
125  
126      switch (encoding) {
127      case kSecDERKeyEncoding:
128      {
129          const SecDERKey *derKey = (const SecDERKey *)keyData;
130          if (keyDataLength != sizeof(SecDERKey)) {
131              err = errSecDecode;
132              break;
133          }
134  
135          require_action_quiet(derKey->parameters && derKey->parametersLength > 2 &&
136                               derKey->parameters[1] <= derKey->parametersLength - 2, errOut, err = errSecDecode);
137          ccec_const_cp_t cp = ccec_cp_for_oid(derKey->parameters);
138          require_action_quiet(cp, errOut, err = errSecDecode);
139  
140          err = (ccec_import_pub(cp, derKey->keyLength, derKey->key, pubkey)
141                 ? errSecDecode : errSecSuccess);
142          break;
143      }
144      case kSecKeyEncodingBytes:
145      {
146          ccec_const_cp_t cp = getCPForPublicSize(keyDataLength);
147          require_action_quiet(cp, errOut, err = errSecDecode);
148          err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey)
149                 ? errSecDecode : errSecSuccess);
150          break;
151      }
152      case kSecExtractPublicFromPrivate:
153      {
154          ccec_full_ctx_t fullKey = (ccec_full_ctx_t)keyData;
155  
156          cc_size fullKeyN = ccec_ctx_n(fullKey);
157          require_quiet(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut);
158          memcpy(pubkey, fullKey, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN)));
159          err = errSecSuccess;
160          break;
161      }
162      case kSecKeyEncodingApplePkcs1:
163      default:
164          err = errSecParam;
165          break;
166      }
167  
168  errOut:
169      return err;
170  }
171  
172  static CFTypeRef SecECPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
173                                                     CFArrayRef algorithms, SecKeyOperationMode mode,
174                                                     CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
175      if (operation != kSecKeyOperationTypeVerify || !CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
176          // EC public key supports only signature verification with X962 algorithm.
177          return kCFNull;
178      }
179  
180      if (mode == kSecKeyOperationModePerform) {
181          bool valid = false;
182          int err = -1;
183          size_t sigLen = CFDataGetLength(in2);
184          uint8_t *sig = (uint8_t *)CFDataGetBytePtr(in2);
185          ccec_pub_ctx_t pubkey = key->key;
186  
187          err = ccec_verify(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), sigLen, sig, &valid);
188          if (err != 0) {
189              SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed (ccerr %d)"), err);
190              return NULL;
191          } else if (!valid) {
192              SecError(errSecVerifyFailed, error, CFSTR("EC signature verification failed, no match"));
193              return NULL;
194          } else {
195              return kCFBooleanTrue;
196          }
197      } else {
198          // Algorithm is supported.
199          return kCFBooleanTrue;
200      }
201  }
202  
203  static size_t SecECPublicKeyBlockSize(SecKeyRef key) {
204      /* Get key size in octets */
205      return ccec_ctx_size(ccec_ctx_pub(key->key));
206  }
207  
208  /* Encode the public key and return it in a newly allocated CFDataRef. */
209  static CFDataRef SecECPublicKeyExport(CFAllocatorRef allocator,
210  	ccec_pub_ctx_t pubkey) {
211      size_t pub_size = ccec_export_pub_size(pubkey);
212  	CFMutableDataRef blob = CFDataCreateMutableWithScratch(allocator, pub_size);
213      ccec_export_pub(pubkey, CFDataGetMutableBytePtr(blob));
214  	return blob;
215  }
216  
217  static CFDataRef SecECPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
218      ccec_pub_ctx_t pubkey = key->key;
219      return SecECPublicKeyExport(NULL, pubkey);
220  }
221  
222  static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
223  {
224      ccec_pub_ctx_t pubkey = key->key;
225  
226  	CFAllocatorRef allocator = CFGetAllocator(key);
227      *serailziation = SecECPublicKeyExport(allocator, pubkey);
228  
229      if (NULL == *serailziation)
230          return errSecDecode;
231      else
232          return errSecSuccess;
233  }
234  
235  static CFDictionaryRef SecECPublicKeyCopyAttributeDictionary(SecKeyRef key) {
236      CFDictionaryRef dict = SecKeyGeneratePublicAttributeDictionary(key, kSecAttrKeyTypeEC);
237      CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
238      CFDictionarySetValue(mutableDict, kSecAttrCanDerive, kCFBooleanFalse);
239      CFAssignRetained(dict, mutableDict);
240      return dict;
241  }
242  
243  static const char *
244  getCurveName(SecKeyRef key)
245  {
246      SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
247  
248      switch (curveType)
249      {
250          case kSecECCurveSecp256r1:
251              return "kSecECCurveSecp256r1";
252              break;
253          case kSecECCurveSecp384r1:
254              return "kSecECCurveSecp384r1";
255              break;
256          case kSecECCurveSecp521r1:
257              return "kSecECCurveSecp521r1";
258          default:
259              return "kSecECCurveNone";
260      }
261  }
262  
263  static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key)
264  {
265      NSMutableString *strings[2];
266      const char* curve = getCurveName(key);
267  
268      ccec_pub_ctx_t ecPubkey = key->key;
269      size_t len = ccec_ctx_size(ecPubkey);
270      NSMutableData *buffer = [NSMutableData dataWithLength:len];
271      for (int i = 0; i < 2; ++i) {
272          ccn_write_uint(ccec_ctx_n(ecPubkey), (i == 0) ? ccec_ctx_x(ecPubkey) : ccec_ctx_y(ecPubkey), len, buffer.mutableBytes);
273          strings[i] = [NSMutableString stringWithCapacity:len * 2];
274          for (size_t byteIndex = 0; byteIndex < len; ++byteIndex) {
275              [strings[i] appendFormat:@"%02X", ((const uint8_t *)buffer.bytes)[byteIndex]];
276          }
277      }
278  
279      NSString *description = [NSString stringWithFormat:@"<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>",
280                               curve, (long)SecKeyGetAlgorithmId(key), key->key_class->name, key->key_class->version,
281                               8 * SecKeyGetBlockSize(key), strings[1], strings[0], key];
282      return CFBridgingRetain(description);
283  }
284  
285  static const struct ccec_rfc6637_curve * get_rfc6637_curve(SecKeyRef key)
286  {
287      SecECNamedCurve curveType = SecECKeyGetNamedCurve(key);
288  
289      if (curveType == kSecECCurveSecp256r1) {
290          return &ccec_rfc6637_dh_curve_p256;
291      } else if (curveType == kSecECCurveSecp521r1) {
292          return &ccec_rfc6637_dh_curve_p521;
293      }
294      return NULL;
295  }
296  
297  static CFDataRef SecECKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
298  {
299      ccec_pub_ctx_t pubkey = key->key;
300      int err = errSecUnimplemented;
301      const struct ccec_rfc6637_curve *curve;
302      const struct ccec_rfc6637_wrap *wrap = NULL;
303      uint8_t sym_alg = 0;
304      int32_t flags = 0;
305  
306      if (type != kSecKeyWrapPublicKeyPGP) {
307          SecError(errSecUnsupportedOperation, error, CFSTR("unsupported key wrapping algorithm"));
308          return NULL;
309      }
310  
311      curve = get_rfc6637_curve(key);
312      if (curve == NULL) {
313          SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
314          return NULL;
315      }
316  
317      CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPSymAlg);
318      if (!isNumber(num) || !CFNumberGetValue(num, kCFNumberSInt8Type, &sym_alg)) {
319          SecError(errSecUnsupportedOperation, error, CFSTR("unknown symalg given"));
320          return NULL;
321      }
322  
323      CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
324      if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
325          SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
326          return NULL;
327      }
328  
329      CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
330      if (wrapAlg == NULL) {
331          SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
332          return NULL;
333      } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
334          wrap = &ccec_rfc6637_wrap_sha256_kek_aes128;
335      } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
336          wrap = &ccec_rfc6637_wrap_sha512_kek_aes256;
337      } else {
338          SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
339          return NULL;
340      }
341  
342      num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
343      if (isNumber(num)) {
344          if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
345              SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
346              return NULL;
347          }
348      } else if (num) {
349          SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
350          return NULL;
351      }
352  
353      CFIndex unwrappedKey_size = CFDataGetLength(unwrappedKey);
354  
355      CFIndex output_size = ccec_rfc6637_wrap_key_size(pubkey, flags, unwrappedKey_size);
356      if (output_size == 0) {
357          SecError(errSecUnsupportedOperation, error, CFSTR("can't wrap that key, can't build size"));
358          return NULL;
359      }
360  
361      CFMutableDataRef data = CFDataCreateMutableWithScratch(NULL, output_size);
362      require_quiet(data, errOut);
363  
364      err = ccec_rfc6637_wrap_key(pubkey, CFDataGetMutableBytePtr(data), flags,
365                                  sym_alg, CFDataGetLength(unwrappedKey), CFDataGetBytePtr(unwrappedKey),
366                                  curve, wrap, CFDataGetBytePtr(fingerprint),
367                                  ccrng_seckey);
368      if (err) {
369          SecError(errSecUnsupportedOperation, error, CFSTR("Failed to wrap key"));
370          CFReleaseNull(data);
371      }
372  
373  errOut:
374      return data;
375  }
376  
377  SecKeyDescriptor kSecECPublicKeyDescriptor = {
378      .version = kSecKeyDescriptorVersion,
379      .name = "ECPublicKey",
380      .extraBytes = ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize)),
381      .init = SecECPublicKeyInit,
382      .destroy = SecECPublicKeyDestroy,
383      .blockSize = SecECPublicKeyBlockSize,
384      .copyDictionary = SecECPublicKeyCopyAttributeDictionary,
385      .copyExternalRepresentation = SecECPublicKeyCopyExternalRepresentation,
386      .describe = SecECPublicKeyCopyKeyDescription,
387      .getAlgorithmID = SecECKeyGetAlgorithmID,
388      .copyPublic = SecECPublicKeyCopyPublicOctets,
389      .copyWrapKey = SecECKeyCopyWrapKey,
390      .copyOperationResult = SecECPublicKeyCopyOperationResult,
391  };
392  
393  /* Public Key API functions. */
394  SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator,
395      const uint8_t *keyData, CFIndex keyDataLength,
396      SecKeyEncoding encoding) {
397      return SecKeyCreate(allocator, &kSecECPublicKeyDescriptor, keyData,
398                          keyDataLength, encoding);
399  }
400  
401  
402  
403  /*
404   *
405   * Private Key
406   *
407   */
408  
409  /* Private key static functions. */
410  static void SecECPrivateKeyDestroy(SecKeyRef key) {
411      /* Zero out the public key */
412      ccec_full_ctx_t fullkey = key->key;
413  
414      if (ccec_ctx_cp(fullkey))
415          cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey);
416  }
417  
418  
419  static OSStatus SecECPrivateKeyInit(SecKeyRef key,
420      const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
421      ccec_full_ctx_t fullkey = key->key;
422      OSStatus err = errSecParam;
423  
424      switch (encoding) {
425      case kSecKeyEncodingPkcs1:
426      {
427          /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */
428          //err = ecc_import(keyData, keyDataLength, fullkey);
429  
430          /* DER != PKCS#1, but we'll go along with it */
431          const unsigned char *oid;
432          size_t n;
433          ccec_const_cp_t cp;
434  
435          require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength, keyData, (ccoid_t*)&oid, &n), abort);
436          cp = ccec_cp_for_oid(oid);
437          if (cp == NULL) {
438              cp = ccec_curve_for_length_lookup(n * 8 /* bytes -> bits */,
439                  ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL);
440          }
441          require_action_quiet(cp != NULL, abort, err = errSecDecode);
442          ccec_ctx_init(cp, fullkey);
443  
444          require_noerr_quiet(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort);
445          err = errSecSuccess;
446          break;
447      }
448      case kSecKeyEncodingBytes:
449      {
450          ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength);
451          require_quiet(cp != NULL, abort);
452  
453          ccec_ctx_init(cp, fullkey);
454          size_t pubSize = ccec_export_pub_size(ccec_ctx_pub(fullkey));
455  
456          require_quiet(pubSize < (size_t) keyDataLength, abort);
457          require_noerr_action_quiet(ccec_import_pub(cp, pubSize, keyData, ccec_ctx_pub(fullkey)),
458                               abort,
459                               err = errSecDecode);
460  
461  
462          keyData += pubSize;
463          keyDataLength -= pubSize;
464  
465          cc_unit *k = ccec_ctx_k(fullkey);
466          require_noerr_action_quiet(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData),
467                                     abort,
468                                     err = errSecDecode);
469  
470          err = errSecSuccess;
471          break;
472  
473      }
474      case kSecGenerateKey:
475      {
476          CFDictionaryRef parameters = (CFDictionaryRef) keyData;
477  
478          CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
479          CFIndex keyLengthInBits = getIntValue(ksize);
480  
481          ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits);
482  
483          if (!cp) {
484              secwarning("Invalid or missing key size in: %@", parameters);
485              return errSecKeySizeNotAllowed;
486          }
487  
488          if (!ccec_generate_key_fips(cp, ccrng_seckey, fullkey))
489              err = errSecSuccess;
490          break;
491      }
492  
493      default:
494          break;
495      }
496  abort:
497      return err;
498  }
499  
500  static CFTypeRef SecECPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
501                                                      CFArrayRef allAlgorithms, SecKeyOperationMode mode,
502                                                      CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
503      // Default answer is 'unsupported', unless we find out that we can support it.
504      CFTypeRef result = kCFNull;
505  
506      ccec_full_ctx_t fullkey = key->key;
507      switch (operation) {
508          case kSecKeyOperationTypeSign: {
509              if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
510                  if (mode == kSecKeyOperationModePerform) {
511                      // Perform x962 mode of signature.
512                      size_t size = ccec_sign_max_size(ccec_ctx_cp(fullkey));
513                      result = CFDataCreateMutableWithScratch(NULL, size);
514                      int err = ccec_sign(fullkey, CFDataGetLength(in1), CFDataGetBytePtr(in1),
515                                          &size, CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
516                      require_action_quiet(err == 0, out, (CFReleaseNull(result),
517                                                           SecError(errSecParam, error, CFSTR("%@: X962 signing failed (ccerr %d)"),
518                                                                    key, err)));
519                      CFDataSetLength((CFMutableDataRef)result, size);
520                  } else {
521                      // Operation is supported.
522                      result = kCFBooleanTrue;
523                  }
524              }
525              break;
526          }
527          case kSecKeyOperationTypeKeyExchange:
528              if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) ||
529                  CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
530                  if (mode == kSecKeyOperationModePerform) {
531                      int err;
532                      ccec_const_cp_t cp = getCPForPublicSize(CFDataGetLength(in1));
533                      require_action_quiet(cp != NULL, out,
534                                           SecError(errSecParam, error, CFSTR("ECpriv sharedsecret: bad public key")));
535                      ccec_pub_ctx_decl_cp(cp, pubkey);
536                      err = ccec_import_pub(cp, CFDataGetLength(in1), CFDataGetBytePtr(in1), pubkey);
537                      require_noerr_action_quiet(err, out, SecError(errSecParam, error,
538                                                                    CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err));
539                      size_t size = ccec_ccn_size(cp);
540                      result = CFDataCreateMutableWithScratch(NULL, size);
541                      err = ccecdh_compute_shared_secret(fullkey, pubkey, &size,
542                                                         CFDataGetMutableBytePtr((CFMutableDataRef)result), ccrng_seckey);
543                      require_noerr_action_quiet(err, out, (CFReleaseNull(result),
544                                                            SecError(errSecDecode, error,
545                                                                     CFSTR("ECpriv failed to compute shared secret (err %d)"), err)));
546                      CFDataSetLength((CFMutableDataRef)result, size);
547                  } else {
548                      // Operation is supported.
549                      result = kCFBooleanTrue;
550                  }
551              }
552              break;
553          default:
554              break;
555      }
556  
557  out:
558      return result;
559  }
560  
561  static size_t SecECPrivateKeyBlockSize(SecKeyRef key) {
562      ccec_full_ctx_t fullkey = key->key;
563      /* Get key size in octets */
564      return ccec_ctx_size(fullkey);
565  }
566  
567  static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation)
568  {
569      ccec_full_ctx_t fullkey = key->key;
570  
571  	CFAllocatorRef allocator = CFGetAllocator(key);
572      *serailziation = SecECPublicKeyExport(allocator, ccec_ctx_pub(fullkey));
573  
574      if (NULL == *serailziation)
575          return errSecDecode;
576      else
577          return errSecSuccess;
578  }
579  
580  static CFDataRef SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
581      ccec_full_ctx_t fullkey = key->key;
582      size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey));
583      size_t key_size = ccec_export_pub_size(ccec_ctx_pub(fullkey)) + prime_size;
584      CFMutableDataRef blob = CFDataCreateMutableWithScratch(NULL, key_size);
585      ccec_export_pub(ccec_ctx_pub(fullkey), CFDataGetMutableBytePtr(blob));
586      UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(ccec_ctx_pub(fullkey));
587      const cc_unit *k = ccec_ctx_k(fullkey);
588      ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest);
589      return blob;
590  }
591  
592  static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) {
593      /* Export the full ec key pair. */
594      CFDataRef fullKeyBlob = SecECPrivateKeyCopyExternalRepresentation(key, NULL);
595  
596      CFDictionaryRef dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob);
597  	CFReleaseSafe(fullKeyBlob);
598  	return dict;
599  }
600  static CFStringRef SecECPrivateKeyCopyKeyDescription(SecKeyRef key) {
601  
602      const char* curve = getCurveName(key);
603  
604  	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);
605  
606  }
607  
608  static CFDataRef SecECKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error)
609  {
610      const struct ccec_rfc6637_curve *curve;
611      const struct ccec_rfc6637_unwrap *unwrap;
612      ccec_full_ctx_t fullkey = key->key;
613      CFMutableDataRef data;
614      int res;
615      uint8_t sym_alg = 0;
616      int32_t flags = 0;
617  
618      curve = get_rfc6637_curve(key);
619      if (curve == NULL) {
620          SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve"));
621          return NULL;
622      }
623  
624      CFTypeRef wrapAlg = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPWrapAlg);
625      if (wrapAlg == NULL) {
626          SecError(errSecUnsupportedOperation, error, CFSTR("no wrap alg"));
627          return NULL;
628      } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA256KekAES128)) {
629          unwrap = &ccec_rfc6637_unwrap_sha256_kek_aes128;
630      } else if (CFEqual(wrapAlg, _kSecKeyWrapRFC6637WrapDigestSHA512KekAES256)) {
631          unwrap = &ccec_rfc6637_unwrap_sha512_kek_aes256;
632      } else {
633          SecError(errSecUnsupportedOperation, error, CFSTR("unknown wrap alg"));
634          return NULL;
635      }
636  
637      CFDataRef fingerprint = CFDictionaryGetValue(parameters, _kSecKeyWrapPGPFingerprint);
638      if (!isData(fingerprint) || CFDataGetLength(fingerprint) < kSecKeyWrapPGPFingerprintMinSize) {
639          SecError(errSecUnsupportedOperation, error, CFSTR("invalid fingerprint"));
640          return NULL;
641      }
642  
643      CFNumberRef num = CFDictionaryGetValue(parameters, _kSecKeyWrapRFC6637Flags);
644      if (isNumber(num)) {
645          if (!CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
646              SecError(errSecUnsupportedOperation, error, CFSTR("invalid flags: %@"), num);
647              return NULL;
648          }
649      } else if (num) {
650          SecError(errSecUnsupportedOperation, error, CFSTR("unknown flags"));
651          return NULL;
652      }
653  
654      size_t keysize = CFDataGetLength(wrappedKey);
655      data = CFDataCreateMutableWithScratch(NULL, keysize);
656      if (data == NULL)
657          return NULL;
658  
659      res = ccec_rfc6637_unwrap_key(fullkey, &keysize, CFDataGetMutableBytePtr(data),
660                                    flags, &sym_alg, curve, unwrap,
661                                    CFDataGetBytePtr(fingerprint),
662                                    CFDataGetLength(wrappedKey), CFDataGetBytePtr(wrappedKey));
663      if (res != 0) {
664          CFReleaseNull(data);
665          SecError(errSecUnsupportedOperation, error, CFSTR("failed to wrap key"));
666          return NULL;
667      }
668      assert(keysize <= (size_t)CFDataGetLength(data));
669      CFDataSetLength(data, keysize);
670  
671      if (outParam) {
672          CFMutableDictionaryRef out =  CFDictionaryCreateMutableForCFTypes(NULL);
673          if (out) {
674              CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &sym_alg);
675              if (num) {
676                  CFDictionarySetValue(out, _kSecKeyWrapPGPSymAlg, num);
677                  CFRelease(num);
678              }
679              *outParam = out;
680          }
681      }
682  
683      return data;
684  }
685  
686  SecKeyDescriptor kSecECPrivateKeyDescriptor = {
687      .version = kSecKeyDescriptorVersion,
688      .name = "ECPrivateKey",
689      .extraBytes = ccec_full_ctx_size(ccn_sizeof(kMaximumECKeySize)),
690  
691      .init = SecECPrivateKeyInit,
692      .destroy = SecECPrivateKeyDestroy,
693      .blockSize = SecECPrivateKeyBlockSize,
694      .copyDictionary = SecECPrivateKeyCopyAttributeDictionary,
695      .describe = SecECPrivateKeyCopyKeyDescription,
696      .getAlgorithmID = SecECKeyGetAlgorithmID,
697      .copyPublic = SecECPrivateKeyCopyPublicOctets,
698      .copyExternalRepresentation = SecECPrivateKeyCopyExternalRepresentation,
699      .copyWrapKey = SecECKeyCopyWrapKey,
700      .copyUnwrapKey = SecECKeyCopyUnwrapKey,
701      .copyOperationResult = SecECPrivateKeyCopyOperationResult,
702  };
703  
704  /* Private Key API functions. */
705  SecKeyRef SecKeyCreateECPrivateKey(CFAllocatorRef allocator,
706      const uint8_t *keyData, CFIndex keyDataLength,
707      SecKeyEncoding encoding) {
708      return SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor, keyData,
709          keyDataLength, encoding);
710  }
711  
712  
713  OSStatus SecECKeyGeneratePair(CFDictionaryRef parameters,
714                                SecKeyRef *publicKey, SecKeyRef *privateKey) {
715      OSStatus status = errSecParam;
716  
717      CFAllocatorRef allocator = NULL; /* @@@ get from parameters. */
718      SecKeyRef pubKey = NULL;
719  
720      SecKeyRef privKey = SecKeyCreate(allocator, &kSecECPrivateKeyDescriptor,
721                                       (const void*) parameters, 0, kSecGenerateKey);
722  
723      require_quiet(privKey, errOut);
724  
725      /* Create SecKeyRef's from the pkcs1 encoded keys. */
726      pubKey = SecKeyCreate(allocator, &kSecECPublicKeyDescriptor,
727                            privKey->key, 0, kSecExtractPublicFromPrivate);
728  
729      require_quiet(pubKey, errOut);
730  
731      if (publicKey) {
732          *publicKey = pubKey;
733          pubKey = NULL;
734      }
735      if (privateKey) {
736          *privateKey = privKey;
737          privKey = NULL;
738      }
739  
740      status = errSecSuccess;
741  
742  errOut:
743      CFReleaseSafe(pubKey);
744      CFReleaseSafe(privKey);
745  
746      return status;
747  }
748  
749  
750  /* It's debatable whether this belongs here or in the ssl code since the
751     curve values come from a tls related rfc4492. */
752  SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) {
753      SecECNamedCurve result = kSecECCurveNone;
754      CFDictionaryRef attributes = NULL;
755      require_quiet(SecKeyGetAlgorithmId(key) == kSecECDSAAlgorithmID, out);
756      require_quiet(attributes = SecKeyCopyAttributes(key), out);
757      CFTypeRef bitsRef = CFDictionaryGetValue(attributes, kSecAttrKeySizeInBits);
758      CFIndex bits = 0;
759      require_quiet(bitsRef != NULL && CFGetTypeID(bitsRef) == CFNumberGetTypeID() &&
760                    CFNumberGetValue(bitsRef, kCFNumberCFIndexType, &bits), out);
761      switch (bits) {
762  #if 0
763          case 192:
764              result = kSecECCurveSecp192r1;
765              break;
766          case 224:
767              result = kSecECCurveSecp224r1;
768              break;
769  #endif
770          case 256:
771              result = kSecECCurveSecp256r1;
772              break;
773          case 384:
774              result = kSecECCurveSecp384r1;
775              break;
776          case 521:
777              result = kSecECCurveSecp521r1;
778              break;
779      }
780  
781  out:
782      CFReleaseSafe(attributes);
783      return result;
784  }
785  
786  CFDataRef SecECKeyCopyPublicBits(SecKeyRef key) {
787      CFDataRef bytes = NULL;
788      SecKeyCopyPublicBytes(key, &bytes);
789      return bytes;
790  }
791  
792  /* Vile accessors that get us the pub or priv key to use temporarily */
793  
794  bool SecECDoWithFullKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_full_ctx_t private)) {
795      if (key->key_class == &kSecECPrivateKeyDescriptor) {
796          action(key->key);
797      } else {
798          return SecError(errSecParam, error, CFSTR("Not an EC Full Key object, sorry can't do."));
799      }
800  
801      return true;
802  }
803  
804  bool SecECDoWithPubKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_pub_ctx_t public)) {
805      if (key->key_class == &kSecECPublicKeyDescriptor) {
806          action(key->key);
807      } else {
808          return SecError(errSecParam, error, CFSTR("Not an EC Public Key object, sorry can't do."));
809      }
810  
811      return true;
812  }
813