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
= DICT_CREATE(allocator
);
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 CFReleaseSafe(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. */
298 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
299 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
301 /* Token-based private keys are automatically stored on the token. */
302 if (tokenID
== NULL
&& getBoolForKey(privParams
, kSecAttrIsPermanent
, false)) {
303 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
311 *privateKey
= privKey
;
316 CFReleaseSafe(pubParams
);
317 CFReleaseSafe(privParams
);
318 CFReleaseSafe(pubKey
);
319 CFReleaseSafe(privKey
);
324 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
325 return SecKeyCopyPublicKey(privateKey
);
328 CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
330 const CFTypeRef refType
= (returnPersistentRef
) ? kSecReturnPersistentRef
: kSecReturnRef
;
332 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
334 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
335 kSecClass
, kSecClassKey
,
336 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
337 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
338 kSecAttrApplicationLabel
, public_key_hash
,
339 refType
, kCFBooleanTrue
,
341 CFReleaseNull(public_key_hash
);
346 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
347 CFTypeRef persistentRef
= NULL
;
348 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
350 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
351 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
353 CFReleaseNull(query
);
354 return (CFDataRef
)persistentRef
;
357 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
358 SecKeyRef privateKey
= NULL
;
359 CFTypeRef queryResult
= NULL
;
360 CFDictionaryRef query
= NULL
;
362 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, CFSTR("Null Public Key")));
364 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
366 require_quiet(SecError(SecItemCopyMatching(query
, &queryResult
), error
,
367 CFSTR("Error finding private key from public: %@"), publicKey
), errOut
);
369 if (CFGetTypeID(queryResult
) == SecKeyGetTypeID()) {
370 privateKey
= (SecKeyRef
) queryResult
;
375 CFReleaseNull(query
);
376 CFReleaseNull(queryResult
);
380 OSStatus
SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey
, CFErrorRef
*error
) {
381 OSStatus retval
= errSecParam
;
382 CFTypeRef private_key
= NULL
;
383 CFDictionaryRef query
= NULL
;
385 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, NULL
, CFSTR("Null Public Key")));
387 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
389 retval
= SecItemCopyMatching(query
, &private_key
);
391 if (!retval
&& CFGetTypeID(private_key
) != SecKeyGetTypeID()) {
392 retval
= errSecInternalComponent
;
396 CFReleaseNull(query
);
397 CFReleaseNull(private_key
);
402 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
403 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
404 const SecAsn1Item
*keyData
) {
405 SecKeyRef publicKey
= NULL
;
406 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
408 /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of
409 SecKeyCreateRSAPublicKey, since on OS X the latter function will return
410 a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here.
412 publicKey
= SecKeyCreateRSAPublicKey_ios(allocator
,
413 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
414 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
417 .oidLength
= oid
->Length
,
418 .key
= keyData
->Data
,
419 .keyLength
= keyData
->Length
,
422 derKey
.parameters
= params
->Data
;
423 derKey
.parametersLength
= params
->Length
;
425 publicKey
= SecKeyCreateECPublicKey(allocator
,
426 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
428 secwarning("Unsupported algorithm oid");
435 SecKeyRef
SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator
, CFDataRef subjectPublicKeyInfoData
)
439 DERItem subjectPublicKeyInfoDER
= {
440 .data
= (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData
),
441 .length
= (DERSize
)CFDataGetLength(subjectPublicKeyInfoData
),
443 DERSubjPubKeyInfo subjectPublicKeyInfo
;
444 DERAlgorithmId algorithmId
;
447 drtn
= DERParseSequence(&subjectPublicKeyInfoDER
,
448 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
449 &subjectPublicKeyInfo
, sizeof(subjectPublicKeyInfo
));
451 require_noerr_quiet(drtn
, out
);
453 drtn
= DERParseSequenceContent(&subjectPublicKeyInfo
.algId
,
454 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
455 &algorithmId
, sizeof(algorithmId
));
456 require_noerr_quiet(drtn
, out
);
459 drtn
= DERParseBitString(&subjectPublicKeyInfo
.pubKey
, &pubKeyBytes
, &unusedBits
);
460 require_noerr_quiet(drtn
, out
);
462 /* Convert DERItem to SecAsn1Item : */
463 const SecAsn1Oid oid
= { .Data
= algorithmId
.oid
.data
, .Length
= algorithmId
.oid
.length
};
464 const SecAsn1Item params
= { .Data
= algorithmId
.params
.data
, .Length
= algorithmId
.params
.length
};
465 const SecAsn1Item pubKey
= { .Data
= pubKeyBytes
.data
, .Length
= pubKeyBytes
.length
};
467 return SecKeyCreatePublicFromDER(allocator
, &oid
, ¶ms
, &pubKey
);
477 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
478 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
479 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
480 if (!key_class
) return NULL
;
481 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
482 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
483 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
485 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
486 result
->key_class
= key_class
;
487 if (key_class
->extraBytes
) {
488 /* Make result->key point to the extraBytes we allocated. */
489 result
->key
= ((char*)result
) + sizeof(*result
);
491 if (key_class
->init
) {
493 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
495 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
504 static SecKeyAlgorithm
SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
505 switch (SecKeyGetAlgorithmIdentifier(key
)) {
506 case kSecRSAAlgorithmID
:
508 case kSecPaddingNone
:
509 return kSecKeyAlgorithmRSASignatureRaw
;
510 case kSecPaddingPKCS1
:
511 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
513 case kSecPaddingPKCS1SHA1
:
514 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
;
515 case kSecPaddingPKCS1SHA224
:
516 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
;
517 case kSecPaddingPKCS1SHA256
:
518 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
;
519 case kSecPaddingPKCS1SHA384
:
520 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
;
521 case kSecPaddingPKCS1SHA512
:
522 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
;
524 // On CSSM-based implementation, these functions actually did hash its input,
525 // so keep doing that for backward compatibility.
526 case kSecPaddingPKCS1SHA1
:
527 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
528 case kSecPaddingPKCS1SHA224
:
529 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
;
530 case kSecPaddingPKCS1SHA256
:
531 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
532 case kSecPaddingPKCS1SHA384
:
533 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
534 case kSecPaddingPKCS1SHA512
:
535 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
540 case kSecECDSAAlgorithmID
:
542 case kSecPaddingSigRaw
:
543 return kSecKeyAlgorithmECDSASignatureRFC4754
;
545 // Although it is not very logical, previous SecECKey implementation really considered
546 // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour
547 // for backward compatibility.
548 return kSecKeyAlgorithmECDSASignatureDigestX962
;
555 // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments
556 // used by legacy RawSign-style functions.
557 static OSStatus
SecKeyPerformLegacyOperation(SecKeyRef key
,
558 const uint8_t *in1Ptr
, size_t in1Len
,
559 const uint8_t *in2Ptr
, size_t in2Len
,
560 uint8_t *outPtr
, size_t *outLen
,
561 CFTypeRef (^operation
)(CFDataRef in1
, CFDataRef in2
, CFRange
*resultRange
, CFErrorRef
*error
)) {
562 CFErrorRef error
= NULL
;
563 OSStatus status
= errSecSuccess
;
564 CFDataRef in1
= CFDataCreateWithBytesNoCopy(NULL
, in1Ptr
, in1Len
, kCFAllocatorNull
);
565 CFDataRef in2
= CFDataCreateWithBytesNoCopy(NULL
, in2Ptr
, in2Len
, kCFAllocatorNull
);
566 CFRange range
= { 0, -1 };
567 CFTypeRef output
= operation(in1
, in2
, &range
, &error
);
568 require_quiet(output
, out
);
569 if (CFGetTypeID(output
) == CFDataGetTypeID() && outLen
!= NULL
) {
570 if (range
.length
== -1) {
571 range
.length
= CFDataGetLength(output
);
573 require_action_quiet((size_t)range
.length
<= *outLen
, out
,
574 SecError(errSecParam
, &error
, CFSTR("buffer too small")));
575 *outLen
= range
.length
;
576 CFDataGetBytes(output
, range
, outPtr
);
582 CFReleaseSafe(output
);
584 status
= SecErrorGetOSStatus(error
);
585 if (status
== errSecVerifyFailed
) {
586 // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed.
587 status
= errSSLCrypto
;
594 OSStatus
SecKeyRawSign(
595 SecKeyRef key
, /* Private key */
596 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
597 const uint8_t *dataToSign
, /* signature over this data */
598 size_t dataToSignLen
, /* length of dataToSign */
599 uint8_t *sig
, /* signature, RETURNED */
600 size_t *sigLen
) { /* IN/OUT */
601 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
602 if (algorithm
== NULL
) {
605 return SecKeyPerformLegacyOperation(key
, dataToSign
, dataToSignLen
, NULL
, 0, sig
, sigLen
,
606 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
607 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
611 OSStatus
SecKeyRawVerify(
612 SecKeyRef key
, /* Public key */
613 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
614 const uint8_t *signedData
, /* signature over this data */
615 size_t signedDataLen
, /* length of dataToSign */
616 const uint8_t *sig
, /* signature */
617 size_t sigLen
) { /* length of signature */
618 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
619 if (algorithm
== NULL
) {
622 OSStatus status
= SecKeyPerformLegacyOperation(key
, signedData
, signedDataLen
, sig
, sigLen
, NULL
, NULL
,
623 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
624 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
)
625 ? kCFBooleanTrue
: NULL
;
630 static SecKeyAlgorithm
SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
631 switch (SecKeyGetAlgorithmIdentifier(key
)) {
632 case kSecRSAAlgorithmID
:
634 case kSecPaddingNone
:
635 return kSecKeyAlgorithmRSAEncryptionRaw
;
636 case kSecPaddingPKCS1
:
637 return kSecKeyAlgorithmRSAEncryptionPKCS1
;
638 case kSecPaddingOAEP
:
639 return kSecKeyAlgorithmRSAEncryptionOAEPSHA1
;
648 OSStatus
SecKeyEncrypt(
649 SecKeyRef key
, /* Public key */
650 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
651 const uint8_t *plainText
,
652 size_t plainTextLen
, /* length of plainText */
654 size_t *cipherTextLen
) { /* IN/OUT */
655 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
656 if (algorithm
== NULL
) {
660 return SecKeyPerformLegacyOperation(key
, plainText
, plainTextLen
, NULL
, 0, cipherText
, cipherTextLen
,
661 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
662 return SecKeyCreateEncryptedData(key
, algorithm
, in1
, error
);
666 OSStatus
SecKeyDecrypt(
667 SecKeyRef key
, /* Private key */
668 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
669 const uint8_t *cipherText
,
670 size_t cipherTextLen
, /* length of cipherText */
672 size_t *plainTextLen
) { /* IN/OUT */
673 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
674 if (algorithm
== NULL
) {
677 return SecKeyPerformLegacyOperation(key
, cipherText
, cipherTextLen
, NULL
, 0, plainText
, plainTextLen
,
678 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
679 CFDataRef decrypted
= SecKeyCreateDecryptedData(key
, algorithm
, in1
, error
);
681 if (decrypted
!= NULL
&& algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
&&
682 *(data
= CFDataGetBytePtr(decrypted
)) == 0x00) {
683 // Strip zero-padding from the beginning of the block, as the contract of this
685 range
->length
= CFDataGetLength(decrypted
);
686 while (*data
== 0x00 && range
->length
> 0) {
696 size_t SecKeyGetBlockSize(SecKeyRef key
) {
697 if (key
->key_class
->blockSize
)
698 return key
->key_class
->blockSize(key
);
702 /* Private API functions. */
704 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
705 if (key
->key_class
->copyDictionary
)
706 return key
->key_class
->copyDictionary(key
);
710 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
711 CFErrorRef error
= NULL
;
712 SecKeyRef key
= SecKeyCreateWithData(CFDictionaryGetValue(refAttributes
, kSecValueData
), refAttributes
, &error
);
714 CFStringRef description
= CFErrorCopyDescription(error
);
715 secwarning("%@", description
);
716 CFRelease(description
);
722 static SecKeyAlgorithm
SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key
, const SecAsn1AlgId
*algId
, bool digestData
) {
723 static const struct TableItem
{
724 const SecAsn1Oid
*oid1
, *oid2
;
725 const SecKeyAlgorithm
*algorithms
[2];
726 } translationTableRSA
[] = {
727 { &CSSMOID_SHA1WithRSA
, &CSSMOID_SHA1
, {
728 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
,
729 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
,
731 { &CSSMOID_SHA224WithRSA
, &CSSMOID_SHA224
, {
732 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
,
733 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
,
735 { &CSSMOID_SHA256WithRSA
, &CSSMOID_SHA256
, {
736 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
,
737 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
,
739 { &CSSMOID_SHA384WithRSA
, &CSSMOID_SHA384
, {
740 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
,
741 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
,
743 { &CSSMOID_SHA512WithRSA
, &CSSMOID_SHA512
, {
744 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
,
745 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
,
747 { &CSSMOID_MD5
, NULL
, {
748 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
749 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
752 }, translationTableECDSA
[] = {
753 { &CSSMOID_ECDSA_WithSHA1
, &CSSMOID_SHA1
, {
754 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
755 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1
,
757 { &CSSMOID_ECDSA_WithSHA224
, &CSSMOID_SHA224
, {
758 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
759 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224
,
761 { &CSSMOID_ECDSA_WithSHA256
, &CSSMOID_SHA256
, {
762 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
763 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256
,
765 { &CSSMOID_ECDSA_WithSHA384
, &CSSMOID_SHA384
, {
766 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
767 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384
,
769 { &CSSMOID_ECDSA_WithSHA512
, &CSSMOID_SHA512
, {
770 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
771 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512
,
776 const struct TableItem
*table
;
777 switch (SecKeyGetAlgorithmIdentifier(key
)) {
778 case kSecRSAAlgorithmID
:
779 table
= translationTableRSA
;
781 case kSecECDSAAlgorithmID
:
782 table
= translationTableECDSA
;
788 for (; table
->oid1
!= NULL
; table
++) {
789 if (SecAsn1OidCompare(table
->oid1
, &algId
->algorithm
) ||
790 (table
->oid2
!= NULL
&& SecAsn1OidCompare(table
->oid2
, &algId
->algorithm
))) {
791 return *table
->algorithms
[digestData
];
797 OSStatus
SecKeyDigestAndVerify(
798 SecKeyRef key
, /* Private key */
799 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
800 const uint8_t *dataToDigest
, /* signature over this data */
801 size_t dataToDigestLen
,/* length of dataToDigest */
802 const uint8_t *sig
, /* signature to verify */
803 size_t sigLen
) { /* length of sig */
805 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
806 if (algorithm
== NULL
) {
807 return errSecUnimplemented
;
810 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, sig
, sigLen
, NULL
, NULL
,
811 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
812 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
813 kCFBooleanTrue
: NULL
;
817 OSStatus
SecKeyDigestAndSign(
818 SecKeyRef key
, /* Private key */
819 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
820 const uint8_t *dataToDigest
, /* signature over this data */
821 size_t dataToDigestLen
,/* length of dataToDigest */
822 uint8_t *sig
, /* signature, RETURNED */
823 size_t *sigLen
) { /* IN/OUT */
824 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
825 if (algorithm
== NULL
) {
826 return errSecUnimplemented
;
829 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, NULL
, 0, sig
, sigLen
,
830 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
831 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
835 OSStatus
SecKeyVerifyDigest(
836 SecKeyRef key
, /* Private key */
837 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
838 const uint8_t *digestData
, /* signature over this digest */
839 size_t digestDataLen
,/* length of dataToDigest */
840 const uint8_t *sig
, /* signature to verify */
841 size_t sigLen
) { /* length of sig */
842 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
843 if (algorithm
== NULL
) {
844 return errSecUnimplemented
;
847 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, sig
, sigLen
, NULL
, NULL
,
848 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
849 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
850 kCFBooleanTrue
: NULL
;
854 OSStatus
SecKeySignDigest(
855 SecKeyRef key
, /* Private key */
856 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
857 const uint8_t *digestData
, /* signature over this digest */
858 size_t digestDataLen
,/* length of digestData */
859 uint8_t *sig
, /* signature, RETURNED */
860 size_t *sigLen
) { /* IN/OUT */
861 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
862 if (algorithm
== NULL
) {
863 return errSecUnimplemented
;
866 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, NULL
, 0, sig
, sigLen
,
867 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
868 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
872 CFIndex
SecKeyGetAlgorithmId(SecKeyRef key
) {
873 return SecKeyGetAlgorithmIdentifier(key
);
876 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
877 /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments,
878 with output in the second argument). Therefore, avoid implementing this function here
879 if compiling for OS X.
882 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
883 return SecKeyGetAlgorithmIdentifier(key
);
887 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
888 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
889 return key
->key_class
->copyPublic(key
, serializedPublic
);
890 return errSecUnimplemented
;
893 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
897 case kSecRSAAlgorithmID
:
898 return SecKeyCreateRSAPublicKey(allocator
,
899 keyData
, keyDataLength
,
900 kSecKeyEncodingBytes
);
901 case kSecECDSAAlgorithmID
:
902 return SecKeyCreateECPublicKey(allocator
,
903 keyData
, keyDataLength
,
904 kSecKeyEncodingBytes
);
910 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
912 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
915 // This is a bit icky hack to avoid changing the vtable for
917 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
919 size_t result
= SecKeyGetBlockSize(key
);
921 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmIdentifier(key
)) {
923 case kSecKeyEncryptedDataSize
:
926 case kSecKeySignatureSize
:
927 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
929 case kSecKeyKeySizeInBits
:
935 if (whichSize
== kSecKeyKeySizeInBits
)
942 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
944 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
945 kSecReturnRef
, kCFBooleanTrue
,
946 kSecClass
, kSecClassKey
,
947 kSecValuePersistentRef
, persistentRef
,
949 CFTypeRef foundRef
= NULL
;
950 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
952 if (status
== errSecSuccess
) {
953 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
954 *lookedUpData
= (SecKeyRef
) foundRef
;
956 status
= errSecSuccess
;
958 status
= errSecItemNotFound
;
962 CFReleaseSafe(foundRef
);
963 CFReleaseSafe(query
);
968 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
970 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
971 kSecReturnPersistentRef
, kCFBooleanTrue
,
973 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
975 CFTypeRef foundRef
= NULL
;
976 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
978 if (status
== errSecSuccess
) {
979 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
980 *persistentRef
= foundRef
;
983 status
= errSecItemNotFound
;
987 CFReleaseSafe(foundRef
);
988 CFReleaseSafe(query
);
997 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
999 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg");
1000 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint");
1001 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg");
1002 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags");
1003 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1004 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1006 #undef SEC_CONST_DECL
1009 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1015 if (key
->key_class
->version
> 2 && key
->key_class
->copyWrapKey
)
1016 return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
);
1017 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
);
1022 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1028 if (key
->key_class
->version
> 2 && key
->key_class
->copyUnwrapKey
)
1029 return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
);
1031 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
);
1035 static SInt32
SecKeyParamsGetSInt32(CFTypeRef value
, CFStringRef errName
, CFErrorRef
*error
) {
1037 if (CFGetTypeID(value
) == CFNumberGetTypeID()) {
1038 if (!CFNumberGetValue(value
, kCFNumberSInt32Type
, &result
) || result
< 0) {
1039 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1041 } else if (isString(value
)) {
1042 result
= CFStringGetIntValue(value
);
1043 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) result
);
1044 if (!CFEqual(t
, value
) || result
< 0) {
1045 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1050 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1055 SecKeyRef
SecKeyCreateWithData(CFDataRef keyData
, CFDictionaryRef parameters
, CFErrorRef
*error
) {
1057 SecKeyRef key
= NULL
;
1058 CFAllocatorRef allocator
= NULL
;
1060 /* First figure out the key type (algorithm). */
1062 CFTypeRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1063 require_quiet((algorithm
= SecKeyParamsGetSInt32(ktype
, CFSTR("key type"), error
)) >= 0, out
);
1065 CFTypeRef kclass
= CFDictionaryGetValue(parameters
, kSecAttrKeyClass
);
1066 require_quiet((class = SecKeyParamsGetSInt32(kclass
, CFSTR("key class"), error
)) >= 0, out
);
1069 case 0: // kSecAttrKeyClassPublic
1070 switch (algorithm
) {
1071 case 42: // kSecAlgorithmRSA
1072 key
= SecKeyCreateRSAPublicKey(allocator
,
1073 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1074 kSecKeyEncodingBytes
);
1076 SecError(errSecParam
, error
, CFSTR("RSA public key creation from data failed"));
1079 case 43: // kSecAlgorithmECDSA
1080 case 73: // kSecAlgorithmEC
1081 key
= SecKeyCreateECPublicKey(allocator
,
1082 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1083 kSecKeyEncodingBytes
);
1085 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1089 SecError(errSecParam
, error
, CFSTR("Unsupported public key type: %@"), ktype
);
1093 case 1: // kSecAttrKeyClassPrivate
1094 if (CFDictionaryGetValue(parameters
, kSecAttrTokenID
) != NULL
) {
1095 key
= SecKeyCreateCTKKey(allocator
, parameters
, error
);
1098 switch (algorithm
) {
1099 case 42: // kSecAlgorithmRSA
1100 key
= SecKeyCreateRSAPrivateKey(allocator
,
1101 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1102 kSecKeyEncodingBytes
);
1104 SecError(errSecParam
, error
, CFSTR("RSA private key creation from data failed"));
1107 case 43: // kSecAlgorithmECDSA
1108 case 73: // kSecAlgorithmEC
1109 key
= SecKeyCreateECPrivateKey(allocator
,
1110 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1111 kSecKeyEncodingBytes
);
1113 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1117 SecError(errSecParam
, error
, CFSTR("Unsupported private key type: %@"), ktype
);
1121 case 2: // kSecAttrKeyClassSymmetric
1122 SecError(errSecUnimplemented
, error
, CFSTR("Unsupported symmetric key type: %@"), ktype
);
1125 SecError(errSecParam
, error
, CFSTR("Unsupported key class: %@"), kclass
);
1133 CFDataRef
SecKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
1134 if (!key
->key_class
->copyExternalRepresentation
) {
1135 SecError(errSecUnimplemented
, error
, CFSTR("export not implemented for key %@"), key
);
1139 return key
->key_class
->copyExternalRepresentation(key
, error
);
1142 CFDictionaryRef
SecKeyCopyAttributes(SecKeyRef key
) {
1143 if (key
->key_class
->copyDictionary
)
1144 return key
->key_class
->copyDictionary(key
);
1148 SecKeyRef
SecKeyCopyPublicKey(SecKeyRef key
) {
1149 SecKeyRef result
= NULL
;
1150 if (key
->key_class
->version
>= 4 && key
->key_class
->copyPublicKey
) {
1151 result
= key
->key_class
->copyPublicKey(key
);
1152 if (result
!= NULL
) {
1157 CFDataRef serializedPublic
= NULL
;
1159 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &serializedPublic
), fail
);
1160 require_quiet(serializedPublic
, fail
);
1162 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmIdentifier(key
), serializedPublic
);
1165 CFReleaseSafe(serializedPublic
);
1169 SecKeyRef
SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1170 SecKeyRef privKey
= NULL
, pubKey
= NULL
;
1171 OSStatus status
= SecKeyGeneratePair(parameters
, &pubKey
, &privKey
);
1172 SecError(status
, error
, CFSTR("Key generation failed, error %d"), (int)status
);
1173 CFReleaseSafe(pubKey
);
1177 SecKeyRef
SecKeyCreateDuplicate(SecKeyRef key
) {
1178 if (key
->key_class
->version
>= 4 && key
->key_class
->createDuplicate
) {
1179 return key
->key_class
->createDuplicate(key
);
1181 return (SecKeyRef
)CFRetain(key
);
1185 Boolean
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
1186 if (key
->key_class
->version
>= 4 && key
->key_class
->setParameter
) {
1187 return key
->key_class
->setParameter(key
, name
, value
, error
);
1189 return SecError(errSecUnimplemented
, error
, CFSTR("setParameter not implemented for %@"), key
);
1193 #pragma mark Generic algorithm adaptor lookup and invocation
1195 static CFTypeRef
SecKeyCopyBackendOperationResult(SecKeyOperationContext
*context
, SecKeyAlgorithm algorithm
,
1196 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1197 CFTypeRef result
= kCFNull
;
1198 assert(CFArrayGetCount(context
->algorithm
) > 0);
1199 if (context
->key
->key_class
->version
>= 4 && context
->key
->key_class
->copyOperationResult
!= NULL
) {
1200 return context
->key
->key_class
->copyOperationResult(context
->key
, context
->operation
, algorithm
,
1201 context
->algorithm
, context
->mode
, in1
, in2
, error
);
1204 // Mapping from algorithms to legacy SecPadding values.
1205 static const struct {
1206 const SecKeyAlgorithm
*algorithm
;
1210 { &kSecKeyAlgorithmRSASignatureRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1211 { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1212 { &kSecKeyAlgorithmECDSASignatureRFC4754
, kSecECDSAAlgorithmID
, kSecPaddingSigRaw
},
1213 { &kSecKeyAlgorithmECDSASignatureDigestX962
, kSecECDSAAlgorithmID
, kSecPaddingPKCS1
},
1214 { &kSecKeyAlgorithmRSAEncryptionRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1215 { &kSecKeyAlgorithmRSAEncryptionPKCS1
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1216 { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1
, kSecRSAAlgorithmID
, kSecPaddingOAEP
},
1218 SecPadding padding
= (SecPadding
)-1;
1219 CFIndex keyAlg
= SecKeyGetAlgorithmIdentifier(context
->key
);
1220 for (size_t i
= 0; i
< array_size(paddingMap
); ++i
) {
1221 if (keyAlg
== paddingMap
[i
].keyAlg
&& CFEqual(algorithm
, *paddingMap
[i
].algorithm
)) {
1222 padding
= paddingMap
[i
].padding
;
1226 require_quiet(padding
!= (SecPadding
)-1, out
);
1228 // Check legacy virtual table entries.
1230 OSStatus status
= errSecSuccess
;
1231 switch (context
->operation
) {
1232 case kSecKeyOperationTypeSign
:
1233 if (context
->key
->key_class
->rawSign
!= NULL
) {
1234 result
= kCFBooleanTrue
;
1235 if (context
->mode
== kSecKeyOperationModePerform
) {
1236 size
= SecKeyGetSize(context
->key
, kSecKeySignatureSize
);
1237 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1238 status
= context
->key
->key_class
->rawSign(context
->key
, padding
,
1239 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1240 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1244 case kSecKeyOperationTypeVerify
:
1245 if (context
->key
->key_class
->rawVerify
!= NULL
) {
1246 result
= kCFBooleanTrue
;
1247 if (context
->mode
== kSecKeyOperationModePerform
) {
1248 status
= context
->key
->key_class
->rawVerify(context
->key
, padding
,
1249 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1250 CFDataGetBytePtr(in2
), CFDataGetLength(in2
));
1254 case kSecKeyOperationTypeEncrypt
:
1255 if (context
->key
->key_class
->encrypt
!= NULL
) {
1256 result
= kCFBooleanTrue
;
1257 if (context
->mode
== kSecKeyOperationModePerform
) {
1258 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1259 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1260 status
= context
->key
->key_class
->encrypt(context
->key
, padding
,
1261 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1262 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1266 case kSecKeyOperationTypeDecrypt
:
1267 if (context
->key
->key_class
->decrypt
!= NULL
) {
1268 result
= kCFBooleanTrue
;
1269 if (context
->mode
== kSecKeyOperationModePerform
) {
1270 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1271 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1272 status
= context
->key
->key_class
->decrypt(context
->key
, padding
,
1273 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1274 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1282 if (status
== errSecSuccess
) {
1283 if (CFGetTypeID(result
) == CFDataGetTypeID()) {
1284 CFDataSetLength((CFMutableDataRef
)result
, size
);
1287 SecError(status
, error
, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context
->operation
, (int)padding
);
1288 CFReleaseNull(result
);
1295 CFTypeRef
SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext
*context
, CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1297 // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error.
1298 CFIndex algorithmCount
= CFArrayGetCount(context
->algorithm
);
1299 for (CFIndex index
= 0; index
< algorithmCount
- 1; index
++) {
1300 SecKeyAlgorithm indexAlgorithm
= CFArrayGetValueAtIndex(context
->algorithm
, index
);
1301 for (CFIndex tested
= index
+ 1; tested
< algorithmCount
; tested
++) {
1302 require_quiet(!CFEqual(indexAlgorithm
, CFArrayGetValueAtIndex(context
->algorithm
, tested
)), fail
);
1306 SecKeyAlgorithm algorithm
= CFArrayGetValueAtIndex(context
->algorithm
, algorithmCount
- 1);
1307 CFTypeRef output
= SecKeyCopyBackendOperationResult(context
, algorithm
, in1
, in2
, error
);
1308 if (output
!= kCFNull
) {
1309 // Backend handled the operation, return result.
1313 // To silence static analyzer.
1314 CFReleaseSafe(output
);
1316 // Get adaptor which is able to handle requested algorithm.
1317 SecKeyAlgorithmAdaptor adaptor
= SecKeyGetAlgorithmAdaptor(context
->operation
, algorithm
);
1318 require_quiet(adaptor
!= NULL
, fail
);
1320 // Invoke the adaptor and return result.
1321 CFTypeRef result
= adaptor(context
, in1
, in2
, error
);
1322 require_quiet(result
!= kCFNull
, fail
);
1326 if (context
->mode
== kSecKeyOperationModePerform
) {
1327 SecError(errSecParam
, error
, CFSTR("%@: algorithm not supported by the key %@"),
1328 CFArrayGetValueAtIndex(context
->algorithm
, 0), context
->key
);
1335 #pragma mark Algorithm-related SecKey API entry points
1337 static CFMutableArrayRef
SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm
) {
1338 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1339 CFArrayAppendValue(result
, algorithm
);
1343 CFDataRef
SecKeyCreateSignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef dataToSign
, CFErrorRef
*error
) {
1344 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeSign
, SecKeyCreateAlgorithmArray(algorithm
) };
1345 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, dataToSign
, NULL
, error
);
1346 SecKeyOperationContextDestroy(&context
);
1350 Boolean
SecKeyVerifySignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef signedData
, CFDataRef signature
,
1351 CFErrorRef
*error
) {
1352 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeVerify
, SecKeyCreateAlgorithmArray(algorithm
) };
1353 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, signedData
, signature
, error
);
1354 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1356 SecKeyOperationContextDestroy(&context
);
1360 CFDataRef
SecKeyCreateEncryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plainText
, CFErrorRef
*error
) {
1361 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeEncrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1362 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, plainText
, NULL
, error
);
1363 SecKeyOperationContextDestroy(&context
);
1367 CFDataRef
SecKeyCreateDecryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef cipherText
, CFErrorRef
*error
) {
1368 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeDecrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1369 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, cipherText
, NULL
, error
);
1370 SecKeyOperationContextDestroy(&context
);
1374 CFDataRef
SecKeyCopyKeyExchangeResult(SecKeyRef key
, SecKeyAlgorithm algorithm
, SecKeyRef publicKey
,
1375 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1376 CFDataRef publicKeyData
= NULL
, result
= NULL
;
1377 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeKeyExchange
, SecKeyCreateAlgorithmArray(algorithm
) };
1378 require_quiet(publicKeyData
= SecKeyCopyExternalRepresentation(publicKey
, error
), out
);
1379 result
= SecKeyRunAlgorithmAndCopyResult(&context
, publicKeyData
, parameters
, error
);
1382 CFReleaseSafe(publicKeyData
);
1383 SecKeyOperationContextDestroy(&context
);
1387 Boolean
SecKeyIsAlgorithmSupported(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
) {
1388 SecKeyOperationContext context
= { key
, operation
, SecKeyCreateAlgorithmArray(algorithm
), kSecKeyOperationModeCheckIfSupported
};
1389 CFErrorRef error
= NULL
;
1390 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, NULL
, NULL
, &error
);
1391 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1393 CFReleaseSafe(error
);
1394 SecKeyOperationContextDestroy(&context
);