2  * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 #include "SecKeyPriv.h" 
  27 #include "SecItemPriv.h" 
  28 #include <libDER/asn1Types.h> 
  29 #include <libDER/DER_Encode.h> 
  30 #include <libDER/DER_Decode.h> 
  31 #include <libDER/DER_Keys.h> 
  32 #include <Security/SecAsn1Types.h> 
  33 #include <Security/SecAsn1Coder.h> 
  34 #include <security_keychain/KeyItem.h> 
  35 #include <security_utilities/casts.h> 
  36 #include <CommonCrypto/CommonKeyDerivation.h> 
  38 #include "SecBridge.h" 
  40 #include <security_keychain/Access.h> 
  41 #include <security_keychain/Keychains.h> 
  42 #include <security_keychain/KeyItem.h> 
  46 #include <security_cdsa_utils/cuCdsaUtils.h> 
  47 #include <security_cdsa_client/wrapkey.h> 
  48 #include <security_cdsa_client/genkey.h> 
  49 #include <security_cdsa_client/signclient.h> 
  50 #include <security_cdsa_client/cryptoclient.h> 
  52 #include "SecImportExportCrypto.h" 
  55 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) { 
  56     key
->key 
= const_cast<KeyItem 
*>(reinterpret_cast<const KeyItem 
*>(keyData
)); 
  57     key
->key
->initializeWithSecKeyRef(key
); 
  58     key
->credentialType 
= kSecCredentialTypeDefault
; 
  63 SecCDSAKeyDestroy(SecKeyRef keyRef
) { 
  64     // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation. 
  65     // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. 
  66     // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. 
  68     KeyItem 
*keyItem 
= keyRef
->key
; 
  69     if (keyItem 
== NULL
) { 
  70         // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. 
  74     Keychain kc 
= keyItem
->keychain(); 
  77         StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject()); 
  78         keyItem 
= keyRef
->key
; 
  79         if (keyItem 
== NULL
) { 
  80             // 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. 
  84         keyItem
->aboutToDestruct(); 
  88     (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. 
  92 SecCDSAKeyGetBlockSize(SecKeyRef key
) { 
  94     CFErrorRef 
*error 
= NULL
; 
  95     BEGIN_SECKEYAPI(size_t,0) 
  97     const CssmKey::Header keyHeader 
= key
->key
->unverifiedKeyHeader(); 
  98     switch(keyHeader
.algorithm()) 
 102             result 
= keyHeader
.LogicalKeySizeInBits 
/ 8; 
 104         case CSSM_ALGID_ECDSA
: 
 106             /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, 
 107              * plus both coordinates for the point used */ 
 108 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) 
 109 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) 
 110             size_t coordSize 
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
); 
 111             assert(coordSize 
< 256); /* size must fit in a byte for DER */ 
 112             size_t coordDERLen 
= (coordSize 
> 127) ? 2 : 1; 
 113             size_t coordLen 
= 1 + coordDERLen 
+ coordSize
; 
 115             size_t pointSize 
= 2 * coordLen
; 
 116             assert(pointSize 
< 256); /* size must fit in a byte for DER */ 
 117             size_t pointDERLen 
= (pointSize 
> 127) ? 2 : 1; 
 118             size_t pointLen 
= 1 + pointDERLen 
+ pointSize
; 
 124             result 
= 16; /* all AES keys use 128-bit blocks */ 
 127         case CSSM_ALGID_3DES_3KEY
: 
 128             result 
= 8; /* all DES keys use 64-bit blocks */ 
 131             assert(0); /* some other key algorithm */ 
 132             result 
= 16; /* FIXME: revisit this */ 
 140 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) { 
 142     CFErrorRef 
*error 
= NULL
; 
 143     BEGIN_SECKEYAPI(CFIndex
, 0) 
 145     result 
= kSecNullAlgorithmID
; 
 146     switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) { 
 148             result 
= kSecRSAAlgorithmID
; 
 151             result 
= kSecDSAAlgorithmID
; 
 153         case CSSM_ALGID_ECDSA
: 
 154             result 
= kSecECDSAAlgorithmID
; 
 157             assert(0); /* other algorithms TBA */ 
 163 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) { 
 164     // First of all, consider x509 format and try to strip SubjPubKey envelope.  If it fails, do not panic 
 165     // and export data as is. 
 166     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
; 
 168     DERSubjPubKeyInfo subjPubKey
; 
 169     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 170                          DERSubjPubKeyInfoItemSpecs
, 
 171                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success 
&& 
 172         DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 173         return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
); 
 176     return CFDataRef(CFRetain(pubKeyInfo
)); 
 179 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) { 
 180     // First check, whether X509 pubkeyinfo is already present.  If not, add it according to the key type. 
 181     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }; 
 182     DERSubjPubKeyInfo subjPubKey
; 
 183     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 184                          DERSubjPubKeyInfoItemSpecs
, 
 185                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) { 
 186         return CFDataRef(CFRetain(pubKeyInfo
)); 
 189     // We have always size rounded to full bytes so bitstring encodes leading 00. 
 190     CFRef
<CFMutableDataRef
> bitStringPubKey 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 191     CFDataSetLength(bitStringPubKey
, 1); 
 192     CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
)); 
 193     subjPubKey
.pubKey
.data 
= static_cast<DERByte 
*>(const_cast<UInt8 
*>(CFDataGetBytePtr(bitStringPubKey
))); 
 194     subjPubKey
.pubKey
.length 
= CFDataGetLength(bitStringPubKey
); 
 196     // Encode algId according to algorithm used. 
 197     static const DERByte oidRSA
[] = { 
 198         0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 
 200     static const DERByte oidECsecp256
[] = { 
 201         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 
 203     static const DERByte oidECsecp384
[] = { 
 204         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 
 206     static const DERByte oidECsecp521
[] = { 
 207         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 
 209     subjPubKey
.algId
.length 
= 0; 
 210     if (algorithm 
== CSSM_ALGID_RSA
) { 
 211         subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidRSA
); 
 212         subjPubKey
.algId
.length 
= sizeof(oidRSA
); 
 213     } else if (algorithm 
== CSSM_ALGID_ECDSA
) { 
 214         if (keySizeInBits 
== 256) { 
 215             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp256
); 
 216             subjPubKey
.algId
.length 
= sizeof(oidECsecp256
); 
 217         } else if (keySizeInBits 
== 384) { 
 218             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp384
); 
 219             subjPubKey
.algId
.length 
= sizeof(oidECsecp384
); 
 220         } if (keySizeInBits 
== 521) { 
 221             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp521
); 
 222             subjPubKey
.algId
.length 
= sizeof(oidECsecp521
); 
 225     DERSize size 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 226                                               DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
); 
 227     CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 228     CFDataSetLength(keyData
, size
); 
 229     if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 230                           DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
, 
 231                           static_cast<DERByte 
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) { 
 232         CFDataSetLength(keyData
, size
); 
 237     return keyData
.yield(); 
 240 static OSStatus 
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef 
*serialization
) { 
 242     CFErrorRef 
*error 
= NULL
; 
 243     BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
) 
 245     const CssmKey::Header 
&header 
= key
->key
->key().header(); 
 246     switch (header
.algorithm()) { 
 247         case CSSM_ALGID_RSA
: { 
 248             switch (header
.keyClass()) { 
 249                 case CSSM_KEYCLASS_PRIVATE_KEY
: { 
 250                     CFRef
<CFDataRef
> privKeyData
; 
 251                     result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take()); 
 252                     if (result 
== errSecSuccess
) { 
 253                         DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) }; 
 254                         DERRSAKeyPair keyPair
; 
 255                         if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
, 
 256                                              &keyPair
, sizeof(keyPair
)) == DR_Success
) { 
 257                             DERRSAPubKeyPKCS1 pubKey 
= { keyPair
.n
, keyPair
.e 
}; 
 258                             DERSize size 
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
, 
 259                                                                       DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
); 
 260                             CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 261                             CFDataSetLength(keyData
, size
); 
 262                             UInt8 
*data 
= CFDataGetMutableBytePtr(keyData
); 
 263                             if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
, 
 264                                                   DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
, 
 265                                                   data
, &size
) == DR_Success
) { 
 266                                 CFDataSetLength(keyData
, size
); 
 267                                 *data 
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
; 
 268                                 *serialization 
= keyData
.yield(); 
 270                                 *serialization 
= NULL
; 
 271                                 result 
= errSecParam
; 
 277                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 278                     result 
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
); 
 283         case CSSM_ALGID_ECDSA
: { 
 284             *serialization 
= NULL
; 
 285             CFRef
<CFDataRef
> tempPublicData
; 
 286             result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take()); 
 287             if (result 
== errSecSuccess
) { 
 288                 *serialization 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
); 
 293             result 
= errSecUnimplemented
; 
 304 static const DERItemSpec DERECPrivateKeyItemSpecs
[] = 
 309     { DER_OFFSET(DERECPrivateKey
, privateKey
), 
 311         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 313         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0, 
 314         DER_DEC_SKIP 
| DER_ENC_NO_OPTS 
}, 
 315     { DER_OFFSET(DERECPrivateKey
, publicKey
), 
 316         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 1, 
 317         DER_DEC_NO_OPTS 
| DER_ENC_SIGNED_INT 
}, 
 319 static const DERSize DERNumECPrivateKeyItemSpecs 
= 
 320 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
); 
 324 } DERECPrivateKeyPublicKey
; 
 326 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] = 
 328     { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
), 
 330         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 332 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs 
= 
 333 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
); 
 336 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef 
*error
) { 
 338     BEGIN_SECKEYAPI(CFDataRef
, NULL
) 
 341     const CssmKey::Header header 
= key
->key
->unverifiedKeyHeader(); 
 342     CFRef
<CFDataRef
> keyData
; 
 343     switch (header
.algorithm()) { 
 345             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 347         case CSSM_ALGID_ECDSA
: { 
 348             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 349             if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) { 
 350                 // Convert DER format into x9.63 format, which is expected for exported key. 
 351                 DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) }; 
 352                 DERECPrivateKey privateKey
; 
 353                 DERECPrivateKeyPublicKey privateKeyPublicKey
; 
 356                 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
, 
 357                                      &privateKey
, sizeof(privateKey
)) == DR_Success 
&& 
 358                     DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
, 
 359                                             DERECPrivateKeyPublicKeyItemSpecs
, 
 360                                             &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success 
&& 
 361                     DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 362                     CFRef
<CFMutableDataRef
> key 
= CFDataCreateMutable(kCFAllocatorDefault
, 
 363                                                                       pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 364                     CFDataSetLength(key
, pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 365                     CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
); 
 366                     CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
), 
 367                                        privateKey
.privateKey
.data
, privateKey
.privateKey
.length
); 
 368                     keyData 
= key
.as
<CFDataRef
>(); 
 374             MacOSError::throwMe(errSecUnimplemented
); 
 377     if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) { 
 378         result 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
); 
 380         result 
= keyData
.yield(); 
 386 static CFDataRef 
SecCDSAKeyCopyLabel(SecKeyRef key
) { 
 387     CFDataRef label 
= NULL
; 
 388     if (key
->key
->isPersistent()) { 
 389         UInt32 tags
[] = { kSecKeyLabel 
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB 
}; 
 390         SecKeychainAttributeInfo info 
= { 1, tags
, formats 
}; 
 391         SecKeychainAttributeList 
*list 
= NULL
; 
 392         key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
); 
 393         if (list
->count 
== 1) { 
 394             SecKeychainAttribute 
*attr 
= list
->attr
; 
 395             label 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)attr
->data
, (CFIndex
)attr
->length
); 
 397         key
->key
->freeAttributesAndData(list
, NULL
); 
 402 static CFDictionaryRef
 
 403 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) { 
 405     CFErrorRef 
*error 
= NULL
; 
 406     BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
) 
 408     CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, 
 409                                                             &kCFTypeDictionaryValueCallBacks
); 
 411     CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
); 
 413     const CssmKey::Header header 
= key
->key
->unverifiedKeyHeader(); 
 414     CFIndex sizeValue 
= header
.LogicalKeySizeInBits
; 
 415     CFRef
<CFNumberRef
> sizeInBits 
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
); 
 416     CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
); 
 417     CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
); 
 419     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(key
); 
 421         // For floating keys, calculate label as SHA1 of pubkey bytes. 
 422         CFRef
<CFDataRef
> pubKeyBlob
; 
 423         if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) { 
 424             uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
]; 
 425             CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
); 
 426             label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
))); 
 431         CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
); 
 434     CSSM_KEYATTR_FLAGS attrs 
= header
.attributes(); 
 435     CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs 
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 436     CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs 
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 437     CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs 
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 438     CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs 
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 439     CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs 
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 440     CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs 
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 441     CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs 
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 443     CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 444     CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 445     CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 446     CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 447     CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 448     CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 449     CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 450     CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 451     CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 453     switch (header
.keyClass()) { 
 454         case CSSM_KEYCLASS_PUBLIC_KEY
: 
 455             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
); 
 457         case CSSM_KEYCLASS_PRIVATE_KEY
: 
 458             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
); 
 462     switch (header
.algorithm()) { 
 464             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
); 
 466         case CSSM_ALGID_ECDSA
: 
 467             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
); 
 471     CFRef
<CFDataRef
> keyData
; 
 472     if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) { 
 473         CFDictionarySetValue(dict
, kSecValueData
, keyData
); 
 476     if (header
.algorithm() == CSSM_ALGID_RSA 
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY 
&& 
 477         header
.blobType() == CSSM_KEYBLOB_RAW
) { 
 478         const CssmData 
&keyData 
= key
->key
->key()->keyData(); 
 479         DERItem keyItem 
= { static_cast<DERByte 
*>(keyData
.data()), keyData
.length() }; 
 480         DERRSAPubKeyPKCS1 decodedKey
; 
 481         if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
, 
 482                              DERRSAPubKeyPKCS1ItemSpecs
, 
 483                              &decodedKey
, sizeof(decodedKey
)) == DR_Success
) { 
 484             CFRef
<CFDataRef
> modulus 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, 
 485                                                     decodedKey
.modulus
.length
); 
 486             CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
); 
 487             CFRef
<CFDataRef
> exponent 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, 
 488                                                      decodedKey
.pubExponent
.length
); 
 489             CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
); 
 498 #pragma clang diagnostic push 
 499 #pragma clang diagnostic ignored "-Wunused-const-variable" 
 500 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
); 
 501 #pragma clang diagnostic pop 
 503 static SecKeyRef 
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) { 
 505     BEGIN_SECKEYAPI(SecKeyRef
, NULL
) 
 508     KeyItem 
*key 
= privateKey
->key
; 
 509     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(privateKey
); 
 511         // Lookup public key in the database. 
 512         DbUniqueRecord uniqueId
; 
 513         SSDb 
ssDb(dynamic_cast<SSDbImpl 
*>(&(*key
->keychain()->database()))); 
 514         SSDbCursor 
dbCursor(ssDb
, 1); 
 515         dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 516         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
))); 
 517         if (dbCursor
->next(NULL
, NULL
, uniqueId
)) { 
 518             Item publicKey 
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
); 
 519             result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 523     if (result 
== NULL 
&& key
->publicKey()) { 
 524         SecPointer
<KeyItem
> publicKey(new KeyItem(key
->publicKey())); 
 525         result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 531 static KeyItem 
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType 
&operation
, SecKeyAlgorithm algorithm
, 
 532                                             CSSM_ALGORITHMS 
&baseAlgorithm
, CSSM_ALGORITHMS 
&secondaryAlgorithm
, 
 533                                             CSSM_ALGORITHMS 
&paddingAlgorithm
, CFIndex 
&inputSizeLimit
) { 
 534     KeyItem 
*keyItem 
= key
->key
; 
 535     CSSM_KEYCLASS keyClass 
= keyItem
->key()->header().keyClass(); 
 536     baseAlgorithm 
= keyItem
->key()->header().algorithm(); 
 537     switch (baseAlgorithm
) { 
 539             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 540                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 541                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) { 
 542                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 543                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 545                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) { 
 546                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 547                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 548                     inputSizeLimit 
= -11; 
 549                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) { 
 550                     secondaryAlgorithm 
= CSSM_ALGID_SHA1
; 
 551                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 553                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) { 
 554                     secondaryAlgorithm 
= CSSM_ALGID_SHA224
; 
 555                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 556                     inputSizeLimit 
= 224 / 8; 
 557                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) { 
 558                     secondaryAlgorithm 
= CSSM_ALGID_SHA256
; 
 559                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 560                     inputSizeLimit 
= 256 / 8; 
 561                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) { 
 562                     secondaryAlgorithm 
= CSSM_ALGID_SHA384
; 
 563                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 564                     inputSizeLimit 
= 384 / 8; 
 565                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) { 
 566                     secondaryAlgorithm 
= CSSM_ALGID_SHA512
; 
 567                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 568                     inputSizeLimit 
= 512 / 8; 
 569                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) { 
 570                     secondaryAlgorithm 
= CSSM_ALGID_MD5
; 
 571                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 576             } else if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt
) || 
 577                        (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeEncrypt
)) { 
 578                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 579                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 580                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 582                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) { 
 583                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 584                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 585                     inputSizeLimit 
= operation 
== kSecKeyOperationTypeEncrypt 
? -11 : 0; 
 589             } else if (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt 
&& 
 590                        CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 591                 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, 
 592                 // because CDSA keys refuses to perform decrypt using public key. 
 593                 operation 
= kSecKeyOperationTypeEncrypt
; 
 594                 secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 595                 paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 601         case CSSM_ALGID_ECDSA
: 
 602             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 603                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 604                 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) { 
 605                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 606                     paddingAlgorithm 
= CSSM_PADDING_SIGRAW
; 
 607                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) { 
 608                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 609                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 613             } else if (keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeKeyExchange
) { 
 614                 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) || 
 615                     CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) { 
 616                     baseAlgorithm 
= CSSM_ALGID_ECDH
; 
 617                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) || 
 618                            CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) { 
 619                     baseAlgorithm 
= CSSM_ALGID_ECDH_X963_KDF
; 
 628             MacOSError::throwMe(errSecParam
); 
 634 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) { 
 635     CFIndex blockSize 
= key
->key
->key().header().LogicalKeySizeInBits 
/ 8; 
 636     CFIndex plaintextLength 
= CFDataGetLength(plaintext
); 
 637     if ((algorithm 
== kSecKeyAlgorithmRSAEncryptionRaw 
|| algorithm 
== kSecKeyAlgorithmRSASignatureRaw
) 
 638         && plaintextLength 
< blockSize
) { 
 639         // Pre-pad with zeroes. 
 640         CFMutableDataRef 
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
)); 
 641         CFDataSetLength(result
, blockSize
); 
 642         CFDataReplaceBytes(result
, CFRangeMake(blockSize 
- plaintextLength
, plaintextLength
), 
 643                            CFDataGetBytePtr(plaintext
), plaintextLength
); 
 646         return CFDataRef(CFRetain(plaintext
)); 
 650 static CFTypeRef 
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
, 
 651                                                CFArrayRef allAlgorithms
, SecKeyOperationMode mode
, 
 652                                                CFTypeRef in1
, CFTypeRef in2
, CFErrorRef 
*error
) { 
 653     BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
) 
 654     CFIndex inputSizeLimit 
= 0; 
 655     CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
; 
 656     KeyItem 
*keyItem 
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
); 
 657     if (keyItem 
== NULL
) { 
 658         // Operation/algorithm/key combination is not supported. 
 660     } else if (mode 
== kSecKeyOperationModeCheckIfSupported
) { 
 661         // Operation is supported and caller wants to just know that. 
 662         return kCFBooleanTrue
; 
 663     } else if (baseAlgorithm 
== CSSM_ALGID_RSA
) { 
 664         if (inputSizeLimit 
<= 0) { 
 665             inputSizeLimit 
+= SecCDSAKeyGetBlockSize(key
); 
 667         if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) { 
 668             MacOSError::throwMe(errSecParam
); 
 673         case kSecKeyOperationTypeSign
: { 
 674             CssmClient::Sign 
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 675             signContext
.key(keyItem
->key()); 
 676             signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
)); 
 677             signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 678             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 679             CssmAutoData 
signature(signContext
.allocator()); 
 680             signContext
.sign(CssmData(CFDataRef(input
)), signature
.get()); 
 681             result 
= CFDataCreate(NULL
, static_cast<const UInt8 
*>(signature
.data()), CFIndex(signature
.length())); 
 684         case kSecKeyOperationTypeVerify
: { 
 685             CssmClient::Verify 
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 686             verifyContext
.key(keyItem
->key()); 
 687             verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
)); 
 688             verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 689             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 690             verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
))); 
 691             result 
= kCFBooleanTrue
; 
 694         case kSecKeyOperationTypeEncrypt
: { 
 695             CssmClient::Encrypt 
encryptContext(keyItem
->csp(), baseAlgorithm
); 
 696             encryptContext
.key(keyItem
->key()); 
 697             encryptContext
.padding(paddingAlgorithm
); 
 698             encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
)); 
 699             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 700             CssmAutoData 
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator()); 
 701             size_t length 
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get()); 
 702             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 703             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 704             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 705             CFDataSetLength(CFMutableDataRef(result
), length
); 
 708         case kSecKeyOperationTypeDecrypt
: { 
 709             CssmClient::Decrypt 
decryptContext(keyItem
->csp(), baseAlgorithm
); 
 710             decryptContext
.key(keyItem
->key()); 
 711             decryptContext
.padding(paddingAlgorithm
); 
 712             decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
)); 
 713             CssmAutoData 
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator()); 
 714             size_t length 
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)), 
 715                                                    output
.get(), remainingData
.get()); 
 716             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 717             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 718             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 719             CFDataSetLength(CFMutableDataRef(result
), length
); 
 722         case kSecKeyOperationTypeKeyExchange
: { 
 723             CFIndex requestedLength 
= 0; 
 725             switch (baseAlgorithm
) { 
 726                 case CSSM_ALGID_ECDH
: 
 727                     requestedLength 
= (keyItem
->key().header().LogicalKeySizeInBits 
+ 7) / 8; 
 729                 case CSSM_ALGID_ECDH_X963_KDF
: 
 730                     CFDictionaryRef params 
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
); 
 731                     CFTypeRef value 
= params 
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
; 
 732                     if (value 
== NULL 
|| CFGetTypeID(value
) != CFNumberGetTypeID() || 
 733                         !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) { 
 734                         MacOSError::throwMe(errSecParam
); 
 736                     value 
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
); 
 737                     if (value 
!= NULL 
&& CFGetTypeID(value
) == CFDataGetTypeID()) { 
 738                         sharedInfo 
= CssmData(CFDataRef(value
)); 
 743             CssmClient::DeriveKey 
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength 
* 8)); 
 744             derive
.key(keyItem
->key()); 
 745             derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
)); 
 746             derive
.salt(sharedInfo
); 
 747             CssmData 
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
)); 
 748             Key derivedKey 
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 750             // Export raw data of newly derived key (by wrapping with an empty key). 
 751             CssmClient::WrapKey 
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
); 
 752             Key wrappedKey 
= wrapper(derivedKey
); 
 753             result 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)wrappedKey
->data(), CFIndex(wrappedKey
->length())); 
 763 static Boolean 
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) { 
 765     BEGIN_SECKEYAPI(Boolean
, false) 
 767     result 
= key1
->key
->equal(*key2
->key
); 
 772 static Boolean 
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef 
*error
) { 
 773     BEGIN_SECKEYAPI(Boolean
, false) 
 775     if (CFEqual(name
, kSecUseAuthenticationUI
)) { 
 776         key
->credentialType 
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault 
: kSecCredentialTypeNoUI
; 
 779         result 
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
); 
 785 const SecKeyDescriptor kSecCDSAKeyDescriptor 
= { 
 786     .version 
= kSecKeyDescriptorVersion
, 
 789     .init 
= SecCDSAKeyInit
, 
 790     .destroy 
= SecCDSAKeyDestroy
, 
 791     .blockSize 
= SecCDSAKeyGetBlockSize
, 
 792     .getAlgorithmID 
= SecCDSAKeyGetAlgorithmId
, 
 793     .copyDictionary 
= SecCDSAKeyCopyAttributeDictionary
, 
 794     .copyPublic 
= SecCDSAKeyCopyPublicBytes
, 
 795     .copyExternalRepresentation 
= SecCDSAKeyCopyExternalRepresentation
, 
 796     .copyPublicKey 
= SecCDSAKeyCopyPublicKey
, 
 797     .copyOperationResult 
= SecCDSAKeyCopyOperationResult
, 
 798     .isEqual 
= SecCDSAKeyIsEqual
, 
 799     .setParameter 
= SecCDSAKeySetParameter
, 
 803     namespace KeychainCore 
{ 
 804         SecCFObject 
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) { 
 805             if (ptr 
== NULL 
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) { 
 809             SecKeyRef key 
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
)); 
 810             if (key
->key_class 
== &kSecCDSAKeyDescriptor
) { 
 811                 return static_cast<SecCFObject 
*>(key
->key
); 
 814             if (key
->cdsaKey 
== NULL
) { 
 815                 // Create CDSA key from exported data of existing key. 
 816                 CFRef
<CFDataRef
> keyData 
= SecKeyCopyExternalRepresentation(key
, NULL
); 
 817                 CFRef
<CFDictionaryRef
> keyAttributes 
= SecKeyCopyAttributes(key
); 
 818                 if (keyData 
&& keyAttributes
) { 
 819                     key
->cdsaKey 
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
); 
 823             return (key
->cdsaKey 
!= NULL
) ? key
->cdsaKey
->key 
: NULL
; 
 826         // You need to hold this key's MutexForObject when you run this 
 827         void KeyItem::attachSecKeyRef() const { 
 828             SecKeyRef key 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0); 
 829             key
->key
->mWeakSecKeyRef 
= key
; 
 835 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
 836 Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
) { 
 837     return ref
->key_class 
== &kSecCDSAKeyDescriptor
; 
 841 static OSStatus 
SecKeyCreatePairInternal( 
 842         SecKeychainRef keychainRef
, 
 843         CSSM_ALGORITHMS algorithm
, 
 844         uint32 keySizeInBits
, 
 845         CSSM_CC_HANDLE contextHandle
, 
 846         CSSM_KEYUSE publicKeyUsage
, 
 847         uint32 publicKeyAttr
, 
 848         CSSM_KEYUSE privateKeyUsage
, 
 849         uint32 privateKeyAttr
, 
 850         SecAccessRef initialAccess
, 
 851         SecKeyRef
* publicKeyRef
, 
 852         SecKeyRef
* privateKeyRef
) 
 857     SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
 858     SecPointer
<KeyItem
> pubItem
, privItem
; 
 859     if (((publicKeyAttr 
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) { 
 860         keychain 
= Keychain::optional(keychainRef
); 
 862     StMaybeLock
<Mutex
> _(keychain 
? keychain
->getKeychainMutex() : NULL
); 
 863     KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
, 
 864                         privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
); 
 866         // Return the generated keys. 
 868                 *publicKeyRef 
= pubItem
->handle(); 
 870                 *privateKeyRef 
= privItem
->handle(); 
 877         SecKeychainRef keychainRef
, 
 878         CSSM_ALGORITHMS algorithm
, 
 879         uint32 keySizeInBits
, 
 880         CSSM_CC_HANDLE contextHandle
, 
 881         CSSM_KEYUSE publicKeyUsage
, 
 882         uint32 publicKeyAttr
, 
 883         CSSM_KEYUSE privateKeyUsage
, 
 884         uint32 privateKeyAttr
, 
 885         SecAccessRef initialAccess
, 
 886         SecKeyRef
* publicKeyRef
, 
 887         SecKeyRef
* privateKeyRef
) 
 889     OSStatus result 
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, 
 890                                                publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
); 
 898 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY 
**cssmKey
) 
 902         Required(cssmKey
) = KeyItem::required(key
)->key(); 
 912 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
; 
 913 static std::set
<CssmClient::CSP
> gSecReturnedKeyCSPs
; 
 916 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE 
*cspHandle
) 
 920         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 922     // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). 
 923     // Keep a global pointer to it to force the CSP to stay live forever. 
 924     CssmClient::CSP returnedKeyCSP 
= keyItem
->csp(); 
 926         StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex()); 
 927         gSecReturnedKeyCSPs
.insert(returnedKeyCSP
); 
 929         Required(cspHandle
) = returnedKeyCSP
->handle(); 
 934 /* deprecated as of 10.8 */ 
 936 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
**algid
) 
 940         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 941         Required(algid
) = &keyItem
->algorithmIdentifier(); 
 947 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
*algid
, unsigned int *strength
) 
 951         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 952         Required(strength
) = keyItem
->strengthInBits(algid
); 
 958 SecKeyGetCredentials( 
 960         CSSM_ACL_AUTHORIZATION_TAG operation
, 
 961         SecCredentialType credentialType
, 
 962         const CSSM_ACCESS_CREDENTIALS 
**outCredentials
) 
 966         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 967         Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
); 
 974         SecKeychainRef keychainRef
, 
 975         const CSSM_KEY 
*publicCssmKey
, 
 976         const CSSM_KEY 
*privateCssmKey
, 
 977         SecAccessRef initialAccess
, 
 978         SecKeyRef
* publicKey
, 
 979         SecKeyRef
* privateKey
) 
 983         Keychain keychain 
= Keychain::optional(keychainRef
); 
 984         SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
 985         SecPointer
<KeyItem
> pubItem
, privItem
; 
 987         KeyItem::importPair(keychain
, 
 988                 Required(publicCssmKey
), 
 989                 Required(privateCssmKey
), 
 994         // Return the generated keys. 
 996                 *publicKey 
= pubItem
->handle(); 
 998                 *privateKey 
= privItem
->handle(); 
1004 SecKeyGenerateWithAttributes( 
1005         SecKeychainAttributeList
* attrList
, 
1006         SecKeychainRef keychainRef
, 
1007         CSSM_ALGORITHMS algorithm
, 
1008         uint32 keySizeInBits
, 
1009         CSSM_CC_HANDLE contextHandle
, 
1010         CSSM_KEYUSE keyUsage
, 
1012         SecAccessRef initialAccess
, 
1018         SecPointer
<Access
> theAccess
; 
1021                 keychain 
= KeychainImpl::required(keychainRef
); 
1023                 theAccess 
= Access::required(initialAccess
); 
1025         SecPointer
<KeyItem
> item 
= KeyItem::generateWithAttributes(attrList
, 
1034         // Return the generated key. 
1036                 *keyRef 
= item
->handle(); 
1043         SecKeychainRef keychainRef
, 
1044         CSSM_ALGORITHMS algorithm
, 
1045         uint32 keySizeInBits
, 
1046         CSSM_CC_HANDLE contextHandle
, 
1047         CSSM_KEYUSE keyUsage
, 
1049         SecAccessRef initialAccess
, 
1052         return SecKeyGenerateWithAttributes(NULL
, 
1053                 keychainRef
, algorithm
, keySizeInBits
, 
1054                 contextHandle
, keyUsage
, keyAttr
, 
1055                 initialAccess
, keyRef
); 
1059 /* Generate a floating key reference from a CSSM_KEY */ 
1061 SecKeyCreateWithCSSMKey(const CSSM_KEY 
*cssmKey
, 
1067     if(cssmKey
->KeyData
.Length 
== 0){ 
1068         MacOSError::throwMe(errSecInvalidAttributeKeyLength
); 
1070     if(cssmKey
->KeyData
.Data 
== NULL
){ 
1071         MacOSError::throwMe(errSecInvalidPointer
); 
1073         CssmClient::CSP 
csp(cssmKey
->KeyHeader
.CspId
); 
1074         CssmClient::Key 
key(csp
, *cssmKey
); 
1075         KeyItem 
*item 
= new KeyItem(key
); 
1077         // Return the generated key. 
1079         *keyRef 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0); 
1086 static u_int32_t 
ConvertCFStringToInteger(CFStringRef ref
) 
1093         // figure out the size of the string 
1094         CFIndex numChars 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
); 
1095         char *buffer 
= (char *)malloc(numChars
); 
1096     if (NULL 
== buffer
) { 
1097         UnixError::throwMe(ENOMEM
); 
1099         if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
)) 
1102                 MacOSError::throwMe(errSecParam
); 
1105     u_int32_t result 
= atoi(buffer
); 
1112 static OSStatus 
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
&algorithms
) 
1114         // figure out the algorithm to use 
1115         CFStringRef ktype 
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
); 
1121         if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) { 
1122                 algorithms 
= CSSM_ALGID_RSA
; 
1123                 return errSecSuccess
; 
1124        } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) || 
1125                        CFEqual(ktype
, kSecAttrKeyTypeEC
)) { 
1126                 algorithms 
= CSSM_ALGID_ECDSA
; 
1127                 return errSecSuccess
; 
1128         } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) { 
1129                 algorithms 
= CSSM_ALGID_AES
; 
1130                 return errSecSuccess
; 
1131         } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) { 
1132                 algorithms 
= CSSM_ALGID_3DES
; 
1133                 return errSecSuccess
; 
1135                 return errSecUnsupportedAlgorithm
; 
1141 static OSStatus 
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32 
&keySizeInBits
) 
1144     // get the key size and check it for validity 
1145     CFTypeRef ref 
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
); 
1147     keySizeInBits 
= kSecDefaultKeySize
; 
1149     CFTypeID bitSizeType 
= CFGetTypeID(ref
); 
1150     if (bitSizeType 
== CFStringGetTypeID()) 
1151         keySizeInBits 
= ConvertCFStringToInteger((CFStringRef
) ref
); 
1152     else if (bitSizeType 
== CFNumberGetTypeID()) 
1153         CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
); 
1154     else return errSecParam
; 
1157     switch (algorithms
) { 
1158     case CSSM_ALGID_ECDSA
: 
1159         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecp256r1
; 
1160         if(keySizeInBits 
== kSecp192r1 
|| keySizeInBits 
== kSecp256r1 
|| keySizeInBits 
== kSecp384r1 
|| keySizeInBits 
== kSecp521r1 
) return errSecSuccess
; 
1162     case CSSM_ALGID_RSA
: 
1163                           if(keySizeInBits 
% 8) return errSecParam
; 
1164         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= 2048; 
1165         if(keySizeInBits 
>= kSecRSAMin 
&& keySizeInBits 
<= kSecRSAMax
) return errSecSuccess
; 
1167     case CSSM_ALGID_AES
: 
1168         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecAES128
; 
1169         if(keySizeInBits 
== kSecAES128 
|| keySizeInBits 
== kSecAES192 
|| keySizeInBits 
== kSecAES256
) return errSecSuccess
; 
1171     case CSSM_ALGID_3DES
: 
1172         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSec3DES192
; 
1173         if(keySizeInBits 
== kSec3DES192
) return errSecSuccess
; 
1192 struct ParameterAttribute
 
1194         const CFStringRef 
*name
; 
1200 static ParameterAttribute gAttributes
[] = 
1207                 &kSecAttrIsPermanent
, 
1211                 &kSecAttrApplicationTag
, 
1215                 &kSecAttrEffectiveKeySize
, 
1219                 &kSecAttrCanEncrypt
, 
1223                 &kSecAttrCanDecrypt
, 
1244 const int kNumberOfAttributes 
= sizeof(gAttributes
) / sizeof(ParameterAttribute
); 
1246 static OSStatus 
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[]) 
1249         for (i 
= 0; i 
< kNumberOfAttributes
; ++i
) 
1251                 // see if the corresponding tag exists in the dictionary 
1252                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
)); 
1255                         switch (gAttributes
[i
].type
) 
1258                                         // just return the value 
1259                                         *(CFTypeRef
*) attributePointers
[i
] = value
; 
1264                                         CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1265                                         *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
); 
1271                                         CFNumberRef nRef 
= (CFNumberRef
) value
; 
1272                                         CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]); 
1279         return errSecSuccess
; 
1284 static OSStatus 
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE 
&keyUse
, uint32 
&attrs
, CFTypeRef 
&labelRef
, CFDataRef 
&applicationTagRef
) 
1286         // establish default values 
1288         bool isPermanent 
= false; 
1289         applicationTagRef 
= NULL
; 
1290         CFTypeRef effectiveKeySize 
= NULL
; 
1291         bool canDecrypt 
= isPublic 
? false : true; 
1292         bool canEncrypt 
= !canDecrypt
; 
1293         bool canDerive 
= true; 
1294         bool canSign 
= isPublic 
? false : true; 
1295         bool canVerify 
= !canSign
; 
1296         bool canUnwrap 
= isPublic 
? false : true; 
1297         attrs 
= CSSM_KEYATTR_EXTRACTABLE
; 
1300         void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
, 
1301                                                                  &canDerive
, &canSign
, &canVerify
, &canUnwrap
}; 
1303         // look for modifiers in the general dictionary 
1304         OSStatus result 
= ScanDictionaryForParameters(parameters
, attributePointers
); 
1305         if (result 
!= errSecSuccess
) 
1310         // see if we have anything which modifies the defaults 
1314                 key 
= kSecPublicKeyAttrs
; 
1318                 key 
= kSecPrivateKeyAttrs
; 
1321         CFTypeRef dType 
= CFDictionaryGetValue(parameters
, key
); 
1324                 // this had better be a dictionary 
1325                 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID()) 
1330                 // pull any additional parameters out of this dictionary 
1331                 result 
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
); 
1332                 if (result 
!= errSecSuccess
) 
1338         // figure out the key usage 
1342                 keyUse 
|= CSSM_KEYUSE_DECRYPT
; 
1347                 keyUse 
|= CSSM_KEYUSE_ENCRYPT
; 
1352                 keyUse 
|= CSSM_KEYUSE_DERIVE
; 
1357                 keyUse 
|= CSSM_KEYUSE_SIGN
; 
1362                 keyUse 
|= CSSM_KEYUSE_VERIFY
; 
1367                 keyUse 
|= CSSM_KEYUSE_UNWRAP
; 
1370         // public key is always extractable; 
1371         // private key is extractable by default unless explicitly set to false 
1372         CFTypeRef value 
= NULL
; 
1373         if (!isPublic 
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
) 
1375                 Boolean keyIsExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1376                 if (!keyIsExtractable
) 
1381         attrs 
|= CSSM_KEYATTR_PERMANENT
; 
1384         return errSecSuccess
; 
1389 static OSStatus 
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
, 
1390                                                                                                    CSSM_ALGORITHMS 
&algorithms
, 
1391                                                                                                    uint32 
&keySizeInBits
, 
1392                                                                                                    CSSM_KEYUSE 
&publicKeyUse
, 
1393                                                                                                    uint32 
&publicKeyAttr
, 
1394                                                                                                    CFTypeRef 
&publicKeyLabelRef
, 
1395                                                                                                    CFDataRef 
&publicKeyAttributeTagRef
, 
1396                                                                                                    CSSM_KEYUSE 
&privateKeyUse
, 
1397                                                                                                    uint32 
&privateKeyAttr
, 
1398                                                                                                    CFTypeRef 
&privateKeyLabelRef
, 
1399                                                                                                    CFDataRef 
&privateKeyAttributeTagRef
, 
1400                                                                                                    SecAccessRef 
&initialAccess
) 
1404         result 
= CheckAlgorithmType(parameters
, algorithms
); 
1405         if (result 
!= errSecSuccess
) 
1410         result 
= GetKeySize(parameters
, algorithms
, keySizeInBits
); 
1411         if (result 
!= errSecSuccess
) 
1416         result 
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1417         if (result 
!= errSecSuccess
) 
1422         result 
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1423         if (result 
!= errSecSuccess
) 
1428         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
)) 
1430                 initialAccess 
= NULL
; 
1432         else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
)) 
1437         return errSecSuccess
; 
1442 static OSStatus 
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
) 
1444         int numToModify 
= 0; 
1455         if (numToModify 
== 0) 
1457                 return errSecSuccess
; 
1460         SecKeychainAttributeList attrList
; 
1461         SecKeychainAttribute attributes
[numToModify
]; 
1468                 if (CFStringGetTypeID() == CFGetTypeID(label
)) { 
1469                         CFStringRef label_string 
= static_cast<CFStringRef
>(label
); 
1470                         attributes
[i
].tag 
= kSecKeyPrintName
; 
1471                         attributes
[i
].data 
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
); 
1472                         if (NULL 
== attributes
[i
].data
) { 
1473                                 CFIndex buffer_length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
); 
1474                                 data 
= attributes
[i
].data 
= malloc((size_t)buffer_length
); 
1475                                 if (NULL 
== attributes
[i
].data
) { 
1476                                         UnixError::throwMe(ENOMEM
); 
1478                                 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) { 
1480                                         MacOSError::throwMe(errSecParam
); 
1483                         attributes
[i
].length 
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
)); 
1484                 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) { 
1485                         // 10.6 bug compatibility 
1486                         CFDataRef label_data 
= static_cast<CFDataRef
>(label
); 
1487                         attributes
[i
].tag 
= kSecKeyLabel
; 
1488                         attributes
[i
].data 
= (void*) CFDataGetBytePtr(label_data
); 
1489                         attributes
[i
].length 
= (UInt32
)CFDataGetLength(label_data
); 
1491                         MacOSError::throwMe(errSecParam
); 
1498                 attributes
[i
].tag 
= kSecKeyApplicationTag
; 
1499                 attributes
[i
].data 
= (void*) CFDataGetBytePtr(tag
); 
1500                 attributes
[i
].length 
= (UInt32
)CFDataGetLength(tag
); 
1504         attrList
.count 
= numToModify
; 
1505         attrList
.attr 
= attributes
; 
1507         OSStatus result 
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
); 
1517 static CFTypeRef 
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) { 
1518     if (subParams 
!= NULL
) { 
1519         CFDictionaryRef subParamsDict 
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
); 
1520         if (subParamsDict 
!= NULL
) { 
1521             CFTypeRef value 
= CFDictionaryGetValue(subParamsDict
, attr
); 
1522             if (value 
!= NULL
) { 
1527     return CFDictionaryGetValue(parameters
, attr
); 
1530 extern "C" OSStatus 
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
); 
1533 /* Generate a private/public keypair. */ 
1535 SecKeyGeneratePairInternal( 
1536     bool alwaysPermanent
, 
1537         CFDictionaryRef parameters
, 
1538         SecKeyRef 
*publicKey
, 
1539         SecKeyRef 
*privateKey
) 
1543         Required(parameters
); 
1544     Required(publicKey
); 
1545     Required(privateKey
); 
1547     CFTypeRef tokenID 
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
); 
1548     CFTypeRef noLegacy 
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
); 
1549     CFTypeRef sync 
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
); 
1550     CFTypeRef accessControl 
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?: 
1551     GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
); 
1552     CFTypeRef accessGroup 
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?: 
1553     GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
); 
1555     // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). 
1556     if (tokenID 
!= NULL 
|| 
1557         (noLegacy 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) || 
1558         (sync 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)sync
)) || 
1559         accessControl 
!= NULL 
|| (accessGroup 
!= NULL 
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))) { 
1560         // Generate keys in iOS keychain. 
1561         return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
); 
1564         CSSM_ALGORITHMS algorithms
; 
1565         uint32 keySizeInBits
; 
1566         CSSM_KEYUSE publicKeyUse
; 
1567         uint32 publicKeyAttr
; 
1568         CFTypeRef publicKeyLabelRef
; 
1569         CFDataRef publicKeyAttributeTagRef
; 
1570         CSSM_KEYUSE privateKeyUse
; 
1571         uint32 privateKeyAttr
; 
1572         CFTypeRef privateKeyLabelRef
; 
1573         CFDataRef privateKeyAttributeTagRef
; 
1574         SecAccessRef initialAccess
; 
1575         SecKeychainRef keychain
; 
1577         OSStatus result 
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, 
1578                                                                                                                  publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
, 
1581         if (result 
!= errSecSuccess
) { 
1585         // verify keychain parameter 
1586     keychain 
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
); 
1587     if (keychain 
!= NULL 
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1591     if (alwaysPermanent
) { 
1592         publicKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1593         privateKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1596         // do the key generation 
1597         result 
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
); 
1598         if (result 
!= errSecSuccess
) { 
1602         // set the label and print attributes on the keys 
1603     SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1604     SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1611 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
) { 
1612     return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
); 
1616 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1617     SecKeyRef privateKey 
= NULL
, publicKey 
= NULL
; 
1618     OSStatus status 
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
); 
1619     SecError(status
, error
, CFSTR("failed to generate asymmetric keypair")); 
1620     if (publicKey 
!= NULL
) { 
1621         CFRelease(publicKey
); 
1626 OSStatus 
SecKeyRawVerifyOSX( 
1627     SecKeyRef           key
,            /* Public key */ 
1628         SecPadding          padding
,            /* kSecPaddingNone or kSecPaddingPKCS1 */ 
1629         const uint8_t       *signedData
,        /* signature over this data */ 
1630         size_t              signedDataLen
,      /* length of dataToSign */ 
1631         const uint8_t       *sig
,                       /* signature */ 
1634     return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
); 
1642 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
) 
1644                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1645         if (value 
!= NULL
) return value
; 
1646         return defaultValue
; 
1650 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
) 
1652         uint32_t integerValue
; 
1653                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1654         if (value 
!= NULL
) { 
1655             CFNumberRef nRef 
= (CFNumberRef
) value
; 
1656             CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
); 
1657             return integerValue
; 
1659         return defaultValue
; 
1663 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
) 
1665                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1666         if (value 
!= NULL
) { 
1667             CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1668             if(CFBooleanGetValue(bRef
)) return maskValue
; 
1674 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
*algorithm
, uint32 
*keySizeInBits
, CSSM_KEYUSE 
*keyUsage
, CSSM_KEYCLASS 
*keyClass
) 
1676     CFTypeRef algorithmDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
); 
1677     CFTypeRef keyClassDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
); 
1679     if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) { 
1680         *algorithm 
= CSSM_ALGID_AES
; 
1681         *keySizeInBits 
= 128; 
1682         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1683     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) { 
1684         *algorithm 
= CSSM_ALGID_DES
; 
1685         *keySizeInBits 
= 128; 
1686          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1687     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) { 
1688         *algorithm 
= CSSM_ALGID_3DES_3KEY_EDE
; 
1689         *keySizeInBits 
= 128; 
1690         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1691     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) { 
1692         *algorithm 
= CSSM_ALGID_RC4
; 
1693         *keySizeInBits 
= 128; 
1694         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1695     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) { 
1696         *algorithm 
= CSSM_ALGID_RC2
; 
1697         *keySizeInBits 
= 128; 
1698          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1699     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) { 
1700         *algorithm 
= CSSM_ALGID_CAST
; 
1701         *keySizeInBits 
= 128; 
1702          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1703     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) { 
1704         *algorithm 
= CSSM_ALGID_RSA
; 
1705         *keySizeInBits 
= 128; 
1706          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1707     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) { 
1708         *algorithm 
= CSSM_ALGID_DSA
; 
1709         *keySizeInBits 
= 128; 
1710          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1711     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) || 
1712             CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) { 
1713         *algorithm 
= CSSM_ALGID_ECDSA
; 
1714         *keySizeInBits 
= 128; 
1715         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1717         *algorithm 
= CSSM_ALGID_AES
; 
1718         *keySizeInBits 
= 128; 
1719         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1722     if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) { 
1723         *keyClass 
= CSSM_KEYCLASS_PUBLIC_KEY
; 
1724     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) { 
1725         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1726     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) { 
1727          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1730     *keySizeInBits 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
); 
1731     *keyUsage 
=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) | 
1732                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) | 
1733                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) | 
1734                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
); 
1737     if(*keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
|| *keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) { 
1738                 *keyUsage 
|=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) | 
1739                                         utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
); 
1742     if(*keyUsage 
== 0) { 
1743                 switch (*keyClass
) { 
1744                         case CSSM_KEYCLASS_PRIVATE_KEY
: 
1745                                 *keyUsage 
= CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN
; 
1747                         case CSSM_KEYCLASS_PUBLIC_KEY
: 
1748                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_VERIFY 
| CSSM_KEYUSE_WRAP
; 
1751                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_VERIFY
; 
1758 utilCopyDefaultKeyLabel(void) 
1760         // generate a default label from the current date 
1761         CFDateRef dateNow 
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent()); 
1762         CFStringRef defaultLabel 
= CFCopyDescription(dateNow
); 
1765         return defaultLabel
; 
1769 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef 
*error
) 
1771         OSStatus result 
= errSecParam
; // default result for an early exit 
1772         SecKeyRef key 
= NULL
; 
1773         SecKeychainRef keychain 
= NULL
; 
1774         SecAccessRef access
; 
1776         CFStringRef appLabel
; 
1778         CFStringRef dateLabel 
= NULL
; 
1780         CSSM_ALGORITHMS algorithm
; 
1781         uint32 keySizeInBits
; 
1782         CSSM_KEYUSE keyUsage
; 
1783         uint32 keyAttr 
= CSSM_KEYATTR_RETURN_DEFAULT
; 
1784         CSSM_KEYCLASS keyClass
; 
1786         Boolean isPermanent
; 
1787         Boolean isExtractable
; 
1789         // verify keychain parameter 
1790         if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
)) 
1792         else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1799         // verify permanent parameter 
1800         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
)) 
1801                 isPermanent 
= false; 
1802         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1805                 isPermanent 
= CFEqual(kCFBooleanTrue
, value
); 
1807                 if (keychain 
== NULL
) { 
1808                         // no keychain was specified, so use the default keychain 
1809                         result 
= SecKeychainCopyDefault(&keychain
); 
1811                 keyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1814         // verify extractable parameter 
1815         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
)) 
1816                 isExtractable 
= true; // default to extractable if value not specified 
1817         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1820                 isExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1822                 keyAttr 
|= CSSM_KEYATTR_EXTRACTABLE
; 
1824         // verify access parameter 
1825         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
)) 
1827         else if (SecAccessGetTypeID() != CFGetTypeID(access
)) 
1830         // verify label parameter 
1831         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
)) 
1832                 label 
= (dateLabel 
= utilCopyDefaultKeyLabel()); // no label provided, so use default 
1833         else if (CFStringGetTypeID() != CFGetTypeID(label
)) 
1836         // verify application label parameter 
1837         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
)) 
1838                 appLabel 
= (dateLabel
) ? dateLabel 
: (dateLabel 
= utilCopyDefaultKeyLabel()); 
1839         else if (CFStringGetTypeID() != CFGetTypeID(appLabel
)) 
1842         // verify application tag parameter 
1843         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
)) 
1845         else if (CFStringGetTypeID() != CFGetTypeID(appTag
)) 
1848     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1851                 // the generated key will not be stored in any keychain 
1852                 result 
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
); 
1855                 // we can set the label attributes on the generated key if it's a keychain item 
1856                 size_t labelBufLen 
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1; 
1857                 char *labelBuf 
= (char *)malloc(labelBufLen
); 
1858                 size_t appLabelBufLen 
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1; 
1859                 char *appLabelBuf 
= (char *)malloc(appLabelBufLen
); 
1860                 size_t appTagBufLen 
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1; 
1861                 char *appTagBuf 
= (char *)malloc(appTagBufLen
); 
1863                 if (!label 
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
)) 
1865                 if (!appLabel 
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
)) 
1867                 if (!appTag 
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
)) 
1870                 SecKeychainAttribute attrs
[] = { 
1871                         { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf 
}, 
1872                         { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf 
}, 
1873                         { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf 
} }; 
1874                 SecKeychainAttributeList attributes 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
1875                 if (!appTag
) --attributes
.count
; 
1877                 result 
= SecKeyGenerateWithAttributes(&attributes
, 
1878                         keychain
, algorithm
, keySizeInBits
, 0, 
1879                         keyUsage
, keyAttr
, access
, &key
); 
1887         if (result 
&& error
) { 
1888                 *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
); 
1891                 CFRelease(dateLabel
); 
1893                 CFRelease(keychain
); 
1901 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef 
*error
) 
1903         CSSM_ALGORITHMS         algorithm
; 
1904     uint32                              keySizeInBits
; 
1905     CSSM_KEYUSE                 keyUsage
; 
1906     CSSM_KEYCLASS               keyClass
; 
1909     if(keyData 
== NULL 
|| CFDataGetLength(keyData
) == 0){ 
1910         MacOSError::throwMe(errSecUnsupportedKeySize
); 
1913     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1915         CSSM_CSP_HANDLE cspHandle 
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL 
1917         SecKeyImportExportParameters iparam
; 
1918         memset(&iparam
, 0, sizeof(iparam
)); 
1919         iparam
.keyUsage 
= keyUsage
; 
1921     CFRef
<CFDataRef
> data
; 
1922         SecExternalItemType itype
; 
1924                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
1925                         itype 
= kSecItemTypePrivateKey
; 
1927         case CSSM_KEYCLASS_PUBLIC_KEY
: { 
1928                         itype 
= kSecItemTypePublicKey
; 
1929             // Public key import expects public key in SubjPublicKey X509 format.  We want to accept both bare and x509 format, 
1930             // so we have to detect bare format here and extend to full X509 if detected. 
1931             data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
)); 
1934                 case CSSM_KEYCLASS_SESSION_KEY
: 
1935                         itype 
= kSecItemTypeSessionKey
; 
1938                         itype 
= kSecItemTypeUnknown
; 
1942         CFMutableArrayRef ka 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
1943         // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. 
1944     crtn 
= impExpImportRawKey(data 
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
); 
1945         if (crtn 
== CSSM_OK 
&& CFArrayGetCount((CFArrayRef
)ka
)) { 
1946                 SecKeyRef sk 
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0); 
1953                         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn 
? crtn 
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
); 
1961 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
, 
1962                                                 SecKeyGeneratePairBlock result
) 
1964         CFDictionaryRef parameters 
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
); 
1965         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{ 
1966                 SecKeyRef publicKey 
= NULL
; 
1967                 SecKeyRef privateKey 
= NULL
; 
1968                 OSStatus status 
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
); 
1969                 dispatch_async(deliveryQueue
, ^{ 
1970                         CFErrorRef error 
= NULL
; 
1971                         if (errSecSuccess 
!= status
) { 
1972                                 error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
); 
1974                         result(publicKey
, privateKey
, error
); 
1979                                 CFRelease(publicKey
); 
1982                                 CFRelease(privateKey
); 
1984                         CFRelease(parameters
); 
1989 static inline void utilClearAndFree(void *p
, size_t len
) { 
1991         if(len
) bzero(p
, len
); 
1997 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
1999     CCPBKDFAlgorithm algorithm
; 
2000     CFIndex passwordLen 
= 0; 
2001     CFDataRef keyData 
= NULL
; 
2002     char *thePassword 
= NULL
; 
2003     uint8_t *salt 
= NULL
; 
2004     uint8_t *derivedKey 
= NULL
; 
2005     size_t  saltLen 
= 0, derivedKeyLen 
= 0; 
2007     CFDataRef saltDictValue
, algorithmDictValue
; 
2008     SecKeyRef retval 
= NULL
; 
2010     /* Pick Values from parameters */ 
2012     if((saltDictValue 
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) { 
2014             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
); 
2019     derivedKeyLen 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128); 
2020         // This value come in bits but the rest of the code treats it as bytes 
2023     algorithmDictValue 
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
); 
2025     rounds 
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0); 
2027     /* Convert any remaining parameters and get the password bytes */ 
2029     saltLen 
= CFDataGetLength(saltDictValue
); 
2030     if((salt 
= (uint8_t *) malloc(saltLen
)) == NULL
) { 
2032             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2037     CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8 
*) salt
); 
2039     passwordLen 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1; 
2040     if((thePassword 
= (char *) malloc(passwordLen
)) == NULL
) { 
2042             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2046     CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
); 
2048     if((derivedKey 
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) { 
2050             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2055     if(algorithmDictValue 
== NULL
) { 
2056         algorithm 
= kCCPRFHmacAlgSHA1
; /* default */ 
2057     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) { 
2058         algorithm 
= kCCPRFHmacAlgSHA1
; 
2059     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) { 
2060         algorithm 
= kCCPRFHmacAlgSHA224
; 
2061     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) { 
2062         algorithm 
= kCCPRFHmacAlgSHA256
; 
2063     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) { 
2064         algorithm 
= kCCPRFHmacAlgSHA384
; 
2065     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) { 
2066         algorithm 
= kCCPRFHmacAlgSHA512
; 
2069             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
); 
2075         rounds 
= 33333; // we need to pass back a consistent value since there's no way to record the round count. 
2078     if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) { 
2080             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2085     if((keyData 
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) { 
2086         retval 
=  SecKeyCreateFromData(parameters
, keyData
, error
); 
2090             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2095     utilClearAndFree(salt
, saltLen
); 
2096     utilClearAndFree(thePassword
, passwordLen
); 
2097     utilClearAndFree(derivedKey
, derivedKeyLen
); 
2102 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2105         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
); 
2111 SecKeyUnwrapSymmetric(CFDataRef 
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2114         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);