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>
34 #include <Security/SecCertificate.h>
36 #include <utilities/SecIOFormat.h>
38 #include <utilities/SecCFWrappers.h>
39 #include <utilities/array_size.h>
41 #include "SecKeyPriv.h"
42 #include "SecRSAKeyPriv.h"
43 #include "SecECKeyPriv.h"
44 #include "SecCTKKeyPriv.h"
45 #include "SecBasePriv.h"
47 #include <CoreFoundation/CFNumber.h>
48 #include <CoreFoundation/CFString.h>
49 #include <CoreFoundation/CFPriv.h>
52 #include <AssertMacros.h>
53 #include <utilities/debugging.h>
54 #include <utilities/SecCFError.h>
55 #include <CommonCrypto/CommonDigest.h>
56 #include <Security/SecAsn1Coder.h>
57 #include <Security/oidsalg.h>
58 #include <Security/SecInternal.h>
59 #include <Security/SecRandom.h>
60 #include <Security/SecureTransport.h> /* For error codes. */
62 #include <corecrypto/ccrng_system.h>
68 #include <libDER/asn1Types.h>
69 #include <libDER/DER_Keys.h>
70 #include <libDER/DER_Encode.h>
72 CFDataRef
SecKeyCopyPublicKeyHash(SecKeyRef key
)
74 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
76 /* encode the public key. */
77 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
78 require_quiet(pubKeyBlob
, errOut
);
80 /* Calculate the digest of the public key. */
81 require_quiet(pubKeyDigest
= SecSHA1DigestCreate(CFGetAllocator(key
),
82 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
85 CFReleaseNull(pubKeyBlob
);
92 static CFDictionaryRef
SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key
,
94 CFDataRef privateBlob
)
96 CFAllocatorRef allocator
= CFGetAllocator(key
);
98 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
99 CFDictionaryRef dict
= NULL
;
101 size_t sizeValue
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
);
102 CFNumberRef sizeInBits
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
);
104 /* encode the public key. */
105 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
106 require_quiet(pubKeyBlob
, errOut
);
108 /* Calculate the digest of the public key. */
109 require_quiet(pubKeyDigest
= SecSHA1DigestCreate(allocator
,
110 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
113 DICT_ADDPAIR(kSecClass
, kSecClassKey
);
114 DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob
? kSecAttrKeyClassPrivate
: kSecAttrKeyClassPublic
);
115 DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
);
116 DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
);
117 DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
);
118 DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
);
119 DICT_ADDPAIR(kSecAttrKeyType
, keyType
);
120 DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
);
121 DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
);
122 DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
);
123 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
);
124 DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
);
125 DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
);
126 DICT_ADDPAIR(kSecAttrCanEncrypt
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
127 DICT_ADDPAIR(kSecAttrCanDecrypt
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
128 DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
);
129 DICT_ADDPAIR(kSecAttrCanSign
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
130 DICT_ADDPAIR(kSecAttrCanVerify
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
131 DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
);
132 DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
);
133 DICT_ADDPAIR(kSecAttrCanWrap
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
134 DICT_ADDPAIR(kSecAttrCanUnwrap
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
135 DICT_ADDPAIR(kSecValueData
, privateBlob
? privateBlob
: pubKeyBlob
);
136 dict
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
139 // @@@ Zero out key material.
140 CFReleaseSafe(pubKeyDigest
);
141 CFReleaseSafe(pubKeyBlob
);
142 CFReleaseSafe(sizeInBits
);
147 CFDictionaryRef
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
,
149 CFDataRef privateBlob
)
151 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, privateBlob
);
154 CFDictionaryRef
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
)
156 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, NULL
);
159 static CFStringRef
SecKeyCopyDescription(CFTypeRef cf
) {
160 SecKeyRef key
= (SecKeyRef
)cf
;
162 if(key
->key_class
->describe
)
163 return key
->key_class
->describe(key
);
165 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
);
168 static void SecKeyDestroy(CFTypeRef cf
) {
169 SecKeyRef key
= (SecKeyRef
)cf
;
171 CFReleaseNull(key
->cdsaKey
);
173 if (key
->key_class
->destroy
)
174 key
->key_class
->destroy(key
);
177 static Boolean
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
)
179 SecKeyRef key1
= (SecKeyRef
)cf1
;
180 SecKeyRef key2
= (SecKeyRef
)cf2
;
183 if (!key2
|| key1
->key_class
!= key2
->key_class
)
185 if (key1
->key_class
->version
>= 4 && key1
->key_class
->isEqual
)
186 return key1
->key_class
->isEqual(key1
, key2
);
187 if (key1
->key_class
->extraBytes
)
188 return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
);
190 /* TODO: Won't work when we get reference keys. */
191 CFDictionaryRef d1
, d2
;
192 d1
= SecKeyCopyAttributeDictionary(key1
);
193 d2
= SecKeyCopyAttributeDictionary(key2
);
194 // Returning NULL is an error; bail out of the equality check
200 Boolean result
= CFEqual(d1
, d2
);
206 struct ccrng_state
*ccrng_seckey
;
208 CFGiblisWithFunctions(SecKey
, NULL
, NULL
, SecKeyDestroy
, SecKeyEqual
, NULL
, NULL
, SecKeyCopyDescription
, NULL
, NULL
, ^{
209 static struct ccrng_system_state ccrng_system_state_seckey
;
210 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
211 ccrng_system_init(&ccrng_system_state_seckey
);
214 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
215 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
217 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
218 return CFBooleanGetValue(value
);
220 secwarning("Value %@ for key %@ is not bool", value
, key
);
224 return default_value
;
227 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
228 CFDictionarySetValue(dict
, kSecValueRef
, item
);
229 return SecItemAdd(dict
, NULL
);
232 static void merge_params_applier(const void *key
, const void *value
,
234 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
235 CFDictionaryAddValue(result
, key
, value
);
238 /* Create a mutable dictionary that is based on the subdictionary for key
239 with any attributes from the top level dict merged in. */
240 static CF_RETURNS_RETAINED CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
242 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
243 CFMutableDictionaryRef result
;
246 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
247 /* Add everything in dict not already in result to result. */
248 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
250 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
253 /* Remove values that only belong in the top level dict. */
254 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
255 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
256 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
257 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
262 CFIndex
SecKeyGetAlgorithmId(SecKeyRef key
) {
263 if (!key
|| !key
->key_class
) {
264 // TBD: somehow, a key can be created with a NULL key_class in the
265 // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path
266 return kSecNullAlgorithmID
;
268 /* This method was added to version 1 keys. */
269 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
) {
270 return key
->key_class
->getAlgorithmID(key
);
272 /* All version 0 keys were RSA. */
273 return kSecRSAAlgorithmID
;
276 /* Generate a private/public keypair. */
277 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
278 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
279 OSStatus result
= errSecUnsupportedAlgorithm
;
280 SecKeyRef privKey
= NULL
;
281 SecKeyRef pubKey
= NULL
;
282 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
283 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
284 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
285 CFStringRef tokenID
= CFDictionaryGetValue(parameters
, kSecAttrTokenID
);
287 require_quiet(ktype
, errOut
);
289 if (tokenID
!= NULL
) {
290 result
= SecCTKKeyGeneratePair(parameters
, &pubKey
, &privKey
);
291 } else if (CFEqual(ktype
, kSecAttrKeyTypeECSECPrimeRandom
)) {
292 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
293 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
294 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
297 require_noerr_quiet(result
, errOut
);
299 // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default
300 // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys).
301 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
302 CFDictionaryRemoveValue(pubParams
, kSecAttrTokenID
);
303 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
305 if (getBoolForKey(privParams
, kSecAttrIsPermanent
, CFDictionaryContainsKey(privParams
, kSecAttrTokenID
))) {
306 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
314 *privateKey
= privKey
;
319 CFReleaseSafe(pubParams
);
320 CFReleaseSafe(privParams
);
321 CFReleaseSafe(pubKey
);
322 CFReleaseSafe(privKey
);
327 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
328 return SecKeyCopyPublicKey(privateKey
);
331 CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
333 const CFTypeRef refType
= (returnPersistentRef
) ? kSecReturnPersistentRef
: kSecReturnRef
;
335 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
337 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
338 kSecClass
, kSecClassKey
,
339 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
340 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
341 kSecAttrApplicationLabel
, public_key_hash
,
342 refType
, kCFBooleanTrue
,
344 CFReleaseNull(public_key_hash
);
349 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
350 CFTypeRef persistentRef
= NULL
;
351 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
353 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
354 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
356 CFReleaseNull(query
);
357 return (CFDataRef
)persistentRef
;
360 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
361 SecKeyRef privateKey
= NULL
;
362 CFTypeRef queryResult
= NULL
;
363 CFDictionaryRef query
= NULL
;
365 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, CFSTR("Null Public Key")));
367 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
369 require_quiet(SecError(SecItemCopyMatching(query
, &queryResult
), error
,
370 CFSTR("Error finding private key from public: %@"), publicKey
), errOut
);
372 if (CFGetTypeID(queryResult
) == SecKeyGetTypeID()) {
373 privateKey
= (SecKeyRef
) queryResult
;
378 CFReleaseNull(query
);
379 CFReleaseNull(queryResult
);
383 OSStatus
SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey
, CFErrorRef
*error
) {
384 OSStatus retval
= errSecParam
;
385 CFTypeRef private_key
= NULL
;
386 CFDictionaryRef query
= NULL
;
388 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, NULL
, CFSTR("Null Public Key")));
390 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
392 retval
= SecItemCopyMatching(query
, &private_key
);
394 if (!retval
&& CFGetTypeID(private_key
) != SecKeyGetTypeID()) {
395 retval
= errSecInternalComponent
;
399 CFReleaseNull(query
);
400 CFReleaseNull(private_key
);
405 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
406 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
407 const SecAsn1Item
*keyData
) {
408 SecKeyRef publicKey
= NULL
;
409 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
411 /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of
412 SecKeyCreateRSAPublicKey, since on OS X the latter function will return
413 a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here.
415 publicKey
= SecKeyCreateRSAPublicKey_ios(allocator
,
416 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
417 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
420 .oidLength
= oid
->Length
,
421 .key
= keyData
->Data
,
422 .keyLength
= keyData
->Length
,
425 derKey
.parameters
= params
->Data
;
426 derKey
.parametersLength
= params
->Length
;
428 publicKey
= SecKeyCreateECPublicKey(allocator
,
429 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
431 secwarning("Unsupported algorithm oid");
438 SecKeyRef
SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator
, CFDataRef subjectPublicKeyInfoData
)
442 DERItem subjectPublicKeyInfoDER
= {
443 .data
= (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData
),
444 .length
= (DERSize
)CFDataGetLength(subjectPublicKeyInfoData
),
446 DERSubjPubKeyInfo subjectPublicKeyInfo
;
447 DERAlgorithmId algorithmId
;
450 drtn
= DERParseSequence(&subjectPublicKeyInfoDER
,
451 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
452 &subjectPublicKeyInfo
, sizeof(subjectPublicKeyInfo
));
454 require_noerr_quiet(drtn
, out
);
456 drtn
= DERParseSequenceContent(&subjectPublicKeyInfo
.algId
,
457 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
458 &algorithmId
, sizeof(algorithmId
));
459 require_noerr_quiet(drtn
, out
);
462 drtn
= DERParseBitString(&subjectPublicKeyInfo
.pubKey
, &pubKeyBytes
, &unusedBits
);
463 require_noerr_quiet(drtn
, out
);
465 /* Convert DERItem to SecAsn1Item : */
466 const SecAsn1Oid oid
= { .Data
= algorithmId
.oid
.data
, .Length
= algorithmId
.oid
.length
};
467 const SecAsn1Item params
= { .Data
= algorithmId
.params
.data
, .Length
= algorithmId
.params
.length
};
468 const SecAsn1Item pubKey
= { .Data
= pubKeyBytes
.data
, .Length
= pubKeyBytes
.length
};
470 return SecKeyCreatePublicFromDER(allocator
, &oid
, ¶ms
, &pubKey
);
477 static const DERByte oidRSA
[] = {
478 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
480 static const DERByte oidECsecp256
[] = {
481 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
483 static const DERByte oidECsecp384
[] = {
484 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
486 static const DERByte oidECsecp521
[] = {
487 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
491 CFDataRef
SecKeyCopySubjectPublicKeyInfo(SecKeyRef key
)
493 CFMutableDataRef data
= NULL
;
494 CFDataRef publicKey
= NULL
;
495 CFDataRef dataret
= NULL
;
496 DERSubjPubKeyInfo spki
;
500 memset(&spki
, 0, sizeof(spki
));
502 /* encode the public key. */
503 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &publicKey
), errOut
);
504 require_quiet(publicKey
, errOut
);
506 require_quiet(CFDataGetLength(publicKey
) != 0, errOut
);
508 // Add prefix 00 is needed to avoid creating negative bit strings
509 if (((uint8_t *)CFDataGetBytePtr(publicKey
))[0] & 0x80)
513 CFMutableDataRef paddedKey
= CFDataCreateMutable(NULL
, 0);
514 /* the bit strings bits used field first */
515 CFDataAppendBytes(paddedKey
, (const UInt8
*)"\x00", 1);
517 CFDataAppendBytes(paddedKey
, (const UInt8
*)"\x00", 1);
519 CFDataAppendBytes(paddedKey
, CFDataGetBytePtr(publicKey
), CFDataGetLength(publicKey
));
520 CFTransferRetained(publicKey
, paddedKey
);
522 spki
.pubKey
.data
= (DERByte
*)CFDataGetBytePtr(publicKey
);
523 spki
.pubKey
.length
= CFDataGetLength(publicKey
);
525 // Encode algId according to algorithm used.
526 CFIndex algorithm
= SecKeyGetAlgorithmId(key
);
527 if (algorithm
== kSecRSAAlgorithmID
) {
528 spki
.algId
.data
= (DERByte
*)oidRSA
;
529 spki
.algId
.length
= sizeof(oidRSA
);
530 } else if (algorithm
== kSecECDSAAlgorithmID
) {
531 SecECNamedCurve curve
= SecECKeyGetNamedCurve(key
);
533 case kSecECCurveSecp256r1
:
534 spki
.algId
.data
= (DERByte
*)oidECsecp256
;
535 spki
.algId
.length
= sizeof(oidECsecp256
);
537 case kSecECCurveSecp384r1
:
538 spki
.algId
.data
= (DERByte
*)oidECsecp384
;
539 spki
.algId
.length
= sizeof(oidECsecp384
);
541 case kSecECCurveSecp521r1
:
542 spki
.algId
.data
= (DERByte
*)oidECsecp521
;
543 spki
.algId
.length
= sizeof(oidECsecp521
);
552 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &spki
,
553 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
554 data
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
555 CFDataSetLength(data
, size
);
557 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &spki
,
558 DERNumSubjPubKeyInfoItemSpecs
,
559 DERSubjPubKeyInfoItemSpecs
,
560 CFDataGetMutableBytePtr(data
), &size
);
561 require_quiet(drtn
== DR_Success
, errOut
);
562 CFDataSetLength(data
, size
);
564 dataret
= CFRetain(data
);
567 CFReleaseNull(publicKey
);
574 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
575 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
576 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
577 if (!key_class
) return NULL
;
578 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
579 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
580 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
582 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
583 result
->key_class
= key_class
;
584 if (key_class
->extraBytes
) {
585 /* Make result->key point to the extraBytes we allocated. */
586 result
->key
= ((char*)result
) + sizeof(*result
);
588 if (key_class
->init
) {
590 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
592 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
601 static SecKeyAlgorithm
SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
602 switch (SecKeyGetAlgorithmId(key
)) {
603 case kSecRSAAlgorithmID
: {
605 if (!_CFMZEnabled()) {
606 // On CSSM-based implementation, these functions actually did hash its input,
607 // so keep doing that for backward compatibility.
609 case kSecPaddingNone
:
610 return kSecKeyAlgorithmRSASignatureRaw
;
611 case kSecPaddingPKCS1
:
612 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
613 case kSecPaddingPKCS1SHA1
:
614 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
615 case kSecPaddingPKCS1SHA224
:
616 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
;
617 case kSecPaddingPKCS1SHA256
:
618 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
619 case kSecPaddingPKCS1SHA384
:
620 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
621 case kSecPaddingPKCS1SHA512
:
622 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
630 case kSecPaddingNone
:
631 return kSecKeyAlgorithmRSASignatureRaw
;
632 case kSecPaddingPKCS1
:
633 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
634 case kSecPaddingPKCS1SHA1
:
635 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
;
636 case kSecPaddingPKCS1SHA224
:
637 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
;
638 case kSecPaddingPKCS1SHA256
:
639 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
;
640 case kSecPaddingPKCS1SHA384
:
641 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
;
642 case kSecPaddingPKCS1SHA512
:
643 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
;
649 case kSecECDSAAlgorithmID
:
651 case kSecPaddingSigRaw
:
652 return kSecKeyAlgorithmECDSASignatureRFC4754
;
654 // Although it is not very logical, previous SecECKey implementation really considered
655 // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour
656 // for backward compatibility.
657 return kSecKeyAlgorithmECDSASignatureDigestX962
;
664 // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments
665 // used by legacy RawSign-style functions.
666 static OSStatus
SecKeyPerformLegacyOperation(SecKeyRef key
,
667 const uint8_t *in1Ptr
, size_t in1Len
,
668 const uint8_t *in2Ptr
, size_t in2Len
,
669 uint8_t *outPtr
, size_t *outLen
,
670 CFTypeRef (^operation
)(CFDataRef in1
, CFDataRef in2
, CFRange
*resultRange
, CFErrorRef
*error
)) {
671 CFErrorRef error
= NULL
;
672 OSStatus status
= errSecSuccess
;
673 CFDataRef in1
= CFDataCreateWithBytesNoCopy(NULL
, in1Ptr
, in1Len
, kCFAllocatorNull
);
674 CFDataRef in2
= CFDataCreateWithBytesNoCopy(NULL
, in2Ptr
, in2Len
, kCFAllocatorNull
);
675 CFRange range
= { 0, -1 };
676 CFTypeRef output
= operation(in1
, in2
, &range
, &error
);
677 require_quiet(output
, out
);
678 if (CFGetTypeID(output
) == CFDataGetTypeID() && outLen
!= NULL
) {
679 if (range
.length
== -1) {
680 range
.length
= CFDataGetLength(output
);
682 require_action_quiet((size_t)range
.length
<= *outLen
, out
,
683 SecError(errSecParam
, &error
, CFSTR("buffer too small")));
684 *outLen
= range
.length
;
685 CFDataGetBytes(output
, range
, outPtr
);
691 CFReleaseSafe(output
);
693 status
= SecErrorGetOSStatus(error
);
694 if (status
== errSecVerifyFailed
) {
695 // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed.
696 status
= errSSLCrypto
;
703 OSStatus
SecKeyRawSign(
704 SecKeyRef key
, /* Private key */
705 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
706 const uint8_t *dataToSign
, /* signature over this data */
707 size_t dataToSignLen
, /* length of dataToSign */
708 uint8_t *sig
, /* signature, RETURNED */
709 size_t *sigLen
) { /* IN/OUT */
710 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
711 if (algorithm
== NULL
) {
714 return SecKeyPerformLegacyOperation(key
, dataToSign
, dataToSignLen
, NULL
, 0, sig
, sigLen
,
715 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
716 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
720 OSStatus
SecKeyRawVerify(
721 SecKeyRef key
, /* Public key */
722 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
723 const uint8_t *signedData
, /* signature over this data */
724 size_t signedDataLen
, /* length of dataToSign */
725 const uint8_t *sig
, /* signature */
726 size_t sigLen
) { /* length of signature */
727 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
728 if (algorithm
== NULL
) {
731 OSStatus status
= SecKeyPerformLegacyOperation(key
, signedData
, signedDataLen
, sig
, sigLen
, NULL
, NULL
,
732 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
733 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
)
734 ? kCFBooleanTrue
: NULL
;
739 static SecKeyAlgorithm
SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
740 switch (SecKeyGetAlgorithmId(key
)) {
741 case kSecRSAAlgorithmID
:
743 case kSecPaddingNone
:
744 return kSecKeyAlgorithmRSAEncryptionRaw
;
745 case kSecPaddingPKCS1
:
746 return kSecKeyAlgorithmRSAEncryptionPKCS1
;
747 case kSecPaddingOAEP
:
748 return kSecKeyAlgorithmRSAEncryptionOAEPSHA1
;
757 OSStatus
SecKeyEncrypt(
758 SecKeyRef key
, /* Public key */
759 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
760 const uint8_t *plainText
,
761 size_t plainTextLen
, /* length of plainText */
763 size_t *cipherTextLen
) { /* IN/OUT */
764 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
765 if (algorithm
== NULL
) {
769 return SecKeyPerformLegacyOperation(key
, plainText
, plainTextLen
, NULL
, 0, cipherText
, cipherTextLen
,
770 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
771 return SecKeyCreateEncryptedData(key
, algorithm
, in1
, error
);
775 OSStatus
SecKeyDecrypt(
776 SecKeyRef key
, /* Private key */
777 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
778 const uint8_t *cipherText
,
779 size_t cipherTextLen
, /* length of cipherText */
781 size_t *plainTextLen
) { /* IN/OUT */
782 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
783 if (algorithm
== NULL
) {
786 return SecKeyPerformLegacyOperation(key
, cipherText
, cipherTextLen
, NULL
, 0, plainText
, plainTextLen
,
787 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
788 CFDataRef decrypted
= SecKeyCreateDecryptedData(key
, algorithm
, in1
, error
);
790 if (decrypted
!= NULL
&& algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
&&
791 *(data
= CFDataGetBytePtr(decrypted
)) == 0x00) {
792 // Strip zero-padding from the beginning of the block, as the contract of this
794 range
->length
= CFDataGetLength(decrypted
);
795 while (*data
== 0x00 && range
->length
> 0) {
805 size_t SecKeyGetBlockSize(SecKeyRef key
) {
806 if (key
->key_class
->blockSize
)
807 return key
->key_class
->blockSize(key
);
811 /* Private API functions. */
813 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
814 return SecKeyCopyAttributes(key
);
817 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
818 CFErrorRef error
= NULL
;
819 SecKeyRef key
= SecKeyCreateWithData(CFDictionaryGetValue(refAttributes
, kSecValueData
), refAttributes
, &error
);
821 CFStringRef description
= CFErrorCopyDescription(error
);
822 secwarning("%@", description
);
823 CFRelease(description
);
829 static SecKeyAlgorithm
SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key
, const SecAsn1AlgId
*algId
, bool digestData
) {
830 static const struct TableItem
{
831 const SecAsn1Oid
*oid1
, *oid2
;
832 const SecKeyAlgorithm
*algorithms
[2];
833 } translationTableRSA
[] = {
834 { &CSSMOID_SHA1WithRSA
, &CSSMOID_SHA1
, {
835 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
,
836 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
,
838 { &CSSMOID_SHA224WithRSA
, &CSSMOID_SHA224
, {
839 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
,
840 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
,
842 { &CSSMOID_SHA256WithRSA
, &CSSMOID_SHA256
, {
843 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
,
844 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
,
846 { &CSSMOID_SHA384WithRSA
, &CSSMOID_SHA384
, {
847 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
,
848 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
,
850 { &CSSMOID_SHA512WithRSA
, &CSSMOID_SHA512
, {
851 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
,
852 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
,
854 { &CSSMOID_MD5
, NULL
, {
855 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
856 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
858 { &CSSMOID_MD5WithRSA
, NULL
, {
859 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
860 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
863 }, translationTableECDSA
[] = {
864 { &CSSMOID_ECDSA_WithSHA1
, &CSSMOID_SHA1
, {
865 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
866 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1
,
868 { &CSSMOID_ECDSA_WithSHA224
, &CSSMOID_SHA224
, {
869 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
870 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224
,
872 { &CSSMOID_ECDSA_WithSHA256
, &CSSMOID_SHA256
, {
873 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
874 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256
,
876 { &CSSMOID_ECDSA_WithSHA384
, &CSSMOID_SHA384
, {
877 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
878 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384
,
880 { &CSSMOID_ECDSA_WithSHA512
, &CSSMOID_SHA512
, {
881 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
882 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512
,
887 const struct TableItem
*table
;
888 switch (SecKeyGetAlgorithmId(key
)) {
889 case kSecRSAAlgorithmID
:
890 table
= translationTableRSA
;
892 case kSecECDSAAlgorithmID
:
893 table
= translationTableECDSA
;
899 for (; table
->oid1
!= NULL
; table
++) {
900 if (SecAsn1OidCompare(table
->oid1
, &algId
->algorithm
) ||
901 (table
->oid2
!= NULL
&& SecAsn1OidCompare(table
->oid2
, &algId
->algorithm
))) {
902 return *table
->algorithms
[digestData
];
908 OSStatus
SecKeyDigestAndVerify(
909 SecKeyRef key
, /* Private key */
910 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
911 const uint8_t *dataToDigest
, /* signature over this data */
912 size_t dataToDigestLen
,/* length of dataToDigest */
913 const uint8_t *sig
, /* signature to verify */
914 size_t sigLen
) { /* length of sig */
916 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
917 if (algorithm
== NULL
) {
918 return errSecUnimplemented
;
921 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, sig
, sigLen
, NULL
, NULL
,
922 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
923 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
924 kCFBooleanTrue
: NULL
;
928 OSStatus
SecKeyDigestAndSign(
929 SecKeyRef key
, /* Private key */
930 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
931 const uint8_t *dataToDigest
, /* signature over this data */
932 size_t dataToDigestLen
,/* length of dataToDigest */
933 uint8_t *sig
, /* signature, RETURNED */
934 size_t *sigLen
) { /* IN/OUT */
935 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
936 if (algorithm
== NULL
) {
937 return errSecUnimplemented
;
940 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, NULL
, 0, sig
, sigLen
,
941 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
942 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
946 OSStatus
SecKeyVerifyDigest(
947 SecKeyRef key
, /* Private key */
948 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
949 const uint8_t *digestData
, /* signature over this digest */
950 size_t digestDataLen
,/* length of dataToDigest */
951 const uint8_t *sig
, /* signature to verify */
952 size_t sigLen
) { /* length of sig */
953 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
954 if (algorithm
== NULL
) {
955 return errSecUnimplemented
;
958 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, sig
, sigLen
, NULL
, NULL
,
959 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
960 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
961 kCFBooleanTrue
: NULL
;
965 OSStatus
SecKeySignDigest(
966 SecKeyRef key
, /* Private key */
967 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
968 const uint8_t *digestData
, /* signature over this digest */
969 size_t digestDataLen
,/* length of digestData */
970 uint8_t *sig
, /* signature, RETURNED */
971 size_t *sigLen
) { /* IN/OUT */
972 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
973 if (algorithm
== NULL
) {
974 return errSecUnimplemented
;
977 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, NULL
, 0, sig
, sigLen
,
978 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
979 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
984 /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments,
985 with output in the second argument). Therefore, avoid implementing this function here
986 if compiling for OS X.
989 // Export original SecKeyGetAlgorithmID symbol for backward binary compatibility.
990 #undef SecKeyGetAlgorithmID
991 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
);
992 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
993 return SecKeyGetAlgorithmId(key
);
997 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
998 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
999 return key
->key_class
->copyPublic(key
, serializedPublic
);
1000 return errSecUnimplemented
;
1003 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
1005 switch (algorithmID
)
1007 case kSecRSAAlgorithmID
:
1008 return SecKeyCreateRSAPublicKey(allocator
,
1009 keyData
, keyDataLength
,
1010 kSecKeyEncodingBytes
);
1011 case kSecECDSAAlgorithmID
:
1012 return SecKeyCreateECPublicKey(allocator
,
1013 keyData
, keyDataLength
,
1014 kSecKeyEncodingBytes
);
1020 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
1022 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
1025 // This is a bit icky hack to avoid changing the vtable for
1027 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
1029 size_t result
= SecKeyGetBlockSize(key
);
1031 if (whichSize
== 0 || whichSize
== 10) {
1032 // kSecKeyKeySizeInBits is declared as 0 on iOS (SPI) and 10 on macOS (API). Unified implementation
1033 // here deals with both values.
1034 whichSize
= kSecKeyKeySizeInBits
;
1037 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmId(key
)) {
1038 switch (whichSize
) {
1039 case kSecKeyEncryptedDataSize
:
1042 case kSecKeySignatureSize
:
1043 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
1045 case kSecKeyKeySizeInBits
:
1051 if (whichSize
== kSecKeyKeySizeInBits
)
1058 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
1060 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1061 kSecReturnRef
, kCFBooleanTrue
,
1062 kSecClass
, kSecClassKey
,
1063 kSecValuePersistentRef
, persistentRef
,
1065 CFTypeRef foundRef
= NULL
;
1066 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1068 if (status
== errSecSuccess
) {
1069 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
1070 *lookedUpData
= (SecKeyRef
) foundRef
;
1072 status
= errSecSuccess
;
1074 status
= errSecItemNotFound
;
1078 CFReleaseSafe(foundRef
);
1079 CFReleaseSafe(query
);
1084 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
1087 secerror("SecKeyCopyPersistentRef: Need a key reference for this to work");
1090 if (!persistentRef
) {
1091 secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work");
1095 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1096 kSecReturnPersistentRef
, kCFBooleanTrue
,
1098 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
1100 CFTypeRef foundRef
= NULL
;
1101 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1103 if (status
== errSecSuccess
) {
1104 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
1105 *persistentRef
= foundRef
;
1108 secerror("SecKeyCopyPersistentRef: SecItemCopyMatching returned success, but we got type %lu instead of CFData for key %@.", CFGetTypeID(foundRef
), key
);
1109 status
= errSecItemNotFound
;
1112 secerror("SecKeyCopyPersistentRef: received status %i for key %@", (int)status
, key
);
1113 CFStringRef str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Expected to find persistentref for key %@"), key
);
1114 __security_stackshotreport(str
, (int)status
);
1118 CFReleaseSafe(foundRef
);
1119 CFReleaseSafe(query
);
1128 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
1130 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg");
1131 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint");
1132 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg");
1133 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags");
1134 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1135 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1137 #undef SEC_CONST_DECL
1140 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1146 if (key
->key_class
->version
> 2 && key
->key_class
->copyWrapKey
)
1147 return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
);
1148 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
);
1153 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1159 if (key
->key_class
->version
> 2 && key
->key_class
->copyUnwrapKey
)
1160 return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
);
1162 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
);
1166 static CFIndex
SecKeyParamsGetCFIndex(CFTypeRef value
, CFStringRef errName
, CFErrorRef
*error
) {
1167 CFIndex result
= -1;
1168 CFNumberRef localValue
= NULL
;
1170 if (isString(value
)) {
1171 CFNumberFormatterRef formatter
= CFNumberFormatterCreate(kCFAllocatorDefault
, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle
);
1172 localValue
= CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault
, formatter
, value
, NULL
, kCFNumberFormatterParseIntegersOnly
);
1173 CFReleaseSafe(formatter
);
1176 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue
);
1177 if (CFEqual(t
, value
)) {
1184 if (value
!= NULL
&& CFGetTypeID(value
) == CFNumberGetTypeID()) {
1185 if (!CFNumberGetValue(value
, kCFNumberCFIndexType
, &result
) || result
< 0) {
1186 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1189 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1192 CFReleaseSafe(localValue
);
1196 SecKeyRef
SecKeyCreateWithData(CFDataRef keyData
, CFDictionaryRef parameters
, CFErrorRef
*error
) {
1198 SecKeyRef key
= NULL
;
1199 CFAllocatorRef allocator
= NULL
;
1201 if (CFDictionaryGetValue(parameters
, kSecAttrTokenID
) != NULL
) {
1202 return SecKeyCreateCTKKey(allocator
, parameters
, error
);
1204 else if (!keyData
) {
1205 SecError(errSecParam
, error
, CFSTR("Failed to provide key data to SecKeyCreateWithData"));
1208 /* First figure out the key type (algorithm). */
1209 CFIndex algorithm
, class;
1210 CFTypeRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1211 require_quiet((algorithm
= SecKeyParamsGetCFIndex(ktype
, CFSTR("key type"), error
)) >= 0, out
);
1212 CFTypeRef kclass
= CFDictionaryGetValue(parameters
, kSecAttrKeyClass
);
1213 require_quiet((class = SecKeyParamsGetCFIndex(kclass
, CFSTR("key class"), error
)) >= 0, out
);
1216 case 0: // kSecAttrKeyClassPublic
1217 switch (algorithm
) {
1218 case 42: // kSecAlgorithmRSA
1219 key
= SecKeyCreateRSAPublicKey(allocator
,
1220 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1221 kSecKeyEncodingBytes
);
1223 SecError(errSecParam
, error
, CFSTR("RSA public key creation from data failed"));
1226 case 43: // kSecAlgorithmECDSA
1227 case 73: // kSecAlgorithmEC
1228 key
= SecKeyCreateECPublicKey(allocator
,
1229 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1230 kSecKeyEncodingBytes
);
1232 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1236 SecError(errSecParam
, error
, CFSTR("Unsupported public key type: %@"), ktype
);
1240 case 1: // kSecAttrKeyClassPrivate
1241 switch (algorithm
) {
1242 case 42: // kSecAlgorithmRSA
1243 key
= SecKeyCreateRSAPrivateKey(allocator
,
1244 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1245 kSecKeyEncodingBytes
);
1247 SecError(errSecParam
, error
, CFSTR("RSA private key creation from data failed"));
1250 case 43: // kSecAlgorithmECDSA
1251 case 73: // kSecAlgorithmEC
1252 key
= SecKeyCreateECPrivateKey(allocator
,
1253 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1254 kSecKeyEncodingBytes
);
1256 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1260 SecError(errSecParam
, error
, CFSTR("Unsupported private key type: %@"), ktype
);
1264 case 2: // kSecAttrKeyClassSymmetric
1265 SecError(errSecUnimplemented
, error
, CFSTR("Unsupported symmetric key type: %@"), ktype
);
1268 SecError(errSecParam
, error
, CFSTR("Unsupported key class: %@"), kclass
);
1276 // Similar to CFErrorPropagate, but does not consult input value of *error, it can contain any garbage and if overwritten, previous value is never released.
1277 static inline bool SecKeyErrorPropagate(bool succeeded
, CFErrorRef possibleError CF_CONSUMED
, CFErrorRef
*error
) {
1282 *error
= possibleError
;
1284 CFRelease(possibleError
);
1290 CFDataRef
SecKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
1291 if (!key
->key_class
->copyExternalRepresentation
) {
1292 if (error
!= NULL
) {
1295 SecError(errSecUnimplemented
, error
, CFSTR("export not implemented for key %@"), key
);
1299 CFErrorRef localError
= NULL
;
1300 CFDataRef result
= key
->key_class
->copyExternalRepresentation(key
, &localError
);
1301 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1305 CFDictionaryRef
SecKeyCopyAttributes(SecKeyRef key
) {
1306 if (key
->key_class
->copyDictionary
) {
1307 return key
->key_class
->copyDictionary(key
);
1309 // Create dictionary with basic values derived from other known information of the key.
1310 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1311 CFIndex blockSize
= SecKeyGetBlockSize(key
) * 8;
1312 if (blockSize
> 0) {
1313 CFNumberRef blockSizeRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &blockSize
);
1314 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, blockSizeRef
);
1315 CFRelease(blockSizeRef
);
1318 switch (SecKeyGetAlgorithmId(key
)) {
1319 case kSecRSAAlgorithmID
:
1320 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
1322 case kSecECDSAAlgorithmID
:
1323 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECSECPrimeRandom
);
1327 if (key
->key_class
->rawSign
!= NULL
|| key
->key_class
->decrypt
!= NULL
) {
1328 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1329 } else if (key
->key_class
->rawVerify
!= NULL
|| key
->key_class
->encrypt
!= NULL
) {
1330 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1337 SecKeyRef
SecKeyCopyPublicKey(SecKeyRef key
) {
1338 SecKeyRef result
= NULL
;
1339 if (key
->key_class
->version
>= 4 && key
->key_class
->copyPublicKey
) {
1340 result
= key
->key_class
->copyPublicKey(key
);
1341 if (result
!= NULL
) {
1346 CFDataRef serializedPublic
= NULL
;
1348 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &serializedPublic
), fail
);
1349 require_quiet(serializedPublic
, fail
);
1351 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmId(key
), serializedPublic
);
1354 CFReleaseSafe(serializedPublic
);
1358 SecKeyRef
SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1359 SecKeyRef privKey
= NULL
, pubKey
= NULL
;
1360 OSStatus status
= SecKeyGeneratePair(parameters
, &pubKey
, &privKey
);
1361 if (status
!= errSecSuccess
) {
1362 if (error
!= NULL
) {
1365 SecError(status
, error
, CFSTR("Key generation failed, error %d"), (int)status
);
1367 CFReleaseSafe(pubKey
);
1371 SecKeyRef
SecKeyCreateDuplicate(SecKeyRef key
) {
1372 if (key
->key_class
->version
>= 4 && key
->key_class
->createDuplicate
) {
1373 return key
->key_class
->createDuplicate(key
);
1375 return (SecKeyRef
)CFRetain(key
);
1379 Boolean
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
1381 SecCTKKeySetTestMode(name
, value
);
1383 } else if (key
->key_class
->version
>= 4 && key
->key_class
->setParameter
) {
1384 CFErrorRef localError
= NULL
;
1385 Boolean result
= key
->key_class
->setParameter(key
, name
, value
, &localError
);
1386 SecKeyErrorPropagate(result
, localError
, error
);
1389 if (error
!= NULL
) {
1392 return SecError(errSecUnimplemented
, error
, CFSTR("setParameter not implemented for %@"), key
);
1396 #pragma mark Generic algorithm adaptor lookup and invocation
1398 static CFTypeRef
SecKeyCopyBackendOperationResult(SecKeyOperationContext
*context
, SecKeyAlgorithm algorithm
,
1399 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1400 CFTypeRef result
= kCFNull
;
1401 assert(CFArrayGetCount(context
->algorithm
) > 0);
1402 if (context
->key
->key_class
->version
>= 4 && context
->key
->key_class
->copyOperationResult
!= NULL
) {
1403 return context
->key
->key_class
->copyOperationResult(context
->key
, context
->operation
, algorithm
,
1404 context
->algorithm
, context
->mode
, in1
, in2
, error
);
1407 // Mapping from algorithms to legacy SecPadding values.
1408 static const struct {
1409 const SecKeyAlgorithm
*algorithm
;
1413 { &kSecKeyAlgorithmRSASignatureRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1414 { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1415 { &kSecKeyAlgorithmECDSASignatureRFC4754
, kSecECDSAAlgorithmID
, kSecPaddingSigRaw
},
1416 { &kSecKeyAlgorithmECDSASignatureDigestX962
, kSecECDSAAlgorithmID
, kSecPaddingPKCS1
},
1417 { &kSecKeyAlgorithmRSAEncryptionRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1418 { &kSecKeyAlgorithmRSAEncryptionPKCS1
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1419 { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1
, kSecRSAAlgorithmID
, kSecPaddingOAEP
},
1421 SecPadding padding
= (SecPadding
)-1;
1422 CFIndex keyAlg
= SecKeyGetAlgorithmId(context
->key
);
1423 for (size_t i
= 0; i
< array_size(paddingMap
); ++i
) {
1424 if (keyAlg
== paddingMap
[i
].keyAlg
&& CFEqual(algorithm
, *paddingMap
[i
].algorithm
)) {
1425 padding
= paddingMap
[i
].padding
;
1429 require_quiet(padding
!= (SecPadding
)-1, out
);
1431 // Check legacy virtual table entries.
1433 OSStatus status
= errSecSuccess
;
1434 switch (context
->operation
) {
1435 case kSecKeyOperationTypeSign
:
1436 if (context
->key
->key_class
->rawSign
!= NULL
) {
1437 result
= kCFBooleanTrue
;
1438 if (context
->mode
== kSecKeyOperationModePerform
) {
1439 size
= SecKeyGetSize(context
->key
, kSecKeySignatureSize
);
1440 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1441 status
= context
->key
->key_class
->rawSign(context
->key
, padding
,
1442 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1443 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1447 case kSecKeyOperationTypeVerify
:
1448 if (context
->key
->key_class
->rawVerify
!= NULL
) {
1449 result
= kCFBooleanTrue
;
1450 if (context
->mode
== kSecKeyOperationModePerform
) {
1451 status
= context
->key
->key_class
->rawVerify(context
->key
, padding
,
1452 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1453 CFDataGetBytePtr(in2
), CFDataGetLength(in2
));
1457 case kSecKeyOperationTypeEncrypt
:
1458 if (context
->key
->key_class
->encrypt
!= NULL
) {
1459 result
= kCFBooleanTrue
;
1460 if (context
->mode
== kSecKeyOperationModePerform
) {
1461 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1462 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1463 status
= context
->key
->key_class
->encrypt(context
->key
, padding
,
1464 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1465 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1469 case kSecKeyOperationTypeDecrypt
:
1470 if (context
->key
->key_class
->decrypt
!= NULL
) {
1471 result
= kCFBooleanTrue
;
1472 if (context
->mode
== kSecKeyOperationModePerform
) {
1473 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1474 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1475 status
= context
->key
->key_class
->decrypt(context
->key
, padding
,
1476 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1477 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1485 if (status
== errSecSuccess
) {
1486 if (CFGetTypeID(result
) == CFDataGetTypeID()) {
1487 CFDataSetLength((CFMutableDataRef
)result
, size
);
1490 SecError(status
, error
, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context
->operation
, (int)padding
);
1491 CFReleaseNull(result
);
1498 CFTypeRef
SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext
*context
, CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1500 // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error.
1501 CFIndex algorithmCount
= CFArrayGetCount(context
->algorithm
);
1502 for (CFIndex index
= 0; index
< algorithmCount
- 1; index
++) {
1503 SecKeyAlgorithm indexAlgorithm
= CFArrayGetValueAtIndex(context
->algorithm
, index
);
1504 for (CFIndex tested
= index
+ 1; tested
< algorithmCount
; tested
++) {
1505 require_quiet(!CFEqual(indexAlgorithm
, CFArrayGetValueAtIndex(context
->algorithm
, tested
)), fail
);
1509 SecKeyAlgorithm algorithm
= CFArrayGetValueAtIndex(context
->algorithm
, algorithmCount
- 1);
1510 CFTypeRef output
= SecKeyCopyBackendOperationResult(context
, algorithm
, in1
, in2
, error
);
1511 if (output
!= kCFNull
) {
1512 // Backend handled the operation, return result.
1516 // To silence static analyzer.
1517 CFReleaseSafe(output
);
1519 // Get adaptor which is able to handle requested algorithm.
1520 SecKeyAlgorithmAdaptor adaptor
= SecKeyGetAlgorithmAdaptor(context
->operation
, algorithm
);
1521 require_quiet(adaptor
!= NULL
, fail
);
1523 // Invoke the adaptor and return result.
1524 CFTypeRef result
= adaptor(context
, in1
, in2
, error
);
1525 require_quiet(result
!= kCFNull
, fail
);
1529 if (context
->mode
== kSecKeyOperationModePerform
) {
1530 SecError(errSecParam
, error
, CFSTR("%@: algorithm not supported by the key %@"),
1531 CFArrayGetValueAtIndex(context
->algorithm
, 0), context
->key
);
1538 #pragma mark Algorithm-related SecKey API entry points
1540 static CFMutableArrayRef
SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm
) {
1541 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1542 CFArrayAppendValue(result
, algorithm
);
1546 CFDataRef
SecKeyCreateSignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef dataToSign
, CFErrorRef
*error
) {
1547 CFErrorRef localError
= NULL
;
1548 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeSign
, SecKeyCreateAlgorithmArray(algorithm
) };
1549 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, dataToSign
, NULL
, &localError
);
1550 SecKeyOperationContextDestroy(&context
);
1551 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1555 Boolean
SecKeyVerifySignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef signedData
, CFDataRef signature
,
1556 CFErrorRef
*error
) {
1557 CFErrorRef localError
= NULL
;
1558 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeVerify
, SecKeyCreateAlgorithmArray(algorithm
) };
1559 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, signedData
, signature
, &localError
);
1560 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1562 SecKeyOperationContextDestroy(&context
);
1563 SecKeyErrorPropagate(result
, localError
, error
);
1567 CFDataRef
SecKeyCreateEncryptedDataWithParameters(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plaintext
,
1568 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1569 CFErrorRef localError
= NULL
;
1570 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeEncrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1571 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, plaintext
, parameters
, &localError
);
1572 SecKeyOperationContextDestroy(&context
);
1573 SecKeyErrorPropagate(result
, localError
, error
);
1577 CFDataRef
SecKeyCreateEncryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plaintext
, CFErrorRef
*error
) {
1578 return SecKeyCreateEncryptedDataWithParameters(key
, algorithm
, plaintext
, NULL
, error
);
1581 CFDataRef
SecKeyCreateDecryptedDataWithParameters(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef ciphertext
,
1582 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1583 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeDecrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1584 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, ciphertext
, parameters
, error
);
1585 SecKeyOperationContextDestroy(&context
);
1589 CFDataRef
SecKeyCreateDecryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef ciphertext
, CFErrorRef
*error
) {
1590 return SecKeyCreateDecryptedDataWithParameters(key
, algorithm
, ciphertext
, NULL
, error
);
1593 CFDataRef
SecKeyCopyKeyExchangeResult(SecKeyRef key
, SecKeyAlgorithm algorithm
, SecKeyRef publicKey
,
1594 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1595 CFErrorRef localError
= NULL
;
1596 CFDataRef publicKeyData
= NULL
, result
= NULL
;
1597 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeKeyExchange
, SecKeyCreateAlgorithmArray(algorithm
) };
1598 require_quiet(publicKeyData
= SecKeyCopyExternalRepresentation(publicKey
, error
), out
);
1599 result
= SecKeyRunAlgorithmAndCopyResult(&context
, publicKeyData
, parameters
, &localError
);
1600 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1603 CFReleaseSafe(publicKeyData
);
1604 SecKeyOperationContextDestroy(&context
);
1608 Boolean
SecKeyIsAlgorithmSupported(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
) {
1609 SecKeyOperationContext context
= { key
, operation
, SecKeyCreateAlgorithmArray(algorithm
), kSecKeyOperationModeCheckIfSupported
};
1610 CFErrorRef error
= NULL
;
1611 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, NULL
, NULL
, &error
);
1612 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1614 CFReleaseSafe(error
);
1615 SecKeyOperationContextDestroy(&context
);