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 <CoreFoundation/CFPriv.h> 
  39 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it. 
  42 #include "SecBridge.h" 
  44 #include <security_keychain/Access.h> 
  45 #include <security_keychain/Keychains.h> 
  46 #include <security_keychain/KeyItem.h> 
  50 #include <security_cdsa_utils/cuCdsaUtils.h> 
  51 #include <security_cdsa_client/wrapkey.h> 
  52 #include <security_cdsa_client/genkey.h> 
  53 #include <security_cdsa_client/signclient.h> 
  54 #include <security_cdsa_client/cryptoclient.h> 
  56 #include "SecImportExportCrypto.h" 
  59 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) { 
  60     key
->key 
= const_cast<KeyItem 
*>(reinterpret_cast<const KeyItem 
*>(keyData
)); 
  61     key
->key
->initializeWithSecKeyRef(key
); 
  62     key
->credentialType 
= kSecCredentialTypeDefault
; 
  63     key
->cdsaKeyMutex 
= new Mutex(); 
  68 SecCDSAKeyDestroy(SecKeyRef keyRef
) { 
  69     // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation. 
  70     // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. 
  71     // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. 
  73     StMaybeLock
<Mutex
> cdsaMutex(keyRef
->cdsaKeyMutex
); 
  75     KeyItem 
*keyItem 
= keyRef
->key
; 
  77     if (keyItem 
== NULL
) { 
  78         // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. 
  80         delete keyRef
->cdsaKeyMutex
; 
  84     Keychain kc 
= keyItem
->keychain(); 
  86     // We have a +1 reference to the KeyItem now; no need to protect our storage any more 
  90         StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject()); 
  91         keyItem 
= keyRef
->key
; 
  92         if (keyItem 
== NULL
) { 
  93             // 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         keyItem
->aboutToDestruct(); 
 101     delete keyRef
->cdsaKeyMutex
; 
 103     (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. 
 107 SecCDSAKeyGetBlockSize(SecKeyRef key
) { 
 109     CFErrorRef 
*error 
= NULL
; 
 110     BEGIN_SECKEYAPI(size_t,0) 
 112     const CssmKey::Header keyHeader 
= key
->key
->unverifiedKeyHeader(); 
 113     switch(keyHeader
.algorithm()) 
 117             result 
= keyHeader
.LogicalKeySizeInBits 
/ 8; 
 119         case CSSM_ALGID_ECDSA
: 
 121             /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, 
 122              * plus both coordinates for the point used */ 
 123 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) 
 124 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) 
 125             size_t coordSize 
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
); 
 126             assert(coordSize 
< 256); /* size must fit in a byte for DER */ 
 127             size_t coordDERLen 
= (coordSize 
> 127) ? 2 : 1; 
 128             size_t coordLen 
= 1 + coordDERLen 
+ coordSize
; 
 130             size_t pointSize 
= 2 * coordLen
; 
 131             assert(pointSize 
< 256); /* size must fit in a byte for DER */ 
 132             size_t pointDERLen 
= (pointSize 
> 127) ? 2 : 1; 
 133             size_t pointLen 
= 1 + pointDERLen 
+ pointSize
; 
 139             result 
= 16; /* all AES keys use 128-bit blocks */ 
 142         case CSSM_ALGID_3DES_3KEY
: 
 143             result 
= 8; /* all DES keys use 64-bit blocks */ 
 146             assert(0); /* some other key algorithm */ 
 147             result 
= 16; /* FIXME: revisit this */ 
 155 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) { 
 157     CFErrorRef 
*error 
= NULL
; 
 158     BEGIN_SECKEYAPI(CFIndex
, 0) 
 160     result 
= kSecNullAlgorithmID
; 
 161     switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) { 
 163             result 
= kSecRSAAlgorithmID
; 
 166             result 
= kSecDSAAlgorithmID
; 
 168         case CSSM_ALGID_ECDSA
: 
 169             result 
= kSecECDSAAlgorithmID
; 
 172             assert(0); /* other algorithms TBA */ 
 178 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) { 
 179     // First of all, consider x509 format and try to strip SubjPubKey envelope.  If it fails, do not panic 
 180     // and export data as is. 
 181     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
; 
 183     DERSubjPubKeyInfo subjPubKey
; 
 184     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 185                          DERSubjPubKeyInfoItemSpecs
, 
 186                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success 
&& 
 187         DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 188         return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
); 
 191     return CFDataRef(CFRetain(pubKeyInfo
)); 
 194 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) { 
 195     // First check, whether X509 pubkeyinfo is already present.  If not, add it according to the key type. 
 196     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }; 
 197     DERSubjPubKeyInfo subjPubKey
; 
 198     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 199                          DERSubjPubKeyInfoItemSpecs
, 
 200                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) { 
 201         return CFDataRef(CFRetain(pubKeyInfo
)); 
 204     // We have always size rounded to full bytes so bitstring encodes leading 00. 
 205     CFRef
<CFMutableDataRef
> bitStringPubKey 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 206     CFDataSetLength(bitStringPubKey
, 1); 
 207     CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
)); 
 208     subjPubKey
.pubKey
.data 
= static_cast<DERByte 
*>(const_cast<UInt8 
*>(CFDataGetBytePtr(bitStringPubKey
))); 
 209     subjPubKey
.pubKey
.length 
= CFDataGetLength(bitStringPubKey
); 
 211     // Encode algId according to algorithm used. 
 212     static const DERByte oidRSA
[] = { 
 213         0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 
 215     static const DERByte oidECsecp256
[] = { 
 216         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 
 218     static const DERByte oidECsecp384
[] = { 
 219         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 
 221     static const DERByte oidECsecp521
[] = { 
 222         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 
 224     subjPubKey
.algId
.length 
= 0; 
 225     if (algorithm 
== CSSM_ALGID_RSA
) { 
 226         subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidRSA
); 
 227         subjPubKey
.algId
.length 
= sizeof(oidRSA
); 
 228     } else if (algorithm 
== CSSM_ALGID_ECDSA
) { 
 229         if (keySizeInBits 
== 256) { 
 230             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp256
); 
 231             subjPubKey
.algId
.length 
= sizeof(oidECsecp256
); 
 232         } else if (keySizeInBits 
== 384) { 
 233             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp384
); 
 234             subjPubKey
.algId
.length 
= sizeof(oidECsecp384
); 
 235         } if (keySizeInBits 
== 521) { 
 236             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp521
); 
 237             subjPubKey
.algId
.length 
= sizeof(oidECsecp521
); 
 240     DERSize size 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 241                                               DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
); 
 242     CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 243     CFDataSetLength(keyData
, size
); 
 244     if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 245                           DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
, 
 246                           static_cast<DERByte 
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) { 
 247         CFDataSetLength(keyData
, size
); 
 252     return keyData
.yield(); 
 255 static OSStatus 
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef 
*serialization
) { 
 257     CFErrorRef 
*error 
= NULL
; 
 258     BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
) 
 260     const CssmKey::Header 
&header 
= key
->key
->key().header(); 
 261     switch (header
.algorithm()) { 
 262         case CSSM_ALGID_RSA
: { 
 263             switch (header
.keyClass()) { 
 264                 case CSSM_KEYCLASS_PRIVATE_KEY
: { 
 265                     CFRef
<CFDataRef
> privKeyData
; 
 266                     result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take()); 
 267                     if (result 
== errSecSuccess
) { 
 268                         DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) }; 
 269                         DERRSAKeyPair keyPair
; 
 270                         if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
, 
 271                                              &keyPair
, sizeof(keyPair
)) == DR_Success
) { 
 272                             DERRSAPubKeyPKCS1 pubKey 
= { keyPair
.n
, keyPair
.e 
}; 
 273                             DERSize size 
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
, 
 274                                                                       DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
); 
 275                             CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 276                             CFDataSetLength(keyData
, size
); 
 277                             UInt8 
*data 
= CFDataGetMutableBytePtr(keyData
); 
 278                             if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
, 
 279                                                   DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
, 
 280                                                   data
, &size
) == DR_Success
) { 
 281                                 CFDataSetLength(keyData
, size
); 
 282                                 *data 
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
; 
 283                                 *serialization 
= keyData
.yield(); 
 285                                 *serialization 
= NULL
; 
 286                                 result 
= errSecParam
; 
 292                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 293                     result 
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
); 
 298         case CSSM_ALGID_ECDSA
: { 
 299             *serialization 
= NULL
; 
 300             CFRef
<CFDataRef
> tempPublicData
; 
 301             result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take()); 
 302             if (result 
== errSecSuccess
) { 
 303                 *serialization 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
); 
 308             result 
= errSecUnimplemented
; 
 319 static const DERItemSpec DERECPrivateKeyItemSpecs
[] = 
 324     { DER_OFFSET(DERECPrivateKey
, privateKey
), 
 326         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 328         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0, 
 329         DER_DEC_SKIP 
| DER_ENC_NO_OPTS 
}, 
 330     { DER_OFFSET(DERECPrivateKey
, publicKey
), 
 331         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 1, 
 332         DER_DEC_NO_OPTS 
| DER_ENC_SIGNED_INT 
}, 
 334 static const DERSize DERNumECPrivateKeyItemSpecs 
= 
 335 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
); 
 339 } DERECPrivateKeyPublicKey
; 
 341 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] = 
 343     { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
), 
 345         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 347 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs 
= 
 348 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
); 
 351 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef 
*error
) { 
 353     BEGIN_SECKEYAPI(CFDataRef
, NULL
) 
 356     const CssmKey::Header header 
= key
->key
->unverifiedKeyHeader(); 
 357     CFRef
<CFDataRef
> keyData
; 
 358     switch (header
.algorithm()) { 
 360             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 362         case CSSM_ALGID_ECDSA
: { 
 363             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 364             if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) { 
 365                 // Convert DER format into x9.63 format, which is expected for exported key. 
 366                 DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) }; 
 367                 DERECPrivateKey privateKey
; 
 368                 DERECPrivateKeyPublicKey privateKeyPublicKey
; 
 371                 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
, 
 372                                      &privateKey
, sizeof(privateKey
)) == DR_Success 
&& 
 373                     DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
, 
 374                                             DERECPrivateKeyPublicKeyItemSpecs
, 
 375                                             &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success 
&& 
 376                     DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 377                     CFRef
<CFMutableDataRef
> key 
= CFDataCreateMutable(kCFAllocatorDefault
, 
 378                                                                       pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 379                     CFDataSetLength(key
, pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 380                     CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
); 
 381                     CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
), 
 382                                        privateKey
.privateKey
.data
, privateKey
.privateKey
.length
); 
 383                     keyData 
= key
.as
<CFDataRef
>(); 
 389             MacOSError::throwMe(errSecUnimplemented
); 
 392     if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) { 
 393         result 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
); 
 395         result 
= keyData
.yield(); 
 401 static CFDataRef 
SecCDSAKeyCopyLabel(SecKeyRef key
) { 
 402     CFDataRef label 
= NULL
; 
 403     if (key
->key
->isPersistent()) { 
 404         UInt32 tags
[] = { kSecKeyLabel 
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB 
}; 
 405         SecKeychainAttributeInfo info 
= { 1, tags
, formats 
}; 
 406         SecKeychainAttributeList 
*list 
= NULL
; 
 407         key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
); 
 408         if (list
->count 
== 1) { 
 409             SecKeychainAttribute 
*attr 
= list
->attr
; 
 410             label 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)attr
->data
, (CFIndex
)attr
->length
); 
 412         key
->key
->freeAttributesAndData(list
, NULL
); 
 417 static CFDictionaryRef
 
 418 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) { 
 420     CFErrorRef 
*error 
= NULL
; 
 421     BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
) 
 423     CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, 
 424                                                             &kCFTypeDictionaryValueCallBacks
); 
 426     CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
); 
 428     const CssmKey::Header header 
= key
->key
->unverifiedKeyHeader(); 
 429     CFIndex sizeValue 
= header
.LogicalKeySizeInBits
; 
 430     CFRef
<CFNumberRef
> sizeInBits 
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
); 
 431     CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
); 
 432     CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
); 
 434     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(key
); 
 436         // For floating keys, calculate label as SHA1 of pubkey bytes. 
 437         CFRef
<CFDataRef
> pubKeyBlob
; 
 438         if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) { 
 439             uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
]; 
 440             CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
); 
 441             label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
))); 
 446         CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
); 
 449     CSSM_KEYATTR_FLAGS attrs 
= header
.attributes(); 
 450     CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs 
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 451     CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs 
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 452     CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs 
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 453     CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs 
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 454     CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs 
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 455     CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs 
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 456     CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs 
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 458     CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 459     CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 460     CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 461     CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 462     CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 463     CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 464     CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 465     CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 466     CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 468     switch (header
.keyClass()) { 
 469         case CSSM_KEYCLASS_PUBLIC_KEY
: 
 470             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
); 
 472         case CSSM_KEYCLASS_PRIVATE_KEY
: 
 473             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
); 
 477     switch (header
.algorithm()) { 
 479             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
); 
 481         case CSSM_ALGID_ECDSA
: 
 482             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
); 
 486     CFRef
<CFDataRef
> keyData
; 
 487     if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) { 
 488         CFDictionarySetValue(dict
, kSecValueData
, keyData
); 
 491     if (header
.algorithm() == CSSM_ALGID_RSA 
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY 
&& 
 492         header
.blobType() == CSSM_KEYBLOB_RAW
) { 
 493         const CssmData 
&keyData 
= key
->key
->key()->keyData(); 
 494         DERItem keyItem 
= { static_cast<DERByte 
*>(keyData
.data()), keyData
.length() }; 
 495         DERRSAPubKeyPKCS1 decodedKey
; 
 496         if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
, 
 497                              DERRSAPubKeyPKCS1ItemSpecs
, 
 498                              &decodedKey
, sizeof(decodedKey
)) == DR_Success
) { 
 499             CFRef
<CFDataRef
> modulus 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, 
 500                                                     decodedKey
.modulus
.length
); 
 501             CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
); 
 502             CFRef
<CFDataRef
> exponent 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, 
 503                                                      decodedKey
.pubExponent
.length
); 
 504             CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
); 
 513 #pragma clang diagnostic push 
 514 #pragma clang diagnostic ignored "-Wunused-const-variable" 
 515 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
); 
 516 #pragma clang diagnostic pop 
 518 static SecKeyRef 
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) { 
 519     CFErrorRef 
*error 
= NULL
; 
 520     BEGIN_SECKEYAPI(SecKeyRef
, NULL
) 
 523     KeyItem 
*key 
= privateKey
->key
; 
 524     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(privateKey
); 
 526         // Lookup public key in the database. 
 527         DbUniqueRecord uniqueId
; 
 528         SSDb 
ssDb(dynamic_cast<SSDbImpl 
*>(&(*key
->keychain()->database()))); 
 529         SSDbCursor 
dbCursor(ssDb
, 1); 
 530         dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 531         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
))); 
 532         if (dbCursor
->next(NULL
, NULL
, uniqueId
)) { 
 533             Item publicKey 
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
); 
 534             result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 538     if (result 
== NULL 
&& key
->publicKey()) { 
 539         SecPointer
<KeyItem
> publicKey(new KeyItem(key
->publicKey())); 
 540         result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 546 static KeyItem 
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType 
&operation
, SecKeyAlgorithm algorithm
, 
 547                                             CSSM_ALGORITHMS 
&baseAlgorithm
, CSSM_ALGORITHMS 
&secondaryAlgorithm
, 
 548                                             CSSM_ALGORITHMS 
&paddingAlgorithm
, CFIndex 
&inputSizeLimit
) { 
 549     KeyItem 
*keyItem 
= key
->key
; 
 550     CSSM_KEYCLASS keyClass 
= keyItem
->key()->header().keyClass(); 
 551     baseAlgorithm 
= keyItem
->key()->header().algorithm(); 
 552     switch (baseAlgorithm
) { 
 554             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 555                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 556                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) { 
 557                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 558                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 560                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) { 
 561                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 562                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 563                     inputSizeLimit 
= -11; 
 564                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) { 
 565                     secondaryAlgorithm 
= CSSM_ALGID_SHA1
; 
 566                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 568                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) { 
 569                     secondaryAlgorithm 
= CSSM_ALGID_SHA224
; 
 570                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 571                     inputSizeLimit 
= 224 / 8; 
 572                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) { 
 573                     secondaryAlgorithm 
= CSSM_ALGID_SHA256
; 
 574                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 575                     inputSizeLimit 
= 256 / 8; 
 576                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) { 
 577                     secondaryAlgorithm 
= CSSM_ALGID_SHA384
; 
 578                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 579                     inputSizeLimit 
= 384 / 8; 
 580                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) { 
 581                     secondaryAlgorithm 
= CSSM_ALGID_SHA512
; 
 582                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 583                     inputSizeLimit 
= 512 / 8; 
 584                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) { 
 585                     secondaryAlgorithm 
= CSSM_ALGID_MD5
; 
 586                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 591             } else if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt
) || 
 592                        (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeEncrypt
)) { 
 593                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 594                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 595                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 597                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) { 
 598                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 599                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 600                     inputSizeLimit 
= operation 
== kSecKeyOperationTypeEncrypt 
? -11 : 0; 
 604             } else if (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt 
&& 
 605                        CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 606                 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, 
 607                 // because CDSA keys refuses to perform decrypt using public key. 
 608                 operation 
= kSecKeyOperationTypeEncrypt
; 
 609                 secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 610                 paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 616         case CSSM_ALGID_ECDSA
: 
 617             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 618                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 619                 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) { 
 620                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 621                     paddingAlgorithm 
= CSSM_PADDING_SIGRAW
; 
 622                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) { 
 623                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 624                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 628             } else if (keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeKeyExchange
) { 
 629                 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) || 
 630                     CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) { 
 631                     baseAlgorithm 
= CSSM_ALGID_ECDH
; 
 632                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) || 
 633                            CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) { 
 634                     baseAlgorithm 
= CSSM_ALGID_ECDH_X963_KDF
; 
 643             MacOSError::throwMe(errSecParam
); 
 649 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) { 
 650     CFIndex blockSize 
= key
->key
->key().header().LogicalKeySizeInBits 
/ 8; 
 651     CFIndex plaintextLength 
= CFDataGetLength(plaintext
); 
 652     if ((algorithm 
== kSecKeyAlgorithmRSAEncryptionRaw 
|| algorithm 
== kSecKeyAlgorithmRSASignatureRaw
) 
 653         && plaintextLength 
< blockSize
) { 
 654         // Pre-pad with zeroes. 
 655         CFMutableDataRef 
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
)); 
 656         CFDataSetLength(result
, blockSize
); 
 657         CFDataReplaceBytes(result
, CFRangeMake(blockSize 
- plaintextLength
, plaintextLength
), 
 658                            CFDataGetBytePtr(plaintext
), plaintextLength
); 
 661         return CFDataRef(CFRetain(plaintext
)); 
 665 static CFTypeRef 
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
, 
 666                                                CFArrayRef allAlgorithms
, SecKeyOperationMode mode
, 
 667                                                CFTypeRef in1
, CFTypeRef in2
, CFErrorRef 
*error
) { 
 668     BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
) 
 669     CFIndex inputSizeLimit 
= 0; 
 670     CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
; 
 671     KeyItem 
*keyItem 
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
); 
 672     if (keyItem 
== NULL
) { 
 673         // Operation/algorithm/key combination is not supported. 
 675     } else if (mode 
== kSecKeyOperationModeCheckIfSupported
) { 
 676         // Operation is supported and caller wants to just know that. 
 677         return kCFBooleanTrue
; 
 678     } else if (baseAlgorithm 
== CSSM_ALGID_RSA
) { 
 679         if (inputSizeLimit 
<= 0) { 
 680             inputSizeLimit 
+= SecCDSAKeyGetBlockSize(key
); 
 682         if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) { 
 683             MacOSError::throwMe(errSecParam
); 
 688         case kSecKeyOperationTypeSign
: { 
 689             CssmClient::Sign 
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 690             signContext
.key(keyItem
->key()); 
 691             signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
)); 
 692             signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 693             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 694             CssmAutoData 
signature(signContext
.allocator()); 
 695             signContext
.sign(CssmData(CFDataRef(input
)), signature
.get()); 
 696             result 
= CFDataCreate(NULL
, static_cast<const UInt8 
*>(signature
.data()), CFIndex(signature
.length())); 
 699         case kSecKeyOperationTypeVerify
: { 
 700             CssmClient::Verify 
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 701             verifyContext
.key(keyItem
->key()); 
 702             verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
)); 
 703             verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 704             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 705             verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
))); 
 706             result 
= kCFBooleanTrue
; 
 709         case kSecKeyOperationTypeEncrypt
: { 
 710             CssmClient::Encrypt 
encryptContext(keyItem
->csp(), baseAlgorithm
); 
 711             encryptContext
.key(keyItem
->key()); 
 712             encryptContext
.padding(paddingAlgorithm
); 
 713             encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
)); 
 714             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 715             CssmAutoData 
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator()); 
 716             size_t length 
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get()); 
 717             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 718             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 719             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 720             CFDataSetLength(CFMutableDataRef(result
), length
); 
 723         case kSecKeyOperationTypeDecrypt
: { 
 724             CssmClient::Decrypt 
decryptContext(keyItem
->csp(), baseAlgorithm
); 
 725             decryptContext
.key(keyItem
->key()); 
 726             decryptContext
.padding(paddingAlgorithm
); 
 727             decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
)); 
 728             CssmAutoData 
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator()); 
 729             size_t length 
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)), 
 730                                                    output
.get(), remainingData
.get()); 
 731             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 732             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 733             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 734             CFDataSetLength(CFMutableDataRef(result
), length
); 
 737         case kSecKeyOperationTypeKeyExchange
: { 
 738             CFIndex requestedLength 
= 0; 
 740             switch (baseAlgorithm
) { 
 741                 case CSSM_ALGID_ECDH
: 
 742                     requestedLength 
= (keyItem
->key().header().LogicalKeySizeInBits 
+ 7) / 8; 
 744                 case CSSM_ALGID_ECDH_X963_KDF
: 
 745                     CFDictionaryRef params 
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
); 
 746                     CFTypeRef value 
= params 
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
; 
 747                     if (value 
== NULL 
|| CFGetTypeID(value
) != CFNumberGetTypeID() || 
 748                         !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) { 
 749                         MacOSError::throwMe(errSecParam
); 
 751                     value 
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
); 
 752                     if (value 
!= NULL 
&& CFGetTypeID(value
) == CFDataGetTypeID()) { 
 753                         sharedInfo 
= CssmData(CFDataRef(value
)); 
 758             CssmClient::DeriveKey 
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength 
* 8)); 
 759             derive
.key(keyItem
->key()); 
 760             derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
)); 
 761             derive
.salt(sharedInfo
); 
 762             CssmData 
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
)); 
 763             Key derivedKey 
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 765             // Export raw data of newly derived key (by wrapping with an empty key). 
 766             CssmClient::WrapKey 
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
); 
 767             Key wrappedKey 
= wrapper(derivedKey
); 
 768             result 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)wrappedKey
->data(), CFIndex(wrappedKey
->length())); 
 778 static Boolean 
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) { 
 779     CFErrorRef 
*error 
= NULL
; 
 780     BEGIN_SECKEYAPI(Boolean
, false) 
 782     result 
= key1
->key
->equal(*key2
->key
); 
 787 static Boolean 
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef 
*error
) { 
 788     BEGIN_SECKEYAPI(Boolean
, false) 
 790     if (CFEqual(name
, kSecUseAuthenticationUI
)) { 
 791         key
->credentialType 
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault 
: kSecCredentialTypeNoUI
; 
 794         result 
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
); 
 800 const SecKeyDescriptor kSecCDSAKeyDescriptor 
= { 
 801     .version 
= kSecKeyDescriptorVersion
, 
 804     .init 
= SecCDSAKeyInit
, 
 805     .destroy 
= SecCDSAKeyDestroy
, 
 806     .blockSize 
= SecCDSAKeyGetBlockSize
, 
 807     .getAlgorithmID 
= SecCDSAKeyGetAlgorithmId
, 
 808     .copyDictionary 
= SecCDSAKeyCopyAttributeDictionary
, 
 809     .copyPublic 
= SecCDSAKeyCopyPublicBytes
, 
 810     .copyExternalRepresentation 
= SecCDSAKeyCopyExternalRepresentation
, 
 811     .copyPublicKey 
= SecCDSAKeyCopyPublicKey
, 
 812     .copyOperationResult 
= SecCDSAKeyCopyOperationResult
, 
 813     .isEqual 
= SecCDSAKeyIsEqual
, 
 814     .setParameter 
= SecCDSAKeySetParameter
, 
 816     .extraBytes 
= (sizeof(struct OpaqueSecKeyRef
) > sizeof(struct __SecKey
) ? (sizeof(struct OpaqueSecKeyRef
) - sizeof(struct __SecKey
)) : 0), 
 820     namespace KeychainCore 
{ 
 821         SecCFObject 
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) { 
 822             if (ptr 
== NULL 
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) { 
 826             SecKeyRef key 
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
)); 
 827             if (key
->key_class 
== &kSecCDSAKeyDescriptor
) { 
 828                 return static_cast<SecCFObject 
*>(key
->key
); 
 831             if (key
->cdsaKey 
== NULL
) { 
 832                 // Create CDSA key from exported data of existing key. 
 833                 CFRef
<CFDataRef
> keyData 
= SecKeyCopyExternalRepresentation(key
, NULL
); 
 834                 CFRef
<CFDictionaryRef
> keyAttributes 
= SecKeyCopyAttributes(key
); 
 835                 if (keyData 
&& keyAttributes
) { 
 836                     key
->cdsaKey 
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
); 
 840             return (key
->cdsaKey 
!= NULL
) ? key
->cdsaKey
->key 
: NULL
; 
 843         // You need to hold this key's MutexForObject when you run this 
 844         void KeyItem::attachSecKeyRef() const { 
 845             SecKeyRef key 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0); 
 846             key
->key
->mWeakSecKeyRef 
= key
; 
 852 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
 853 Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
) { 
 854     return ref
->key_class 
== &kSecCDSAKeyDescriptor
; 
 858 static OSStatus 
SecKeyCreatePairInternal( 
 859         SecKeychainRef keychainRef
, 
 860         CSSM_ALGORITHMS algorithm
, 
 861         uint32 keySizeInBits
, 
 862         CSSM_CC_HANDLE contextHandle
, 
 863         CSSM_KEYUSE publicKeyUsage
, 
 864         uint32 publicKeyAttr
, 
 865         CSSM_KEYUSE privateKeyUsage
, 
 866         uint32 privateKeyAttr
, 
 867         SecAccessRef initialAccess
, 
 868         SecKeyRef
* publicKeyRef
, 
 869         SecKeyRef
* privateKeyRef
) 
 874     SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
 875     SecPointer
<KeyItem
> pubItem
, privItem
; 
 876     if (((publicKeyAttr 
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) { 
 877         keychain 
= Keychain::optional(keychainRef
); 
 879     StMaybeLock
<Mutex
> _(keychain 
? keychain
->getKeychainMutex() : NULL
); 
 880     KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
, 
 881                         privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
); 
 883         // Return the generated keys. 
 885                 *publicKeyRef 
= pubItem
->handle(); 
 887                 *privateKeyRef 
= privItem
->handle(); 
 894         SecKeychainRef keychainRef
, 
 895         CSSM_ALGORITHMS algorithm
, 
 896         uint32 keySizeInBits
, 
 897         CSSM_CC_HANDLE contextHandle
, 
 898         CSSM_KEYUSE publicKeyUsage
, 
 899         uint32 publicKeyAttr
, 
 900         CSSM_KEYUSE privateKeyUsage
, 
 901         uint32 privateKeyAttr
, 
 902         SecAccessRef initialAccess
, 
 903         SecKeyRef
* publicKeyRef
, 
 904         SecKeyRef
* privateKeyRef
) 
 906     OSStatus result 
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, 
 907                                                publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
); 
 915 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY 
**cssmKey
) 
 919         Required(cssmKey
) = KeyItem::required(key
)->key(); 
 929 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
; 
 930 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
; 
 933 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE 
*cspHandle
) 
 937         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 939     // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). 
 940     // Keep a global pointer to it to force the CSP to stay live forever. 
 941     CssmClient::CSP returnedKeyCSP 
= keyItem
->csp(); 
 943         StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex()); 
 944         gSecReturnedKeyCSPs().insert(returnedKeyCSP
); 
 946         Required(cspHandle
) = returnedKeyCSP
->handle(); 
 951 /* deprecated as of 10.8 */ 
 953 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
**algid
) 
 957         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 958         Required(algid
) = &keyItem
->algorithmIdentifier(); 
 964 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
*algid
, unsigned int *strength
) 
 968         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 969         Required(strength
) = keyItem
->strengthInBits(algid
); 
 975 SecKeyGetCredentials( 
 977         CSSM_ACL_AUTHORIZATION_TAG operation
, 
 978         SecCredentialType credentialType
, 
 979         const CSSM_ACCESS_CREDENTIALS 
**outCredentials
) 
 983         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 984         Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
); 
 991         SecKeychainRef keychainRef
, 
 992         const CSSM_KEY 
*publicCssmKey
, 
 993         const CSSM_KEY 
*privateCssmKey
, 
 994         SecAccessRef initialAccess
, 
 995         SecKeyRef
* publicKey
, 
 996         SecKeyRef
* privateKey
) 
1000         Keychain keychain 
= Keychain::optional(keychainRef
); 
1001         SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
1002         SecPointer
<KeyItem
> pubItem
, privItem
; 
1004         KeyItem::importPair(keychain
, 
1005                 Required(publicCssmKey
), 
1006                 Required(privateCssmKey
), 
1011         // Return the generated keys. 
1013                 *publicKey 
= pubItem
->handle(); 
1015                 *privateKey 
= privItem
->handle(); 
1021 SecKeyGenerateWithAttributes( 
1022         SecKeychainAttributeList
* attrList
, 
1023         SecKeychainRef keychainRef
, 
1024         CSSM_ALGORITHMS algorithm
, 
1025         uint32 keySizeInBits
, 
1026         CSSM_CC_HANDLE contextHandle
, 
1027         CSSM_KEYUSE keyUsage
, 
1029         SecAccessRef initialAccess
, 
1035         SecPointer
<Access
> theAccess
; 
1038                 keychain 
= KeychainImpl::required(keychainRef
); 
1040                 theAccess 
= Access::required(initialAccess
); 
1042         SecPointer
<KeyItem
> item 
= KeyItem::generateWithAttributes(attrList
, 
1051         // Return the generated key. 
1053                 *keyRef 
= item
->handle(); 
1060         SecKeychainRef keychainRef
, 
1061         CSSM_ALGORITHMS algorithm
, 
1062         uint32 keySizeInBits
, 
1063         CSSM_CC_HANDLE contextHandle
, 
1064         CSSM_KEYUSE keyUsage
, 
1066         SecAccessRef initialAccess
, 
1069         return SecKeyGenerateWithAttributes(NULL
, 
1070                 keychainRef
, algorithm
, keySizeInBits
, 
1071                 contextHandle
, keyUsage
, keyAttr
, 
1072                 initialAccess
, keyRef
); 
1076 /* Generate a floating key reference from a CSSM_KEY */ 
1078 SecKeyCreateWithCSSMKey(const CSSM_KEY 
*cssmKey
, 
1084     if(cssmKey
->KeyData
.Length 
== 0){ 
1085         MacOSError::throwMe(errSecInvalidAttributeKeyLength
); 
1087     if(cssmKey
->KeyData
.Data 
== NULL
){ 
1088         MacOSError::throwMe(errSecInvalidPointer
); 
1090         CssmClient::CSP 
csp(cssmKey
->KeyHeader
.CspId
); 
1091         CssmClient::Key 
key(csp
, *cssmKey
); 
1092         KeyItem 
*item 
= new KeyItem(key
); 
1094         // Return the generated key. 
1096         *keyRef 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0); 
1103 static u_int32_t 
ConvertCFStringToInteger(CFStringRef ref
) 
1110         // figure out the size of the string 
1111         CFIndex numChars 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
); 
1112         char *buffer 
= (char *)malloc(numChars
); 
1113     if (NULL 
== buffer
) { 
1114         UnixError::throwMe(ENOMEM
); 
1116         if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
)) 
1119                 MacOSError::throwMe(errSecParam
); 
1122     u_int32_t result 
= atoi(buffer
); 
1129 static OSStatus 
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
&algorithms
) 
1131         // figure out the algorithm to use 
1132         CFStringRef ktype 
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
); 
1138         if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) { 
1139                 algorithms 
= CSSM_ALGID_RSA
; 
1140                 return errSecSuccess
; 
1141        } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) || 
1142                        CFEqual(ktype
, kSecAttrKeyTypeEC
)) { 
1143                 algorithms 
= CSSM_ALGID_ECDSA
; 
1144                 return errSecSuccess
; 
1145         } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) { 
1146                 algorithms 
= CSSM_ALGID_AES
; 
1147                 return errSecSuccess
; 
1148         } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) { 
1149                 algorithms 
= CSSM_ALGID_3DES
; 
1150                 return errSecSuccess
; 
1152                 return errSecUnsupportedAlgorithm
; 
1158 static OSStatus 
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32 
&keySizeInBits
) 
1161     // get the key size and check it for validity 
1162     CFTypeRef ref 
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
); 
1164     keySizeInBits 
= kSecDefaultKeySize
; 
1166     CFTypeID bitSizeType 
= CFGetTypeID(ref
); 
1167     if (bitSizeType 
== CFStringGetTypeID()) 
1168         keySizeInBits 
= ConvertCFStringToInteger((CFStringRef
) ref
); 
1169     else if (bitSizeType 
== CFNumberGetTypeID()) 
1170         CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
); 
1171     else return errSecParam
; 
1174     switch (algorithms
) { 
1175     case CSSM_ALGID_ECDSA
: 
1176         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecp256r1
; 
1177         if(keySizeInBits 
== kSecp192r1 
|| keySizeInBits 
== kSecp256r1 
|| keySizeInBits 
== kSecp384r1 
|| keySizeInBits 
== kSecp521r1 
) return errSecSuccess
; 
1179     case CSSM_ALGID_RSA
: 
1180                           if(keySizeInBits 
% 8) return errSecParam
; 
1181         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= 2048; 
1182         if(keySizeInBits 
>= kSecRSAMin 
&& keySizeInBits 
<= kSecRSAMax
) return errSecSuccess
; 
1184     case CSSM_ALGID_AES
: 
1185         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecAES128
; 
1186         if(keySizeInBits 
== kSecAES128 
|| keySizeInBits 
== kSecAES192 
|| keySizeInBits 
== kSecAES256
) return errSecSuccess
; 
1188     case CSSM_ALGID_3DES
: 
1189         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSec3DES192
; 
1190         if(keySizeInBits 
== kSec3DES192
) return errSecSuccess
; 
1209 struct ParameterAttribute
 
1211         const CFStringRef 
*name
; 
1217 static ParameterAttribute gAttributes
[] = 
1224                 &kSecAttrIsPermanent
, 
1228                 &kSecAttrApplicationTag
, 
1232                 &kSecAttrEffectiveKeySize
, 
1236                 &kSecAttrCanEncrypt
, 
1240                 &kSecAttrCanDecrypt
, 
1261 const int kNumberOfAttributes 
= sizeof(gAttributes
) / sizeof(ParameterAttribute
); 
1263 static OSStatus 
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[]) 
1266         for (i 
= 0; i 
< kNumberOfAttributes
; ++i
) 
1268                 // see if the corresponding tag exists in the dictionary 
1269                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
)); 
1272                         switch (gAttributes
[i
].type
) 
1275                                         // just return the value 
1276                                         *(CFTypeRef
*) attributePointers
[i
] = value
; 
1281                                         CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1282                                         *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
); 
1288                                         CFNumberRef nRef 
= (CFNumberRef
) value
; 
1289                                         CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]); 
1296         return errSecSuccess
; 
1301 static OSStatus 
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE 
&keyUse
, uint32 
&attrs
, CFTypeRef 
&labelRef
, CFDataRef 
&applicationTagRef
) 
1303         // establish default values 
1305         bool isPermanent 
= false; 
1306         applicationTagRef 
= NULL
; 
1307         CFTypeRef effectiveKeySize 
= NULL
; 
1308         bool canDecrypt 
= isPublic 
? false : true; 
1309         bool canEncrypt 
= !canDecrypt
; 
1310         bool canDerive 
= true; 
1311         bool canSign 
= isPublic 
? false : true; 
1312         bool canVerify 
= !canSign
; 
1313         bool canUnwrap 
= isPublic 
? false : true; 
1314         attrs 
= CSSM_KEYATTR_EXTRACTABLE
; 
1317         void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
, 
1318                                                                  &canDerive
, &canSign
, &canVerify
, &canUnwrap
}; 
1320         // look for modifiers in the general dictionary 
1321         OSStatus result 
= ScanDictionaryForParameters(parameters
, attributePointers
); 
1322         if (result 
!= errSecSuccess
) 
1327         // see if we have anything which modifies the defaults 
1331                 key 
= kSecPublicKeyAttrs
; 
1335                 key 
= kSecPrivateKeyAttrs
; 
1338         CFTypeRef dType 
= CFDictionaryGetValue(parameters
, key
); 
1341                 // this had better be a dictionary 
1342                 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID()) 
1347                 // pull any additional parameters out of this dictionary 
1348                 result 
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
); 
1349                 if (result 
!= errSecSuccess
) 
1355         // figure out the key usage 
1359                 keyUse 
|= CSSM_KEYUSE_DECRYPT
; 
1364                 keyUse 
|= CSSM_KEYUSE_ENCRYPT
; 
1369                 keyUse 
|= CSSM_KEYUSE_DERIVE
; 
1374                 keyUse 
|= CSSM_KEYUSE_SIGN
; 
1379                 keyUse 
|= CSSM_KEYUSE_VERIFY
; 
1384                 keyUse 
|= CSSM_KEYUSE_UNWRAP
; 
1387         // public key is always extractable; 
1388         // private key is extractable by default unless explicitly set to false 
1389         CFTypeRef value 
= NULL
; 
1390         if (!isPublic 
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
) 
1392                 Boolean keyIsExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1393                 if (!keyIsExtractable
) 
1398         attrs 
|= CSSM_KEYATTR_PERMANENT
; 
1401         return errSecSuccess
; 
1406 static OSStatus 
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
, 
1407                                                                                                    CSSM_ALGORITHMS 
&algorithms
, 
1408                                                                                                    uint32 
&keySizeInBits
, 
1409                                                                                                    CSSM_KEYUSE 
&publicKeyUse
, 
1410                                                                                                    uint32 
&publicKeyAttr
, 
1411                                                                                                    CFTypeRef 
&publicKeyLabelRef
, 
1412                                                                                                    CFDataRef 
&publicKeyAttributeTagRef
, 
1413                                                                                                    CSSM_KEYUSE 
&privateKeyUse
, 
1414                                                                                                    uint32 
&privateKeyAttr
, 
1415                                                                                                    CFTypeRef 
&privateKeyLabelRef
, 
1416                                                                                                    CFDataRef 
&privateKeyAttributeTagRef
, 
1417                                                                                                    SecAccessRef 
&initialAccess
) 
1421         result 
= CheckAlgorithmType(parameters
, algorithms
); 
1422         if (result 
!= errSecSuccess
) 
1427         result 
= GetKeySize(parameters
, algorithms
, keySizeInBits
); 
1428         if (result 
!= errSecSuccess
) 
1433         result 
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1434         if (result 
!= errSecSuccess
) 
1439         result 
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1440         if (result 
!= errSecSuccess
) 
1445         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
)) 
1447                 initialAccess 
= NULL
; 
1449         else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
)) 
1454         return errSecSuccess
; 
1459 static OSStatus 
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
) 
1461         int numToModify 
= 0; 
1472         if (numToModify 
== 0) 
1474                 return errSecSuccess
; 
1477         SecKeychainAttributeList attrList
; 
1478         SecKeychainAttribute attributes
[numToModify
]; 
1485                 if (CFStringGetTypeID() == CFGetTypeID(label
)) { 
1486                         CFStringRef label_string 
= static_cast<CFStringRef
>(label
); 
1487                         attributes
[i
].tag 
= kSecKeyPrintName
; 
1488                         attributes
[i
].data 
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
); 
1489                         if (NULL 
== attributes
[i
].data
) { 
1490                                 CFIndex buffer_length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
); 
1491                                 data 
= attributes
[i
].data 
= malloc((size_t)buffer_length
); 
1492                                 if (NULL 
== attributes
[i
].data
) { 
1493                                         UnixError::throwMe(ENOMEM
); 
1495                                 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) { 
1497                                         MacOSError::throwMe(errSecParam
); 
1500                         attributes
[i
].length 
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
)); 
1501                 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) { 
1502                         // 10.6 bug compatibility 
1503                         CFDataRef label_data 
= static_cast<CFDataRef
>(label
); 
1504                         attributes
[i
].tag 
= kSecKeyLabel
; 
1505                         attributes
[i
].data 
= (void*) CFDataGetBytePtr(label_data
); 
1506                         attributes
[i
].length 
= (UInt32
)CFDataGetLength(label_data
); 
1508                         MacOSError::throwMe(errSecParam
); 
1515                 attributes
[i
].tag 
= kSecKeyApplicationTag
; 
1516                 attributes
[i
].data 
= (void*) CFDataGetBytePtr(tag
); 
1517                 attributes
[i
].length 
= (UInt32
)CFDataGetLength(tag
); 
1521         attrList
.count 
= numToModify
; 
1522         attrList
.attr 
= attributes
; 
1524         OSStatus result 
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
); 
1534 static CFTypeRef 
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) { 
1535     if (subParams 
!= NULL
) { 
1536         CFDictionaryRef subParamsDict 
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
); 
1537         if (subParamsDict 
!= NULL
) { 
1538             CFTypeRef value 
= CFDictionaryGetValue(subParamsDict
, attr
); 
1539             if (value 
!= NULL
) { 
1544     return CFDictionaryGetValue(parameters
, attr
); 
1547 extern "C" OSStatus 
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
); 
1550 /* Generate a private/public keypair. */ 
1552 SecKeyGeneratePairInternal( 
1553     bool alwaysPermanent
, 
1554         CFDictionaryRef parameters
, 
1555         SecKeyRef 
*publicKey
, 
1556         SecKeyRef 
*privateKey
) 
1560         Required(parameters
); 
1561     Required(publicKey
); 
1562     Required(privateKey
); 
1564     bool forceIOSKey 
= false; 
1565     if (_CFMZEnabled()) { 
1566         // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in. 
1569         CFTypeRef tokenID 
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
); 
1570         CFTypeRef noLegacy 
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
); 
1571         CFTypeRef sync 
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
); 
1572         CFTypeRef accessControl 
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?: 
1573         GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
); 
1574         CFTypeRef accessGroup 
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?: 
1575         GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
); 
1576         // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). 
1577         forceIOSKey 
= (tokenID 
!= NULL 
|| 
1578                        (noLegacy 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) || 
1579                        (sync 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)sync
)) || 
1580                        accessControl 
!= NULL 
|| (accessGroup 
!= NULL 
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))); 
1584         // Generate keys in iOS keychain. 
1585         return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
); 
1588         CSSM_ALGORITHMS algorithms
; 
1589         uint32 keySizeInBits
; 
1590         CSSM_KEYUSE publicKeyUse
; 
1591         uint32 publicKeyAttr
; 
1592         CFTypeRef publicKeyLabelRef
; 
1593         CFDataRef publicKeyAttributeTagRef
; 
1594         CSSM_KEYUSE privateKeyUse
; 
1595         uint32 privateKeyAttr
; 
1596         CFTypeRef privateKeyLabelRef
; 
1597         CFDataRef privateKeyAttributeTagRef
; 
1598         SecAccessRef initialAccess
; 
1599         SecKeychainRef keychain
; 
1601         OSStatus result 
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, 
1602                                                                                                                  publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
, 
1605         if (result 
!= errSecSuccess
) { 
1609         // verify keychain parameter 
1610     keychain 
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
); 
1611     if (keychain 
!= NULL 
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1615     if (alwaysPermanent
) { 
1616         publicKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1617         privateKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1620         // do the key generation 
1621         result 
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
); 
1622         if (result 
!= errSecSuccess
) { 
1626         // set the label and print attributes on the keys 
1627     SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1628     SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1635 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
) { 
1636     return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
); 
1640 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1641     SecKeyRef privateKey 
= NULL
, publicKey 
= NULL
; 
1642     OSStatus status 
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
); 
1643     SecError(status
, error
, CFSTR("failed to generate asymmetric keypair")); 
1644     if (publicKey 
!= NULL
) { 
1645         CFRelease(publicKey
); 
1650 OSStatus 
SecKeyRawVerifyOSX( 
1651     SecKeyRef           key
,            /* Public key */ 
1652         SecPadding          padding
,            /* kSecPaddingNone or kSecPaddingPKCS1 */ 
1653         const uint8_t       *signedData
,        /* signature over this data */ 
1654         size_t              signedDataLen
,      /* length of dataToSign */ 
1655         const uint8_t       *sig
,                       /* signature */ 
1658     return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
); 
1666 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
) 
1668                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1669         if (value 
!= NULL
) return value
; 
1670         return defaultValue
; 
1674 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
) 
1676         uint32_t integerValue
; 
1677                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1678         if (value 
!= NULL
) { 
1679             CFNumberRef nRef 
= (CFNumberRef
) value
; 
1680             CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
); 
1681             return integerValue
; 
1683         return defaultValue
; 
1687 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
) 
1689                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1690         if (value 
!= NULL
) { 
1691             CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1692             if(CFBooleanGetValue(bRef
)) return maskValue
; 
1698 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
*algorithm
, uint32 
*keySizeInBits
, CSSM_KEYUSE 
*keyUsage
, CSSM_KEYCLASS 
*keyClass
) 
1700     CFTypeRef algorithmDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
); 
1701     CFTypeRef keyClassDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
); 
1703     if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) { 
1704         *algorithm 
= CSSM_ALGID_AES
; 
1705         *keySizeInBits 
= 128; 
1706         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1707     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) { 
1708         *algorithm 
= CSSM_ALGID_DES
; 
1709         *keySizeInBits 
= 128; 
1710          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1711     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) { 
1712         *algorithm 
= CSSM_ALGID_3DES_3KEY_EDE
; 
1713         *keySizeInBits 
= 128; 
1714         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1715     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) { 
1716         *algorithm 
= CSSM_ALGID_RC4
; 
1717         *keySizeInBits 
= 128; 
1718         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1719     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) { 
1720         *algorithm 
= CSSM_ALGID_RC2
; 
1721         *keySizeInBits 
= 128; 
1722          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1723     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) { 
1724         *algorithm 
= CSSM_ALGID_CAST
; 
1725         *keySizeInBits 
= 128; 
1726          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1727     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) { 
1728         *algorithm 
= CSSM_ALGID_RSA
; 
1729         *keySizeInBits 
= 128; 
1730          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1731     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) { 
1732         *algorithm 
= CSSM_ALGID_DSA
; 
1733         *keySizeInBits 
= 128; 
1734          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1735     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) || 
1736             CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) { 
1737         *algorithm 
= CSSM_ALGID_ECDSA
; 
1738         *keySizeInBits 
= 128; 
1739         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1741         *algorithm 
= CSSM_ALGID_AES
; 
1742         *keySizeInBits 
= 128; 
1743         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1746     if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) { 
1747         *keyClass 
= CSSM_KEYCLASS_PUBLIC_KEY
; 
1748     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) { 
1749         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1750     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) { 
1751          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1754     *keySizeInBits 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
); 
1755     *keyUsage 
=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) | 
1756                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) | 
1757                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) | 
1758                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
); 
1761     if(*keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
|| *keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) { 
1762                 *keyUsage 
|=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) | 
1763                                         utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
); 
1766     if(*keyUsage 
== 0) { 
1767                 switch (*keyClass
) { 
1768                         case CSSM_KEYCLASS_PRIVATE_KEY
: 
1769                                 *keyUsage 
= CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN
; 
1771                         case CSSM_KEYCLASS_PUBLIC_KEY
: 
1772                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_VERIFY 
| CSSM_KEYUSE_WRAP
; 
1775                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_VERIFY
; 
1782 utilCopyDefaultKeyLabel(void) 
1784         // generate a default label from the current date 
1785         CFDateRef dateNow 
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent()); 
1786         CFStringRef defaultLabel 
= CFCopyDescription(dateNow
); 
1789         return defaultLabel
; 
1793 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef 
*error
) 
1795         OSStatus result 
= errSecParam
; // default result for an early exit 
1796         SecKeyRef key 
= NULL
; 
1797         SecKeychainRef keychain 
= NULL
; 
1798         SecAccessRef access
; 
1800         CFStringRef appLabel
; 
1802         CFStringRef dateLabel 
= NULL
; 
1804         CSSM_ALGORITHMS algorithm
; 
1805         uint32 keySizeInBits
; 
1806         CSSM_KEYUSE keyUsage
; 
1807         uint32 keyAttr 
= CSSM_KEYATTR_RETURN_DEFAULT
; 
1808         CSSM_KEYCLASS keyClass
; 
1810         Boolean isPermanent
; 
1811         Boolean isExtractable
; 
1813         // verify keychain parameter 
1814         if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
)) 
1816         else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1823         // verify permanent parameter 
1824         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
)) 
1825                 isPermanent 
= false; 
1826         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1829                 isPermanent 
= CFEqual(kCFBooleanTrue
, value
); 
1831                 if (keychain 
== NULL
) { 
1832                         // no keychain was specified, so use the default keychain 
1833                         result 
= SecKeychainCopyDefault(&keychain
); 
1835                 keyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1838         // verify extractable parameter 
1839         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
)) 
1840                 isExtractable 
= true; // default to extractable if value not specified 
1841         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1844                 isExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1846                 keyAttr 
|= CSSM_KEYATTR_EXTRACTABLE
; 
1848         // verify access parameter 
1849         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
)) 
1851         else if (SecAccessGetTypeID() != CFGetTypeID(access
)) 
1854         // verify label parameter 
1855         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
)) 
1856                 label 
= (dateLabel 
= utilCopyDefaultKeyLabel()); // no label provided, so use default 
1857         else if (CFStringGetTypeID() != CFGetTypeID(label
)) 
1860         // verify application label parameter 
1861         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
)) 
1862                 appLabel 
= (dateLabel
) ? dateLabel 
: (dateLabel 
= utilCopyDefaultKeyLabel()); 
1863         else if (CFStringGetTypeID() != CFGetTypeID(appLabel
)) 
1866         // verify application tag parameter 
1867         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
)) 
1869         else if (CFStringGetTypeID() != CFGetTypeID(appTag
)) 
1872     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1875                 // the generated key will not be stored in any keychain 
1876                 result 
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
); 
1879                 // we can set the label attributes on the generated key if it's a keychain item 
1880                 size_t labelBufLen 
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1; 
1881                 char *labelBuf 
= (char *)malloc(labelBufLen
); 
1882                 size_t appLabelBufLen 
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1; 
1883                 char *appLabelBuf 
= (char *)malloc(appLabelBufLen
); 
1884                 size_t appTagBufLen 
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1; 
1885                 char *appTagBuf 
= (char *)malloc(appTagBufLen
); 
1887                 if (!label 
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
)) 
1889                 if (!appLabel 
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
)) 
1891                 if (!appTag 
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
)) 
1894                 SecKeychainAttribute attrs
[] = { 
1895                         { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf 
}, 
1896                         { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf 
}, 
1897                         { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf 
} }; 
1898                 SecKeychainAttributeList attributes 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
1899                 if (!appTag
) --attributes
.count
; 
1901                 result 
= SecKeyGenerateWithAttributes(&attributes
, 
1902                         keychain
, algorithm
, keySizeInBits
, 0, 
1903                         keyUsage
, keyAttr
, access
, &key
); 
1911         if (result 
&& error
) { 
1912                 *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
); 
1915                 CFRelease(dateLabel
); 
1917                 CFRelease(keychain
); 
1925 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef 
*error
) 
1927         CSSM_ALGORITHMS         algorithm
; 
1928     uint32                              keySizeInBits
; 
1929     CSSM_KEYUSE                 keyUsage
; 
1930     CSSM_KEYCLASS               keyClass
; 
1933     if(keyData 
== NULL 
|| CFDataGetLength(keyData
) == 0){ 
1934         MacOSError::throwMe(errSecUnsupportedKeySize
); 
1937     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1939         CSSM_CSP_HANDLE cspHandle 
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL 
1941         SecKeyImportExportParameters iparam
; 
1942         memset(&iparam
, 0, sizeof(iparam
)); 
1943         iparam
.keyUsage 
= keyUsage
; 
1945     CFRef
<CFDataRef
> data
; 
1946         SecExternalItemType itype
; 
1948                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
1949                         itype 
= kSecItemTypePrivateKey
; 
1951         case CSSM_KEYCLASS_PUBLIC_KEY
: { 
1952                         itype 
= kSecItemTypePublicKey
; 
1953             // Public key import expects public key in SubjPublicKey X509 format.  We want to accept both bare and x509 format, 
1954             // so we have to detect bare format here and extend to full X509 if detected. 
1955             data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
)); 
1958                 case CSSM_KEYCLASS_SESSION_KEY
: 
1959                         itype 
= kSecItemTypeSessionKey
; 
1962                         itype 
= kSecItemTypeUnknown
; 
1966         CFMutableArrayRef ka 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
1967         // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. 
1968     crtn 
= impExpImportRawKey(data 
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
); 
1969         if (crtn 
== CSSM_OK 
&& CFArrayGetCount((CFArrayRef
)ka
)) { 
1970                 SecKeyRef sk 
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0); 
1977                         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn 
? crtn 
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
); 
1985 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
, 
1986                                                 SecKeyGeneratePairBlock result
) 
1988         CFDictionaryRef parameters 
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
); 
1989         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{ 
1990                 SecKeyRef publicKey 
= NULL
; 
1991                 SecKeyRef privateKey 
= NULL
; 
1992                 OSStatus status 
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
); 
1993                 dispatch_async(deliveryQueue
, ^{ 
1994                         CFErrorRef error 
= NULL
; 
1995                         if (errSecSuccess 
!= status
) { 
1996                                 error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
); 
1998                         result(publicKey
, privateKey
, error
); 
2003                                 CFRelease(publicKey
); 
2006                                 CFRelease(privateKey
); 
2008                         CFRelease(parameters
); 
2013 static inline void utilClearAndFree(void *p
, size_t len
) { 
2015         if(len
) bzero(p
, len
); 
2021 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2023     CCPBKDFAlgorithm algorithm
; 
2024     CFIndex passwordLen 
= 0; 
2025     CFDataRef keyData 
= NULL
; 
2026     char *thePassword 
= NULL
; 
2027     uint8_t *salt 
= NULL
; 
2028     uint8_t *derivedKey 
= NULL
; 
2029     size_t  saltLen 
= 0, derivedKeyLen 
= 0; 
2031     CFDataRef saltDictValue
, algorithmDictValue
; 
2032     SecKeyRef retval 
= NULL
; 
2034     /* Pick Values from parameters */ 
2036     if((saltDictValue 
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) { 
2038             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
); 
2043     derivedKeyLen 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128); 
2044         // This value come in bits but the rest of the code treats it as bytes 
2047     algorithmDictValue 
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
); 
2049     rounds 
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0); 
2051     /* Convert any remaining parameters and get the password bytes */ 
2053     saltLen 
= CFDataGetLength(saltDictValue
); 
2054     if((salt 
= (uint8_t *) malloc(saltLen
)) == NULL
) { 
2056             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2061     CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8 
*) salt
); 
2063     passwordLen 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1; 
2064     if((thePassword 
= (char *) malloc(passwordLen
)) == NULL
) { 
2066             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2070     CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
); 
2072     if((derivedKey 
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) { 
2074             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2079     if(algorithmDictValue 
== NULL
) { 
2080         algorithm 
= kCCPRFHmacAlgSHA1
; /* default */ 
2081     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) { 
2082         algorithm 
= kCCPRFHmacAlgSHA1
; 
2083     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) { 
2084         algorithm 
= kCCPRFHmacAlgSHA224
; 
2085     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) { 
2086         algorithm 
= kCCPRFHmacAlgSHA256
; 
2087     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) { 
2088         algorithm 
= kCCPRFHmacAlgSHA384
; 
2089     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) { 
2090         algorithm 
= kCCPRFHmacAlgSHA512
; 
2093             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
); 
2099         rounds 
= 33333; // we need to pass back a consistent value since there's no way to record the round count. 
2102     if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) { 
2104             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2109     if((keyData 
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) { 
2110         retval 
=  SecKeyCreateFromData(parameters
, keyData
, error
); 
2114             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2119     utilClearAndFree(salt
, saltLen
); 
2120     utilClearAndFree(thePassword
, passwordLen
); 
2121     utilClearAndFree(derivedKey
, derivedKeyLen
); 
2126 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2129         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
); 
2135 SecKeyUnwrapSymmetric(CFDataRef 
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2138         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);