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@ 
  24 #include <Security/SecKey.h> 
  25 #include <Security/SecKeyPriv.h> 
  26 #include <Security/SecKeyInternal.h> 
  27 #include <Security/SecItem.h> 
  28 #include <Security/SecItemPriv.h> 
  29 #include <libDER/asn1Types.h> 
  30 #include <libDER/DER_Encode.h> 
  31 #include <libDER/DER_Decode.h> 
  32 #include <libDER/DER_Keys.h> 
  33 #include <Security/SecAsn1Types.h> 
  34 #include <Security/SecAsn1Coder.h> 
  35 #include <security_keychain/KeyItem.h> 
  36 #include <security_utilities/casts.h> 
  37 #include <CommonCrypto/CommonKeyDerivation.h> 
  39 #include <CoreFoundation/CFPriv.h> 
  40 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it. 
  43 #include "SecBridge.h" 
  45 #include <security_keychain/Access.h> 
  46 #include <security_keychain/Keychains.h> 
  47 #include <security_keychain/KeyItem.h> 
  51 #include <security_cdsa_utils/cuCdsaUtils.h> 
  52 #include <security_cdsa_client/wrapkey.h> 
  53 #include <security_cdsa_client/genkey.h> 
  54 #include <security_cdsa_client/signclient.h> 
  55 #include <security_cdsa_client/cryptoclient.h> 
  57 #include "SecImportExportCrypto.h" 
  60 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) { 
  61     CDSASecKey 
*cdsaKey 
= (CDSASecKey 
*)key
; 
  62     cdsaKey
->key 
= const_cast<KeyItem 
*>(reinterpret_cast<const KeyItem 
*>(keyData
)); 
  63     CDSASecKey::keyItem(key
)->initializeWithSecKeyRef(key
); 
  64     cdsaKey
->credentialType 
= kSecCredentialTypeDefault
; 
  65     cdsaKey
->cdsaKeyMutex 
= new Mutex(); 
  70 SecCDSAKeyDestroy(SecKeyRef keyRef
) { 
  71     // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation. 
  72     // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. 
  73     // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. 
  75     CDSASecKey 
*cdsaKey 
= static_cast<CDSASecKey 
*>(keyRef
); 
  76     StMaybeLock
<Mutex
> cdsaMutex(cdsaKey
->cdsaKeyMutex
); 
  78     KeyItem 
*keyItem 
= static_cast<KeyItem 
*>(keyRef
->key
); 
  80     if (keyItem 
== NULL
) { 
  81         // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. 
  83         delete cdsaKey
->cdsaKeyMutex
; 
  87     Keychain kc 
= keyItem
->keychain(); 
  89     // We have a +1 reference to the KeyItem now; no need to protect our storage any more 
  93         StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject()); 
  94         keyItem 
= static_cast<KeyItem 
*>(keyRef
->key
); 
  95         if (keyItem 
== NULL
) { 
  96             // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance. 
 100         keyItem
->aboutToDestruct(); 
 104     delete cdsaKey
->cdsaKeyMutex
; 
 106     (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. 
 110 SecCDSAKeyGetBlockSize(SecKeyRef key
) { 
 112     CFErrorRef 
*error 
= NULL
; 
 113     BEGIN_SECKEYAPI(size_t,0) 
 115     const CssmKey::Header keyHeader 
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader(); 
 116     switch(keyHeader
.algorithm()) 
 120             result 
= keyHeader
.LogicalKeySizeInBits 
/ 8; 
 122         case CSSM_ALGID_ECDSA
: 
 124             /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, 
 125              * plus both coordinates for the point used */ 
 126 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) 
 127 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) 
 128             size_t coordSize 
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
); 
 129             assert(coordSize 
< 256); /* size must fit in a byte for DER */ 
 130             size_t coordDERLen 
= (coordSize 
> 127) ? 2 : 1; 
 131             size_t coordLen 
= 1 + coordDERLen 
+ coordSize
; 
 133             size_t pointSize 
= 2 * coordLen
; 
 134             assert(pointSize 
< 256); /* size must fit in a byte for DER */ 
 135             size_t pointDERLen 
= (pointSize 
> 127) ? 2 : 1; 
 136             size_t pointLen 
= 1 + pointDERLen 
+ pointSize
; 
 142             result 
= 16; /* all AES keys use 128-bit blocks */ 
 145         case CSSM_ALGID_3DES_3KEY
: 
 146             result 
= 8; /* all DES keys use 64-bit blocks */ 
 149             assert(0); /* some other key algorithm */ 
 150             result 
= 16; /* FIXME: revisit this */ 
 158 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) { 
 160     CFErrorRef 
*error 
= NULL
; 
 161     BEGIN_SECKEYAPI(CFIndex
, 0) 
 163     result 
= kSecNullAlgorithmID
; 
 164     switch (CDSASecKey::keyItem(key
)->unverifiedKeyHeader().AlgorithmId
) { 
 166             result 
= kSecRSAAlgorithmID
; 
 169             result 
= kSecDSAAlgorithmID
; 
 171         case CSSM_ALGID_ECDSA
: 
 172             result 
= kSecECDSAAlgorithmID
; 
 175             assert(0); /* other algorithms TBA */ 
 181 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) { 
 182     // First of all, consider x509 format and try to strip SubjPubKey envelope.  If it fails, do not panic 
 183     // and export data as is. 
 184     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
; 
 186     DERSubjPubKeyInfo subjPubKey
; 
 187     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 188                          DERSubjPubKeyInfoItemSpecs
, 
 189                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success 
&& 
 190         DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 191         return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
); 
 194     return CFDataRef(CFRetain(pubKeyInfo
)); 
 197 static CFDataRef 
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) { 
 198     // First check, whether X509 pubkeyinfo is already present.  If not, add it according to the key type. 
 199     DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }; 
 200     DERSubjPubKeyInfo subjPubKey
; 
 201     if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
, 
 202                          DERSubjPubKeyInfoItemSpecs
, 
 203                          &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) { 
 204         return CFDataRef(CFRetain(pubKeyInfo
)); 
 207     // We have always size rounded to full bytes so bitstring encodes leading 00. 
 208     CFRef
<CFMutableDataRef
> bitStringPubKey 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 209     CFDataSetLength(bitStringPubKey
, 1); 
 210     CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
)); 
 211     subjPubKey
.pubKey
.data 
= static_cast<DERByte 
*>(const_cast<UInt8 
*>(CFDataGetBytePtr(bitStringPubKey
))); 
 212     subjPubKey
.pubKey
.length 
= CFDataGetLength(bitStringPubKey
); 
 214     // Encode algId according to algorithm used. 
 215     static const DERByte oidRSA
[] = { 
 216         0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 
 218     static const DERByte oidECsecp256
[] = { 
 219         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 
 221     static const DERByte oidECsecp384
[] = { 
 222         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 
 224     static const DERByte oidECsecp521
[] = { 
 225         0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 
 227     subjPubKey
.algId
.length 
= 0; 
 228     if (algorithm 
== CSSM_ALGID_RSA
) { 
 229         subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidRSA
); 
 230         subjPubKey
.algId
.length 
= sizeof(oidRSA
); 
 231     } else if (algorithm 
== CSSM_ALGID_ECDSA
) { 
 232         if (keySizeInBits 
== 256) { 
 233             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp256
); 
 234             subjPubKey
.algId
.length 
= sizeof(oidECsecp256
); 
 235         } else if (keySizeInBits 
== 384) { 
 236             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp384
); 
 237             subjPubKey
.algId
.length 
= sizeof(oidECsecp384
); 
 238         } if (keySizeInBits 
== 521) { 
 239             subjPubKey
.algId
.data 
= const_cast<DERByte 
*>(oidECsecp521
); 
 240             subjPubKey
.algId
.length 
= sizeof(oidECsecp521
); 
 243     DERSize size 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 244                                               DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
); 
 245     CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 246     CFDataSetLength(keyData
, size
); 
 247     if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
, 
 248                           DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
, 
 249                           static_cast<DERByte 
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) { 
 250         CFDataSetLength(keyData
, size
); 
 255     return keyData
.yield(); 
 258 static OSStatus 
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef 
*serialization
) { 
 260     CFErrorRef 
*error 
= NULL
; 
 261     BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
) 
 263     const CssmKey::Header 
&header 
= CDSASecKey::keyItem(key
)->key().header(); 
 264     switch (header
.algorithm()) { 
 265         case CSSM_ALGID_RSA
: { 
 266             switch (header
.keyClass()) { 
 267                 case CSSM_KEYCLASS_PRIVATE_KEY
: { 
 268                     CFRef
<CFDataRef
> privKeyData
; 
 269                     result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take()); 
 270                     if (result 
== errSecSuccess
) { 
 271                         DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) }; 
 272                         DERRSAKeyPair keyPair
; 
 273                         if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
, 
 274                                              &keyPair
, sizeof(keyPair
)) == DR_Success
) { 
 275                             DERRSAPubKeyPKCS1 pubKey 
= { keyPair
.n
, keyPair
.e 
}; 
 276                             DERSize size 
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
, 
 277                                                                       DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
); 
 278                             CFRef
<CFMutableDataRef
> keyData 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 279                             CFDataSetLength(keyData
, size
); 
 280                             UInt8 
*data 
= CFDataGetMutableBytePtr(keyData
); 
 281                             if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
, 
 282                                                   DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
, 
 283                                                   data
, &size
) == DR_Success
) { 
 284                                 CFDataSetLength(keyData
, size
); 
 285                                 *data 
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
; 
 286                                 *serialization 
= keyData
.yield(); 
 288                                 *serialization 
= NULL
; 
 289                                 result 
= errSecParam
; 
 295                 case CSSM_KEYCLASS_PUBLIC_KEY
: 
 296                     result 
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
); 
 301         case CSSM_ALGID_ECDSA
: { 
 302             *serialization 
= NULL
; 
 303             CFRef
<CFDataRef
> tempPublicData
; 
 304             result 
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take()); 
 305             if (result 
== errSecSuccess
) { 
 306                 *serialization 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
); 
 311             result 
= errSecUnimplemented
; 
 322 static const DERItemSpec DERECPrivateKeyItemSpecs
[] = 
 327     { DER_OFFSET(DERECPrivateKey
, privateKey
), 
 329         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 331         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0, 
 332         DER_DEC_SKIP 
| DER_ENC_NO_OPTS 
}, 
 333     { DER_OFFSET(DERECPrivateKey
, publicKey
), 
 334         ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 1, 
 335         DER_DEC_NO_OPTS 
| DER_ENC_SIGNED_INT 
}, 
 337 static const DERSize DERNumECPrivateKeyItemSpecs 
= 
 338 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
); 
 342 } DERECPrivateKeyPublicKey
; 
 344 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] = 
 346     { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
), 
 348         DER_DEC_NO_OPTS 
| DER_ENC_NO_OPTS 
}, 
 350 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs 
= 
 351 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
); 
 354 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef 
*error
) { 
 356     BEGIN_SECKEYAPI(CFDataRef
, NULL
) 
 359     const CssmKey::Header header 
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader(); 
 360     CFRef
<CFDataRef
> keyData
; 
 361     switch (header
.algorithm()) { 
 363             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 365         case CSSM_ALGID_ECDSA
: { 
 366             MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take())); 
 367             if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) { 
 368                 // Convert DER format into x9.63 format, which is expected for exported key. 
 369                 DERItem keyItem 
= { (DERByte 
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) }; 
 370                 DERECPrivateKey privateKey
; 
 371                 DERECPrivateKeyPublicKey privateKeyPublicKey
; 
 374                 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
, 
 375                                      &privateKey
, sizeof(privateKey
)) == DR_Success 
&& 
 376                     DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
, 
 377                                             DERECPrivateKeyPublicKeyItemSpecs
, 
 378                                             &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success 
&& 
 379                     DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) { 
 380                     CFRef
<CFMutableDataRef
> key 
= CFDataCreateMutable(kCFAllocatorDefault
, 
 381                                                                       pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 382                     CFDataSetLength(key
, pubKeyItem
.length 
+ privateKey
.privateKey
.length
); 
 383                     CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
); 
 384                     CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
), 
 385                                        privateKey
.privateKey
.data
, privateKey
.privateKey
.length
); 
 386                     keyData 
= key
.as
<CFDataRef
>(); 
 392             MacOSError::throwMe(errSecUnimplemented
); 
 395     if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) { 
 396         result 
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
); 
 398         result 
= keyData
.yield(); 
 404 static CFDataRef 
SecCDSAKeyCopyLabel(SecKeyRef key
) { 
 405     CFDataRef label 
= NULL
; 
 406     if (CDSASecKey::keyItem(key
)->isPersistent()) { 
 407         UInt32 tags
[] = { kSecKeyLabel 
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB 
}; 
 408         SecKeychainAttributeInfo info 
= { 1, tags
, formats 
}; 
 409         SecKeychainAttributeList 
*list 
= NULL
; 
 410         CDSASecKey::keyItem(key
)->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
); 
 411         if (list
->count 
== 1) { 
 412             SecKeychainAttribute 
*attr 
= list
->attr
; 
 413             label 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)attr
->data
, (CFIndex
)attr
->length
); 
 415         CDSASecKey::keyItem(key
)->freeAttributesAndData(list
, NULL
); 
 420 static CFDictionaryRef
 
 421 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) { 
 423     CFErrorRef 
*error 
= NULL
; 
 424     BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
) 
 426     CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, 
 427                                                             &kCFTypeDictionaryValueCallBacks
); 
 429     CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
); 
 431     const CssmKey::Header header 
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader(); 
 432     CFIndex sizeValue 
= header
.LogicalKeySizeInBits
; 
 433     CFRef
<CFNumberRef
> sizeInBits 
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
); 
 434     CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
); 
 435     CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
); 
 437     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(key
); 
 439         // For floating keys, calculate label as SHA1 of pubkey bytes. 
 440         CFRef
<CFDataRef
> pubKeyBlob
; 
 441         if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) { 
 442             uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
]; 
 443             CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
); 
 444             label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
))); 
 449         CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
); 
 452     CSSM_KEYATTR_FLAGS attrs 
= header
.attributes(); 
 453     CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs 
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 454     CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs 
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 455     CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs 
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 456     CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs 
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 457     CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs 
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 458     CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs 
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 459     CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs 
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 461     CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 462     CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 463     CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 464     CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 465     CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 466     CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 467     CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 468     CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 469     CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue 
: kCFBooleanFalse
); 
 471     switch (header
.keyClass()) { 
 472         case CSSM_KEYCLASS_PUBLIC_KEY
: 
 473             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
); 
 475         case CSSM_KEYCLASS_PRIVATE_KEY
: 
 476             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
); 
 480     switch (header
.algorithm()) { 
 482             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
); 
 484         case CSSM_ALGID_ECDSA
: 
 485             CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
); 
 489     CFRef
<CFDataRef
> keyData
; 
 490     if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) { 
 491         CFDictionarySetValue(dict
, kSecValueData
, keyData
); 
 494     if (header
.algorithm() == CSSM_ALGID_RSA 
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY 
&& 
 495         header
.blobType() == CSSM_KEYBLOB_RAW
) { 
 496         const CssmData 
&keyData 
= CDSASecKey::keyItem(key
)->key()->keyData(); 
 497         DERItem keyItem 
= { static_cast<DERByte 
*>(keyData
.data()), keyData
.length() }; 
 498         DERRSAPubKeyPKCS1 decodedKey
; 
 499         if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
, 
 500                              DERRSAPubKeyPKCS1ItemSpecs
, 
 501                              &decodedKey
, sizeof(decodedKey
)) == DR_Success
) { 
 502             CFRef
<CFDataRef
> modulus 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, 
 503                                                     decodedKey
.modulus
.length
); 
 504             CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
); 
 505             CFRef
<CFDataRef
> exponent 
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, 
 506                                                      decodedKey
.pubExponent
.length
); 
 507             CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
); 
 516 #pragma clang diagnostic push 
 517 #pragma clang diagnostic ignored "-Wunused-const-variable" 
 518 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
); 
 519 #pragma clang diagnostic pop 
 521 static SecKeyRef 
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) { 
 522     CFErrorRef 
*error 
= NULL
; 
 523     BEGIN_SECKEYAPI(SecKeyRef
, NULL
) 
 526     KeyItem 
*key 
= CDSASecKey::keyItem(privateKey
); 
 527     CFRef
<CFDataRef
> label 
= SecCDSAKeyCopyLabel(privateKey
); 
 529         // Lookup public key in the database. 
 530         DbUniqueRecord uniqueId
; 
 531         SSDb 
ssDb(dynamic_cast<SSDbImpl 
*>(&(*key
->keychain()->database()))); 
 532         SSDbCursor 
dbCursor(ssDb
, 1); 
 533         dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 534         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
))); 
 535         if (dbCursor
->next(NULL
, NULL
, uniqueId
)) { 
 536             Item publicKey 
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
); 
 537             result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 541     if (result 
== NULL 
&& key
->publicKey()) { 
 542         SecPointer
<KeyItem
> publicKey(new KeyItem(key
->publicKey())); 
 543         result 
= reinterpret_cast<SecKeyRef
>(publicKey
->handle()); 
 549 static KeyItem 
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType 
&operation
, SecKeyAlgorithm algorithm
, 
 550                                             CSSM_ALGORITHMS 
&baseAlgorithm
, CSSM_ALGORITHMS 
&secondaryAlgorithm
, 
 551                                             CSSM_ALGORITHMS 
&paddingAlgorithm
, CFIndex 
&inputSizeLimit
) { 
 552     KeyItem 
*keyItem 
= CDSASecKey::keyItem(key
); 
 553     CSSM_KEYCLASS keyClass 
= keyItem
->key()->header().keyClass(); 
 554     baseAlgorithm 
= keyItem
->key()->header().algorithm(); 
 555     switch (baseAlgorithm
) { 
 557             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 558                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 559                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) { 
 560                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 561                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 563                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) { 
 564                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 565                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 566                     inputSizeLimit 
= -11; 
 567                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) { 
 568                     secondaryAlgorithm 
= CSSM_ALGID_SHA1
; 
 569                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 571                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) { 
 572                     secondaryAlgorithm 
= CSSM_ALGID_SHA224
; 
 573                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 574                     inputSizeLimit 
= 224 / 8; 
 575                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) { 
 576                     secondaryAlgorithm 
= CSSM_ALGID_SHA256
; 
 577                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 578                     inputSizeLimit 
= 256 / 8; 
 579                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) { 
 580                     secondaryAlgorithm 
= CSSM_ALGID_SHA384
; 
 581                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 582                     inputSizeLimit 
= 384 / 8; 
 583                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) { 
 584                     secondaryAlgorithm 
= CSSM_ALGID_SHA512
; 
 585                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 586                     inputSizeLimit 
= 512 / 8; 
 587                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) { 
 588                     secondaryAlgorithm 
= CSSM_ALGID_MD5
; 
 589                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 594             } else if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt
) || 
 595                        (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeEncrypt
)) { 
 596                 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 597                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 598                     paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 600                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) { 
 601                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 602                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 603                     inputSizeLimit 
= operation 
== kSecKeyOperationTypeEncrypt 
? -11 : 0; 
 607             } else if (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeDecrypt 
&& 
 608                        CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) { 
 609                 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, 
 610                 // because CDSA keys refuses to perform decrypt using public key. 
 611                 operation 
= kSecKeyOperationTypeEncrypt
; 
 612                 secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 613                 paddingAlgorithm 
= CSSM_PADDING_NONE
; 
 619         case CSSM_ALGID_ECDSA
: 
 620             if ((keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeSign
) || 
 621                 (keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY 
&& operation 
== kSecKeyOperationTypeVerify
)) { 
 622                 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) { 
 623                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 624                     paddingAlgorithm 
= CSSM_PADDING_SIGRAW
; 
 625                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) { 
 626                     secondaryAlgorithm 
= CSSM_ALGID_NONE
; 
 627                     paddingAlgorithm 
= CSSM_PADDING_PKCS1
; 
 631             } else if (keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
&& operation 
== kSecKeyOperationTypeKeyExchange
) { 
 632                 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) || 
 633                     CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) { 
 634                     baseAlgorithm 
= CSSM_ALGID_ECDH
; 
 635                 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) || 
 636                            CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) { 
 637                     baseAlgorithm 
= CSSM_ALGID_ECDH_X963_KDF
; 
 646             MacOSError::throwMe(errSecParam
); 
 652 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) { 
 653     CFIndex blockSize 
= CDSASecKey::keyItem(key
)->key().header().LogicalKeySizeInBits 
/ 8; 
 654     CFIndex plaintextLength 
= CFDataGetLength(plaintext
); 
 655     if ((algorithm 
== kSecKeyAlgorithmRSAEncryptionRaw 
|| algorithm 
== kSecKeyAlgorithmRSASignatureRaw
) 
 656         && plaintextLength 
< blockSize
) { 
 657         // Pre-pad with zeroes. 
 658         CFMutableDataRef 
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
)); 
 659         CFDataSetLength(result
, blockSize
); 
 660         CFDataReplaceBytes(result
, CFRangeMake(blockSize 
- plaintextLength
, plaintextLength
), 
 661                            CFDataGetBytePtr(plaintext
), plaintextLength
); 
 664         return CFDataRef(CFRetain(plaintext
)); 
 668 static CFTypeRef 
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
, 
 669                                                CFArrayRef allAlgorithms
, SecKeyOperationMode mode
, 
 670                                                CFTypeRef in1
, CFTypeRef in2
, CFErrorRef 
*error
) { 
 671     BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
) 
 672     CFIndex inputSizeLimit 
= 0; 
 673     CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
; 
 674     KeyItem 
*keyItem 
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
); 
 675     if (keyItem 
== NULL
) { 
 676         // Operation/algorithm/key combination is not supported. 
 678     } else if (mode 
== kSecKeyOperationModeCheckIfSupported
) { 
 679         // Operation is supported and caller wants to just know that. 
 680         return kCFBooleanTrue
; 
 681     } else if (baseAlgorithm 
== CSSM_ALGID_RSA
) { 
 682         if (inputSizeLimit 
<= 0) { 
 683             inputSizeLimit 
+= SecCDSAKeyGetBlockSize(key
); 
 685         if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) { 
 686             MacOSError::throwMe(errSecParam
); 
 690     CDSASecKey 
*cdsaKey 
= static_cast<CDSASecKey 
*>(key
); 
 692         case kSecKeyOperationTypeSign
: { 
 693             CssmClient::Sign 
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 694             signContext
.key(keyItem
->key()); 
 695             signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, cdsaKey
->credentialType
)); 
 696             signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 697             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 698             CssmAutoData 
signature(signContext
.allocator()); 
 699             signContext
.sign(CssmData(CFDataRef(input
)), signature
.get()); 
 700             result 
= CFDataCreate(NULL
, static_cast<const UInt8 
*>(signature
.data()), CFIndex(signature
.length())); 
 703         case kSecKeyOperationTypeVerify
: { 
 704             CssmClient::Verify 
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
); 
 705             verifyContext
.key(keyItem
->key()); 
 706             verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, cdsaKey
->credentialType
)); 
 707             verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
); 
 708             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 709             verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
))); 
 710             result 
= kCFBooleanTrue
; 
 713         case kSecKeyOperationTypeEncrypt
: { 
 714             CssmClient::Encrypt 
encryptContext(keyItem
->csp(), baseAlgorithm
); 
 715             encryptContext
.key(keyItem
->key()); 
 716             encryptContext
.padding(paddingAlgorithm
); 
 717             encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, cdsaKey
->credentialType
)); 
 718             CFRef
<CFDataRef
> input 
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
); 
 719             CssmAutoData 
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator()); 
 720             size_t length 
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get()); 
 721             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 722             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 723             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 724             CFDataSetLength(CFMutableDataRef(result
), length
); 
 727         case kSecKeyOperationTypeDecrypt
: { 
 728             CssmClient::Decrypt 
decryptContext(keyItem
->csp(), baseAlgorithm
); 
 729             decryptContext
.key(keyItem
->key()); 
 730             decryptContext
.padding(paddingAlgorithm
); 
 731             decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, cdsaKey
->credentialType
)); 
 732             CssmAutoData 
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator()); 
 733             size_t length 
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)), 
 734                                                    output
.get(), remainingData
.get()); 
 735             result 
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length()); 
 736             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(output
.data()), output
.length()); 
 737             CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8 
*>(remainingData
.data()), remainingData
.length()); 
 738             CFDataSetLength(CFMutableDataRef(result
), length
); 
 741         case kSecKeyOperationTypeKeyExchange
: { 
 742             CFIndex requestedLength 
= 0; 
 744             switch (baseAlgorithm
) { 
 745                 case CSSM_ALGID_ECDH
: 
 746                     requestedLength 
= (keyItem
->key().header().LogicalKeySizeInBits 
+ 7) / 8; 
 748                 case CSSM_ALGID_ECDH_X963_KDF
: 
 749                     CFDictionaryRef params 
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
); 
 750                     CFTypeRef value 
= params 
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
; 
 751                     if (value 
== NULL 
|| CFGetTypeID(value
) != CFNumberGetTypeID() || 
 752                         !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) { 
 753                         MacOSError::throwMe(errSecParam
); 
 755                     value 
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
); 
 756                     if (value 
!= NULL 
&& CFGetTypeID(value
) == CFDataGetTypeID()) { 
 757                         sharedInfo 
= CssmData(CFDataRef(value
)); 
 762             CssmClient::DeriveKey 
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength 
* 8)); 
 763             derive
.key(keyItem
->key()); 
 764             derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
)); 
 765             derive
.salt(sharedInfo
); 
 766             CssmData 
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
)); 
 767             Key derivedKey 
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 769             // Export raw data of newly derived key (by wrapping with an empty key). 
 770             CssmClient::WrapKey 
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
); 
 771             Key wrappedKey 
= wrapper(derivedKey
); 
 772             result 
= CFDataCreate(kCFAllocatorDefault
, (const UInt8 
*)wrappedKey
->data(), CFIndex(wrappedKey
->length())); 
 782 static Boolean 
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) { 
 783     CFErrorRef 
*error 
= NULL
; 
 784     BEGIN_SECKEYAPI(Boolean
, false) 
 786     result 
= CDSASecKey::keyItem(key1
)->equal(*CDSASecKey::keyItem(key2
)); 
 791 static Boolean 
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef 
*error
) { 
 792     BEGIN_SECKEYAPI(Boolean
, false) 
 794     if (CFEqual(name
, kSecUseAuthenticationUI
)) { 
 795         static_cast<CDSASecKey 
*>(key
)->credentialType 
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault 
: kSecCredentialTypeNoUI
; 
 798         result 
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
); 
 804 const SecKeyDescriptor kSecCDSAKeyDescriptor 
= { 
 805     .version 
= kSecKeyDescriptorVersion
, 
 808     .init 
= SecCDSAKeyInit
, 
 809     .destroy 
= SecCDSAKeyDestroy
, 
 810     .blockSize 
= SecCDSAKeyGetBlockSize
, 
 811     .getAlgorithmID 
= SecCDSAKeyGetAlgorithmId
, 
 812     .copyDictionary 
= SecCDSAKeyCopyAttributeDictionary
, 
 813     .copyPublic 
= SecCDSAKeyCopyPublicBytes
, 
 814     .copyExternalRepresentation 
= SecCDSAKeyCopyExternalRepresentation
, 
 815     .copyPublicKey 
= SecCDSAKeyCopyPublicKey
, 
 816     .copyOperationResult 
= SecCDSAKeyCopyOperationResult
, 
 817     .isEqual 
= SecCDSAKeyIsEqual
, 
 818     .setParameter 
= SecCDSAKeySetParameter
, 
 820     .extraBytes 
= (sizeof(class CDSASecKey
) > sizeof(struct __SecKey
) ? (sizeof(class CDSASecKey
) - sizeof(struct __SecKey
)) : 0), 
 824     namespace KeychainCore 
{ 
 825         SecCFObject 
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) { 
 826             if (ptr 
== NULL 
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) { 
 830             SecKeyRef key 
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
)); 
 831             if (key
->key_class 
== &kSecCDSAKeyDescriptor
) { 
 832                 return static_cast<SecCFObject 
*>(key
->key
); 
 835             CFRef
<SecKeyRef
> cdsaKey 
= SecKeyCopyAuxilliaryCDSAKeyForKey(key
); 
 837                 // Create CDSA key from exported data of existing key. 
 838                 CFRef
<CFDictionaryRef
> keyAttributes 
= SecKeyCopyAttributes(key
); 
 840                     CFRef
<CFDataRef
> keyData 
= SecKeyCopyExternalRepresentation(key
, NULL
); 
 842                         CFTypeRef pubKeyHash 
= CFDictionaryGetValue(keyAttributes
, kSecAttrApplicationLabel
); 
 843                         const void *keys
[] = { kSecClass
, kSecUseDataProtectionKeychain
, kSecReturnRef
, kSecMatchLimit 
}; 
 844                         const void *values
[] = { kSecClassIdentity
, kCFBooleanFalse
, kCFBooleanTrue
, kSecMatchLimitAll 
}; 
 845                         CFRef
<CFDictionaryRef
> query 
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, 
 846                                                                           sizeof(keys
) / sizeof(*keys
), 
 847                                                                           &kCFTypeDictionaryKeyCallBacks
, 
 848                                                                           &kCFTypeDictionaryValueCallBacks
); 
 849                         CFRef
<CFArrayRef
> identities
; 
 850                         OSStatus status 
= SecItemCopyMatching(query
, (CFTypeRef 
*)identities
.take()); 
 851                         if (status 
== errSecSuccess
) { 
 852                             for (int i 
= 0; i 
< CFArrayGetCount(identities
); ++i
) { 
 853                                 CFRef
<SecKeyRef
> privateKey
; 
 854                                 if (SecIdentityCopyPrivateKey((SecIdentityRef
)CFArrayGetValueAtIndex(identities
, i
), privateKey
.take()) != errSecSuccess
) { 
 857                                 CFRef
<CFDictionaryRef
> attrs 
= SecKeyCopyAttributes(privateKey
); 
 858                                 if (CFEqual(CFDictionaryGetValue(attrs
, kSecAttrApplicationLabel
), pubKeyHash
)) { 
 859                                     cdsaKey 
= privateKey
; 
 860                                     SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.get()); 
 866                         cdsaKey 
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
); 
 868                             SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.retain()); 
 874             return cdsaKey 
? CDSASecKey::keyItem(cdsaKey
.get()) : NULL
; 
 877         // You need to hold this key's MutexForObject when you run this 
 878         void KeyItem::attachSecKeyRef() const { 
 879             SecKeyRef key 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0); 
 880             CDSASecKey::keyItem(key
)->mWeakSecKeyRef 
= key
; 
 886 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
 887 Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
) { 
 888     return ref
->key_class 
== &kSecCDSAKeyDescriptor
; 
 892 static OSStatus 
SecKeyCreatePairInternal( 
 893         SecKeychainRef keychainRef
, 
 894         CSSM_ALGORITHMS algorithm
, 
 895         uint32 keySizeInBits
, 
 896         CSSM_CC_HANDLE contextHandle
, 
 897         CSSM_KEYUSE publicKeyUsage
, 
 898         uint32 publicKeyAttr
, 
 899         CSSM_KEYUSE privateKeyUsage
, 
 900         uint32 privateKeyAttr
, 
 901         SecAccessRef initialAccess
, 
 902         SecKeyRef
* publicKeyRef
, 
 903         SecKeyRef
* privateKeyRef
) 
 908     SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
 909     SecPointer
<KeyItem
> pubItem
, privItem
; 
 910     if (((publicKeyAttr 
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) { 
 911         keychain 
= Keychain::optional(keychainRef
); 
 913     StMaybeLock
<Mutex
> _(keychain 
? keychain
->getKeychainMutex() : NULL
); 
 914     KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
, 
 915                         privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
); 
 917         // Return the generated keys. 
 919                 *publicKeyRef 
= pubItem
->handle(); 
 921                 *privateKeyRef 
= privItem
->handle(); 
 928         SecKeychainRef keychainRef
, 
 929         CSSM_ALGORITHMS algorithm
, 
 930         uint32 keySizeInBits
, 
 931         CSSM_CC_HANDLE contextHandle
, 
 932         CSSM_KEYUSE publicKeyUsage
, 
 933         uint32 publicKeyAttr
, 
 934         CSSM_KEYUSE privateKeyUsage
, 
 935         uint32 privateKeyAttr
, 
 936         SecAccessRef initialAccess
, 
 937         SecKeyRef
* publicKeyRef
, 
 938         SecKeyRef
* privateKeyRef
) 
 940     OSStatus result 
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, 
 941                                                publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
); 
 949 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY 
**cssmKey
) 
 953         Required(cssmKey
) = KeyItem::required(key
)->key(); 
 963 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
; 
 964 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
; 
 967 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE 
*cspHandle
) 
 971         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 973     // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). 
 974     // Keep a global pointer to it to force the CSP to stay live forever. 
 975     CssmClient::CSP returnedKeyCSP 
= keyItem
->csp(); 
 977         StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex()); 
 978         gSecReturnedKeyCSPs().insert(returnedKeyCSP
); 
 980         Required(cspHandle
) = returnedKeyCSP
->handle(); 
 985 /* deprecated as of 10.8 */ 
 987 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
**algid
) 
 991         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
 992         Required(algid
) = &keyItem
->algorithmIdentifier(); 
 998 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER 
*algid
, unsigned int *strength
) 
1002         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
1003         Required(strength
) = keyItem
->strengthInBits(algid
); 
1009 SecKeyGetCredentials( 
1011         CSSM_ACL_AUTHORIZATION_TAG operation
, 
1012         SecCredentialType credentialType
, 
1013         const CSSM_ACCESS_CREDENTIALS 
**outCredentials
) 
1017         SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
)); 
1018         Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
); 
1025         SecKeychainRef keychainRef
, 
1026         const CSSM_KEY 
*publicCssmKey
, 
1027         const CSSM_KEY 
*privateCssmKey
, 
1028         SecAccessRef initialAccess
, 
1029         SecKeyRef
* publicKey
, 
1030         SecKeyRef
* privateKey
) 
1034         Keychain keychain 
= Keychain::optional(keychainRef
); 
1035         SecPointer
<Access
> theAccess(initialAccess 
? Access::required(initialAccess
) : new Access("<key>")); 
1036         SecPointer
<KeyItem
> pubItem
, privItem
; 
1038         KeyItem::importPair(keychain
, 
1039                 Required(publicCssmKey
), 
1040                 Required(privateCssmKey
), 
1045         // Return the generated keys. 
1047                 *publicKey 
= pubItem
->handle(); 
1049                 *privateKey 
= privItem
->handle(); 
1055 SecKeyGenerateWithAttributes( 
1056         SecKeychainAttributeList
* attrList
, 
1057         SecKeychainRef keychainRef
, 
1058         CSSM_ALGORITHMS algorithm
, 
1059         uint32 keySizeInBits
, 
1060         CSSM_CC_HANDLE contextHandle
, 
1061         CSSM_KEYUSE keyUsage
, 
1063         SecAccessRef initialAccess
, 
1069         SecPointer
<Access
> theAccess
; 
1072                 keychain 
= KeychainImpl::required(keychainRef
); 
1074                 theAccess 
= Access::required(initialAccess
); 
1076         SecPointer
<KeyItem
> item 
= KeyItem::generateWithAttributes(attrList
, 
1085         // Return the generated key. 
1087                 *keyRef 
= item
->handle(); 
1094         SecKeychainRef keychainRef
, 
1095         CSSM_ALGORITHMS algorithm
, 
1096         uint32 keySizeInBits
, 
1097         CSSM_CC_HANDLE contextHandle
, 
1098         CSSM_KEYUSE keyUsage
, 
1100         SecAccessRef initialAccess
, 
1103         return SecKeyGenerateWithAttributes(NULL
, 
1104                 keychainRef
, algorithm
, keySizeInBits
, 
1105                 contextHandle
, keyUsage
, keyAttr
, 
1106                 initialAccess
, keyRef
); 
1110 /* Generate a floating key reference from a CSSM_KEY */ 
1112 SecKeyCreateWithCSSMKey(const CSSM_KEY 
*cssmKey
, 
1118     if(cssmKey
->KeyData
.Length 
== 0){ 
1119         MacOSError::throwMe(errSecInvalidAttributeKeyLength
); 
1121     if(cssmKey
->KeyData
.Data 
== NULL
){ 
1122         MacOSError::throwMe(errSecInvalidPointer
); 
1124         CssmClient::CSP 
csp(cssmKey
->KeyHeader
.CspId
); 
1125         CssmClient::Key 
key(csp
, *cssmKey
); 
1126         KeyItem 
*item 
= new KeyItem(key
); 
1128         // Return the generated key. 
1130         *keyRef 
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0); 
1137 static u_int32_t 
ConvertCFStringToInteger(CFStringRef ref
) 
1144         // figure out the size of the string 
1145         CFIndex numChars 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
); 
1146         char *buffer 
= (char *)malloc(numChars
); 
1147     if (NULL 
== buffer
) { 
1148         UnixError::throwMe(ENOMEM
); 
1150         if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
)) 
1153                 MacOSError::throwMe(errSecParam
); 
1156     u_int32_t result 
= atoi(buffer
); 
1163 static OSStatus 
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
&algorithms
) 
1165         // figure out the algorithm to use 
1166         CFStringRef ktype 
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
); 
1172         if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) { 
1173                 algorithms 
= CSSM_ALGID_RSA
; 
1174                 return errSecSuccess
; 
1175        } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) || 
1176                        CFEqual(ktype
, kSecAttrKeyTypeEC
)) { 
1177                 algorithms 
= CSSM_ALGID_ECDSA
; 
1178                 return errSecSuccess
; 
1179         } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) { 
1180                 algorithms 
= CSSM_ALGID_AES
; 
1181                 return errSecSuccess
; 
1182         } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) { 
1183                 algorithms 
= CSSM_ALGID_3DES
; 
1184                 return errSecSuccess
; 
1186                 return errSecUnsupportedAlgorithm
; 
1192 static OSStatus 
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32 
&keySizeInBits
) 
1195     // get the key size and check it for validity 
1196     CFTypeRef ref 
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
); 
1198     keySizeInBits 
= kSecDefaultKeySize
; 
1200     CFTypeID bitSizeType 
= CFGetTypeID(ref
); 
1201     if (bitSizeType 
== CFStringGetTypeID()) 
1202         keySizeInBits 
= ConvertCFStringToInteger((CFStringRef
) ref
); 
1203     else if (bitSizeType 
== CFNumberGetTypeID()) 
1204         CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
); 
1205     else return errSecParam
; 
1208     switch (algorithms
) { 
1209     case CSSM_ALGID_ECDSA
: 
1210         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecp256r1
; 
1211         if(keySizeInBits 
== kSecp192r1 
|| keySizeInBits 
== kSecp256r1 
|| keySizeInBits 
== kSecp384r1 
|| keySizeInBits 
== kSecp521r1 
) return errSecSuccess
; 
1213     case CSSM_ALGID_RSA
: 
1214                           if(keySizeInBits 
% 8) return errSecParam
; 
1215         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= 2048; 
1216         if(keySizeInBits 
>= kSecRSAMin 
&& keySizeInBits 
<= kSecRSAMax
) return errSecSuccess
; 
1218     case CSSM_ALGID_AES
: 
1219         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSecAES128
; 
1220         if(keySizeInBits 
== kSecAES128 
|| keySizeInBits 
== kSecAES192 
|| keySizeInBits 
== kSecAES256
) return errSecSuccess
; 
1222     case CSSM_ALGID_3DES
: 
1223         if(keySizeInBits 
== kSecDefaultKeySize
) keySizeInBits 
= kSec3DES192
; 
1224         if(keySizeInBits 
== kSec3DES192
) return errSecSuccess
; 
1243 struct ParameterAttribute
 
1245         const CFStringRef 
*name
; 
1251 static ParameterAttribute gAttributes
[] = 
1258                 &kSecAttrIsPermanent
, 
1262                 &kSecAttrApplicationTag
, 
1266                 &kSecAttrEffectiveKeySize
, 
1270                 &kSecAttrCanEncrypt
, 
1274                 &kSecAttrCanDecrypt
, 
1295 const int kNumberOfAttributes 
= sizeof(gAttributes
) / sizeof(ParameterAttribute
); 
1297 static OSStatus 
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[]) 
1300         for (i 
= 0; i 
< kNumberOfAttributes
; ++i
) 
1302                 // see if the corresponding tag exists in the dictionary 
1303                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
)); 
1306                         switch (gAttributes
[i
].type
) 
1309                                         // just return the value 
1310                                         *(CFTypeRef
*) attributePointers
[i
] = value
; 
1315                                         CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1316                                         *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
); 
1322                                         CFNumberRef nRef 
= (CFNumberRef
) value
; 
1323                                         CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]); 
1330         return errSecSuccess
; 
1335 static OSStatus 
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE 
&keyUse
, uint32 
&attrs
, CFTypeRef 
&labelRef
, CFDataRef 
&applicationTagRef
) 
1337         // establish default values 
1339         bool isPermanent 
= false; 
1340         applicationTagRef 
= NULL
; 
1341         CFTypeRef effectiveKeySize 
= NULL
; 
1342         bool canDecrypt 
= isPublic 
? false : true; 
1343         bool canEncrypt 
= !canDecrypt
; 
1344         bool canDerive 
= true; 
1345         bool canSign 
= isPublic 
? false : true; 
1346         bool canVerify 
= !canSign
; 
1347         bool canUnwrap 
= isPublic 
? false : true; 
1348         attrs 
= CSSM_KEYATTR_EXTRACTABLE
; 
1351         void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
, 
1352                                                                  &canDerive
, &canSign
, &canVerify
, &canUnwrap
}; 
1354         // look for modifiers in the general dictionary 
1355         OSStatus result 
= ScanDictionaryForParameters(parameters
, attributePointers
); 
1356         if (result 
!= errSecSuccess
) 
1361         // see if we have anything which modifies the defaults 
1365                 key 
= kSecPublicKeyAttrs
; 
1369                 key 
= kSecPrivateKeyAttrs
; 
1372         CFTypeRef dType 
= CFDictionaryGetValue(parameters
, key
); 
1375                 // this had better be a dictionary 
1376                 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID()) 
1381                 // pull any additional parameters out of this dictionary 
1382                 result 
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
); 
1383                 if (result 
!= errSecSuccess
) 
1389         // figure out the key usage 
1393                 keyUse 
|= CSSM_KEYUSE_DECRYPT
; 
1398                 keyUse 
|= CSSM_KEYUSE_ENCRYPT
; 
1403                 keyUse 
|= CSSM_KEYUSE_DERIVE
; 
1408                 keyUse 
|= CSSM_KEYUSE_SIGN
; 
1413                 keyUse 
|= CSSM_KEYUSE_VERIFY
; 
1418                 keyUse 
|= CSSM_KEYUSE_UNWRAP
; 
1421         // public key is always extractable; 
1422         // private key is extractable by default unless explicitly set to false 
1423         CFTypeRef value 
= NULL
; 
1424         if (!isPublic 
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
) 
1426                 Boolean keyIsExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1427                 if (!keyIsExtractable
) 
1432         attrs 
|= CSSM_KEYATTR_PERMANENT
; 
1435         return errSecSuccess
; 
1440 static OSStatus 
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
, 
1441                                                                                                    CSSM_ALGORITHMS 
&algorithms
, 
1442                                                                                                    uint32 
&keySizeInBits
, 
1443                                                                                                    CSSM_KEYUSE 
&publicKeyUse
, 
1444                                                                                                    uint32 
&publicKeyAttr
, 
1445                                                                                                    CFTypeRef 
&publicKeyLabelRef
, 
1446                                                                                                    CFDataRef 
&publicKeyAttributeTagRef
, 
1447                                                                                                    CSSM_KEYUSE 
&privateKeyUse
, 
1448                                                                                                    uint32 
&privateKeyAttr
, 
1449                                                                                                    CFTypeRef 
&privateKeyLabelRef
, 
1450                                                                                                    CFDataRef 
&privateKeyAttributeTagRef
, 
1451                                                                                                    SecAccessRef 
&initialAccess
) 
1455         result 
= CheckAlgorithmType(parameters
, algorithms
); 
1456         if (result 
!= errSecSuccess
) 
1461         result 
= GetKeySize(parameters
, algorithms
, keySizeInBits
); 
1462         if (result 
!= errSecSuccess
) 
1467         result 
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1468         if (result 
!= errSecSuccess
) 
1473         result 
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1474         if (result 
!= errSecSuccess
) 
1479         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
)) 
1481                 initialAccess 
= NULL
; 
1483         else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
)) 
1488         return errSecSuccess
; 
1493 static OSStatus 
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
) 
1495         int numToModify 
= 0; 
1506         if (numToModify 
== 0) 
1508                 return errSecSuccess
; 
1511         SecKeychainAttributeList attrList
; 
1512         SecKeychainAttribute attributes
[numToModify
]; 
1519                 if (CFStringGetTypeID() == CFGetTypeID(label
)) { 
1520                         CFStringRef label_string 
= static_cast<CFStringRef
>(label
); 
1521                         attributes
[i
].tag 
= kSecKeyPrintName
; 
1522                         attributes
[i
].data 
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
); 
1523                         if (NULL 
== attributes
[i
].data
) { 
1524                                 CFIndex buffer_length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
); 
1525                                 data 
= attributes
[i
].data 
= malloc((size_t)buffer_length
); 
1526                                 if (NULL 
== attributes
[i
].data
) { 
1527                                         UnixError::throwMe(ENOMEM
); 
1529                                 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) { 
1531                                         MacOSError::throwMe(errSecParam
); 
1534                         attributes
[i
].length 
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
)); 
1535                 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) { 
1536                         // 10.6 bug compatibility 
1537                         CFDataRef label_data 
= static_cast<CFDataRef
>(label
); 
1538                         attributes
[i
].tag 
= kSecKeyLabel
; 
1539                         attributes
[i
].data 
= (void*) CFDataGetBytePtr(label_data
); 
1540                         attributes
[i
].length 
= (UInt32
)CFDataGetLength(label_data
); 
1542                         MacOSError::throwMe(errSecParam
); 
1549                 attributes
[i
].tag 
= kSecKeyApplicationTag
; 
1550                 attributes
[i
].data 
= (void*) CFDataGetBytePtr(tag
); 
1551                 attributes
[i
].length 
= (UInt32
)CFDataGetLength(tag
); 
1555         attrList
.count 
= numToModify
; 
1556         attrList
.attr 
= attributes
; 
1558         OSStatus result 
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
); 
1568 static CFTypeRef 
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) { 
1569     if (subParams 
!= NULL
) { 
1570         CFDictionaryRef subParamsDict 
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
); 
1571         if (subParamsDict 
!= NULL
) { 
1572             CFTypeRef value 
= CFDictionaryGetValue(subParamsDict
, attr
); 
1573             if (value 
!= NULL
) { 
1578     return CFDictionaryGetValue(parameters
, attr
); 
1581 extern "C" OSStatus 
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
); 
1584 /* Generate a private/public keypair. */ 
1586 SecKeyGeneratePairInternal( 
1587     bool alwaysPermanent
, 
1588         CFDictionaryRef parameters
, 
1589         SecKeyRef 
*publicKey
, 
1590         SecKeyRef 
*privateKey
) 
1594         Required(parameters
); 
1595     Required(publicKey
); 
1596     Required(privateKey
); 
1598     bool forceIOSKey 
= false; 
1599     if (_CFMZEnabled()) { 
1600         // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in. 
1603         CFTypeRef tokenID 
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
); 
1604         CFTypeRef noLegacy 
= GetAttributeFromParams(parameters
, kSecUseDataProtectionKeychain
, NULL
); 
1605 #pragma clang diagnostic push 
1606 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1607         if (!noLegacy
) {    // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot 
1608             noLegacy 
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
); 
1610 #pragma clang diagnostic pop 
1611         CFTypeRef sync 
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
); 
1612         CFTypeRef accessControl 
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?: 
1613         GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
); 
1614         CFTypeRef accessGroup 
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?: 
1615         GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
); 
1616         // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). 
1617         forceIOSKey 
= (tokenID 
!= NULL 
|| 
1618                        (noLegacy 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) || 
1619                        (sync 
!= NULL 
&& CFBooleanGetValue((CFBooleanRef
)sync
)) || 
1620                        accessControl 
!= NULL 
|| (accessGroup 
!= NULL 
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))); 
1624         // Generate keys in iOS keychain. 
1625         return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
); 
1628         CSSM_ALGORITHMS algorithms
; 
1629         uint32 keySizeInBits
; 
1630         CSSM_KEYUSE publicKeyUse
; 
1631         uint32 publicKeyAttr
; 
1632         CFTypeRef publicKeyLabelRef
; 
1633         CFDataRef publicKeyAttributeTagRef
; 
1634         CSSM_KEYUSE privateKeyUse
; 
1635         uint32 privateKeyAttr
; 
1636         CFTypeRef privateKeyLabelRef
; 
1637         CFDataRef privateKeyAttributeTagRef
; 
1638         SecAccessRef initialAccess
; 
1639         SecKeychainRef keychain
; 
1641         OSStatus result 
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, 
1642                                                                                                                  publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
, 
1645         if (result 
!= errSecSuccess
) { 
1649         // verify keychain parameter 
1650     keychain 
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
); 
1651     if (keychain 
!= NULL 
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1655     if (alwaysPermanent
) { 
1656         publicKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1657         privateKeyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1660         // do the key generation 
1661         result 
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
); 
1662         if (result 
!= errSecSuccess
) { 
1666         // set the label and print attributes on the keys 
1667     SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
); 
1668     SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
); 
1675 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
) { 
1676     return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
); 
1680 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1681     SecKeyRef privateKey 
= NULL
, publicKey 
= NULL
; 
1682     OSStatus status 
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
); 
1683     SecError(status
, error
, CFSTR("failed to generate asymmetric keypair")); 
1684     if (publicKey 
!= NULL
) { 
1685         CFRelease(publicKey
); 
1690 OSStatus 
SecKeyRawVerifyOSX( 
1691     SecKeyRef           key
,            /* Public key */ 
1692         SecPadding          padding
,            /* kSecPaddingNone or kSecPaddingPKCS1 */ 
1693         const uint8_t       *signedData
,        /* signature over this data */ 
1694         size_t              signedDataLen
,      /* length of dataToSign */ 
1695         const uint8_t       *sig
,                       /* signature */ 
1698     return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
); 
1706 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
) 
1708                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1709         if (value 
!= NULL
) return value
; 
1710         return defaultValue
; 
1714 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
) 
1716         uint32_t integerValue
; 
1717                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1718         if (value 
!= NULL
) { 
1719             CFNumberRef nRef 
= (CFNumberRef
) value
; 
1720             CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
); 
1721             return integerValue
; 
1723         return defaultValue
; 
1727 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
) 
1729                 CFTypeRef value 
= CFDictionaryGetValue(parameters
, key
); 
1730         if (value 
!= NULL
) { 
1731             CFBooleanRef bRef 
= (CFBooleanRef
) value
; 
1732             if(CFBooleanGetValue(bRef
)) return maskValue
; 
1738 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS 
*algorithm
, uint32 
*keySizeInBits
, CSSM_KEYUSE 
*keyUsage
, CSSM_KEYCLASS 
*keyClass
) 
1740     CFTypeRef algorithmDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
); 
1741     CFTypeRef keyClassDictValue 
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
); 
1743     if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) { 
1744         *algorithm 
= CSSM_ALGID_AES
; 
1745         *keySizeInBits 
= 128; 
1746         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1747     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) { 
1748         *algorithm 
= CSSM_ALGID_DES
; 
1749         *keySizeInBits 
= 128; 
1750          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1751     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) { 
1752         *algorithm 
= CSSM_ALGID_3DES_3KEY_EDE
; 
1753         *keySizeInBits 
= 128; 
1754         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1755     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) { 
1756         *algorithm 
= CSSM_ALGID_RC4
; 
1757         *keySizeInBits 
= 128; 
1758         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1759     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) { 
1760         *algorithm 
= CSSM_ALGID_RC2
; 
1761         *keySizeInBits 
= 128; 
1762          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1763     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) { 
1764         *algorithm 
= CSSM_ALGID_CAST
; 
1765         *keySizeInBits 
= 128; 
1766          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1767     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) { 
1768         *algorithm 
= CSSM_ALGID_RSA
; 
1769         *keySizeInBits 
= 128; 
1770          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1771     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) { 
1772         *algorithm 
= CSSM_ALGID_DSA
; 
1773         *keySizeInBits 
= 128; 
1774          *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1775     } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) || 
1776             CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) { 
1777         *algorithm 
= CSSM_ALGID_ECDSA
; 
1778         *keySizeInBits 
= 128; 
1779         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1781         *algorithm 
= CSSM_ALGID_AES
; 
1782         *keySizeInBits 
= 128; 
1783         *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1786     if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) { 
1787         *keyClass 
= CSSM_KEYCLASS_PUBLIC_KEY
; 
1788     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) { 
1789         *keyClass 
= CSSM_KEYCLASS_PRIVATE_KEY
; 
1790     } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) { 
1791          *keyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1794     *keySizeInBits 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
); 
1795     *keyUsage 
=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) | 
1796                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) | 
1797                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) | 
1798                 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
); 
1801     if(*keyClass 
== CSSM_KEYCLASS_PRIVATE_KEY 
|| *keyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) { 
1802                 *keyUsage 
|=  utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) | 
1803                                         utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
); 
1806     if(*keyUsage 
== 0) { 
1807                 switch (*keyClass
) { 
1808                         case CSSM_KEYCLASS_PRIVATE_KEY
: 
1809                                 *keyUsage 
= CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN
; 
1811                         case CSSM_KEYCLASS_PUBLIC_KEY
: 
1812                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_VERIFY 
| CSSM_KEYUSE_WRAP
; 
1815                                 *keyUsage 
= CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT 
| CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP 
| CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_VERIFY
; 
1822 utilCopyDefaultKeyLabel(void) 
1824         // generate a default label from the current date 
1825         CFDateRef dateNow 
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent()); 
1826         CFStringRef defaultLabel 
= CFCopyDescription(dateNow
); 
1829         return defaultLabel
; 
1833 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef 
*error
) 
1835         OSStatus result 
= errSecParam
; // default result for an early exit 
1836         SecKeyRef key 
= NULL
; 
1837         SecKeychainRef keychain 
= NULL
; 
1838         SecAccessRef access
; 
1840         CFStringRef appLabel
; 
1842         CFStringRef dateLabel 
= NULL
; 
1844         CSSM_ALGORITHMS algorithm
; 
1845         uint32 keySizeInBits
; 
1846         CSSM_KEYUSE keyUsage
; 
1847         uint32 keyAttr 
= CSSM_KEYATTR_RETURN_DEFAULT
; 
1848         CSSM_KEYCLASS keyClass
; 
1850         Boolean isPermanent
; 
1851         Boolean isExtractable
; 
1853         // verify keychain parameter 
1854         if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
)) 
1856         else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) { 
1863         // verify permanent parameter 
1864         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
)) 
1865                 isPermanent 
= false; 
1866         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1869                 isPermanent 
= CFEqual(kCFBooleanTrue
, value
); 
1871                 if (keychain 
== NULL
) { 
1872                         // no keychain was specified, so use the default keychain 
1873                         result 
= SecKeychainCopyDefault(&keychain
); 
1875                 keyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1878         // verify extractable parameter 
1879         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
)) 
1880                 isExtractable 
= true; // default to extractable if value not specified 
1881         else if (!value 
|| (CFBooleanGetTypeID() != CFGetTypeID(value
))) 
1884                 isExtractable 
= CFEqual(kCFBooleanTrue
, value
); 
1886                 keyAttr 
|= CSSM_KEYATTR_EXTRACTABLE
; 
1888         // verify access parameter 
1889         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
)) 
1891         else if (SecAccessGetTypeID() != CFGetTypeID(access
)) 
1894         // verify label parameter 
1895         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
)) 
1896                 label 
= (dateLabel 
= utilCopyDefaultKeyLabel()); // no label provided, so use default 
1897         else if (CFStringGetTypeID() != CFGetTypeID(label
)) 
1900         // verify application label parameter 
1901         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
)) 
1902                 appLabel 
= (dateLabel
) ? dateLabel 
: (dateLabel 
= utilCopyDefaultKeyLabel()); 
1903         else if (CFStringGetTypeID() != CFGetTypeID(appLabel
)) 
1906         // verify application tag parameter 
1907         if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
)) 
1909         else if (CFStringGetTypeID() != CFGetTypeID(appTag
)) 
1912     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1915                 // the generated key will not be stored in any keychain 
1916                 result 
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
); 
1919                 // we can set the label attributes on the generated key if it's a keychain item 
1920                 size_t labelBufLen 
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1; 
1921                 char *labelBuf 
= (char *)malloc(labelBufLen
); 
1922                 size_t appLabelBufLen 
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1; 
1923                 char *appLabelBuf 
= (char *)malloc(appLabelBufLen
); 
1924                 size_t appTagBufLen 
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1; 
1925                 char *appTagBuf 
= (char *)malloc(appTagBufLen
); 
1927                 if (!label 
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
)) 
1929                 if (!appLabel 
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
)) 
1931                 if (!appTag 
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
)) 
1934                 SecKeychainAttribute attrs
[] = { 
1935                         { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf 
}, 
1936                         { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf 
}, 
1937                         { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf 
} }; 
1938                 SecKeychainAttributeList attributes 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
1939                 if (!appTag
) --attributes
.count
; 
1941                 result 
= SecKeyGenerateWithAttributes(&attributes
, 
1942                         keychain
, algorithm
, keySizeInBits
, 0, 
1943                         keyUsage
, keyAttr
, access
, &key
); 
1951         if (result 
&& error
) { 
1952                 *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
); 
1955                 CFRelease(dateLabel
); 
1957                 CFRelease(keychain
); 
1965 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef 
*error
) 
1967         CSSM_ALGORITHMS         algorithm
; 
1968     uint32                              keySizeInBits
; 
1969     CSSM_KEYUSE                 keyUsage
; 
1970     CSSM_KEYCLASS               keyClass
; 
1973     if(keyData 
== NULL 
|| CFDataGetLength(keyData
) == 0){ 
1974         MacOSError::throwMe(errSecUnsupportedKeySize
); 
1977     utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
); 
1979         CSSM_CSP_HANDLE cspHandle 
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL 
1981         SecKeyImportExportParameters iparam
; 
1982         memset(&iparam
, 0, sizeof(iparam
)); 
1983         iparam
.keyUsage 
= keyUsage
; 
1985     CFRef
<CFDataRef
> data
; 
1986         SecExternalItemType itype
; 
1988                 case CSSM_KEYCLASS_PRIVATE_KEY
: 
1989                         itype 
= kSecItemTypePrivateKey
; 
1991         case CSSM_KEYCLASS_PUBLIC_KEY
: { 
1992                         itype 
= kSecItemTypePublicKey
; 
1993             // Public key import expects public key in SubjPublicKey X509 format.  We want to accept both bare and x509 format, 
1994             // so we have to detect bare format here and extend to full X509 if detected. 
1995             data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
)); 
1998                 case CSSM_KEYCLASS_SESSION_KEY
: 
1999                         itype 
= kSecItemTypeSessionKey
; 
2002                         itype 
= kSecItemTypeUnknown
; 
2006         CFMutableArrayRef ka 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
2007         // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. 
2008     crtn 
= impExpImportRawKey(data 
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
); 
2009         if (crtn 
== CSSM_OK 
&& CFArrayGetCount((CFArrayRef
)ka
)) { 
2010                 SecKeyRef sk 
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0); 
2017                         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn 
? crtn 
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
); 
2025 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
, 
2026                                                 SecKeyGeneratePairBlock result
) 
2028         CFDictionaryRef parameters 
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
); 
2029         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{ 
2030                 SecKeyRef publicKey 
= NULL
; 
2031                 SecKeyRef privateKey 
= NULL
; 
2032                 OSStatus status 
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
); 
2033                 dispatch_async(deliveryQueue
, ^{ 
2034                         CFErrorRef error 
= NULL
; 
2035                         if (errSecSuccess 
!= status
) { 
2036                                 error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
); 
2038                         result(publicKey
, privateKey
, error
); 
2043                                 CFRelease(publicKey
); 
2046                                 CFRelease(privateKey
); 
2048                         CFRelease(parameters
); 
2053 static inline void utilClearAndFree(void *p
, size_t len
) { 
2055         if(len
) bzero(p
, len
); 
2061 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2063     CCPBKDFAlgorithm algorithm
; 
2064     CFIndex passwordLen 
= 0; 
2065     CFDataRef keyData 
= NULL
; 
2066     char *thePassword 
= NULL
; 
2067     uint8_t *salt 
= NULL
; 
2068     uint8_t *derivedKey 
= NULL
; 
2069     size_t  saltLen 
= 0, derivedKeyLen 
= 0; 
2071     CFDataRef saltDictValue
, algorithmDictValue
; 
2072     SecKeyRef retval 
= NULL
; 
2074     /* Pick Values from parameters */ 
2076     if((saltDictValue 
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) { 
2078             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
); 
2083     derivedKeyLen 
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128); 
2084         // This value come in bits but the rest of the code treats it as bytes 
2087     algorithmDictValue 
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
); 
2089     rounds 
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0); 
2091     /* Convert any remaining parameters and get the password bytes */ 
2093     saltLen 
= CFDataGetLength(saltDictValue
); 
2094     if((salt 
= (uint8_t *) malloc(saltLen
)) == NULL
) { 
2096             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2101     CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8 
*) salt
); 
2103     passwordLen 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1; 
2104     if((thePassword 
= (char *) malloc(passwordLen
)) == NULL
) { 
2106             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2110     CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
); 
2112     if((derivedKey 
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) { 
2114             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
); 
2119     if(algorithmDictValue 
== NULL
) { 
2120         algorithm 
= kCCPRFHmacAlgSHA1
; /* default */ 
2121     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) { 
2122         algorithm 
= kCCPRFHmacAlgSHA1
; 
2123     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) { 
2124         algorithm 
= kCCPRFHmacAlgSHA224
; 
2125     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) { 
2126         algorithm 
= kCCPRFHmacAlgSHA256
; 
2127     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) { 
2128         algorithm 
= kCCPRFHmacAlgSHA384
; 
2129     } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) { 
2130         algorithm 
= kCCPRFHmacAlgSHA512
; 
2133             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
); 
2139         rounds 
= 33333; // we need to pass back a consistent value since there's no way to record the round count. 
2142     if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) { 
2144             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2149     if((keyData 
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) { 
2150         retval 
=  SecKeyCreateFromData(parameters
, keyData
, error
); 
2154             *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
); 
2159     utilClearAndFree(salt
, saltLen
); 
2160     utilClearAndFree(thePassword
, passwordLen
); 
2161     utilClearAndFree(derivedKey
, derivedKeyLen
); 
2166 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2169         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
); 
2175 SecKeyUnwrapSymmetric(CFDataRef 
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef 
*error
) 
2178         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);