2  * Copyright (c) 2006-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  * SecKey.c - CoreFoundation based key object 
  27 #include <Security/SecBase.h> 
  29 #include <Security/SecKeyInternal.h> 
  30 #include <Security/SecItem.h> 
  31 #include <Security/SecItemPriv.h> 
  32 #include <Security/SecItemShim.h> 
  33 #include <Security/SecFramework.h> 
  35 #include <utilities/SecIOFormat.h> 
  37 #include <utilities/SecCFWrappers.h> 
  38 #include <utilities/array_size.h> 
  40 #include "SecRSAKeyPriv.h" 
  41 #include "SecECKeyPriv.h" 
  42 #include "SecCTKKeyPriv.h" 
  43 #include "SecBasePriv.h" 
  44 #include <Security/SecKeyPriv.h> 
  46 #include <CoreFoundation/CFNumber.h> 
  47 #include <CoreFoundation/CFString.h> 
  50 #include <AssertMacros.h> 
  51 #include <utilities/debugging.h> 
  52 #include <utilities/SecCFError.h> 
  53 #include <CommonCrypto/CommonDigest.h> 
  54 #include <Security/SecAsn1Coder.h> 
  55 #include <Security/oidsalg.h> 
  56 #include <Security/SecInternal.h> 
  57 #include <Security/SecRandom.h> 
  58 #include <Security/SecureTransport.h> /* For error codes. */ 
  60 #include <corecrypto/ccrng_system.h> 
  66 #include <libDER/asn1Types.h> 
  67 #include <libDER/DER_Keys.h> 
  68 #include <libDER/DER_Encode.h> 
  70 CFDataRef 
SecKeyCopyPublicKeyHash(SecKeyRef key
) 
  72         CFDataRef pubKeyDigest 
= NULL
, pubKeyBlob 
= NULL
; 
  74         /* encode the public key. */ 
  75     require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
); 
  76     require_quiet(pubKeyBlob
, errOut
); 
  78         /* Calculate the digest of the public key. */ 
  79         require_quiet(pubKeyDigest 
= SecSHA1DigestCreate(CFGetAllocator(key
), 
  80                                                      CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)), 
  83     CFReleaseNull(pubKeyBlob
); 
  90 static CFDictionaryRef 
SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key
, 
  92                                                                  CFDataRef privateBlob
) 
  94         CFAllocatorRef allocator 
= CFGetAllocator(key
); 
  96         CFDataRef pubKeyDigest 
= NULL
, pubKeyBlob 
= NULL
; 
  97         CFDictionaryRef dict 
= NULL
; 
  99     size_t sizeValue 
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
); 
 100     CFNumberRef sizeInBits 
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
); 
 102         /* encode the public key. */ 
 103     require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
); 
 104     require_quiet(pubKeyBlob
, errOut
); 
 106         /* Calculate the digest of the public key. */ 
 107         require_quiet(pubKeyDigest 
= SecSHA1DigestCreate(allocator
, 
 108                                                      CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)), 
 111         DICT_ADDPAIR(kSecClass
, kSecClassKey
); 
 112         DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob 
? kSecAttrKeyClassPrivate 
: kSecAttrKeyClassPublic
); 
 113         DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
); 
 114         DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
); 
 115         DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
); 
 116         DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
); 
 117         DICT_ADDPAIR(kSecAttrKeyType
, keyType
); 
 118         DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
); 
 119         DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
); 
 120         DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
); 
 121         DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
); 
 122         DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
); 
 123         DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
); 
 124         DICT_ADDPAIR(kSecAttrCanEncrypt
, privateBlob 
? kCFBooleanFalse 
: kCFBooleanTrue
); 
 125         DICT_ADDPAIR(kSecAttrCanDecrypt
, privateBlob 
? kCFBooleanTrue 
: kCFBooleanFalse
); 
 126         DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
); 
 127         DICT_ADDPAIR(kSecAttrCanSign
, privateBlob 
? kCFBooleanTrue 
: kCFBooleanFalse
); 
 128         DICT_ADDPAIR(kSecAttrCanVerify
, privateBlob 
? kCFBooleanFalse 
: kCFBooleanTrue
); 
 129         DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
); 
 130         DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
); 
 131         DICT_ADDPAIR(kSecAttrCanWrap
, privateBlob 
? kCFBooleanFalse 
: kCFBooleanTrue
); 
 132         DICT_ADDPAIR(kSecAttrCanUnwrap
, privateBlob 
? kCFBooleanTrue 
: kCFBooleanFalse
); 
 133         DICT_ADDPAIR(kSecValueData
, privateBlob 
? privateBlob 
: pubKeyBlob
); 
 134     dict 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 137         // @@@ Zero out key material. 
 138         CFReleaseSafe(pubKeyDigest
); 
 139         CFReleaseSafe(pubKeyBlob
); 
 140         CFReleaseSafe(sizeInBits
); 
 145 CFDictionaryRef 
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
, 
 147                                                          CFDataRef privateBlob
) 
 149     return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, privateBlob
); 
 152 CFDictionaryRef 
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
) 
 154     return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, NULL
); 
 157 static CFStringRef 
SecKeyCopyDescription(CFTypeRef cf
) { 
 158     SecKeyRef key 
= (SecKeyRef
)cf
; 
 160     if(key
->key_class
->describe
) 
 161         return key
->key_class
->describe(key
); 
 163         return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
); 
 166 static void SecKeyDestroy(CFTypeRef cf
) { 
 167     SecKeyRef key 
= (SecKeyRef
)cf
; 
 168 #if !TARGET_OS_IPHONE 
 169     CFReleaseNull(key
->cdsaKey
); 
 171     if (key
->key_class
->destroy
) 
 172         key
->key_class
->destroy(key
); 
 175 static Boolean 
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
) 
 177     SecKeyRef key1 
= (SecKeyRef
)cf1
; 
 178     SecKeyRef key2 
= (SecKeyRef
)cf2
; 
 181     if (!key2 
|| key1
->key_class 
!= key2
->key_class
) 
 183     if (key1
->key_class
->version 
>= 4 && key1
->key_class
->isEqual
) 
 184         return key1
->key_class
->isEqual(key1
, key2
); 
 185     if (key1
->key_class
->extraBytes
) 
 186         return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
); 
 188     /* TODO: Won't work when we get reference keys. */ 
 189     CFDictionaryRef d1
, d2
; 
 190     d1 
= SecKeyCopyAttributeDictionary(key1
); 
 191     d2 
= SecKeyCopyAttributeDictionary(key2
); 
 192     // Returning NULL is an error; bail out of the equality check 
 198     Boolean result 
= CFEqual(d1
, d2
); 
 204 struct ccrng_state 
*ccrng_seckey
; 
 206 CFGiblisWithFunctions(SecKey
, NULL
, NULL
, SecKeyDestroy
, SecKeyEqual
, NULL
, NULL
, SecKeyCopyDescription
, NULL
, NULL
, ^{ 
 207     static struct ccrng_system_state ccrng_system_state_seckey
; 
 208     ccrng_seckey 
= (struct ccrng_state 
*)&ccrng_system_state_seckey
; 
 209     ccrng_system_init(&ccrng_system_state_seckey
); 
 212 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) { 
 213         CFTypeRef value 
= CFDictionaryGetValue(dict
, key
); 
 215                 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) { 
 216                         return CFBooleanGetValue(value
); 
 218                         secwarning("Value %@ for key %@ is not bool", value
, key
); 
 222         return default_value
; 
 225 static OSStatus 
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) { 
 226         CFDictionarySetValue(dict
, kSecValueRef
, item
); 
 227         return SecItemAdd(dict
, NULL
); 
 230 static void merge_params_applier(const void *key
, const void *value
, 
 232         CFMutableDictionaryRef result 
= (CFMutableDictionaryRef
)context
; 
 233         CFDictionaryAddValue(result
, key
, value
); 
 236 /* Create a mutable dictionary that is based on the subdictionary for key 
 237  with any attributes from the top level dict merged in. */ 
 238 static CF_RETURNS_RETAINED CFMutableDictionaryRef 
merge_params(CFDictionaryRef dict
, 
 240         CFDictionaryRef subdict 
= CFDictionaryGetValue(dict
, key
); 
 241         CFMutableDictionaryRef result
; 
 244                 result 
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
); 
 245                 /* Add everything in dict not already in result to result. */ 
 246                 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
); 
 248                 result 
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
); 
 251         /* Remove values that only belong in the top level dict. */ 
 252         CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
); 
 253         CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
); 
 254         CFDictionaryRemoveValue(result
, kSecAttrKeyType
); 
 255         CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
); 
 260 CFIndex 
SecKeyGetAlgorithmIdentifier(SecKeyRef key
) { 
 261     if (!key 
|| !key
->key_class
)  { 
 262     // TBD: somehow, a key can be created with a NULL key_class in the 
 263     // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path 
 264         return kSecNullAlgorithmID
; 
 266     /* This method was added to version 1 keys. */ 
 267     if (key
->key_class
->version 
> 0 && key
->key_class
->getAlgorithmID
) { 
 268         return key
->key_class
->getAlgorithmID(key
); 
 270     /* All version 0 keys were RSA. */ 
 271     return kSecRSAAlgorithmID
; 
 274 /* Generate a private/public keypair. */ 
 275 OSStatus 
SecKeyGeneratePair(CFDictionaryRef parameters
, 
 276                             SecKeyRef 
*publicKey
, SecKeyRef 
*privateKey
) { 
 277     OSStatus result 
= errSecUnsupportedAlgorithm
; 
 278     SecKeyRef privKey 
= NULL
; 
 279         SecKeyRef pubKey 
= NULL
; 
 280     CFMutableDictionaryRef pubParams 
= merge_params(parameters
, kSecPublicKeyAttrs
), 
 281     privParams 
= merge_params(parameters
, kSecPrivateKeyAttrs
); 
 282         CFStringRef ktype 
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
); 
 283     CFStringRef tokenID 
= CFDictionaryGetValue(parameters
, kSecAttrTokenID
); 
 285     require_quiet(ktype
, errOut
); 
 287     if (tokenID 
!= NULL
) { 
 288         result 
= SecCTKKeyGeneratePair(parameters
, &pubKey
, &privKey
); 
 289     } else if (CFEqual(ktype
, kSecAttrKeyTypeECSECPrimeRandom
)) { 
 290         result 
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
); 
 291     } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) { 
 292         result 
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
); 
 295     require_noerr_quiet(result
, errOut
); 
 297     // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default 
 298     // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys). 
 299     if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) { 
 300         CFDictionaryRemoveValue(pubParams
, kSecAttrTokenID
); 
 301         require_noerr_quiet(result 
= add_ref(pubKey
, pubParams
), errOut
); 
 303     if (getBoolForKey(privParams
, kSecAttrIsPermanent
, CFDictionaryContainsKey(privParams
, kSecAttrTokenID
))) { 
 304         require_noerr_quiet(result 
= add_ref(privKey
, privParams
), errOut
); 
 312         *privateKey 
= privKey
; 
 317         CFReleaseSafe(pubParams
); 
 318         CFReleaseSafe(privParams
); 
 319     CFReleaseSafe(pubKey
); 
 320     CFReleaseSafe(privKey
); 
 325 SecKeyRef 
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) { 
 326     return SecKeyCopyPublicKey(privateKey
); 
 329 CFDictionaryRef 
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
) 
 331     const CFTypeRef refType 
= (returnPersistentRef
) ? kSecReturnPersistentRef
: kSecReturnRef
; 
 333     CFDataRef public_key_hash 
= SecKeyCopyPublicKeyHash(publicKey
); 
 335     CFDictionaryRef query 
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, 
 336                                                          kSecClass
,                 kSecClassKey
, 
 337                                                          kSecAttrKeyClass
,          kSecAttrKeyClassPrivate
, 
 338                                                          kSecAttrSynchronizable
,    kSecAttrSynchronizableAny
, 
 339                                                          kSecAttrApplicationLabel
,  public_key_hash
, 
 340                                                          refType
,                   kCFBooleanTrue
, 
 342     CFReleaseNull(public_key_hash
); 
 347 CFDataRef 
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef 
*error
) { 
 348     CFTypeRef persistentRef 
= NULL
; 
 349     CFDictionaryRef query 
= CreatePrivateKeyMatchingQuery(publicKey
, true); 
 351     require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error 
, 
 352                            CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
); 
 354     CFReleaseNull(query
); 
 355     return (CFDataRef
)persistentRef
; 
 358 SecKeyRef 
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef 
*error
) { 
 359     SecKeyRef privateKey 
= NULL
; 
 360     CFTypeRef queryResult 
= NULL
; 
 361     CFDictionaryRef query 
= NULL
; 
 363     require_action_quiet(publicKey 
!= NULL
, errOut
, SecError(errSecParam
, error
, CFSTR("Null Public Key"))); 
 365     query 
= CreatePrivateKeyMatchingQuery(publicKey
, false); 
 367     require_quiet(SecError(SecItemCopyMatching(query
, &queryResult
), error
, 
 368                            CFSTR("Error finding private key from public: %@"), publicKey
), errOut
); 
 370     if (CFGetTypeID(queryResult
) == SecKeyGetTypeID()) { 
 371         privateKey 
= (SecKeyRef
) queryResult
; 
 376     CFReleaseNull(query
); 
 377     CFReleaseNull(queryResult
); 
 381 OSStatus 
SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey
, CFErrorRef 
*error
) { 
 382     OSStatus retval 
= errSecParam
; 
 383     CFTypeRef private_key 
= NULL
; 
 384     CFDictionaryRef query 
= NULL
; 
 386     require_action_quiet(publicKey 
!= NULL
, errOut
, SecError(errSecParam
, error
, NULL
, CFSTR("Null Public Key"))); 
 388     query 
= CreatePrivateKeyMatchingQuery(publicKey
, false); 
 390     retval 
= SecItemCopyMatching(query
, &private_key
); 
 392     if (!retval 
&& CFGetTypeID(private_key
) != SecKeyGetTypeID()) { 
 393         retval 
= errSecInternalComponent
; 
 397     CFReleaseNull(query
); 
 398     CFReleaseNull(private_key
); 
 403 SecKeyRef 
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
, 
 404                                     const SecAsn1Oid 
*oid
, const SecAsn1Item 
*params
, 
 405                                     const SecAsn1Item 
*keyData
) { 
 406     SecKeyRef publicKey 
= NULL
; 
 407         if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) { 
 409         /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of 
 410            SecKeyCreateRSAPublicKey, since on OS X the latter function will return 
 411            a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here. 
 413                 publicKey 
= SecKeyCreateRSAPublicKey_ios(allocator
, 
 414                                              keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
); 
 415         } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) { 
 418             .oidLength 
= oid
->Length
, 
 419             .key 
= keyData
->Data
, 
 420             .keyLength 
= keyData
->Length
, 
 423             derKey
.parameters 
= params
->Data
; 
 424             derKey
.parametersLength 
= params
->Length
; 
 426                 publicKey 
= SecKeyCreateECPublicKey(allocator
, 
 427                                             (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
); 
 429                 secwarning("Unsupported algorithm oid"); 
 436 SecKeyRef 
SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator
, CFDataRef subjectPublicKeyInfoData
) 
 440     DERItem subjectPublicKeyInfoDER 
= { 
 441         .data 
= (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData
), 
 442         .length 
= (DERSize
)CFDataGetLength(subjectPublicKeyInfoData
), 
 444     DERSubjPubKeyInfo subjectPublicKeyInfo
; 
 445     DERAlgorithmId algorithmId
; 
 448     drtn 
= DERParseSequence(&subjectPublicKeyInfoDER
, 
 449                             DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
, 
 450                             &subjectPublicKeyInfo
, sizeof(subjectPublicKeyInfo
)); 
 452     require_noerr_quiet(drtn
, out
); 
 454     drtn 
= DERParseSequenceContent(&subjectPublicKeyInfo
.algId
, 
 455                                    DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
, 
 456                                    &algorithmId
, sizeof(algorithmId
)); 
 457     require_noerr_quiet(drtn
, out
); 
 460     drtn 
= DERParseBitString(&subjectPublicKeyInfo
.pubKey
, &pubKeyBytes
, &unusedBits
); 
 461     require_noerr_quiet(drtn
, out
); 
 463     /* Convert DERItem to SecAsn1Item : */ 
 464     const SecAsn1Oid oid 
= { .Data 
= algorithmId
.oid
.data
, .Length 
= algorithmId
.oid
.length 
}; 
 465     const SecAsn1Item params 
= { .Data 
= algorithmId
.params
.data
, .Length 
= algorithmId
.params
.length 
}; 
 466     const SecAsn1Item pubKey 
= { .Data 
= pubKeyBytes
.data
, .Length 
= pubKeyBytes
.length 
}; 
 468     return SecKeyCreatePublicFromDER(allocator
, &oid
, ¶ms
, &pubKey
); 
 475 static const DERByte oidRSA
[] = { 
 476     0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 
 478 static const DERByte oidECsecp256
[] = { 
 479     0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 
 481 static const DERByte oidECsecp384
[] = { 
 482     0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 
 484 static const DERByte oidECsecp521
[] = { 
 485     0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 
 489 CFDataRef 
SecKeyCopySubjectPublicKeyInfo(SecKeyRef key
) 
 491     CFMutableDataRef data 
= NULL
; 
 492     CFDataRef publicKey 
= NULL
; 
 493     CFDataRef dataret 
= NULL
; 
 494     DERSubjPubKeyInfo spki
; 
 498     memset(&spki
, 0, sizeof(spki
)); 
 500     /* encode the public key. */ 
 501     require_noerr(SecKeyCopyPublicBytes(key
, &publicKey
), errOut
); 
 502     require_quiet(publicKey
, errOut
); 
 504     require(CFDataGetLength(publicKey
) != 0, errOut
); 
 506     // Add prefix 00 is needed to avoid creating negative bit strings 
 507     if (((uint8_t *)CFDataGetBytePtr(publicKey
))[0] & 0x80) 
 511     CFMutableDataRef paddedKey 
= CFDataCreateMutable(NULL
, 0); 
 512     /* the bit strings bits used field first */ 
 513     CFDataAppendBytes(paddedKey
, (const UInt8 
*)"\x00", 1); 
 515         CFDataAppendBytes(paddedKey
, (const UInt8 
*)"\x00", 1); 
 517     CFDataAppendBytes(paddedKey
, CFDataGetBytePtr(publicKey
), CFDataGetLength(publicKey
)); 
 518     CFTransferRetained(publicKey
, paddedKey
); 
 520     spki
.pubKey
.data 
= (DERByte 
*)CFDataGetBytePtr(publicKey
); 
 521     spki
.pubKey
.length 
= CFDataGetLength(publicKey
); 
 523     // Encode algId according to algorithm used. 
 524     CFIndex algorithm 
= SecKeyGetAlgorithmIdentifier(key
); 
 525     if (algorithm 
== kSecRSAAlgorithmID
) { 
 526         spki
.algId
.data 
= (DERByte 
*)oidRSA
; 
 527         spki
.algId
.length 
= sizeof(oidRSA
); 
 528     } else if (algorithm 
== kSecECDSAAlgorithmID
) { 
 529         SecECNamedCurve curve 
= SecECKeyGetNamedCurve(key
); 
 531             case kSecECCurveSecp256r1
: 
 532                 spki
.algId
.data 
= (DERByte 
*)oidECsecp256
; 
 533                 spki
.algId
.length 
= sizeof(oidECsecp256
); 
 535             case kSecECCurveSecp384r1
: 
 536                 spki
.algId
.data 
= (DERByte 
*)oidECsecp384
; 
 537                 spki
.algId
.length 
= sizeof(oidECsecp384
); 
 539             case kSecECCurveSecp521r1
: 
 540                 spki
.algId
.data 
= (DERByte 
*)oidECsecp521
; 
 541                 spki
.algId
.length 
= sizeof(oidECsecp521
); 
 550     DERSize size 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &spki
, 
 551                                               DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
); 
 552     data 
= CFDataCreateMutable(kCFAllocatorDefault
, size
); 
 553     CFDataSetLength(data
, size
); 
 555     drtn 
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &spki
, 
 556                              DERNumSubjPubKeyInfoItemSpecs
, 
 557                              DERSubjPubKeyInfoItemSpecs
, 
 558                              CFDataGetMutableBytePtr(data
), &size
); 
 559     require(drtn 
== DR_Success
, errOut
); 
 560     CFDataSetLength(data
, size
); 
 562     dataret 
= CFRetain(data
); 
 565     CFReleaseNull(publicKey
); 
 572 SecKeyRef 
SecKeyCreate(CFAllocatorRef allocator
, 
 573                        const SecKeyDescriptor 
*key_class
, const uint8_t *keyData
, 
 574                        CFIndex keyDataLength
, SecKeyEncoding encoding
) { 
 575         if (!key_class
) return NULL
; 
 576     size_t size 
= sizeof(struct __SecKey
) + key_class
->extraBytes
; 
 577     SecKeyRef result 
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
, 
 578                                                            SecKeyGetTypeID(), size 
- sizeof(CFRuntimeBase
), NULL
); 
 580                 memset((char*)result 
+ sizeof(result
->_base
), 0, size 
- sizeof(result
->_base
)); 
 581         result
->key_class 
= key_class
; 
 582         if (key_class
->extraBytes
) { 
 583             /* Make result->key point to the extraBytes we allocated. */ 
 584             result
->key 
= ((char*)result
) + sizeof(*result
); 
 586         if (key_class
->init
) { 
 588                         status 
= key_class
->init(result
, keyData
, keyDataLength
, encoding
); 
 590                                 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
); 
 599 static SecKeyAlgorithm 
SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) { 
 600     switch (SecKeyGetAlgorithmIdentifier(key
)) { 
 601         case kSecRSAAlgorithmID
: 
 603                 case kSecPaddingNone
: 
 604                     return kSecKeyAlgorithmRSASignatureRaw
; 
 605                 case kSecPaddingPKCS1
: 
 606                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
; 
 608                 case kSecPaddingPKCS1SHA1
: 
 609                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
; 
 610                 case kSecPaddingPKCS1SHA224
: 
 611                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
; 
 612                 case kSecPaddingPKCS1SHA256
: 
 613                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
; 
 614                 case kSecPaddingPKCS1SHA384
: 
 615                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
; 
 616                 case kSecPaddingPKCS1SHA512
: 
 617                     return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
; 
 619                     // On CSSM-based implementation, these functions actually did hash its input, 
 620                     // so keep doing that for backward compatibility. 
 621                 case kSecPaddingPKCS1SHA1
: 
 622                     return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
; 
 623                 case kSecPaddingPKCS1SHA224
: 
 624                     return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
; 
 625                 case kSecPaddingPKCS1SHA256
: 
 626                     return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
; 
 627                 case kSecPaddingPKCS1SHA384
: 
 628                     return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
; 
 629                 case kSecPaddingPKCS1SHA512
: 
 630                     return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
; 
 635         case kSecECDSAAlgorithmID
: 
 637                 case kSecPaddingSigRaw
: 
 638                     return kSecKeyAlgorithmECDSASignatureRFC4754
; 
 640                     // Although it is not very logical, previous SecECKey implementation really considered 
 641                     // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour 
 642                     // for backward compatibility. 
 643                     return kSecKeyAlgorithmECDSASignatureDigestX962
; 
 650 // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments 
 651 // used by legacy RawSign-style functions. 
 652 static OSStatus 
SecKeyPerformLegacyOperation(SecKeyRef key
, 
 653                                              const uint8_t *in1Ptr
, size_t in1Len
, 
 654                                              const uint8_t *in2Ptr
, size_t in2Len
, 
 655                                              uint8_t *outPtr
, size_t *outLen
, 
 656                                              CFTypeRef (^operation
)(CFDataRef in1
, CFDataRef in2
, CFRange 
*resultRange
, CFErrorRef 
*error
)) { 
 657     CFErrorRef error 
= NULL
; 
 658     OSStatus status 
= errSecSuccess
; 
 659     CFDataRef in1 
= CFDataCreateWithBytesNoCopy(NULL
, in1Ptr
, in1Len
, kCFAllocatorNull
); 
 660     CFDataRef in2 
= CFDataCreateWithBytesNoCopy(NULL
, in2Ptr
, in2Len
, kCFAllocatorNull
); 
 661     CFRange range 
= { 0, -1 }; 
 662     CFTypeRef output 
= operation(in1
, in2
, &range
, &error
); 
 663     require_quiet(output
, out
); 
 664     if (CFGetTypeID(output
) == CFDataGetTypeID() && outLen 
!= NULL
) { 
 665         if (range
.length 
== -1) { 
 666             range
.length 
= CFDataGetLength(output
); 
 668         require_action_quiet((size_t)range
.length 
<= *outLen
, out
, 
 669                              SecError(errSecParam
, &error
, CFSTR("buffer too small"))); 
 670         *outLen 
= range
.length
; 
 671         CFDataGetBytes(output
, range
, outPtr
); 
 677     CFReleaseSafe(output
); 
 679         status 
= SecErrorGetOSStatus(error
); 
 680         if (status 
== errSecVerifyFailed
) { 
 681             // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed. 
 682             status 
= errSSLCrypto
; 
 689 OSStatus 
SecKeyRawSign( 
 690                        SecKeyRef           key
,            /* Private key */ 
 691                        SecPadding          padding
,             /* kSecPaddingNone or kSecPaddingPKCS1 */ 
 692                        const uint8_t       *dataToSign
, /* signature over this data */ 
 693                        size_t              dataToSignLen
,       /* length of dataToSign */ 
 694                        uint8_t             *sig
,                        /* signature, RETURNED */ 
 695                        size_t              *sigLen
) {           /* IN/OUT */ 
 696     SecKeyAlgorithm algorithm 
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
); 
 697     if (algorithm 
== NULL
) { 
 700     return SecKeyPerformLegacyOperation(key
, dataToSign
, dataToSignLen
, NULL
, 0, sig
, sigLen
, 
 701                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 702                                             return SecKeyCreateSignature(key
, algorithm
, in1
, error
); 
 706 OSStatus 
SecKeyRawVerify( 
 707                          SecKeyRef           key
,            /* Public key */ 
 708                          SecPadding          padding
,           /* kSecPaddingNone or kSecPaddingPKCS1 */ 
 709                          const uint8_t       *signedData
,       /* signature over this data */ 
 710                          size_t              signedDataLen
,     /* length of dataToSign */ 
 711                          const uint8_t       *sig
,                      /* signature */ 
 712                          size_t              sigLen
) {          /* length of signature */ 
 713     SecKeyAlgorithm algorithm 
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
); 
 714     if (algorithm 
== NULL
) { 
 717     OSStatus status 
= SecKeyPerformLegacyOperation(key
, signedData
, signedDataLen
, sig
, sigLen
, NULL
, NULL
, 
 718                                                    ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 719                                                        return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) 
 720                                                        ? kCFBooleanTrue 
: NULL
; 
 725 static SecKeyAlgorithm 
SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) { 
 726     switch (SecKeyGetAlgorithmIdentifier(key
)) { 
 727         case kSecRSAAlgorithmID
: 
 729                 case kSecPaddingNone
: 
 730                     return kSecKeyAlgorithmRSAEncryptionRaw
; 
 731                 case kSecPaddingPKCS1
: 
 732                     return kSecKeyAlgorithmRSAEncryptionPKCS1
; 
 733                 case kSecPaddingOAEP
: 
 734                     return kSecKeyAlgorithmRSAEncryptionOAEPSHA1
; 
 743 OSStatus 
SecKeyEncrypt( 
 744                        SecKeyRef           key
,                /* Public key */ 
 745                        SecPadding          padding
,                     /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ 
 746                        const uint8_t            *plainText
, 
 747                        size_t              plainTextLen
,                /* length of plainText */ 
 749                        size_t              *cipherTextLen
) {    /* IN/OUT */ 
 750     SecKeyAlgorithm algorithm 
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
); 
 751     if (algorithm 
== NULL
) { 
 755     return SecKeyPerformLegacyOperation(key
, plainText
, plainTextLen
, NULL
, 0, cipherText
, cipherTextLen
, 
 756                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 757                                             return SecKeyCreateEncryptedData(key
, algorithm
, in1
, error
); 
 761 OSStatus 
SecKeyDecrypt( 
 762                        SecKeyRef           key
,                /* Private key */ 
 763                        SecPadding          padding
,                     /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ 
 764                        const uint8_t       *cipherText
, 
 765                        size_t              cipherTextLen
,               /* length of cipherText */ 
 767                        size_t              *plainTextLen
) {     /* IN/OUT */ 
 768     SecKeyAlgorithm algorithm 
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
); 
 769     if (algorithm 
== NULL
) { 
 772     return SecKeyPerformLegacyOperation(key
, cipherText
, cipherTextLen
, NULL
, 0, plainText
, plainTextLen
, 
 773                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 774                                             CFDataRef decrypted 
= SecKeyCreateDecryptedData(key
, algorithm
, in1
, error
); 
 776                                             if (decrypted 
!= NULL 
&& algorithm 
== kSecKeyAlgorithmRSAEncryptionRaw 
&& 
 777                                                 *(data 
= CFDataGetBytePtr(decrypted
)) == 0x00) { 
 778                                                 // Strip zero-padding from the beginning of the block, as the contract of this 
 780                                                 range
->length 
= CFDataGetLength(decrypted
); 
 781                                                 while (*data 
== 0x00 && range
->length 
> 0) { 
 791 size_t SecKeyGetBlockSize(SecKeyRef key
) { 
 792     if (key
->key_class
->blockSize
) 
 793         return key
->key_class
->blockSize(key
); 
 797 /* Private API functions. */ 
 799 CFDictionaryRef 
SecKeyCopyAttributeDictionary(SecKeyRef key
) { 
 800     return SecKeyCopyAttributes(key
); 
 803 SecKeyRef 
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) { 
 804     CFErrorRef error 
= NULL
; 
 805     SecKeyRef key 
= SecKeyCreateWithData(CFDictionaryGetValue(refAttributes
, kSecValueData
), refAttributes
, &error
); 
 807         CFStringRef description 
= CFErrorCopyDescription(error
); 
 808         secwarning("%@", description
); 
 809         CFRelease(description
); 
 815 static SecKeyAlgorithm 
SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key
, const SecAsn1AlgId 
*algId
, bool digestData
) { 
 816     static const struct TableItem 
{ 
 817         const SecAsn1Oid 
*oid1
, *oid2
; 
 818         const SecKeyAlgorithm 
*algorithms
[2]; 
 819     } translationTableRSA
[] = { 
 820         { &CSSMOID_SHA1WithRSA
, &CSSMOID_SHA1
, { 
 821             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
, 
 822             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
, 
 824         { &CSSMOID_SHA224WithRSA
, &CSSMOID_SHA224
, { 
 825             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
, 
 826             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
, 
 828         { &CSSMOID_SHA256WithRSA
, &CSSMOID_SHA256
, { 
 829             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
, 
 830             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
, 
 832         { &CSSMOID_SHA384WithRSA
, &CSSMOID_SHA384
, { 
 833             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
, 
 834             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
, 
 836         { &CSSMOID_SHA512WithRSA
, &CSSMOID_SHA512
, { 
 837             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
, 
 838             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
, 
 840         { &CSSMOID_MD5
, NULL
, { 
 841             [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
, 
 842             [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
, 
 845     }, translationTableECDSA
[] = { 
 846         { &CSSMOID_ECDSA_WithSHA1
, &CSSMOID_SHA1
, { 
 847             [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
, 
 848             [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1
, 
 850         { &CSSMOID_ECDSA_WithSHA224
, &CSSMOID_SHA224
, { 
 851             [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
, 
 852             [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224
, 
 854         { &CSSMOID_ECDSA_WithSHA256
, &CSSMOID_SHA256
, { 
 855             [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
, 
 856             [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256
, 
 858         { &CSSMOID_ECDSA_WithSHA384
, &CSSMOID_SHA384
, { 
 859             [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
, 
 860             [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384
, 
 862         { &CSSMOID_ECDSA_WithSHA512
, &CSSMOID_SHA512
, { 
 863             [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
, 
 864             [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512
, 
 869     const struct TableItem 
*table
; 
 870     switch (SecKeyGetAlgorithmIdentifier(key
)) { 
 871         case kSecRSAAlgorithmID
: 
 872             table 
= translationTableRSA
; 
 874         case kSecECDSAAlgorithmID
: 
 875             table 
= translationTableECDSA
; 
 881     for (; table
->oid1 
!= NULL
; table
++) { 
 882         if (SecAsn1OidCompare(table
->oid1
, &algId
->algorithm
) || 
 883             (table
->oid2 
!= NULL 
&& SecAsn1OidCompare(table
->oid2
, &algId
->algorithm
))) { 
 884             return *table
->algorithms
[digestData
]; 
 890 OSStatus 
SecKeyDigestAndVerify( 
 891                                SecKeyRef           key
,            /* Private key */ 
 892                                const SecAsn1AlgId  
*algId
,         /* algorithm oid/params */ 
 893                                const uint8_t       *dataToDigest
,       /* signature over this data */ 
 894                                size_t              dataToDigestLen
,/* length of dataToDigest */ 
 895                                const uint8_t       *sig
,                        /* signature to verify */ 
 896                                size_t              sigLen
) {            /* length of sig */ 
 898     SecKeyAlgorithm algorithm 
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true); 
 899     if (algorithm 
== NULL
) { 
 900         return errSecUnimplemented
; 
 903     return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, sig
, sigLen
, NULL
, NULL
, 
 904                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 905                                             return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ? 
 906                                             kCFBooleanTrue 
: NULL
; 
 910 OSStatus 
SecKeyDigestAndSign( 
 911                              SecKeyRef           key
,            /* Private key */ 
 912                              const SecAsn1AlgId  
*algId
,         /* algorithm oid/params */ 
 913                              const uint8_t       *dataToDigest
, /* signature over this data */ 
 914                              size_t              dataToDigestLen
,/* length of dataToDigest */ 
 915                              uint8_t             *sig
,                  /* signature, RETURNED */ 
 916                              size_t              *sigLen
) {             /* IN/OUT */ 
 917     SecKeyAlgorithm algorithm 
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true); 
 918     if (algorithm 
== NULL
) { 
 919         return errSecUnimplemented
; 
 922     return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, NULL
, 0, sig
, sigLen
, 
 923                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 924                                             return SecKeyCreateSignature(key
, algorithm
, in1
, error
); 
 928 OSStatus 
SecKeyVerifyDigest( 
 929                             SecKeyRef           key
,            /* Private key */ 
 930                             const SecAsn1AlgId  
*algId
,         /* algorithm oid/params */ 
 931                             const uint8_t       *digestData
,    /* signature over this digest */ 
 932                             size_t              digestDataLen
,/* length of dataToDigest */ 
 933                             const uint8_t       *sig
,                   /* signature to verify */ 
 934                             size_t              sigLen
) {               /* length of sig */ 
 935     SecKeyAlgorithm algorithm 
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false); 
 936     if (algorithm 
== NULL
) { 
 937         return errSecUnimplemented
; 
 940     return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, sig
, sigLen
, NULL
, NULL
, 
 941                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 942                                             return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ? 
 943                                             kCFBooleanTrue 
: NULL
; 
 947 OSStatus 
SecKeySignDigest( 
 948                           SecKeyRef           key
,            /* Private key */ 
 949                           const SecAsn1AlgId  
*algId
,         /* algorithm oid/params */ 
 950                           const uint8_t       *digestData
,      /* signature over this digest */ 
 951                           size_t              digestDataLen
,/* length of digestData */ 
 952                           uint8_t             *sig
,                     /* signature, RETURNED */ 
 953                           size_t              *sigLen
) {                /* IN/OUT */ 
 954     SecKeyAlgorithm algorithm 
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false); 
 955     if (algorithm 
== NULL
) { 
 956         return errSecUnimplemented
; 
 959     return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, NULL
, 0, sig
, sigLen
, 
 960                                         ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange 
*range
, CFErrorRef 
*error
) { 
 961                                             return SecKeyCreateSignature(key
, algorithm
, in1
, error
); 
 965 CFIndex 
SecKeyGetAlgorithmId(SecKeyRef key
) { 
 966         return SecKeyGetAlgorithmIdentifier(key
); 
 969 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) 
 970 /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments, 
 971    with output in the second argument). Therefore, avoid implementing this function here 
 972    if compiling for OS X. 
 975 CFIndex 
SecKeyGetAlgorithmID(SecKeyRef key
) { 
 976         return SecKeyGetAlgorithmIdentifier(key
); 
 980 OSStatus 
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) { 
 981     if (key
->key_class
->version 
> 1 && key
->key_class
->copyPublic
) 
 982         return key
->key_class
->copyPublic(key
, serializedPublic
); 
 983     return errSecUnimplemented
; 
 986 SecKeyRef 
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
) 
 990         case kSecRSAAlgorithmID
: 
 991             return SecKeyCreateRSAPublicKey(allocator
, 
 992                                             keyData
, keyDataLength
, 
 993                                             kSecKeyEncodingBytes
); 
 994         case kSecECDSAAlgorithmID
: 
 995             return SecKeyCreateECPublicKey(allocator
, 
 996                                            keyData
, keyDataLength
, 
 997                                            kSecKeyEncodingBytes
); 
1003 SecKeyRef 
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
) 
1005     return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
)); 
1008 // This is a bit icky hack to avoid changing the vtable for 
1010 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
) 
1012     size_t result 
= SecKeyGetBlockSize(key
); 
1014     if (kSecECDSAAlgorithmID 
== SecKeyGetAlgorithmIdentifier(key
)) { 
1015         switch (whichSize
) { 
1016             case kSecKeyEncryptedDataSize
: 
1019             case kSecKeySignatureSize
: 
1020                 result 
= (result 
>= 66 ? 9 : 8) + 2 * result
; 
1022             case kSecKeyKeySizeInBits
: 
1028     if (whichSize 
== kSecKeyKeySizeInBits
) 
1035 OSStatus 
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
) 
1037     CFDictionaryRef query 
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, 
1038                                                          kSecReturnRef
,             kCFBooleanTrue
, 
1039                                                          kSecClass
,                 kSecClassKey
, 
1040                                                          kSecValuePersistentRef
,    persistentRef
, 
1042     CFTypeRef foundRef 
= NULL
; 
1043     OSStatus status 
= SecItemCopyMatching(query
, &foundRef
); 
1045     if (status 
== errSecSuccess
) { 
1046         if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) { 
1047             *lookedUpData 
= (SecKeyRef
) foundRef
; 
1049             status 
= errSecSuccess
; 
1051             status 
= errSecItemNotFound
; 
1055     CFReleaseSafe(foundRef
); 
1056     CFReleaseSafe(query
); 
1061 OSStatus 
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
) 
1064         secerror("SecKeyCopyPersistentRef: Need a key reference for this to work"); 
1067     if (!persistentRef
) { 
1068         secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work"); 
1072     CFDictionaryRef query 
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, 
1073                                                          kSecReturnPersistentRef
,   kCFBooleanTrue
, 
1075                                                          kSecAttrSynchronizable
,    kSecAttrSynchronizableAny
, 
1077     CFTypeRef foundRef 
= NULL
; 
1078     OSStatus status 
= SecItemCopyMatching(query
, &foundRef
); 
1080     if (status 
== errSecSuccess
) { 
1081         if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) { 
1082             *persistentRef 
= foundRef
; 
1085             secerror("SecKeyCopyPersistentRef: SecItemCopyMatching returned success, but we got type %lu instead of CFData for key %@.", CFGetTypeID(foundRef
), key
); 
1086             status 
= errSecItemNotFound
; 
1089         secerror("SecKeyCopyPersistentRef: received status %i for key %@", (int)status
, key
); 
1090         CFStringRef str 
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Expected to find persistentref for key %@"), key
); 
1091         __security_stackshotreport(str
, (int)status
); 
1095     CFReleaseSafe(foundRef
); 
1096     CFReleaseSafe(query
); 
1105 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); 
1107 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg"); 
1108 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint"); 
1109 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg"); 
1110 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags"); 
1111 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128"); 
1112 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256"); 
1114 #undef SEC_CONST_DECL 
1117 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef 
*outParam
, CFErrorRef 
*error
) 
1123     if (key
->key_class
->version 
> 2 && key
->key_class
->copyWrapKey
) 
1124         return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
); 
1125     SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
); 
1130 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef 
*outParam
, CFErrorRef 
*error
) 
1136     if (key
->key_class
->version 
> 2 && key
->key_class
->copyUnwrapKey
) 
1137         return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
); 
1139     SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
); 
1143 static CFIndex 
SecKeyParamsGetCFIndex(CFTypeRef value
, CFStringRef errName
, CFErrorRef 
*error
) { 
1144     CFIndex result 
= -1; 
1145     CFNumberRef localValue 
= NULL
; 
1147     if (isString(value
)) { 
1148         CFNumberFormatterRef formatter 
= CFNumberFormatterCreate(kCFAllocatorDefault
, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle
); 
1149         localValue 
= CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault
, formatter
, value
, NULL
, kCFNumberFormatterParseIntegersOnly
); 
1150         CFReleaseSafe(formatter
); 
1153             CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue
); 
1154             if (CFEqual(t
, value
)) { 
1161     if (value 
!= NULL 
&& CFGetTypeID(value
) == CFNumberGetTypeID()) { 
1162         if (!CFNumberGetValue(value
, kCFNumberCFIndexType
, &result
) || result 
< 0) { 
1163             SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
); 
1166         SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
); 
1169     CFReleaseSafe(localValue
); 
1173 SecKeyRef 
SecKeyCreateWithData(CFDataRef keyData
, CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1175     SecKeyRef key 
= NULL
; 
1176     CFAllocatorRef allocator 
= NULL
; 
1178     if (CFDictionaryGetValue(parameters
, kSecAttrTokenID
) != NULL
) { 
1179         return SecKeyCreateCTKKey(allocator
, parameters
, error
); 
1181     else if (!keyData
) { 
1182         SecError(errSecParam
, error
, CFSTR("Failed to provide key data to SecKeyCreateWithData")); 
1185     /* First figure out the key type (algorithm). */ 
1186     CFIndex algorithm
, class; 
1187     CFTypeRef ktype 
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
); 
1188     require_quiet((algorithm 
= SecKeyParamsGetCFIndex(ktype
, CFSTR("key type"), error
)) >= 0, out
); 
1189     CFTypeRef kclass 
= CFDictionaryGetValue(parameters
, kSecAttrKeyClass
); 
1190     require_quiet((class = SecKeyParamsGetCFIndex(kclass
, CFSTR("key class"), error
)) >= 0, out
); 
1193         case 0: // kSecAttrKeyClassPublic 
1194             switch (algorithm
) { 
1195                 case 42: // kSecAlgorithmRSA 
1196                     key 
= SecKeyCreateRSAPublicKey(allocator
, 
1197                                                    CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
), 
1198                                                    kSecKeyEncodingBytes
); 
1200                         SecError(errSecParam
, error
, CFSTR("RSA public key creation from data failed")); 
1203                 case 43: // kSecAlgorithmECDSA 
1204                 case 73: // kSecAlgorithmEC 
1205                     key 
= SecKeyCreateECPublicKey(allocator
, 
1206                                                   CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
), 
1207                                                   kSecKeyEncodingBytes
); 
1209                         SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed")); 
1213                     SecError(errSecParam
, error
, CFSTR("Unsupported public key type: %@"), ktype
); 
1217         case 1: // kSecAttrKeyClassPrivate 
1218             switch (algorithm
) { 
1219                 case 42: // kSecAlgorithmRSA 
1220                     key 
= SecKeyCreateRSAPrivateKey(allocator
, 
1221                                                     CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
), 
1222                                                     kSecKeyEncodingBytes
); 
1224                         SecError(errSecParam
, error
, CFSTR("RSA private key creation from data failed")); 
1227                 case 43: // kSecAlgorithmECDSA 
1228                 case 73: // kSecAlgorithmEC 
1229                     key 
= SecKeyCreateECPrivateKey(allocator
, 
1230                                                    CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
), 
1231                                                    kSecKeyEncodingBytes
); 
1233                         SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed")); 
1237                     SecError(errSecParam
, error
, CFSTR("Unsupported private key type: %@"), ktype
); 
1241         case 2: // kSecAttrKeyClassSymmetric 
1242             SecError(errSecUnimplemented
, error
, CFSTR("Unsupported symmetric key type: %@"), ktype
); 
1245             SecError(errSecParam
, error
, CFSTR("Unsupported key class: %@"), kclass
); 
1253 // Similar to CFErrorPropagate, but does not consult input value of *error, it can contain any garbage and if overwritten, previous value is never released. 
1254 static inline bool SecKeyErrorPropagate(bool succeeded
, CFErrorRef possibleError CF_CONSUMED
, CFErrorRef 
*error
) { 
1259             *error 
= possibleError
; 
1261             CFRelease(possibleError
); 
1267 CFDataRef 
SecKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef 
*error
) { 
1268     if (!key
->key_class
->copyExternalRepresentation
) { 
1269         if (error 
!= NULL
) { 
1272         SecError(errSecUnimplemented
, error
, CFSTR("export not implemented for key %@"), key
); 
1276     CFErrorRef localError 
= NULL
; 
1277     CFDataRef result 
= key
->key_class
->copyExternalRepresentation(key
, &localError
); 
1278     SecKeyErrorPropagate(result 
!= NULL
, localError
, error
); 
1282 CFDictionaryRef 
SecKeyCopyAttributes(SecKeyRef key
) { 
1283     if (key
->key_class
->copyDictionary
) { 
1284         return key
->key_class
->copyDictionary(key
); 
1286         // Create dictionary with basic values derived from other known information of the key. 
1287         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
); 
1288         CFIndex blockSize 
= SecKeyGetBlockSize(key
) * 8; 
1289         if (blockSize 
> 0) { 
1290             CFNumberRef blockSizeRef 
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &blockSize
); 
1291             CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, blockSizeRef
); 
1292             CFRelease(blockSizeRef
); 
1295         switch (SecKeyGetAlgorithmIdentifier(key
)) { 
1296             case kSecRSAAlgorithmID
: 
1297                 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
); 
1299             case kSecECDSAAlgorithmID
: 
1300                 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECSECPrimeRandom
); 
1304         if (key
->key_class
->rawSign 
!= NULL 
|| key
->key_class
->decrypt 
!= NULL
) { 
1305             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
); 
1306         } else if (key
->key_class
->rawVerify 
!= NULL 
|| key
->key_class
->encrypt 
!= NULL
) { 
1307             CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
); 
1314 SecKeyRef 
SecKeyCopyPublicKey(SecKeyRef key
) { 
1315     SecKeyRef result 
= NULL
; 
1316     if (key
->key_class
->version 
>= 4 && key
->key_class
->copyPublicKey
) { 
1317         result 
= key
->key_class
->copyPublicKey(key
); 
1318         if (result 
!= NULL
) { 
1323     CFDataRef serializedPublic 
= NULL
; 
1325     require_noerr_quiet(SecKeyCopyPublicBytes(key
, &serializedPublic
), fail
); 
1326     require_quiet(serializedPublic
, fail
); 
1328     result 
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmIdentifier(key
), serializedPublic
); 
1331     CFReleaseSafe(serializedPublic
); 
1335 SecKeyRef 
SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1336     SecKeyRef privKey 
= NULL
, pubKey 
= NULL
; 
1337     OSStatus status 
= SecKeyGeneratePair(parameters
, &pubKey
, &privKey
); 
1338     if (status 
!= errSecSuccess
) { 
1339         if (error 
!= NULL
) { 
1342         SecError(status
, error
, CFSTR("Key generation failed, error %d"), (int)status
); 
1344     CFReleaseSafe(pubKey
); 
1348 SecKeyRef 
SecKeyCreateDuplicate(SecKeyRef key
) { 
1349     if (key
->key_class
->version 
>= 4 && key
->key_class
->createDuplicate
) { 
1350         return key
->key_class
->createDuplicate(key
); 
1352         return (SecKeyRef
)CFRetain(key
); 
1356 Boolean 
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef 
*error
) { 
1357     if (key
->key_class
->version 
>= 4 && key
->key_class
->setParameter
) { 
1358         CFErrorRef localError 
= NULL
; 
1359         Boolean result 
= key
->key_class
->setParameter(key
, name
, value
, &localError
); 
1360         SecKeyErrorPropagate(result
, localError
, error
); 
1363         if (error 
!= NULL
) { 
1366         return SecError(errSecUnimplemented
, error
, CFSTR("setParameter not implemented for %@"), key
); 
1370 #pragma mark Generic algorithm adaptor lookup and invocation 
1372 static CFTypeRef 
SecKeyCopyBackendOperationResult(SecKeyOperationContext 
*context
, SecKeyAlgorithm algorithm
, 
1373                                                   CFTypeRef in1
, CFTypeRef in2
, CFErrorRef 
*error
) { 
1374     CFTypeRef result 
= kCFNull
; 
1375     assert(CFArrayGetCount(context
->algorithm
) > 0); 
1376     if (context
->key
->key_class
->version 
>= 4 && context
->key
->key_class
->copyOperationResult 
!= NULL
) { 
1377         return context
->key
->key_class
->copyOperationResult(context
->key
, context
->operation
, algorithm
, 
1378                                                             context
->algorithm
, context
->mode
, in1
, in2
, error
); 
1381     // Mapping from algorithms to legacy SecPadding values. 
1382     static const struct { 
1383         const SecKeyAlgorithm 
*algorithm
; 
1387         { &kSecKeyAlgorithmRSASignatureRaw
, kSecRSAAlgorithmID
, kSecPaddingNone 
}, 
1388         { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
, kSecRSAAlgorithmID
, kSecPaddingPKCS1 
}, 
1389         { &kSecKeyAlgorithmECDSASignatureRFC4754
, kSecECDSAAlgorithmID
, kSecPaddingSigRaw 
}, 
1390         { &kSecKeyAlgorithmECDSASignatureDigestX962
, kSecECDSAAlgorithmID
, kSecPaddingPKCS1 
}, 
1391         { &kSecKeyAlgorithmRSAEncryptionRaw
, kSecRSAAlgorithmID
, kSecPaddingNone 
}, 
1392         { &kSecKeyAlgorithmRSAEncryptionPKCS1
, kSecRSAAlgorithmID
, kSecPaddingPKCS1 
}, 
1393         { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1
, kSecRSAAlgorithmID
, kSecPaddingOAEP 
}, 
1395     SecPadding padding 
= (SecPadding
)-1; 
1396     CFIndex keyAlg 
= SecKeyGetAlgorithmIdentifier(context
->key
); 
1397     for (size_t i 
= 0; i 
< array_size(paddingMap
); ++i
) { 
1398         if (keyAlg 
== paddingMap
[i
].keyAlg 
&& CFEqual(algorithm
, *paddingMap
[i
].algorithm
)) { 
1399             padding 
= paddingMap
[i
].padding
; 
1403     require_quiet(padding 
!= (SecPadding
)-1, out
); 
1405     // Check legacy virtual table entries. 
1407     OSStatus status 
= errSecSuccess
; 
1408     switch (context
->operation
) { 
1409         case kSecKeyOperationTypeSign
: 
1410             if (context
->key
->key_class
->rawSign 
!= NULL
) { 
1411                 result 
= kCFBooleanTrue
; 
1412                 if (context
->mode 
== kSecKeyOperationModePerform
) { 
1413                     size 
= SecKeyGetSize(context
->key
, kSecKeySignatureSize
); 
1414                     result 
= CFDataCreateMutableWithScratch(NULL
, size
); 
1415                     status 
= context
->key
->key_class
->rawSign(context
->key
, padding
, 
1416                                                               CFDataGetBytePtr(in1
), CFDataGetLength(in1
), 
1417                                                               CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
); 
1421         case kSecKeyOperationTypeVerify
: 
1422             if (context
->key
->key_class
->rawVerify 
!= NULL
) { 
1423                 result 
= kCFBooleanTrue
; 
1424                 if (context
->mode 
== kSecKeyOperationModePerform
) { 
1425                     status 
= context
->key
->key_class
->rawVerify(context
->key
, padding
, 
1426                                                                 CFDataGetBytePtr(in1
), CFDataGetLength(in1
), 
1427                                                                 CFDataGetBytePtr(in2
), CFDataGetLength(in2
)); 
1431         case kSecKeyOperationTypeEncrypt
: 
1432             if (context
->key
->key_class
->encrypt 
!= NULL
) { 
1433                 result 
= kCFBooleanTrue
; 
1434                 if (context
->mode 
== kSecKeyOperationModePerform
) { 
1435                     size 
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
); 
1436                     result 
= CFDataCreateMutableWithScratch(NULL
, size
); 
1437                     status 
= context
->key
->key_class
->encrypt(context
->key
, padding
, 
1438                                                               CFDataGetBytePtr(in1
), CFDataGetLength(in1
), 
1439                                                               CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
); 
1443         case kSecKeyOperationTypeDecrypt
: 
1444             if (context
->key
->key_class
->decrypt 
!= NULL
) { 
1445                 result 
= kCFBooleanTrue
; 
1446                 if (context
->mode 
== kSecKeyOperationModePerform
) { 
1447                     size 
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
); 
1448                     result 
= CFDataCreateMutableWithScratch(NULL
, size
); 
1449                     status 
= context
->key
->key_class
->decrypt(context
->key
, padding
, 
1450                                                               CFDataGetBytePtr(in1
), CFDataGetLength(in1
), 
1451                                                               CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
); 
1459     if (status 
== errSecSuccess
) { 
1460         if (CFGetTypeID(result
) == CFDataGetTypeID()) { 
1461             CFDataSetLength((CFMutableDataRef
)result
, size
); 
1464         SecError(status
, error
, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context
->operation
, (int)padding
); 
1465         CFReleaseNull(result
); 
1472 CFTypeRef 
SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext 
*context
, CFTypeRef in1
, CFTypeRef in2
, CFErrorRef 
*error
) { 
1474     // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error. 
1475     CFIndex algorithmCount 
= CFArrayGetCount(context
->algorithm
); 
1476     for (CFIndex index 
= 0; index 
< algorithmCount 
- 1; index
++) { 
1477         SecKeyAlgorithm indexAlgorithm 
= CFArrayGetValueAtIndex(context
->algorithm
, index
); 
1478         for (CFIndex tested 
= index 
+ 1; tested 
< algorithmCount
; tested
++) { 
1479             require_quiet(!CFEqual(indexAlgorithm
, CFArrayGetValueAtIndex(context
->algorithm
, tested
)), fail
); 
1483     SecKeyAlgorithm algorithm 
= CFArrayGetValueAtIndex(context
->algorithm
, algorithmCount 
- 1); 
1484     CFTypeRef output 
= SecKeyCopyBackendOperationResult(context
, algorithm
, in1
, in2
, error
); 
1485     if (output 
!= kCFNull
) { 
1486         // Backend handled the operation, return result. 
1490     // To silence static analyzer. 
1491     CFReleaseSafe(output
); 
1493     // Get adaptor which is able to handle requested algorithm. 
1494     SecKeyAlgorithmAdaptor adaptor 
= SecKeyGetAlgorithmAdaptor(context
->operation
, algorithm
); 
1495     require_quiet(adaptor 
!= NULL
, fail
); 
1497     // Invoke the adaptor and return result. 
1498     CFTypeRef result 
= adaptor(context
, in1
, in2
, error
); 
1499     require_quiet(result 
!= kCFNull
, fail
); 
1503     if (context
->mode 
== kSecKeyOperationModePerform
) { 
1504         SecError(errSecParam
, error
, CFSTR("%@: algorithm not supported by the key %@"), 
1505                  CFArrayGetValueAtIndex(context
->algorithm
, 0), context
->key
); 
1512 #pragma mark Algorithm-related SecKey API entry points 
1514 static CFMutableArrayRef 
SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm
) { 
1515     CFMutableArrayRef result 
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
); 
1516     CFArrayAppendValue(result
, algorithm
); 
1520 CFDataRef 
SecKeyCreateSignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef dataToSign
, CFErrorRef 
*error
) { 
1521     CFErrorRef localError 
= NULL
; 
1522     SecKeyOperationContext context 
= { key
, kSecKeyOperationTypeSign
, SecKeyCreateAlgorithmArray(algorithm
) }; 
1523     CFDataRef result 
= SecKeyRunAlgorithmAndCopyResult(&context
, dataToSign
, NULL
, &localError
); 
1524     SecKeyOperationContextDestroy(&context
); 
1525     SecKeyErrorPropagate(result 
!= NULL
, localError
, error
); 
1529 Boolean 
SecKeyVerifySignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef signedData
, CFDataRef signature
, 
1530                               CFErrorRef 
*error
) { 
1531     CFErrorRef localError 
= NULL
; 
1532     SecKeyOperationContext context 
= { key
, kSecKeyOperationTypeVerify
, SecKeyCreateAlgorithmArray(algorithm
) }; 
1533     CFTypeRef res 
= SecKeyRunAlgorithmAndCopyResult(&context
, signedData
, signature
, &localError
); 
1534     Boolean result 
= CFEqualSafe(res
, kCFBooleanTrue
); 
1536     SecKeyOperationContextDestroy(&context
); 
1537     SecKeyErrorPropagate(result
, localError
, error
); 
1541 CFDataRef 
SecKeyCreateEncryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plainText
, CFErrorRef 
*error
) { 
1542     CFErrorRef localError 
= NULL
; 
1543     SecKeyOperationContext context 
= { key
, kSecKeyOperationTypeEncrypt
, SecKeyCreateAlgorithmArray(algorithm
) }; 
1544     CFDataRef result 
= SecKeyRunAlgorithmAndCopyResult(&context
, plainText
, NULL
, &localError
); 
1545     SecKeyOperationContextDestroy(&context
); 
1546     SecKeyErrorPropagate(result
, localError
, error
); 
1550 CFDataRef 
SecKeyCreateDecryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef cipherText
, CFErrorRef 
*error
) { 
1551     SecKeyOperationContext context 
= { key
, kSecKeyOperationTypeDecrypt
, SecKeyCreateAlgorithmArray(algorithm
) }; 
1552     CFDataRef result 
= SecKeyRunAlgorithmAndCopyResult(&context
, cipherText
, NULL
, error
); 
1553     SecKeyOperationContextDestroy(&context
); 
1557 CFDataRef 
SecKeyCopyKeyExchangeResult(SecKeyRef key
, SecKeyAlgorithm algorithm
, SecKeyRef publicKey
, 
1558                                       CFDictionaryRef parameters
, CFErrorRef 
*error
) { 
1559     CFErrorRef localError 
= NULL
; 
1560     CFDataRef publicKeyData 
= NULL
, result 
= NULL
; 
1561     SecKeyOperationContext context 
= { key
, kSecKeyOperationTypeKeyExchange
, SecKeyCreateAlgorithmArray(algorithm
) }; 
1562     require_quiet(publicKeyData 
= SecKeyCopyExternalRepresentation(publicKey
, error
), out
); 
1563     result 
= SecKeyRunAlgorithmAndCopyResult(&context
, publicKeyData
, parameters
, &localError
); 
1564     SecKeyErrorPropagate(result 
!= NULL
, localError
, error
); 
1567     CFReleaseSafe(publicKeyData
); 
1568     SecKeyOperationContextDestroy(&context
); 
1572 Boolean 
SecKeyIsAlgorithmSupported(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
) { 
1573     SecKeyOperationContext context 
= { key
, operation
, SecKeyCreateAlgorithmArray(algorithm
), kSecKeyOperationModeCheckIfSupported 
}; 
1574     CFErrorRef error 
= NULL
; 
1575     CFTypeRef res 
= SecKeyRunAlgorithmAndCopyResult(&context
, NULL
, NULL
, &error
); 
1576     Boolean result 
= CFEqualSafe(res
, kCFBooleanTrue
); 
1578     CFReleaseSafe(error
); 
1579     SecKeyOperationContextDestroy(&context
);