/ OSX / libsecurity_keychain / lib / SecKey.cpp
SecKey.cpp
   1  /*
   2   * Copyright (c) 2002-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  #include <Security/SecKey.h>
  25  #include <Security/SecKeyPriv.h>
  26  #include <Security/SecKeyInternal.h>
  27  #include <Security/SecItem.h>
  28  #include <Security/SecItemPriv.h>
  29  #include <libDER/asn1Types.h>
  30  #include <libDER/DER_Encode.h>
  31  #include <libDER/DER_Decode.h>
  32  #include <libDER/DER_Keys.h>
  33  #include <Security/SecAsn1Types.h>
  34  #include <Security/SecAsn1Coder.h>
  35  #include <security_keychain/KeyItem.h>
  36  #include <security_utilities/casts.h>
  37  #include <CommonCrypto/CommonKeyDerivation.h>
  38  
  39  #include <CoreFoundation/CFPriv.h>
  40  // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it.
  41  #undef verify
  42  
  43  #include "SecBridge.h"
  44  
  45  #include <security_keychain/Access.h>
  46  #include <security_keychain/Keychains.h>
  47  #include <security_keychain/KeyItem.h>
  48  #include <string.h>
  49  #include <syslog.h>
  50  
  51  #include <security_cdsa_utils/cuCdsaUtils.h>
  52  #include <security_cdsa_client/wrapkey.h>
  53  #include <security_cdsa_client/genkey.h>
  54  #include <security_cdsa_client/signclient.h>
  55  #include <security_cdsa_client/cryptoclient.h>
  56  
  57  #include "SecImportExportCrypto.h"
  58  
  59  static OSStatus
  60  SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
  61      CDSASecKey *cdsaKey = (CDSASecKey *)key;
  62      cdsaKey->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
  63      CDSASecKey::keyItem(key)->initializeWithSecKeyRef(key);
  64      cdsaKey->credentialType = kSecCredentialTypeDefault;
  65      cdsaKey->cdsaKeyMutex = new Mutex();
  66      return errSecSuccess;
  67  }
  68  
  69  static void
  70  SecCDSAKeyDestroy(SecKeyRef keyRef) {
  71      // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
  72      // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
  73      // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
  74  
  75      CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(keyRef);
  76      StMaybeLock<Mutex> cdsaMutex(cdsaKey->cdsaKeyMutex);
  77  
  78      KeyItem *keyItem = static_cast<KeyItem *>(keyRef->key);
  79  
  80      if (keyItem == NULL) {
  81          // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
  82          cdsaMutex.unlock();
  83          delete cdsaKey->cdsaKeyMutex;
  84          return;
  85      }
  86  
  87      Keychain kc = keyItem->keychain();
  88  
  89      // We have a +1 reference to the KeyItem now; no need to protect our storage any more
  90      cdsaMutex.unlock();
  91  
  92      {
  93          StMaybeLock<Mutex> _(keyItem->getMutexForObject());
  94          keyItem = static_cast<KeyItem *>(keyRef->key);
  95          if (keyItem == NULL) {
  96              // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance.
  97              return;
  98          }
  99  
 100          keyItem->aboutToDestruct();
 101          delete keyItem;
 102      }
 103  
 104      delete cdsaKey->cdsaKeyMutex;
 105  
 106      (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
 107  }
 108  
 109  static size_t
 110  SecCDSAKeyGetBlockSize(SecKeyRef key) {
 111  
 112      CFErrorRef *error = NULL;
 113      BEGIN_SECKEYAPI(size_t,0)
 114  
 115      const CssmKey::Header keyHeader = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
 116      switch(keyHeader.algorithm())
 117      {
 118          case CSSM_ALGID_RSA:
 119          case CSSM_ALGID_DSA:
 120              result = keyHeader.LogicalKeySizeInBits / 8;
 121              break;
 122          case CSSM_ALGID_ECDSA:
 123          {
 124              /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
 125               * plus both coordinates for the point used */
 126  #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
 127  #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
 128              size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader.LogicalKeySizeInBits);
 129              assert(coordSize < 256); /* size must fit in a byte for DER */
 130              size_t coordDERLen = (coordSize > 127) ? 2 : 1;
 131              size_t coordLen = 1 + coordDERLen + coordSize;
 132  
 133              size_t pointSize = 2 * coordLen;
 134              assert(pointSize < 256); /* size must fit in a byte for DER */
 135              size_t pointDERLen = (pointSize > 127) ? 2 : 1;
 136              size_t pointLen = 1 + pointDERLen + pointSize;
 137  
 138              result = pointLen;
 139          }
 140              break;
 141          case CSSM_ALGID_AES:
 142              result = 16; /* all AES keys use 128-bit blocks */
 143              break;
 144          case CSSM_ALGID_DES:
 145          case CSSM_ALGID_3DES_3KEY:
 146              result = 8; /* all DES keys use 64-bit blocks */
 147              break;
 148          default:
 149              assert(0); /* some other key algorithm */
 150              result = 16; /* FIXME: revisit this */
 151              break;
 152      }
 153  
 154      END_SECKEYAPI
 155  }
 156  
 157  static CFIndex
 158  SecCDSAKeyGetAlgorithmId(SecKeyRef key) {
 159  
 160      CFErrorRef *error = NULL;
 161      BEGIN_SECKEYAPI(CFIndex, 0)
 162  
 163      result = kSecNullAlgorithmID;
 164      switch (CDSASecKey::keyItem(key)->unverifiedKeyHeader().AlgorithmId) {
 165          case CSSM_ALGID_RSA:
 166              result = kSecRSAAlgorithmID;
 167              break;
 168          case CSSM_ALGID_DSA:
 169              result = kSecDSAAlgorithmID;
 170              break;
 171          case CSSM_ALGID_ECDSA:
 172              result = kSecECDSAAlgorithmID;
 173              break;
 174          default:
 175              assert(0); /* other algorithms TBA */
 176      }
 177  
 178      END_SECKEYAPI
 179  }
 180  
 181  static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) {
 182      // First of all, consider x509 format and try to strip SubjPubKey envelope.  If it fails, do not panic
 183      // and export data as is.
 184      DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem;
 185      DERByte numUnused;
 186      DERSubjPubKeyInfo subjPubKey;
 187      if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
 188                           DERSubjPubKeyInfoItemSpecs,
 189                           &subjPubKey, sizeof(subjPubKey)) == DR_Success &&
 190          DERParseBitString(&subjPubKey.pubKey, &pubKeyItem, &numUnused) == DR_Success) {
 191          return CFDataCreate(kCFAllocatorDefault, pubKeyItem.data, pubKeyItem.length);
 192      }
 193  
 194      return CFDataRef(CFRetain(pubKeyInfo));
 195  }
 196  
 197  static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) {
 198      // First check, whether X509 pubkeyinfo is already present.  If not, add it according to the key type.
 199      DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) };
 200      DERSubjPubKeyInfo subjPubKey;
 201      if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
 202                           DERSubjPubKeyInfoItemSpecs,
 203                           &subjPubKey, sizeof(subjPubKey)) == DR_Success) {
 204          return CFDataRef(CFRetain(pubKeyInfo));
 205      }
 206  
 207      // We have always size rounded to full bytes so bitstring encodes leading 00.
 208      CFRef<CFMutableDataRef> bitStringPubKey = CFDataCreateMutable(kCFAllocatorDefault, 0);
 209      CFDataSetLength(bitStringPubKey, 1);
 210      CFDataAppendBytes(bitStringPubKey, CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo));
 211      subjPubKey.pubKey.data = static_cast<DERByte *>(const_cast<UInt8 *>(CFDataGetBytePtr(bitStringPubKey)));
 212      subjPubKey.pubKey.length = CFDataGetLength(bitStringPubKey);
 213  
 214      // Encode algId according to algorithm used.
 215      static const DERByte oidRSA[] = {
 216          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
 217      };
 218      static const DERByte oidECsecp256[] = {
 219          0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
 220      };
 221      static const DERByte oidECsecp384[] = {
 222          0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
 223      };
 224      static const DERByte oidECsecp521[] = {
 225          0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
 226      };
 227      subjPubKey.algId.length = 0;
 228      if (algorithm == CSSM_ALGID_RSA) {
 229          subjPubKey.algId.data = const_cast<DERByte *>(oidRSA);
 230          subjPubKey.algId.length = sizeof(oidRSA);
 231      } else if (algorithm == CSSM_ALGID_ECDSA) {
 232          if (keySizeInBits == 256) {
 233              subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp256);
 234              subjPubKey.algId.length = sizeof(oidECsecp256);
 235          } else if (keySizeInBits == 384) {
 236              subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384);
 237              subjPubKey.algId.length = sizeof(oidECsecp384);
 238          } if (keySizeInBits == 521) {
 239              subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521);
 240              subjPubKey.algId.length = sizeof(oidECsecp521);
 241          }
 242      }
 243      DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
 244                                                DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs);
 245      CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size);
 246      CFDataSetLength(keyData, size);
 247      if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
 248                            DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs,
 249                            static_cast<DERByte *>(CFDataGetMutableBytePtr(keyData)), &size) == DR_Success) {
 250          CFDataSetLength(keyData, size);
 251      } else {
 252          keyData.release();
 253      }
 254  
 255      return keyData.yield();
 256  }
 257  
 258  static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serialization) {
 259  
 260      CFErrorRef *error = NULL;
 261      BEGIN_SECKEYAPI(OSStatus, errSecSuccess)
 262  
 263      const CssmKey::Header &header = CDSASecKey::keyItem(key)->key().header();
 264      switch (header.algorithm()) {
 265          case CSSM_ALGID_RSA: {
 266              switch (header.keyClass()) {
 267                  case CSSM_KEYCLASS_PRIVATE_KEY: {
 268                      CFRef<CFDataRef> privKeyData;
 269                      result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take());
 270                      if (result == errSecSuccess) {
 271                          DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) };
 272                          DERRSAKeyPair keyPair;
 273                          if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
 274                                               &keyPair, sizeof(keyPair)) == DR_Success) {
 275                              DERRSAPubKeyPKCS1 pubKey = { keyPair.n, keyPair.e };
 276                              DERSize size = DERLengthOfEncodedSequence(ASN1_SEQUENCE, &pubKey,
 277                                                                        DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs);
 278                              CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size);
 279                              CFDataSetLength(keyData, size);
 280                              UInt8 *data = CFDataGetMutableBytePtr(keyData);
 281                              if (DEREncodeSequence(ASN1_SEQUENCE, &pubKey,
 282                                                    DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs,
 283                                                    data, &size) == DR_Success) {
 284                                  CFDataSetLength(keyData, size);
 285                                  *data = ONE_BYTE_ASN1_CONSTR_SEQUENCE;
 286                                  *serialization = keyData.yield();
 287                              } else {
 288                                  *serialization = NULL;
 289                                  result = errSecParam;
 290                              }
 291                          }
 292                      }
 293                      break;
 294                  }
 295                  case CSSM_KEYCLASS_PUBLIC_KEY:
 296                      result = SecItemExport(key, kSecFormatBSAFE, 0, NULL, serialization);
 297                      break;
 298              }
 299              break;
 300          }
 301          case CSSM_ALGID_ECDSA: {
 302              *serialization = NULL;
 303              CFRef<CFDataRef> tempPublicData;
 304              result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, tempPublicData.take());
 305              if (result == errSecSuccess) {
 306                  *serialization = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData);
 307              }
 308              break;
 309          }
 310          default:
 311              result = errSecUnimplemented;
 312      }
 313  
 314      END_SECKEYAPI
 315  }
 316  
 317  typedef struct {
 318      DERItem	privateKey;
 319      DERItem	publicKey;
 320  } DERECPrivateKey;
 321  
 322  static const DERItemSpec DERECPrivateKeyItemSpecs[] =
 323  {
 324      { 0,
 325          ASN1_INTEGER,
 326          DER_DEC_SKIP },
 327      { DER_OFFSET(DERECPrivateKey, privateKey),
 328          ASN1_OCTET_STRING,
 329          DER_DEC_NO_OPTS | DER_ENC_NO_OPTS },
 330      { 0,
 331          ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0,
 332          DER_DEC_SKIP | DER_ENC_NO_OPTS },
 333      { DER_OFFSET(DERECPrivateKey, publicKey),
 334          ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1,
 335          DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
 336  };
 337  static const DERSize DERNumECPrivateKeyItemSpecs =
 338  sizeof(DERECPrivateKeyItemSpecs) / sizeof(DERItemSpec);
 339  
 340  typedef struct {
 341      DERItem bitString;
 342  } DERECPrivateKeyPublicKey;
 343  
 344  static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs[] =
 345  {
 346      { DER_OFFSET(DERECPrivateKeyPublicKey, bitString),
 347          ASN1_BIT_STRING,
 348          DER_DEC_NO_OPTS | DER_ENC_NO_OPTS },
 349  };
 350  static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs =
 351  sizeof(DERECPrivateKeyPublicKeyItemSpecs) / sizeof(DERItemSpec);
 352  
 353  static CFDataRef
 354  SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
 355  
 356      BEGIN_SECKEYAPI(CFDataRef, NULL)
 357  
 358      result = NULL;
 359      const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
 360      CFRef<CFDataRef> keyData;
 361      switch (header.algorithm()) {
 362          case CSSM_ALGID_RSA:
 363              MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
 364              break;
 365          case CSSM_ALGID_ECDSA: {
 366              MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
 367              if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) {
 368                  // Convert DER format into x9.63 format, which is expected for exported key.
 369                  DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) };
 370                  DERECPrivateKey privateKey;
 371                  DERECPrivateKeyPublicKey privateKeyPublicKey;
 372                  DERByte numUnused;
 373                  DERItem pubKeyItem;
 374                  if (DERParseSequence(&keyItem, DERNumECPrivateKeyItemSpecs, DERECPrivateKeyItemSpecs,
 375                                       &privateKey, sizeof(privateKey)) == DR_Success &&
 376                      DERParseSequenceContent(&privateKey.publicKey, DERNumECPrivateKeyPublicKeyItemSpecs,
 377                                              DERECPrivateKeyPublicKeyItemSpecs,
 378                                              &privateKeyPublicKey, sizeof(privateKeyPublicKey)) == DR_Success &&
 379                      DERParseBitString(&privateKeyPublicKey.bitString, &pubKeyItem, &numUnused) == DR_Success) {
 380                      CFRef<CFMutableDataRef> key = CFDataCreateMutable(kCFAllocatorDefault,
 381                                                                        pubKeyItem.length + privateKey.privateKey.length);
 382                      CFDataSetLength(key, pubKeyItem.length + privateKey.privateKey.length);
 383                      CFDataReplaceBytes(key, CFRangeMake(0, pubKeyItem.length), pubKeyItem.data, pubKeyItem.length);
 384                      CFDataReplaceBytes(key, CFRangeMake(pubKeyItem.length, privateKey.privateKey.length),
 385                                         privateKey.privateKey.data, privateKey.privateKey.length);
 386                      keyData = key.as<CFDataRef>();
 387                  }
 388              }
 389              break;
 390          }
 391          default:
 392              MacOSError::throwMe(errSecUnimplemented);
 393      }
 394  
 395      if (header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
 396          result = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData);
 397      } else {
 398          result = keyData.yield();
 399      }
 400  
 401      END_SECKEYAPI
 402  }
 403  
 404  static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) {
 405      CFDataRef label = NULL;
 406      if (CDSASecKey::keyItem(key)->isPersistent()) {
 407          UInt32 tags[] = { kSecKeyLabel }, formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB };
 408          SecKeychainAttributeInfo info = { 1, tags, formats };
 409          SecKeychainAttributeList *list = NULL;
 410          CDSASecKey::keyItem(key)->getAttributesAndData(&info, NULL, &list, NULL, NULL);
 411          if (list->count == 1) {
 412              SecKeychainAttribute *attr = list->attr;
 413              label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attr->data, (CFIndex)attr->length);
 414          }
 415          CDSASecKey::keyItem(key)->freeAttributesAndData(list, NULL);
 416      }
 417      return label;
 418  }
 419  
 420  static CFDictionaryRef
 421  SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) {
 422  
 423      CFErrorRef *error = NULL;
 424      BEGIN_SECKEYAPI(CFDictionaryRef, NULL)
 425  
 426      CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
 427                                                              &kCFTypeDictionaryValueCallBacks);
 428  
 429      CFDictionarySetValue(dict, kSecClass, kSecClassKey);
 430  
 431      const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
 432      CFIndex sizeValue = header.LogicalKeySizeInBits;
 433      CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue);
 434      CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits);
 435      CFDictionarySetValue(dict, kSecAttrEffectiveKeySize, sizeInBits);
 436  
 437      CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(key);
 438      if (!label) {
 439          // For floating keys, calculate label as SHA1 of pubkey bytes.
 440          CFRef<CFDataRef> pubKeyBlob;
 441          if (SecCDSAKeyCopyPublicBytes(key, pubKeyBlob.take()) == errSecSuccess) {
 442              uint8_t pubKeyHash[CC_SHA1_DIGEST_LENGTH];
 443              CC_SHA1(CFDataGetBytePtr(pubKeyBlob), CC_LONG(CFDataGetLength(pubKeyBlob)), pubKeyHash);
 444              label.take(CFDataCreate(kCFAllocatorDefault, pubKeyHash, sizeof(pubKeyHash)));
 445          }
 446      }
 447  
 448      if (label) {
 449          CFDictionarySetValue(dict, kSecAttrApplicationLabel, label);
 450      }
 451  
 452      CSSM_KEYATTR_FLAGS attrs = header.attributes();
 453      CFDictionarySetValue(dict, kSecAttrIsPermanent, (attrs & CSSM_KEYATTR_PERMANENT) ? kCFBooleanTrue : kCFBooleanFalse);
 454      CFDictionarySetValue(dict, kSecAttrIsPrivate, (attrs & CSSM_KEYATTR_PRIVATE) ? kCFBooleanTrue : kCFBooleanFalse);
 455      CFDictionarySetValue(dict, kSecAttrIsModifiable, (attrs & CSSM_KEYATTR_MODIFIABLE) ? kCFBooleanTrue : kCFBooleanFalse);
 456      CFDictionarySetValue(dict, kSecAttrIsSensitive, (attrs & CSSM_KEYATTR_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse);
 457      CFDictionarySetValue(dict, kSecAttrIsExtractable, (attrs & CSSM_KEYATTR_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse);
 458      CFDictionarySetValue(dict, kSecAttrWasAlwaysSensitive, (attrs & CSSM_KEYATTR_ALWAYS_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse);
 459      CFDictionarySetValue(dict, kSecAttrWasNeverExtractable, (attrs & CSSM_KEYATTR_NEVER_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse);
 460  
 461      CFDictionarySetValue(dict, kSecAttrCanEncrypt, (header.useFor(CSSM_KEYUSE_ENCRYPT)) ? kCFBooleanTrue : kCFBooleanFalse);
 462      CFDictionarySetValue(dict, kSecAttrCanDecrypt, (header.useFor(CSSM_KEYUSE_DECRYPT)) ? kCFBooleanTrue : kCFBooleanFalse);
 463      CFDictionarySetValue(dict, kSecAttrCanSign, (header.useFor(CSSM_KEYUSE_SIGN)) ? kCFBooleanTrue : kCFBooleanFalse);
 464      CFDictionarySetValue(dict, kSecAttrCanVerify, (header.useFor(CSSM_KEYUSE_VERIFY)) ? kCFBooleanTrue : kCFBooleanFalse);
 465      CFDictionarySetValue(dict, kSecAttrCanSignRecover, (header.useFor(CSSM_KEYUSE_SIGN_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse);
 466      CFDictionarySetValue(dict, kSecAttrCanVerifyRecover, (header.useFor(CSSM_KEYUSE_VERIFY_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse);
 467      CFDictionarySetValue(dict, kSecAttrCanWrap, (header.useFor(CSSM_KEYUSE_WRAP)) ? kCFBooleanTrue : kCFBooleanFalse);
 468      CFDictionarySetValue(dict, kSecAttrCanUnwrap, (header.useFor(CSSM_KEYUSE_UNWRAP)) ? kCFBooleanTrue : kCFBooleanFalse);
 469      CFDictionarySetValue(dict, kSecAttrCanDerive, (header.useFor(CSSM_KEYUSE_DERIVE)) ? kCFBooleanTrue : kCFBooleanFalse);
 470  
 471      switch (header.keyClass()) {
 472          case CSSM_KEYCLASS_PUBLIC_KEY:
 473              CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic);
 474              break;
 475          case CSSM_KEYCLASS_PRIVATE_KEY:
 476              CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
 477              break;
 478      }
 479  
 480      switch (header.algorithm()) {
 481          case CSSM_ALGID_RSA:
 482              CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA);
 483              break;
 484          case CSSM_ALGID_ECDSA:
 485              CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECDSA);
 486              break;
 487      }
 488  
 489      CFRef<CFDataRef> keyData;
 490      if (SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()) == errSecSuccess) {
 491          CFDictionarySetValue(dict, kSecValueData, keyData);
 492      }
 493  
 494      if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY &&
 495          header.blobType() == CSSM_KEYBLOB_RAW) {
 496          const CssmData &keyData = CDSASecKey::keyItem(key)->key()->keyData();
 497          DERItem keyItem = { static_cast<DERByte *>(keyData.data()), keyData.length() };
 498          DERRSAPubKeyPKCS1 decodedKey;
 499          if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
 500                               DERRSAPubKeyPKCS1ItemSpecs,
 501                               &decodedKey, sizeof(decodedKey)) == DR_Success) {
 502              CFRef<CFDataRef> modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data,
 503                                                      decodedKey.modulus.length);
 504              CFDictionarySetValue(dict, CFSTR("_rsam"), modulus);
 505              CFRef<CFDataRef> exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data,
 506                                                       decodedKey.pubExponent.length);
 507              CFDictionarySetValue(dict, CFSTR("_rsae"), exponent);
 508          }
 509      }
 510  
 511      result = dict;
 512  
 513      END_SECKEYAPI
 514  }
 515  
 516  #pragma clang diagnostic push
 517  #pragma clang diagnostic ignored "-Wunused-const-variable"
 518  static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, BLOB);
 519  #pragma clang diagnostic pop
 520  
 521  static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
 522      CFErrorRef *error = NULL;
 523      BEGIN_SECKEYAPI(SecKeyRef, NULL)
 524  
 525      result = NULL;
 526      KeyItem *key = CDSASecKey::keyItem(privateKey);
 527      CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey);
 528      if (label) {
 529          // Lookup public key in the database.
 530          DbUniqueRecord uniqueId;
 531          SSDb ssDb(dynamic_cast<SSDbImpl *>(&(*key->keychain()->database())));
 532          SSDbCursor dbCursor(ssDb, 1);
 533          dbCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
 534          dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, CssmData(CFDataRef(label)));
 535          if (dbCursor->next(NULL, NULL, uniqueId)) {
 536              Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId);
 537              result = reinterpret_cast<SecKeyRef>(publicKey->handle());
 538          }
 539      }
 540  
 541      if (result == NULL && key->publicKey()) {
 542          SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey()));
 543          result = reinterpret_cast<SecKeyRef>(publicKey->handle());
 544      }
 545  
 546      END_SECKEYAPI
 547  }
 548  
 549  static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm,
 550                                              CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm,
 551                                              CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) {
 552      KeyItem *keyItem = CDSASecKey::keyItem(key);
 553      CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
 554      baseAlgorithm = keyItem->key()->header().algorithm();
 555      switch (baseAlgorithm) {
 556          case CSSM_ALGID_RSA:
 557              if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) ||
 558                  (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) {
 559                  if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) {
 560                      secondaryAlgorithm = CSSM_ALGID_NONE;
 561                      paddingAlgorithm = CSSM_PADDING_NONE;
 562                      inputSizeLimit = 0;
 563                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) {
 564                      secondaryAlgorithm = CSSM_ALGID_NONE;
 565                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 566                      inputSizeLimit = -11;
 567                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
 568                      secondaryAlgorithm = CSSM_ALGID_SHA1;
 569                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 570                      inputSizeLimit = 20;
 571                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
 572                      secondaryAlgorithm = CSSM_ALGID_SHA224;
 573                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 574                      inputSizeLimit = 224 / 8;
 575                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
 576                      secondaryAlgorithm = CSSM_ALGID_SHA256;
 577                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 578                      inputSizeLimit = 256 / 8;
 579                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
 580                      secondaryAlgorithm = CSSM_ALGID_SHA384;
 581                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 582                      inputSizeLimit = 384 / 8;
 583                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
 584                      secondaryAlgorithm = CSSM_ALGID_SHA512;
 585                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 586                      inputSizeLimit = 512 / 8;
 587                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) {
 588                      secondaryAlgorithm = CSSM_ALGID_MD5;
 589                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 590                      inputSizeLimit = 16;
 591                  } else {
 592                      return NULL;
 593                  }
 594              } else if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeDecrypt) ||
 595                         (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeEncrypt)) {
 596                  if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
 597                      secondaryAlgorithm = CSSM_ALGID_NONE;
 598                      paddingAlgorithm = CSSM_PADDING_NONE;
 599                      inputSizeLimit = 0;
 600                  } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) {
 601                      secondaryAlgorithm = CSSM_ALGID_NONE;
 602                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 603                      inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0;
 604                  } else {
 605                      return NULL;
 606                  }
 607              } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt &&
 608                         CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
 609                  // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption,
 610                  // because CDSA keys refuses to perform decrypt using public key.
 611                  operation = kSecKeyOperationTypeEncrypt;
 612                  secondaryAlgorithm = CSSM_ALGID_NONE;
 613                  paddingAlgorithm = CSSM_PADDING_NONE;
 614                  inputSizeLimit = 0;
 615              } else {
 616                  return NULL;
 617              }
 618              break;
 619          case CSSM_ALGID_ECDSA:
 620              if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) ||
 621                  (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) {
 622                  if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) {
 623                      secondaryAlgorithm = CSSM_ALGID_NONE;
 624                      paddingAlgorithm = CSSM_PADDING_SIGRAW;
 625                  } else if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
 626                      secondaryAlgorithm = CSSM_ALGID_NONE;
 627                      paddingAlgorithm = CSSM_PADDING_PKCS1;
 628                  } else {
 629                      return NULL;
 630                  }
 631              } else if (keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeKeyExchange) {
 632                  if (CFEqual(algorithm,kSecKeyAlgorithmECDHKeyExchangeStandard) ||
 633                      CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
 634                      baseAlgorithm = CSSM_ALGID_ECDH;
 635                  } else if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1) ||
 636                             CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1)) {
 637                      baseAlgorithm = CSSM_ALGID_ECDH_X963_KDF;
 638                  } else {
 639                      return NULL;
 640                  }
 641              } else {
 642                  return NULL;
 643              }
 644              break;
 645          default:
 646              MacOSError::throwMe(errSecParam);
 647      }
 648      return keyItem;
 649  }
 650  
 651  static CFDataRef
 652  SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) {
 653      CFIndex blockSize = CDSASecKey::keyItem(key)->key().header().LogicalKeySizeInBits / 8;
 654      CFIndex plaintextLength = CFDataGetLength(plaintext);
 655      if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw)
 656          && plaintextLength < blockSize) {
 657          // Pre-pad with zeroes.
 658          CFMutableDataRef result(CFDataCreateMutable(kCFAllocatorDefault, blockSize));
 659          CFDataSetLength(result, blockSize);
 660          CFDataReplaceBytes(result, CFRangeMake(blockSize - plaintextLength, plaintextLength),
 661                             CFDataGetBytePtr(plaintext), plaintextLength);
 662          return result;
 663      } else {
 664          return CFDataRef(CFRetain(plaintext));
 665      }
 666  }
 667  
 668  static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
 669                                                 CFArrayRef allAlgorithms, SecKeyOperationMode mode,
 670                                                 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
 671      BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
 672      CFIndex inputSizeLimit = 0;
 673      CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm;
 674      KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit);
 675      if (keyItem == NULL) {
 676          // Operation/algorithm/key combination is not supported.
 677          return kCFNull;
 678      } else if (mode == kSecKeyOperationModeCheckIfSupported) {
 679          // Operation is supported and caller wants to just know that.
 680          return kCFBooleanTrue;
 681      } else if (baseAlgorithm == CSSM_ALGID_RSA) {
 682          if (inputSizeLimit <= 0) {
 683              inputSizeLimit += SecCDSAKeyGetBlockSize(key);
 684          }
 685          if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) {
 686              MacOSError::throwMe(errSecParam);
 687          }
 688      }
 689  
 690      CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(key);
 691      switch (operation) {
 692          case kSecKeyOperationTypeSign: {
 693              CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
 694              signContext.key(keyItem->key());
 695              signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, cdsaKey->credentialType));
 696              signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
 697              CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
 698              CssmAutoData signature(signContext.allocator());
 699              signContext.sign(CssmData(CFDataRef(input)), signature.get());
 700              result = CFDataCreate(NULL, static_cast<const UInt8 *>(signature.data()), CFIndex(signature.length()));
 701              break;
 702          }
 703          case kSecKeyOperationTypeVerify: {
 704              CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
 705              verifyContext.key(keyItem->key());
 706              verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, cdsaKey->credentialType));
 707              verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
 708              CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
 709              verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam)));
 710              result = kCFBooleanTrue;
 711              break;
 712          }
 713          case kSecKeyOperationTypeEncrypt: {
 714              CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm);
 715              encryptContext.key(keyItem->key());
 716              encryptContext.padding(paddingAlgorithm);
 717              encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, cdsaKey->credentialType));
 718              CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
 719              CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator());
 720              size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get());
 721              result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length());
 722              CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length());
 723              CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length());
 724              CFDataSetLength(CFMutableDataRef(result), length);
 725              break;
 726          }
 727          case kSecKeyOperationTypeDecrypt: {
 728              CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm);
 729              decryptContext.key(keyItem->key());
 730              decryptContext.padding(paddingAlgorithm);
 731              decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, cdsaKey->credentialType));
 732              CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
 733              size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
 734                                                     output.get(), remainingData.get());
 735              result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length());
 736              CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length());
 737              CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length());
 738              CFDataSetLength(CFMutableDataRef(result), length);
 739              break;
 740          }
 741          case kSecKeyOperationTypeKeyExchange: {
 742              CFIndex requestedLength = 0;
 743              CssmData sharedInfo;
 744              switch (baseAlgorithm) {
 745                  case CSSM_ALGID_ECDH:
 746                      requestedLength = (keyItem->key().header().LogicalKeySizeInBits + 7) / 8;
 747                      break;
 748                  case CSSM_ALGID_ECDH_X963_KDF:
 749                      CFDictionaryRef params = CFRef<CFDictionaryRef>::check(in2, errSecParam);
 750                      CFTypeRef value = params ? CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterRequestedSize) : NULL;
 751                      if (value == NULL || CFGetTypeID(value) != CFNumberGetTypeID() ||
 752                          !CFNumberGetValue(CFNumberRef(value), kCFNumberCFIndexType, &requestedLength)) {
 753                          MacOSError::throwMe(errSecParam);
 754                      }
 755                      value = CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterSharedInfo);
 756                      if (value != NULL && CFGetTypeID(value) == CFDataGetTypeID()) {
 757                          sharedInfo = CssmData(CFDataRef(value));
 758                      }
 759                      break;
 760              }
 761  
 762              CssmClient::DeriveKey derive(keyItem->csp(), baseAlgorithm, CSSM_ALGID_AES, uint32(requestedLength * 8));
 763              derive.key(keyItem->key());
 764              derive.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE, kSecCredentialTypeDefault));
 765              derive.salt(sharedInfo);
 766              CssmData param(CFRef<CFDataRef>::check(in1, errSecParam));
 767              Key derivedKey = derive(&param, KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE));
 768  
 769              // Export raw data of newly derived key (by wrapping with an empty key).
 770              CssmClient::WrapKey wrapper(keyItem->csp(), CSSM_ALGID_NONE);
 771              Key wrappedKey = wrapper(derivedKey);
 772              result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)wrappedKey->data(), CFIndex(wrappedKey->length()));
 773              break;
 774          }
 775          default:
 776              break;
 777      }
 778  
 779      END_SECKEYAPI
 780  }
 781  
 782  static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
 783      CFErrorRef *error = NULL;
 784      BEGIN_SECKEYAPI(Boolean, false)
 785  
 786      result = CDSASecKey::keyItem(key1)->equal(*CDSASecKey::keyItem(key2));
 787  
 788      END_SECKEYAPI
 789  }
 790  
 791  static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
 792      BEGIN_SECKEYAPI(Boolean, false)
 793  
 794      if (CFEqual(name, kSecUseAuthenticationUI)) {
 795          static_cast<CDSASecKey *>(key)->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI;
 796          result = true;
 797      } else {
 798          result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name);
 799      }
 800  
 801      END_SECKEYAPI
 802  }
 803  
 804  const SecKeyDescriptor kSecCDSAKeyDescriptor = {
 805      .version = kSecKeyDescriptorVersion,
 806      .name = "CDSAKey",
 807      .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
 808  
 809      .init = SecCDSAKeyInit,
 810      .destroy = SecCDSAKeyDestroy,
 811      .blockSize = SecCDSAKeyGetBlockSize,
 812      .copyDictionary = SecCDSAKeyCopyAttributeDictionary,
 813      .getAlgorithmID = SecCDSAKeyGetAlgorithmId,
 814      .copyPublic = SecCDSAKeyCopyPublicBytes,
 815      .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
 816      .copyPublicKey = SecCDSAKeyCopyPublicKey,
 817      .copyOperationResult = SecCDSAKeyCopyOperationResult,
 818      .isEqual = SecCDSAKeyIsEqual,
 819      .setParameter = SecCDSAKeySetParameter,
 820  };
 821  
 822  namespace Security {
 823      namespace KeychainCore {
 824          SecCFObject *KeyItem::fromSecKeyRef(CFTypeRef ptr) {
 825              if (ptr == NULL || CFGetTypeID(ptr) != SecKeyGetTypeID()) {
 826                  return NULL;
 827              }
 828  
 829              SecKeyRef key = static_cast<SecKeyRef>(const_cast<void *>(ptr));
 830              if (key->key_class == &kSecCDSAKeyDescriptor) {
 831                  return static_cast<SecCFObject *>(key->key);
 832              }
 833  
 834              CFRef<SecKeyRef> cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key);
 835              if (!cdsaKey) {
 836                  // Create CDSA key from exported data of existing key.
 837                  CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
 838                  if (keyAttributes) {
 839                      CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
 840                      if (!keyData) {
 841                          CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel);
 842                          const void *keys[] = { kSecClass, kSecUseDataProtectionKeychain, kSecReturnRef, kSecMatchLimit };
 843                          const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll };
 844                          CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
 845                                                                            sizeof(keys) / sizeof(*keys),
 846                                                                            &kCFTypeDictionaryKeyCallBacks,
 847                                                                            &kCFTypeDictionaryValueCallBacks);
 848                          CFRef<CFArrayRef> identities;
 849                          OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
 850                          if (status == errSecSuccess) {
 851                              for (int i = 0; i < CFArrayGetCount(identities); ++i) {
 852                                  CFRef<SecKeyRef> privateKey;
 853                                  if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
 854                                      continue;
 855                                  }
 856                                  CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey);
 857                                  if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) {
 858                                      cdsaKey = privateKey;
 859                                      SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
 860                                      break;
 861                                  }
 862                              }
 863                          }
 864                      } else {
 865                          cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL));
 866                          if (cdsaKey) {
 867                              SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
 868                          }
 869                      }
 870                  }
 871              }
 872  
 873              return cdsaKey ? CDSASecKey::keyItem(cdsaKey.get()) : NULL;
 874          }
 875  
 876          // You need to hold this key's MutexForObject when you run this
 877          void KeyItem::attachSecKeyRef() const {
 878              SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0);
 879              CDSASecKey::keyItem(key)->mWeakSecKeyRef = key;
 880          }
 881  
 882      }
 883  }
 884  
 885  extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
 886  Boolean SecKeyIsCDSAKey(SecKeyRef ref) {
 887      return ref->key_class == &kSecCDSAKeyDescriptor;
 888  }
 889  
 890  
 891  static OSStatus SecKeyCreatePairInternal(
 892  	SecKeychainRef keychainRef,
 893  	CSSM_ALGORITHMS algorithm,
 894  	uint32 keySizeInBits,
 895  	CSSM_CC_HANDLE contextHandle,
 896  	CSSM_KEYUSE publicKeyUsage,
 897  	uint32 publicKeyAttr,
 898  	CSSM_KEYUSE privateKeyUsage,
 899  	uint32 privateKeyAttr,
 900  	SecAccessRef initialAccess,
 901  	SecKeyRef* publicKeyRef,
 902  	SecKeyRef* privateKeyRef)
 903  {
 904  	BEGIN_SECAPI
 905  
 906      Keychain keychain;
 907      SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
 908      SecPointer<KeyItem> pubItem, privItem;
 909      if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) {
 910          keychain = Keychain::optional(keychainRef);
 911      }
 912      StMaybeLock<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL);
 913      KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr,
 914                          privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem);
 915  
 916  	// Return the generated keys.
 917  	if (publicKeyRef)
 918  		*publicKeyRef = pubItem->handle();
 919  	if (privateKeyRef)
 920  		*privateKeyRef = privItem->handle();
 921  
 922  	END_SECAPI
 923  }
 924  
 925  OSStatus
 926  SecKeyCreatePair(
 927  	SecKeychainRef keychainRef,
 928  	CSSM_ALGORITHMS algorithm,
 929  	uint32 keySizeInBits,
 930  	CSSM_CC_HANDLE contextHandle,
 931  	CSSM_KEYUSE publicKeyUsage,
 932  	uint32 publicKeyAttr,
 933  	CSSM_KEYUSE privateKeyUsage,
 934  	uint32 privateKeyAttr,
 935  	SecAccessRef initialAccess,
 936  	SecKeyRef* publicKeyRef,
 937  	SecKeyRef* privateKeyRef)
 938  {
 939      OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage,
 940                                                 publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef);
 941  
 942      return result;
 943  }
 944  
 945  
 946  
 947  OSStatus
 948  SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
 949  {
 950  	BEGIN_SECAPI
 951  
 952  	Required(cssmKey) = KeyItem::required(key)->key();
 953  
 954  	END_SECAPI
 955  }
 956  
 957  
 958  //
 959  // Private APIs
 960  //
 961  
 962  static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex;
 963  static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeyCSPs;
 964  
 965  OSStatus
 966  SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
 967  {
 968      BEGIN_SECAPI
 969  
 970  	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
 971  
 972      // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
 973      // Keep a global pointer to it to force the CSP to stay live forever.
 974      CssmClient::CSP returnedKeyCSP = keyItem->csp();
 975      {
 976          StLock<Mutex> _(gSecReturnedKeyCSPsMutex());
 977          gSecReturnedKeyCSPs().insert(returnedKeyCSP);
 978      }
 979  	Required(cspHandle) = returnedKeyCSP->handle();
 980  
 981  	END_SECAPI
 982  }
 983  
 984  /* deprecated as of 10.8 */
 985  OSStatus
 986  SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
 987  {
 988  	BEGIN_SECAPI
 989  
 990  	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
 991  	Required(algid) = &keyItem->algorithmIdentifier();
 992  
 993  	END_SECAPI
 994  }
 995  
 996  OSStatus
 997  SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength)
 998  {
 999      BEGIN_SECAPI
1000  
1001  	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1002  	Required(strength) = keyItem->strengthInBits(algid);
1003  
1004  	END_SECAPI
1005  }
1006  
1007  OSStatus
1008  SecKeyGetCredentials(
1009  	SecKeyRef keyRef,
1010  	CSSM_ACL_AUTHORIZATION_TAG operation,
1011  	SecCredentialType credentialType,
1012  	const CSSM_ACCESS_CREDENTIALS **outCredentials)
1013  {
1014  	BEGIN_SECAPI
1015  
1016  	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1017  	Required(outCredentials) = keyItem->getCredentials(operation, credentialType);
1018  
1019  	END_SECAPI
1020  }
1021  
1022  OSStatus
1023  SecKeyImportPair(
1024  	SecKeychainRef keychainRef,
1025  	const CSSM_KEY *publicCssmKey,
1026  	const CSSM_KEY *privateCssmKey,
1027  	SecAccessRef initialAccess,
1028  	SecKeyRef* publicKey,
1029  	SecKeyRef* privateKey)
1030  {
1031  	BEGIN_SECAPI
1032  
1033  	Keychain keychain = Keychain::optional(keychainRef);
1034  	SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
1035  	SecPointer<KeyItem> pubItem, privItem;
1036  
1037  	KeyItem::importPair(keychain,
1038  		Required(publicCssmKey),
1039  		Required(privateCssmKey),
1040          theAccess,
1041          pubItem,
1042          privItem);
1043  
1044  	// Return the generated keys.
1045  	if (publicKey)
1046  		*publicKey = pubItem->handle();
1047  	if (privateKey)
1048  		*privateKey = privItem->handle();
1049  
1050  	END_SECAPI
1051  }
1052  
1053  static OSStatus
1054  SecKeyGenerateWithAttributes(
1055  	SecKeychainAttributeList* attrList,
1056  	SecKeychainRef keychainRef,
1057  	CSSM_ALGORITHMS algorithm,
1058  	uint32 keySizeInBits,
1059  	CSSM_CC_HANDLE contextHandle,
1060  	CSSM_KEYUSE keyUsage,
1061  	uint32 keyAttr,
1062  	SecAccessRef initialAccess,
1063  	SecKeyRef* keyRef)
1064  {
1065  	BEGIN_SECAPI
1066  
1067  	Keychain keychain;
1068  	SecPointer<Access> theAccess;
1069  
1070  	if (keychainRef)
1071  		keychain = KeychainImpl::required(keychainRef);
1072  	if (initialAccess)
1073  		theAccess = Access::required(initialAccess);
1074  
1075  	SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList,
1076          keychain,
1077          algorithm,
1078          keySizeInBits,
1079          contextHandle,
1080          keyUsage,
1081          keyAttr,
1082          theAccess);
1083  
1084  	// Return the generated key.
1085  	if (keyRef)
1086  		*keyRef = item->handle();
1087  
1088  	END_SECAPI
1089  }
1090  
1091  OSStatus
1092  SecKeyGenerate(
1093  	SecKeychainRef keychainRef,
1094  	CSSM_ALGORITHMS algorithm,
1095  	uint32 keySizeInBits,
1096  	CSSM_CC_HANDLE contextHandle,
1097  	CSSM_KEYUSE keyUsage,
1098  	uint32 keyAttr,
1099  	SecAccessRef initialAccess,
1100  	SecKeyRef* keyRef)
1101  {
1102  	return SecKeyGenerateWithAttributes(NULL,
1103  		keychainRef, algorithm, keySizeInBits,
1104  		contextHandle, keyUsage, keyAttr,
1105  		initialAccess, keyRef);
1106  }
1107  
1108  /* new in 10.6 */
1109  /* Generate a floating key reference from a CSSM_KEY */
1110  OSStatus
1111  SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey,
1112      SecKeyRef *keyRef)
1113  {
1114  	BEGIN_SECAPI
1115  
1116  	Required(cssmKey);
1117      if(cssmKey->KeyData.Length == 0){
1118          MacOSError::throwMe(errSecInvalidAttributeKeyLength);
1119      }
1120      if(cssmKey->KeyData.Data == NULL){
1121          MacOSError::throwMe(errSecInvalidPointer);
1122      }
1123  	CssmClient::CSP csp(cssmKey->KeyHeader.CspId);
1124  	CssmClient::Key key(csp, *cssmKey);
1125  	KeyItem *item = new KeyItem(key);
1126  
1127  	// Return the generated key.
1128  	if (keyRef)
1129          *keyRef = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, (const uint8_t *)item, 0, 0);
1130  
1131  	END_SECAPI
1132  }
1133  
1134  
1135  
1136  static u_int32_t ConvertCFStringToInteger(CFStringRef ref)
1137  {
1138  	if (ref == NULL)
1139  	{
1140  		return 0;
1141  	}
1142  
1143  	// figure out the size of the string
1144  	CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8);
1145  	char *buffer = (char *)malloc(numChars);
1146      if (NULL == buffer) {
1147          UnixError::throwMe(ENOMEM);
1148      }
1149  	if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8))
1150  	{
1151          free(buffer);
1152  		MacOSError::throwMe(errSecParam);
1153  	}
1154  
1155      u_int32_t result = atoi(buffer);
1156      free(buffer);
1157      return result;
1158  }
1159  
1160  
1161  
1162  static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms)
1163  {
1164  	// figure out the algorithm to use
1165  	CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType);
1166  	if (ktype == NULL)
1167  	{
1168  		return errSecParam;
1169  	}
1170  
1171  	if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
1172  		algorithms = CSSM_ALGID_RSA;
1173  		return errSecSuccess;
1174         } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) ||
1175                         CFEqual(ktype, kSecAttrKeyTypeEC)) {
1176  		algorithms = CSSM_ALGID_ECDSA;
1177  		return errSecSuccess;
1178  	} else if(CFEqual(ktype, kSecAttrKeyTypeAES)) {
1179  		algorithms = CSSM_ALGID_AES;
1180  		return errSecSuccess;
1181  	} else if(CFEqual(ktype, kSecAttrKeyType3DES)) {
1182  		algorithms = CSSM_ALGID_3DES;
1183  		return errSecSuccess;
1184  	} else {
1185  		return errSecUnsupportedAlgorithm;
1186  	}
1187  }
1188  
1189  
1190  
1191  static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits)
1192  {
1193  
1194      // get the key size and check it for validity
1195      CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
1196  
1197      keySizeInBits = kSecDefaultKeySize;
1198  
1199      CFTypeID bitSizeType = CFGetTypeID(ref);
1200      if (bitSizeType == CFStringGetTypeID())
1201          keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref);
1202      else if (bitSizeType == CFNumberGetTypeID())
1203          CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits);
1204      else return errSecParam;
1205  
1206  
1207      switch (algorithms) {
1208      case CSSM_ALGID_ECDSA:
1209          if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1;
1210          if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess;
1211          break;
1212      case CSSM_ALGID_RSA:
1213  			  if(keySizeInBits % 8) return errSecParam;
1214          if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048;
1215          if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess;
1216          break;
1217      case CSSM_ALGID_AES:
1218          if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128;
1219          if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess;
1220          break;
1221      case CSSM_ALGID_3DES:
1222          if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192;
1223          if(keySizeInBits == kSec3DES192) return errSecSuccess;
1224          break;
1225      default:
1226          break;
1227      }
1228      return errSecParam;
1229  }
1230  
1231  
1232  
1233  enum AttributeType
1234  {
1235  	kStringType,
1236  	kBooleanType,
1237  	kIntegerType
1238  };
1239  
1240  
1241  
1242  struct ParameterAttribute
1243  {
1244  	const CFStringRef *name;
1245  	AttributeType type;
1246  };
1247  
1248  
1249  
1250  static ParameterAttribute gAttributes[] =
1251  {
1252  	{
1253  		&kSecAttrLabel,
1254  		kStringType
1255  	},
1256  	{
1257  		&kSecAttrIsPermanent,
1258  		kBooleanType
1259  	},
1260  	{
1261  		&kSecAttrApplicationTag,
1262  		kStringType
1263  	},
1264  	{
1265  		&kSecAttrEffectiveKeySize,
1266  		kBooleanType
1267  	},
1268  	{
1269  		&kSecAttrCanEncrypt,
1270  		kBooleanType
1271  	},
1272  	{
1273  		&kSecAttrCanDecrypt,
1274  		kBooleanType
1275  	},
1276  	{
1277  		&kSecAttrCanDerive,
1278  		kBooleanType
1279  	},
1280  	{
1281  		&kSecAttrCanSign,
1282  		kBooleanType
1283  	},
1284  	{
1285  		&kSecAttrCanVerify,
1286  		kBooleanType
1287  	},
1288  	{
1289  		&kSecAttrCanUnwrap,
1290  		kBooleanType
1291  	}
1292  };
1293  
1294  const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute);
1295  
1296  static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[])
1297  {
1298  	int i;
1299  	for (i = 0; i < kNumberOfAttributes; ++i)
1300  	{
1301  		// see if the corresponding tag exists in the dictionary
1302  		CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name));
1303  		if (value != NULL)
1304  		{
1305  			switch (gAttributes[i].type)
1306  			{
1307  				case kStringType:
1308  					// just return the value
1309  					*(CFTypeRef*) attributePointers[i] = value;
1310  				break;
1311  
1312  				case kBooleanType:
1313  				{
1314  					CFBooleanRef bRef = (CFBooleanRef) value;
1315  					*(bool*) attributePointers[i] = CFBooleanGetValue(bRef);
1316  				}
1317  				break;
1318  
1319  				case kIntegerType:
1320  				{
1321  					CFNumberRef nRef = (CFNumberRef) value;
1322  					CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]);
1323  				}
1324  				break;
1325  			}
1326  		}
1327  	}
1328  
1329  	return errSecSuccess;
1330  }
1331  
1332  
1333  
1334  static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef)
1335  {
1336  	// establish default values
1337  	labelRef = NULL;
1338  	bool isPermanent = false;
1339  	applicationTagRef = NULL;
1340  	CFTypeRef effectiveKeySize = NULL;
1341  	bool canDecrypt = isPublic ? false : true;
1342  	bool canEncrypt = !canDecrypt;
1343  	bool canDerive = true;
1344  	bool canSign = isPublic ? false : true;
1345  	bool canVerify = !canSign;
1346  	bool canUnwrap = isPublic ? false : true;
1347  	attrs = CSSM_KEYATTR_EXTRACTABLE;
1348  	keyUse = 0;
1349  
1350  	void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt,
1351  								 &canDerive, &canSign, &canVerify, &canUnwrap};
1352  
1353  	// look for modifiers in the general dictionary
1354  	OSStatus result = ScanDictionaryForParameters(parameters, attributePointers);
1355  	if (result != errSecSuccess)
1356  	{
1357  		return result;
1358  	}
1359  
1360  	// see if we have anything which modifies the defaults
1361  	CFTypeRef key;
1362  	if (isPublic)
1363  	{
1364  		key = kSecPublicKeyAttrs;
1365  	}
1366  	else
1367  	{
1368  		key = kSecPrivateKeyAttrs;
1369  	}
1370  
1371  	CFTypeRef dType = CFDictionaryGetValue(parameters, key);
1372  	if (dType != NULL)
1373  	{
1374  		// this had better be a dictionary
1375  		if (CFGetTypeID(dType) != CFDictionaryGetTypeID())
1376  		{
1377  			return errSecParam;
1378  		}
1379  
1380  		// pull any additional parameters out of this dictionary
1381  		result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers);
1382  		if (result != errSecSuccess)
1383  		{
1384  			return result;
1385  		}
1386  	}
1387  
1388  	// figure out the key usage
1389  	keyUse = 0;
1390  	if (canDecrypt)
1391  	{
1392  		keyUse |= CSSM_KEYUSE_DECRYPT;
1393  	}
1394  
1395  	if (canEncrypt)
1396  	{
1397  		keyUse |= CSSM_KEYUSE_ENCRYPT;
1398  	}
1399  
1400  	if (canDerive)
1401  	{
1402  		keyUse |= CSSM_KEYUSE_DERIVE;
1403  	}
1404  
1405  	if (canSign)
1406  	{
1407  		keyUse |= CSSM_KEYUSE_SIGN;
1408  	}
1409  
1410  	if (canVerify)
1411  	{
1412  		keyUse |= CSSM_KEYUSE_VERIFY;
1413  	}
1414  
1415  	if (canUnwrap)
1416  	{
1417  		keyUse |= CSSM_KEYUSE_UNWRAP;
1418  	}
1419  
1420  	// public key is always extractable;
1421  	// private key is extractable by default unless explicitly set to false
1422  	CFTypeRef value = NULL;
1423  	if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value)
1424  	{
1425  		Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value);
1426  		if (!keyIsExtractable)
1427  			attrs = 0;
1428  	}
1429  
1430      if (isPermanent) {
1431          attrs |= CSSM_KEYATTR_PERMANENT;
1432      }
1433  
1434  	return errSecSuccess;
1435  }
1436  
1437  
1438  
1439  static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters,
1440  												   CSSM_ALGORITHMS &algorithms,
1441  												   uint32 &keySizeInBits,
1442  												   CSSM_KEYUSE &publicKeyUse,
1443  												   uint32 &publicKeyAttr,
1444  												   CFTypeRef &publicKeyLabelRef,
1445  												   CFDataRef &publicKeyAttributeTagRef,
1446  												   CSSM_KEYUSE &privateKeyUse,
1447  												   uint32 &privateKeyAttr,
1448  												   CFTypeRef &privateKeyLabelRef,
1449  												   CFDataRef &privateKeyAttributeTagRef,
1450  												   SecAccessRef &initialAccess)
1451  {
1452  	OSStatus result;
1453  
1454  	result = CheckAlgorithmType(parameters, algorithms);
1455  	if (result != errSecSuccess)
1456  	{
1457  		return result;
1458  	}
1459  
1460  	result = GetKeySize(parameters, algorithms, keySizeInBits);
1461  	if (result != errSecSuccess)
1462  	{
1463  		return result;
1464  	}
1465  
1466  	result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef);
1467  	if (result != errSecSuccess)
1468  	{
1469  		return result;
1470  	}
1471  
1472  	result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef);
1473  	if (result != errSecSuccess)
1474  	{
1475  		return result;
1476  	}
1477  
1478  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess))
1479  	{
1480  		initialAccess = NULL;
1481  	}
1482  	else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess))
1483  	{
1484  		return errSecParam;
1485  	}
1486  
1487  	return errSecSuccess;
1488  }
1489  
1490  
1491  
1492  static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag)
1493  {
1494  	int numToModify = 0;
1495  	if (label != NULL)
1496  	{
1497  		numToModify += 1;
1498  	}
1499  
1500  	if (tag != NULL)
1501  	{
1502  		numToModify += 1;
1503  	}
1504  
1505  	if (numToModify == 0)
1506  	{
1507  		return errSecSuccess;
1508  	}
1509  
1510  	SecKeychainAttributeList attrList;
1511  	SecKeychainAttribute attributes[numToModify];
1512  
1513  	int i = 0;
1514      void *data = NULL;
1515  
1516  	if (label != NULL)
1517  	{
1518  		if (CFStringGetTypeID() == CFGetTypeID(label)) {
1519  			CFStringRef label_string = static_cast<CFStringRef>(label);
1520  			attributes[i].tag = kSecKeyPrintName;
1521  			attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8);
1522  			if (NULL == attributes[i].data) {
1523  				CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8);
1524  				data = attributes[i].data = malloc((size_t)buffer_length);
1525  				if (NULL == attributes[i].data) {
1526  					UnixError::throwMe(ENOMEM);
1527  				}
1528  				if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
1529                      free(data);
1530  					MacOSError::throwMe(errSecParam);
1531  				}
1532  			}
1533  			attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data));
1534  		} else if (CFDataGetTypeID() == CFGetTypeID(label)) {
1535  			// 10.6 bug compatibility
1536  			CFDataRef label_data = static_cast<CFDataRef>(label);
1537  			attributes[i].tag = kSecKeyLabel;
1538  			attributes[i].data = (void*) CFDataGetBytePtr(label_data);
1539  			attributes[i].length = (UInt32)CFDataGetLength(label_data);
1540  		} else {
1541  			MacOSError::throwMe(errSecParam);
1542  		}
1543  		i++;
1544  	}
1545  
1546  	if (tag != NULL)
1547  	{
1548  		attributes[i].tag = kSecKeyApplicationTag;
1549  		attributes[i].data = (void*) CFDataGetBytePtr(tag);
1550  		attributes[i].length = (UInt32)CFDataGetLength(tag);
1551  		i++;
1552  	}
1553  
1554  	attrList.count = numToModify;
1555  	attrList.attr = attributes;
1556      
1557  	OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL);
1558      if (data)
1559      {
1560          free(data);
1561      }
1562      
1563      return result;
1564  }
1565  
1566  
1567  static CFTypeRef GetAttributeFromParams(CFDictionaryRef parameters, CFTypeRef attr, CFTypeRef subParams) {
1568      if (subParams != NULL) {
1569          CFDictionaryRef subParamsDict = (CFDictionaryRef)CFDictionaryGetValue(parameters, subParams);
1570          if (subParamsDict != NULL) {
1571              CFTypeRef value = CFDictionaryGetValue(subParamsDict, attr);
1572              if (value != NULL) {
1573                  return value;
1574              }
1575          }
1576      }
1577      return CFDictionaryGetValue(parameters, attr);
1578  }
1579  
1580  extern "C" OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey);
1581  
1582  /* new in 10.6 */
1583  /* Generate a private/public keypair. */
1584  static OSStatus
1585  SecKeyGeneratePairInternal(
1586      bool alwaysPermanent,
1587  	CFDictionaryRef parameters,
1588  	SecKeyRef *publicKey,
1589  	SecKeyRef *privateKey)
1590  {
1591  	BEGIN_SECAPI
1592  
1593  	Required(parameters);
1594      Required(publicKey);
1595      Required(privateKey);
1596  
1597      bool forceIOSKey = false;
1598      if (_CFMZEnabled()) {
1599          // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1600          forceIOSKey = true;
1601      } else {
1602          CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL);
1603          CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecUseDataProtectionKeychain, NULL);
1604  #pragma clang diagnostic push
1605  #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1606          if (!noLegacy) {    // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot
1607              noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL);
1608          }
1609  #pragma clang diagnostic pop
1610          CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs);
1611          CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?:
1612          GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs);
1613          CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?:
1614          GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs);
1615          // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1616          forceIOSKey = (tokenID != NULL ||
1617                         (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) ||
1618                         (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) ||
1619                         accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken)));
1620      }
1621  
1622      if (forceIOSKey) {
1623          // Generate keys in iOS keychain.
1624          return SecKeyGeneratePair_ios(parameters, publicKey, privateKey);
1625      }
1626  
1627  	CSSM_ALGORITHMS algorithms;
1628  	uint32 keySizeInBits;
1629  	CSSM_KEYUSE publicKeyUse;
1630  	uint32 publicKeyAttr;
1631  	CFTypeRef publicKeyLabelRef;
1632  	CFDataRef publicKeyAttributeTagRef;
1633  	CSSM_KEYUSE privateKeyUse;
1634  	uint32 privateKeyAttr;
1635  	CFTypeRef privateKeyLabelRef;
1636  	CFDataRef privateKeyAttributeTagRef;
1637  	SecAccessRef initialAccess;
1638  	SecKeychainRef keychain;
1639  
1640  	OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef,
1641  														 publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef,
1642  														 initialAccess);
1643  
1644  	if (result != errSecSuccess) {
1645  		return result;
1646  	}
1647  
1648  	// verify keychain parameter
1649      keychain = (SecKeychainRef)CFDictionaryGetValue(parameters, kSecUseKeychain);
1650      if (keychain != NULL && SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1651  		keychain = NULL;
1652      }
1653  
1654      if (alwaysPermanent) {
1655          publicKeyAttr |= CSSM_KEYATTR_PERMANENT;
1656          privateKeyAttr |= CSSM_KEYATTR_PERMANENT;
1657      }
1658  
1659  	// do the key generation
1660  	result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey);
1661  	if (result != errSecSuccess) {
1662  		return result;
1663  	}
1664  
1665  	// set the label and print attributes on the keys
1666      SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef);
1667      SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef);
1668  	return result;
1669  
1670  	END_SECAPI
1671  }
1672  
1673  OSStatus
1674  SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
1675      return SecKeyGeneratePairInternal(true, parameters, publicKey, privateKey);
1676  }
1677  
1678  SecKeyRef
1679  SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) {
1680      SecKeyRef privateKey = NULL, publicKey = NULL;
1681      OSStatus status = SecKeyGeneratePairInternal(false, parameters, &publicKey, &privateKey);
1682      SecError(status, error, CFSTR("failed to generate asymmetric keypair"));
1683      if (publicKey != NULL) {
1684          CFRelease(publicKey);
1685      }
1686      return privateKey;
1687  }
1688  
1689  OSStatus SecKeyRawVerifyOSX(
1690      SecKeyRef           key,            /* Public key */
1691  	SecPadding          padding,		/* kSecPaddingNone or kSecPaddingPKCS1 */
1692  	const uint8_t       *signedData,	/* signature over this data */
1693  	size_t              signedDataLen,	/* length of dataToSign */
1694  	const uint8_t       *sig,			/* signature */
1695  	size_t              sigLen)
1696  {
1697      return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen);
1698  }
1699  
1700  /*
1701      M4 Additions
1702  */
1703  
1704  static CFTypeRef
1705  utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue)
1706  {
1707  		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1708          if (value != NULL) return value;
1709          return defaultValue;
1710  }
1711  
1712  static uint32_t
1713  utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue)
1714  {
1715          uint32_t integerValue;
1716  		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1717          if (value != NULL) {
1718              CFNumberRef nRef = (CFNumberRef) value;
1719              CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue);
1720              return integerValue;
1721          }
1722          return defaultValue;
1723   }
1724  
1725  static uint32_t
1726  utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue)
1727  {
1728  		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1729          if (value != NULL) {
1730              CFBooleanRef bRef = (CFBooleanRef) value;
1731              if(CFBooleanGetValue(bRef)) return maskValue;
1732          }
1733          return 0;
1734  }
1735  
1736  static void
1737  utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass)
1738  {
1739      CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
1740      CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
1741  
1742      if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) {
1743          *algorithm = CSSM_ALGID_AES;
1744          *keySizeInBits = 128;
1745          *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1746      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) {
1747          *algorithm = CSSM_ALGID_DES;
1748          *keySizeInBits = 128;
1749           *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1750      } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) {
1751          *algorithm = CSSM_ALGID_3DES_3KEY_EDE;
1752          *keySizeInBits = 128;
1753          *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1754      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) {
1755          *algorithm = CSSM_ALGID_RC4;
1756          *keySizeInBits = 128;
1757          *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1758      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) {
1759          *algorithm = CSSM_ALGID_RC2;
1760          *keySizeInBits = 128;
1761           *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1762      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) {
1763          *algorithm = CSSM_ALGID_CAST;
1764          *keySizeInBits = 128;
1765           *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1766      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) {
1767          *algorithm = CSSM_ALGID_RSA;
1768          *keySizeInBits = 128;
1769           *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1770      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) {
1771          *algorithm = CSSM_ALGID_DSA;
1772          *keySizeInBits = 128;
1773           *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1774      } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) ||
1775              CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) {
1776          *algorithm = CSSM_ALGID_ECDSA;
1777          *keySizeInBits = 128;
1778          *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1779      } else {
1780          *algorithm = CSSM_ALGID_AES;
1781          *keySizeInBits = 128;
1782          *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1783      }
1784  
1785      if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) {
1786          *keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
1787      } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) {
1788          *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1789      } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) {
1790           *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1791      }
1792  
1793      *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits);
1794      *keyUsage =  utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) |
1795                  utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) |
1796                  utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) |
1797                  utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP);
1798  
1799  
1800      if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
1801  		*keyUsage |=  utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) |
1802  					utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY);
1803      }
1804  
1805      if(*keyUsage == 0) {
1806  		switch (*keyClass) {
1807  			case CSSM_KEYCLASS_PRIVATE_KEY:
1808  				*keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN;
1809  				break;
1810  			case CSSM_KEYCLASS_PUBLIC_KEY:
1811  				*keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
1812  				break;
1813  			default:
1814  				*keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY;
1815  				break;
1816  		}
1817  	}
1818  }
1819  
1820  static CFStringRef
1821  utilCopyDefaultKeyLabel(void)
1822  {
1823  	// generate a default label from the current date
1824  	CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1825  	CFStringRef defaultLabel = CFCopyDescription(dateNow);
1826  	CFRelease(dateNow);
1827  
1828  	return defaultLabel;
1829  }
1830  
1831  SecKeyRef
1832  SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error)
1833  {
1834  	OSStatus result = errSecParam; // default result for an early exit
1835  	SecKeyRef key = NULL;
1836  	SecKeychainRef keychain = NULL;
1837  	SecAccessRef access;
1838  	CFStringRef label;
1839  	CFStringRef appLabel;
1840  	CFStringRef appTag;
1841  	CFStringRef dateLabel = NULL;
1842  
1843  	CSSM_ALGORITHMS algorithm;
1844  	uint32 keySizeInBits;
1845  	CSSM_KEYUSE keyUsage;
1846  	uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT;
1847  	CSSM_KEYCLASS keyClass;
1848  	CFTypeRef value;
1849  	Boolean isPermanent;
1850  	Boolean isExtractable;
1851  
1852  	// verify keychain parameter
1853  	if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain))
1854  		keychain = NULL;
1855  	else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1856  		keychain = NULL;
1857  		goto errorExit;
1858  	}
1859  	else
1860  		CFRetain(keychain);
1861  
1862  	// verify permanent parameter
1863  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value))
1864  		isPermanent = false;
1865  	else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1866  		goto errorExit;
1867  	else
1868  		isPermanent = CFEqual(kCFBooleanTrue, value);
1869  	if (isPermanent) {
1870  		if (keychain == NULL) {
1871  			// no keychain was specified, so use the default keychain
1872  			result = SecKeychainCopyDefault(&keychain);
1873  		}
1874  		keyAttr |= CSSM_KEYATTR_PERMANENT;
1875  	}
1876  
1877  	// verify extractable parameter
1878  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value))
1879  		isExtractable = true; // default to extractable if value not specified
1880  	else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1881  		goto errorExit;
1882  	else
1883  		isExtractable = CFEqual(kCFBooleanTrue, value);
1884  	if (isExtractable)
1885  		keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
1886  
1887  	// verify access parameter
1888  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access))
1889  		access = NULL;
1890  	else if (SecAccessGetTypeID() != CFGetTypeID(access))
1891  		goto errorExit;
1892  
1893  	// verify label parameter
1894  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label))
1895  		label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default
1896  	else if (CFStringGetTypeID() != CFGetTypeID(label))
1897  		goto errorExit;
1898  
1899  	// verify application label parameter
1900  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel))
1901  		appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel());
1902  	else if (CFStringGetTypeID() != CFGetTypeID(appLabel))
1903  		goto errorExit;
1904  
1905  	// verify application tag parameter
1906  	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag))
1907  		appTag = NULL;
1908  	else if (CFStringGetTypeID() != CFGetTypeID(appTag))
1909  		goto errorExit;
1910  
1911      utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1912  
1913  	if (!keychain) {
1914  		// the generated key will not be stored in any keychain
1915  		result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key);
1916  	}
1917  	else {
1918  		// we can set the label attributes on the generated key if it's a keychain item
1919  		size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1;
1920  		char *labelBuf = (char *)malloc(labelBufLen);
1921  		size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1;
1922  		char *appLabelBuf = (char *)malloc(appLabelBufLen);
1923  		size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1;
1924  		char *appTagBuf = (char *)malloc(appTagBufLen);
1925  
1926  		if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
1927  			labelBuf[0]=0;
1928  		if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
1929  			appLabelBuf[0]=0;
1930  		if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
1931  			appTagBuf[0]=0;
1932  
1933  		SecKeychainAttribute attrs[] = {
1934  			{ kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf },
1935  			{ kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf },
1936  			{ kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf }	};
1937  		SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
1938  		if (!appTag) --attributes.count;
1939  
1940  		result = SecKeyGenerateWithAttributes(&attributes,
1941  			keychain, algorithm, keySizeInBits, 0,
1942  			keyUsage, keyAttr, access, &key);
1943  
1944  		free(labelBuf);
1945  		free(appLabelBuf);
1946  		free(appTagBuf);
1947  	}
1948  
1949  errorExit:
1950  	if (result && error) {
1951  		*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL);
1952  	}
1953  	if (dateLabel)
1954  		CFRelease(dateLabel);
1955  	if (keychain)
1956  		CFRelease(keychain);
1957  
1958      return key;
1959  }
1960  
1961  
1962  
1963  SecKeyRef
1964  SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error)
1965  {
1966  	CSSM_ALGORITHMS		algorithm;
1967      uint32				keySizeInBits;
1968      CSSM_KEYUSE			keyUsage;
1969      CSSM_KEYCLASS		keyClass;
1970      CSSM_RETURN			crtn;
1971  
1972      if(keyData == NULL || CFDataGetLength(keyData) == 0){
1973          MacOSError::throwMe(errSecUnsupportedKeySize);
1974      }
1975  
1976      utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1977  
1978  	CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL
1979  
1980  	SecKeyImportExportParameters iparam;
1981  	memset(&iparam, 0, sizeof(iparam));
1982  	iparam.keyUsage = keyUsage;
1983  
1984      CFRef<CFDataRef> data;
1985  	SecExternalItemType itype;
1986  	switch (keyClass) {
1987  		case CSSM_KEYCLASS_PRIVATE_KEY:
1988  			itype = kSecItemTypePrivateKey;
1989  			break;
1990          case CSSM_KEYCLASS_PUBLIC_KEY: {
1991  			itype = kSecItemTypePublicKey;
1992              // Public key import expects public key in SubjPublicKey X509 format.  We want to accept both bare and x509 format,
1993              // so we have to detect bare format here and extend to full X509 if detected.
1994              data.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm, keySizeInBits, keyData));
1995              break;
1996          }
1997  		case CSSM_KEYCLASS_SESSION_KEY:
1998  			itype = kSecItemTypeSessionKey;
1999  			break;
2000  		default:
2001  			itype = kSecItemTypeUnknown;
2002  			break;
2003  	}
2004  
2005  	CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2006  	// NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
2007      crtn = impExpImportRawKey(data ? CFDataRef(data) : keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka);
2008  	if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) {
2009  		SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0);
2010  		CFRetain(sk);
2011  		CFRelease(ka);
2012  		return sk;
2013  	} else {
2014          CFRelease(ka);
2015  		if (error) {
2016  			*error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL);
2017  		}
2018  		return NULL;
2019  	}
2020  }
2021  
2022  
2023  void
2024  SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue,
2025  						SecKeyGeneratePairBlock result)
2026  {
2027  	CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable);
2028  	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2029  		SecKeyRef publicKey = NULL;
2030  		SecKeyRef privateKey = NULL;
2031  		OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
2032  		dispatch_async(deliveryQueue, ^{
2033  			CFErrorRef error = NULL;
2034  			if (errSecSuccess != status) {
2035  				error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
2036  			}
2037  			result(publicKey, privateKey, error);
2038  			if (error) {
2039  				CFRelease(error);
2040  			}
2041  			if (publicKey) {
2042  				CFRelease(publicKey);
2043  			}
2044  			if (privateKey) {
2045  				CFRelease(privateKey);
2046  			}
2047  			CFRelease(parameters);
2048  		});
2049  	});
2050  }
2051  
2052  static inline void utilClearAndFree(void *p, size_t len) {
2053      if(p) {
2054          if(len) bzero(p, len);
2055          free(p);
2056      }
2057  }
2058  
2059  SecKeyRef
2060  SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error)
2061  {
2062      CCPBKDFAlgorithm algorithm;
2063      CFIndex passwordLen = 0;
2064      CFDataRef keyData = NULL;
2065      char *thePassword = NULL;
2066      uint8_t *salt = NULL;
2067      uint8_t *derivedKey = NULL;
2068      size_t  saltLen = 0, derivedKeyLen = 0;
2069      uint rounds;
2070      CFDataRef saltDictValue, algorithmDictValue;
2071      SecKeyRef retval = NULL;
2072  
2073      /* Pick Values from parameters */
2074  
2075      if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) {
2076          if(error) {
2077              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL);
2078          }
2079          goto errOut;
2080      }
2081  
2082      derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128);
2083  	// This value come in bits but the rest of the code treats it as bytes
2084  	derivedKeyLen /= 8;
2085  
2086      algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256);
2087  
2088      rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0);
2089  
2090      /* Convert any remaining parameters and get the password bytes */
2091  
2092      saltLen = CFDataGetLength(saltDictValue);
2093      if((salt = (uint8_t *) malloc(saltLen)) == NULL) {
2094          if(error) {
2095              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2096          }
2097          goto errOut;
2098      }
2099  
2100      CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt);
2101  
2102      passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1;
2103      if((thePassword = (char *) malloc(passwordLen)) == NULL) {
2104          if(error) {
2105              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2106          }
2107          goto errOut;
2108      }
2109      CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen);
2110  
2111      if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) {
2112          if(error) {
2113              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2114          }
2115          goto errOut;
2116      }
2117  
2118      if(algorithmDictValue == NULL) {
2119          algorithm = kCCPRFHmacAlgSHA1; /* default */
2120      } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) {
2121          algorithm = kCCPRFHmacAlgSHA1;
2122      } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) {
2123          algorithm = kCCPRFHmacAlgSHA224;
2124      } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) {
2125          algorithm = kCCPRFHmacAlgSHA256;
2126      } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) {
2127          algorithm = kCCPRFHmacAlgSHA384;
2128      } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
2129          algorithm = kCCPRFHmacAlgSHA512;
2130      } else {
2131          if(error) {
2132              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
2133          }
2134          goto errOut;
2135      }
2136  
2137      if(rounds == 0) {
2138          rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count.
2139      }
2140  
2141      if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) {
2142          if(error) {
2143              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2144          }
2145          goto errOut;
2146      }
2147  
2148      if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) {
2149          retval =  SecKeyCreateFromData(parameters, keyData, error);
2150          CFRelease(keyData);
2151      } else {
2152          if(error) {
2153              *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2154          }
2155      }
2156  
2157  errOut:
2158      utilClearAndFree(salt, saltLen);
2159      utilClearAndFree(thePassword, passwordLen);
2160      utilClearAndFree(derivedKey, derivedKeyLen);
2161      return retval;
2162  }
2163  
2164  CFDataRef
2165  SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2166  {
2167      if(error) {
2168          *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2169      }
2170      return NULL;
2171  }
2172  
2173  SecKeyRef
2174  SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2175  {
2176      if(error) {
2177          *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2178      }
2179      return NULL;
2180  }