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
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"
45 #include <CoreFoundation/CFNumber.h>
46 #include <CoreFoundation/CFString.h>
47 #include <Security/SecBase.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
196 Boolean result
= CFEqual(d1
, d2
);
202 struct ccrng_state
*ccrng_seckey
;
204 CFGiblisWithFunctions(SecKey
, NULL
, NULL
, SecKeyDestroy
, SecKeyEqual
, NULL
, NULL
, SecKeyCopyDescription
, NULL
, NULL
, ^{
205 static struct ccrng_system_state ccrng_system_state_seckey
;
206 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
207 ccrng_system_init(&ccrng_system_state_seckey
);
210 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
211 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
213 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
214 return CFBooleanGetValue(value
);
216 secwarning("Value %@ for key %@ is not bool", value
, key
);
220 return default_value
;
223 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
224 CFDictionarySetValue(dict
, kSecValueRef
, item
);
225 return SecItemAdd(dict
, NULL
);
228 static void merge_params_applier(const void *key
, const void *value
,
230 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
231 CFDictionaryAddValue(result
, key
, value
);
234 /* Create a mutable dictionary that is based on the subdictionary for key
235 with any attributes from the top level dict merged in. */
236 static CF_RETURNS_RETAINED CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
238 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
239 CFMutableDictionaryRef result
;
242 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
243 /* Add everything in dict not already in result to result. */
244 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
246 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
249 /* Remove values that only belong in the top level dict. */
250 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
251 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
252 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
253 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
258 CFIndex
SecKeyGetAlgorithmIdentifier(SecKeyRef key
) {
259 if (!key
|| !key
->key_class
) {
260 // TBD: somehow, a key can be created with a NULL key_class in the
261 // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path
262 return kSecNullAlgorithmID
;
264 /* This method was added to version 1 keys. */
265 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
) {
266 return key
->key_class
->getAlgorithmID(key
);
268 /* All version 0 keys were RSA. */
269 return kSecRSAAlgorithmID
;
272 /* Generate a private/public keypair. */
273 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
274 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
275 OSStatus result
= errSecUnsupportedAlgorithm
;
276 SecKeyRef privKey
= NULL
;
277 SecKeyRef pubKey
= NULL
;
278 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
279 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
280 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
281 CFStringRef tokenID
= CFDictionaryGetValue(parameters
, kSecAttrTokenID
);
283 require_quiet(ktype
, errOut
);
285 if (tokenID
!= NULL
) {
286 result
= SecCTKKeyGeneratePair(parameters
, &pubKey
, &privKey
);
287 } else if (CFEqual(ktype
, kSecAttrKeyTypeECSECPrimeRandom
)) {
288 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
289 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
290 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
293 require_noerr_quiet(result
, errOut
);
295 /* Store the keys in the keychain if they are marked as permanent. */
296 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
297 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
299 /* Token-based private keys are automatically stored on the token. */
300 if (tokenID
== NULL
&& getBoolForKey(privParams
, kSecAttrIsPermanent
, false)) {
301 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
309 *privateKey
= privKey
;
314 CFReleaseSafe(pubParams
);
315 CFReleaseSafe(privParams
);
316 CFReleaseSafe(pubKey
);
317 CFReleaseSafe(privKey
);
322 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
323 return SecKeyCopyPublicKey(privateKey
);
326 CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
328 const CFTypeRef refType
= (returnPersistentRef
) ? kSecReturnPersistentRef
: kSecReturnRef
;
330 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
332 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
333 kSecClass
, kSecClassKey
,
334 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
335 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
336 kSecAttrApplicationLabel
, public_key_hash
,
337 refType
, kCFBooleanTrue
,
339 CFReleaseNull(public_key_hash
);
344 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
345 CFTypeRef persistentRef
= NULL
;
346 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
348 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
349 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
351 CFReleaseNull(query
);
352 return (CFDataRef
)persistentRef
;
355 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
356 SecKeyRef privateKey
= NULL
;
357 CFTypeRef queryResult
= NULL
;
358 CFDictionaryRef query
= NULL
;
360 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, CFSTR("Null Public Key")));
362 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
364 require_quiet(SecError(SecItemCopyMatching(query
, &queryResult
), error
,
365 CFSTR("Error finding private key from public: %@"), publicKey
), errOut
);
367 if (CFGetTypeID(queryResult
) == SecKeyGetTypeID()) {
368 privateKey
= (SecKeyRef
) queryResult
;
373 CFReleaseNull(query
);
374 CFReleaseNull(queryResult
);
378 OSStatus
SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey
, CFErrorRef
*error
) {
379 OSStatus retval
= errSecParam
;
380 CFTypeRef private_key
= NULL
;
381 CFDictionaryRef query
= NULL
;
383 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, NULL
, CFSTR("Null Public Key")));
385 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
387 retval
= SecItemCopyMatching(query
, &private_key
);
389 if (!retval
&& CFGetTypeID(private_key
) != SecKeyGetTypeID()) {
390 retval
= errSecInternalComponent
;
394 CFReleaseNull(query
);
395 CFReleaseNull(private_key
);
400 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
401 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
402 const SecAsn1Item
*keyData
) {
403 SecKeyRef publicKey
= NULL
;
404 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
406 /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of
407 SecKeyCreateRSAPublicKey, since on OS X the latter function will return
408 a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here.
410 publicKey
= SecKeyCreateRSAPublicKey_ios(allocator
,
411 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
412 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
415 .oidLength
= oid
->Length
,
416 .key
= keyData
->Data
,
417 .keyLength
= keyData
->Length
,
420 derKey
.parameters
= params
->Data
;
421 derKey
.parametersLength
= params
->Length
;
423 publicKey
= SecKeyCreateECPublicKey(allocator
,
424 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
426 secwarning("Unsupported algorithm oid");
433 SecKeyRef
SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator
, CFDataRef subjectPublicKeyInfoData
)
437 DERItem subjectPublicKeyInfoDER
= {
438 .data
= (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData
),
439 .length
= (DERSize
)CFDataGetLength(subjectPublicKeyInfoData
),
441 DERSubjPubKeyInfo subjectPublicKeyInfo
;
442 DERAlgorithmId algorithmId
;
445 drtn
= DERParseSequence(&subjectPublicKeyInfoDER
,
446 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
447 &subjectPublicKeyInfo
, sizeof(subjectPublicKeyInfo
));
449 require_noerr_quiet(drtn
, out
);
451 drtn
= DERParseSequenceContent(&subjectPublicKeyInfo
.algId
,
452 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
453 &algorithmId
, sizeof(algorithmId
));
454 require_noerr_quiet(drtn
, out
);
457 drtn
= DERParseBitString(&subjectPublicKeyInfo
.pubKey
, &pubKeyBytes
, &unusedBits
);
458 require_noerr_quiet(drtn
, out
);
460 /* Convert DERItem to SecAsn1Item : */
461 const SecAsn1Oid oid
= { .Data
= algorithmId
.oid
.data
, .Length
= algorithmId
.oid
.length
};
462 const SecAsn1Item params
= { .Data
= algorithmId
.params
.data
, .Length
= algorithmId
.params
.length
};
463 const SecAsn1Item pubKey
= { .Data
= pubKeyBytes
.data
, .Length
= pubKeyBytes
.length
};
465 return SecKeyCreatePublicFromDER(allocator
, &oid
, ¶ms
, &pubKey
);
475 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
476 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
477 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
478 if (!key_class
) return NULL
;
479 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
480 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
481 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
483 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
484 result
->key_class
= key_class
;
485 if (key_class
->extraBytes
) {
486 /* Make result->key point to the extraBytes we allocated. */
487 result
->key
= ((char*)result
) + sizeof(*result
);
489 if (key_class
->init
) {
491 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
493 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
502 static SecKeyAlgorithm
SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
503 switch (SecKeyGetAlgorithmIdentifier(key
)) {
504 case kSecRSAAlgorithmID
:
506 case kSecPaddingNone
:
507 return kSecKeyAlgorithmRSASignatureRaw
;
508 case kSecPaddingPKCS1
:
509 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
511 case kSecPaddingPKCS1SHA1
:
512 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
;
513 case kSecPaddingPKCS1SHA224
:
514 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
;
515 case kSecPaddingPKCS1SHA256
:
516 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
;
517 case kSecPaddingPKCS1SHA384
:
518 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
;
519 case kSecPaddingPKCS1SHA512
:
520 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
;
522 // On CSSM-based implementation, these functions actually did hash its input,
523 // so keep doing that for backward compatibility.
524 case kSecPaddingPKCS1SHA1
:
525 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
526 case kSecPaddingPKCS1SHA224
:
527 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
;
528 case kSecPaddingPKCS1SHA256
:
529 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
530 case kSecPaddingPKCS1SHA384
:
531 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
532 case kSecPaddingPKCS1SHA512
:
533 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
538 case kSecECDSAAlgorithmID
:
540 case kSecPaddingSigRaw
:
541 return kSecKeyAlgorithmECDSASignatureRFC4754
;
543 // Although it is not very logical, previous SecECKey implementation really considered
544 // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour
545 // for backward compatibility.
546 return kSecKeyAlgorithmECDSASignatureDigestX962
;
553 // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments
554 // used by legacy RawSign-style functions.
555 static OSStatus
SecKeyPerformLegacyOperation(SecKeyRef key
,
556 const uint8_t *in1Ptr
, size_t in1Len
,
557 const uint8_t *in2Ptr
, size_t in2Len
,
558 uint8_t *outPtr
, size_t *outLen
,
559 CFTypeRef (^operation
)(CFDataRef in1
, CFDataRef in2
, CFRange
*resultRange
, CFErrorRef
*error
)) {
560 CFErrorRef error
= NULL
;
561 OSStatus status
= errSecSuccess
;
562 CFDataRef in1
= CFDataCreateWithBytesNoCopy(NULL
, in1Ptr
, in1Len
, kCFAllocatorNull
);
563 CFDataRef in2
= in2Ptr
? CFDataCreateWithBytesNoCopy(NULL
, in2Ptr
, in2Len
, kCFAllocatorNull
) : NULL
;
564 CFRange range
= { 0, -1 };
565 CFTypeRef output
= operation(in1
, in2
, &range
, &error
);
566 require_quiet(output
, out
);
567 if (CFGetTypeID(output
) == CFDataGetTypeID() && outLen
!= NULL
) {
568 if (range
.length
== -1) {
569 range
.length
= CFDataGetLength(output
);
571 require_action_quiet((size_t)range
.length
<= *outLen
, out
,
572 SecError(errSecParam
, &error
, CFSTR("buffer too small")));
573 *outLen
= range
.length
;
574 CFDataGetBytes(output
, range
, outPtr
);
580 CFReleaseSafe(output
);
582 status
= SecErrorGetOSStatus(error
);
583 if (status
== errSecVerifyFailed
) {
584 // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed.
585 status
= errSSLCrypto
;
592 OSStatus
SecKeyRawSign(
593 SecKeyRef key
, /* Private key */
594 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
595 const uint8_t *dataToSign
, /* signature over this data */
596 size_t dataToSignLen
, /* length of dataToSign */
597 uint8_t *sig
, /* signature, RETURNED */
598 size_t *sigLen
) { /* IN/OUT */
599 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
600 if (algorithm
== NULL
) {
603 return SecKeyPerformLegacyOperation(key
, dataToSign
, dataToSignLen
, NULL
, 0, sig
, sigLen
,
604 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
605 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
609 OSStatus
SecKeyRawVerify(
610 SecKeyRef key
, /* Public key */
611 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
612 const uint8_t *signedData
, /* signature over this data */
613 size_t signedDataLen
, /* length of dataToSign */
614 const uint8_t *sig
, /* signature */
615 size_t sigLen
) { /* length of signature */
616 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
617 if (algorithm
== NULL
) {
620 OSStatus status
= SecKeyPerformLegacyOperation(key
, signedData
, signedDataLen
, sig
, sigLen
, NULL
, NULL
,
621 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
622 return in2
!= NULL
&& SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
)
623 ? kCFBooleanTrue
: NULL
;
628 static SecKeyAlgorithm
SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
629 switch (SecKeyGetAlgorithmIdentifier(key
)) {
630 case kSecRSAAlgorithmID
:
632 case kSecPaddingNone
:
633 return kSecKeyAlgorithmRSAEncryptionRaw
;
634 case kSecPaddingPKCS1
:
635 return kSecKeyAlgorithmRSAEncryptionPKCS1
;
636 case kSecPaddingOAEP
:
637 return kSecKeyAlgorithmRSAEncryptionOAEPSHA1
;
646 OSStatus
SecKeyEncrypt(
647 SecKeyRef key
, /* Public key */
648 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
649 const uint8_t *plainText
,
650 size_t plainTextLen
, /* length of plainText */
652 size_t *cipherTextLen
) { /* IN/OUT */
653 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
654 if (algorithm
== NULL
) {
658 return SecKeyPerformLegacyOperation(key
, plainText
, plainTextLen
, NULL
, 0, cipherText
, cipherTextLen
,
659 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
660 return SecKeyCreateEncryptedData(key
, algorithm
, in1
, error
);
664 OSStatus
SecKeyDecrypt(
665 SecKeyRef key
, /* Private key */
666 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
667 const uint8_t *cipherText
,
668 size_t cipherTextLen
, /* length of cipherText */
670 size_t *plainTextLen
) { /* IN/OUT */
671 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
672 if (algorithm
== NULL
) {
675 return SecKeyPerformLegacyOperation(key
, cipherText
, cipherTextLen
, NULL
, 0, plainText
, plainTextLen
,
676 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
677 CFDataRef decrypted
= SecKeyCreateDecryptedData(key
, algorithm
, in1
, error
);
679 if (decrypted
!= NULL
&& algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
&&
680 *(data
= CFDataGetBytePtr(decrypted
)) == 0x00) {
681 // Strip zero-padding from the beginning of the block, as the contract of this
683 range
->length
= CFDataGetLength(decrypted
);
684 while (*data
== 0x00 && range
->length
> 0) {
694 size_t SecKeyGetBlockSize(SecKeyRef key
) {
695 if (key
->key_class
->blockSize
)
696 return key
->key_class
->blockSize(key
);
700 /* Private API functions. */
702 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
703 if (key
->key_class
->copyDictionary
)
704 return key
->key_class
->copyDictionary(key
);
708 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
709 CFErrorRef error
= NULL
;
710 SecKeyRef key
= SecKeyCreateWithData(CFDictionaryGetValue(refAttributes
, kSecValueData
), refAttributes
, &error
);
712 CFStringRef description
= CFErrorCopyDescription(error
);
713 secwarning("%@", description
);
714 CFRelease(description
);
720 static SecKeyAlgorithm
SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key
, const SecAsn1AlgId
*algId
, bool digestData
) {
721 static const struct TableItem
{
722 const SecAsn1Oid
*oid1
, *oid2
;
723 const SecKeyAlgorithm
*algorithms
[2];
724 } translationTableRSA
[] = {
725 { &CSSMOID_SHA1WithRSA
, &CSSMOID_SHA1
, {
726 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
,
727 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
,
729 { &CSSMOID_SHA224WithRSA
, &CSSMOID_SHA224
, {
730 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
,
731 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
,
733 { &CSSMOID_SHA256WithRSA
, &CSSMOID_SHA256
, {
734 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
,
735 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
,
737 { &CSSMOID_SHA384WithRSA
, &CSSMOID_SHA384
, {
738 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
,
739 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
,
741 { &CSSMOID_SHA512WithRSA
, &CSSMOID_SHA512
, {
742 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
,
743 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
,
745 { &CSSMOID_MD5
, NULL
, {
746 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
747 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
750 }, translationTableECDSA
[] = {
751 { &CSSMOID_ECDSA_WithSHA1
, &CSSMOID_SHA1
, {
752 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
753 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1
,
755 { &CSSMOID_ECDSA_WithSHA224
, &CSSMOID_SHA224
, {
756 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
757 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224
,
759 { &CSSMOID_ECDSA_WithSHA256
, &CSSMOID_SHA256
, {
760 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
761 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256
,
763 { &CSSMOID_ECDSA_WithSHA384
, &CSSMOID_SHA384
, {
764 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
765 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384
,
767 { &CSSMOID_ECDSA_WithSHA512
, &CSSMOID_SHA512
, {
768 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
769 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512
,
774 const struct TableItem
*table
;
775 switch (SecKeyGetAlgorithmIdentifier(key
)) {
776 case kSecRSAAlgorithmID
:
777 table
= translationTableRSA
;
779 case kSecECDSAAlgorithmID
:
780 table
= translationTableECDSA
;
786 for (; table
->oid1
!= NULL
; table
++) {
787 if (SecAsn1OidCompare(table
->oid1
, &algId
->algorithm
) ||
788 (table
->oid2
!= NULL
&& SecAsn1OidCompare(table
->oid2
, &algId
->algorithm
))) {
789 return *table
->algorithms
[digestData
];
795 OSStatus
SecKeyDigestAndVerify(
796 SecKeyRef key
, /* Private key */
797 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
798 const uint8_t *dataToDigest
, /* signature over this data */
799 size_t dataToDigestLen
,/* length of dataToDigest */
800 const uint8_t *sig
, /* signature to verify */
801 size_t sigLen
) { /* length of sig */
803 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
804 if (algorithm
== NULL
) {
805 return errSecUnimplemented
;
808 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, sig
, sigLen
, NULL
, NULL
,
809 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
810 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
811 kCFBooleanTrue
: NULL
;
815 OSStatus
SecKeyDigestAndSign(
816 SecKeyRef key
, /* Private key */
817 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
818 const uint8_t *dataToDigest
, /* signature over this data */
819 size_t dataToDigestLen
,/* length of dataToDigest */
820 uint8_t *sig
, /* signature, RETURNED */
821 size_t *sigLen
) { /* IN/OUT */
822 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
823 if (algorithm
== NULL
) {
824 return errSecUnimplemented
;
827 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, NULL
, 0, sig
, sigLen
,
828 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
829 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
833 OSStatus
SecKeyVerifyDigest(
834 SecKeyRef key
, /* Private key */
835 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
836 const uint8_t *digestData
, /* signature over this digest */
837 size_t digestDataLen
,/* length of dataToDigest */
838 const uint8_t *sig
, /* signature to verify */
839 size_t sigLen
) { /* length of sig */
840 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
841 if (algorithm
== NULL
) {
842 return errSecUnimplemented
;
845 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, sig
, sigLen
, NULL
, NULL
,
846 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
847 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
848 kCFBooleanTrue
: NULL
;
852 OSStatus
SecKeySignDigest(
853 SecKeyRef key
, /* Private key */
854 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
855 const uint8_t *digestData
, /* signature over this digest */
856 size_t digestDataLen
,/* length of digestData */
857 uint8_t *sig
, /* signature, RETURNED */
858 size_t *sigLen
) { /* IN/OUT */
859 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
860 if (algorithm
== NULL
) {
861 return errSecUnimplemented
;
864 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, NULL
, 0, sig
, sigLen
,
865 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
866 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
870 CFIndex
SecKeyGetAlgorithmId(SecKeyRef key
) {
871 return SecKeyGetAlgorithmIdentifier(key
);
874 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
875 /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments,
876 with output in the second argument). Therefore, avoid implementing this function here
877 if compiling for OS X.
880 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
881 return SecKeyGetAlgorithmIdentifier(key
);
885 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
886 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
887 return key
->key_class
->copyPublic(key
, serializedPublic
);
888 return errSecUnimplemented
;
891 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
895 case kSecRSAAlgorithmID
:
896 return SecKeyCreateRSAPublicKey(allocator
,
897 keyData
, keyDataLength
,
898 kSecKeyEncodingBytes
);
899 case kSecECDSAAlgorithmID
:
900 return SecKeyCreateECPublicKey(allocator
,
901 keyData
, keyDataLength
,
902 kSecKeyEncodingBytes
);
908 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
910 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
913 // This is a bit icky hack to avoid changing the vtable for
915 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
917 size_t result
= SecKeyGetBlockSize(key
);
919 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmIdentifier(key
)) {
921 case kSecKeyEncryptedDataSize
:
924 case kSecKeySignatureSize
:
925 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
927 case kSecKeyKeySizeInBits
:
933 if (whichSize
== kSecKeyKeySizeInBits
)
940 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
942 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
943 kSecReturnRef
, kCFBooleanTrue
,
944 kSecClass
, kSecClassKey
,
945 kSecValuePersistentRef
, persistentRef
,
947 CFTypeRef foundRef
= NULL
;
948 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
950 if (status
== errSecSuccess
) {
951 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
952 *lookedUpData
= (SecKeyRef
) foundRef
;
954 status
= errSecSuccess
;
956 status
= errSecItemNotFound
;
960 CFReleaseSafe(foundRef
);
961 CFReleaseSafe(query
);
966 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
968 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
969 kSecReturnPersistentRef
, kCFBooleanTrue
,
971 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
973 CFTypeRef foundRef
= NULL
;
974 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
976 if (status
== errSecSuccess
) {
977 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
978 *persistentRef
= foundRef
;
981 status
= errSecItemNotFound
;
985 CFReleaseSafe(foundRef
);
986 CFReleaseSafe(query
);
995 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
997 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg");
998 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint");
999 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg");
1000 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags");
1001 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1002 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1004 #undef SEC_CONST_DECL
1007 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1013 if (key
->key_class
->version
> 2 && key
->key_class
->copyWrapKey
)
1014 return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
);
1015 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
);
1020 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1026 if (key
->key_class
->version
> 2 && key
->key_class
->copyUnwrapKey
)
1027 return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
);
1029 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
);
1033 static SInt32
SecKeyParamsGetSInt32(CFTypeRef value
, CFStringRef errName
, CFErrorRef
*error
) {
1035 if (CFGetTypeID(value
) == CFNumberGetTypeID()) {
1036 if (!CFNumberGetValue(value
, kCFNumberSInt32Type
, &result
) || result
< 0) {
1037 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1039 } else if (isString(value
)) {
1040 result
= CFStringGetIntValue(value
);
1041 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) result
);
1042 if (!CFEqual(t
, value
) || result
< 0) {
1043 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1048 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1053 SecKeyRef
SecKeyCreateWithData(CFDataRef keyData
, CFDictionaryRef parameters
, CFErrorRef
*error
) {
1055 SecKeyRef key
= NULL
;
1056 CFAllocatorRef allocator
= NULL
;
1058 /* First figure out the key type (algorithm). */
1060 CFTypeRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1061 require_quiet((algorithm
= SecKeyParamsGetSInt32(ktype
, CFSTR("key type"), error
)) >= 0, out
);
1063 CFTypeRef kclass
= CFDictionaryGetValue(parameters
, kSecAttrKeyClass
);
1064 require_quiet((class = SecKeyParamsGetSInt32(kclass
, CFSTR("key class"), error
)) >= 0, out
);
1067 case 0: // kSecAttrKeyClassPublic
1068 switch (algorithm
) {
1069 case 42: // kSecAlgorithmRSA
1070 key
= SecKeyCreateRSAPublicKey(allocator
,
1071 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1072 kSecKeyEncodingBytes
);
1074 SecError(errSecParam
, error
, CFSTR("RSA public key creation from data failed"));
1077 case 43: // kSecAlgorithmECDSA
1078 case 73: // kSecAlgorithmEC
1079 key
= SecKeyCreateECPublicKey(allocator
,
1080 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1081 kSecKeyEncodingBytes
);
1083 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1087 SecError(errSecParam
, error
, CFSTR("Unsupported public key type: %@"), ktype
);
1091 case 1: // kSecAttrKeyClassPrivate
1092 if (CFDictionaryGetValue(parameters
, kSecAttrTokenID
) != NULL
) {
1093 key
= SecKeyCreateCTKKey(allocator
, parameters
, error
);
1096 switch (algorithm
) {
1097 case 42: // kSecAlgorithmRSA
1098 key
= SecKeyCreateRSAPrivateKey(allocator
,
1099 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1100 kSecKeyEncodingBytes
);
1102 SecError(errSecParam
, error
, CFSTR("RSA private key creation from data failed"));
1105 case 43: // kSecAlgorithmECDSA
1106 case 73: // kSecAlgorithmEC
1107 key
= SecKeyCreateECPrivateKey(allocator
,
1108 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1109 kSecKeyEncodingBytes
);
1111 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1115 SecError(errSecParam
, error
, CFSTR("Unsupported private key type: %@"), ktype
);
1119 case 2: // kSecAttrKeyClassSymmetric
1120 SecError(errSecUnimplemented
, error
, CFSTR("Unsupported symmetric key type: %@"), ktype
);
1123 SecError(errSecParam
, error
, CFSTR("Unsupported key class: %@"), kclass
);
1131 CFDataRef
SecKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
1132 if (!key
->key_class
->copyExternalRepresentation
) {
1133 SecError(errSecUnimplemented
, error
, CFSTR("export not implemented for key %@"), key
);
1137 return key
->key_class
->copyExternalRepresentation(key
, error
);
1140 CFDictionaryRef
SecKeyCopyAttributes(SecKeyRef key
) {
1141 if (key
->key_class
->copyDictionary
)
1142 return key
->key_class
->copyDictionary(key
);
1146 SecKeyRef
SecKeyCopyPublicKey(SecKeyRef key
) {
1147 SecKeyRef result
= NULL
;
1148 if (key
->key_class
->version
>= 4 && key
->key_class
->copyPublicKey
) {
1149 result
= key
->key_class
->copyPublicKey(key
);
1150 if (result
!= NULL
) {
1155 CFDataRef serializedPublic
= NULL
;
1157 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &serializedPublic
), fail
);
1158 require_quiet(serializedPublic
, fail
);
1160 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmIdentifier(key
), serializedPublic
);
1163 CFReleaseSafe(serializedPublic
);
1167 SecKeyRef
SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1168 SecKeyRef privKey
= NULL
, pubKey
= NULL
;
1169 OSStatus status
= SecKeyGeneratePair(parameters
, &pubKey
, &privKey
);
1170 SecError(status
, error
, CFSTR("Key generation failed, error %d"), (int)status
);
1171 CFReleaseSafe(pubKey
);
1175 SecKeyRef
SecKeyCreateDuplicate(SecKeyRef key
) {
1176 if (key
->key_class
->version
>= 4 && key
->key_class
->createDuplicate
) {
1177 return key
->key_class
->createDuplicate(key
);
1179 return (SecKeyRef
)CFRetain(key
);
1183 #pragma mark Generic algorithm adaptor lookup and invocation
1185 static CFTypeRef
SecKeyCopyBackendOperationResult(SecKeyOperationContext
*context
, SecKeyAlgorithm algorithm
,
1186 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1187 CFTypeRef result
= NULL
;
1188 assert(CFArrayGetCount(context
->algorithm
) > 0);
1189 if (context
->key
->key_class
->version
>= 4 && context
->key
->key_class
->copyOperationResult
!= NULL
) {
1190 return context
->key
->key_class
->copyOperationResult(context
->key
, context
->operation
, algorithm
,
1191 context
->algorithm
, context
->mode
, in1
, in2
, error
);
1194 // Mapping from algorithms to legacy SecPadding values.
1195 static const struct {
1196 const SecKeyAlgorithm
*algorithm
;
1200 { &kSecKeyAlgorithmRSASignatureRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1201 { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1202 { &kSecKeyAlgorithmECDSASignatureRFC4754
, kSecECDSAAlgorithmID
, kSecPaddingSigRaw
},
1203 { &kSecKeyAlgorithmECDSASignatureDigestX962
, kSecECDSAAlgorithmID
, kSecPaddingPKCS1
},
1204 { &kSecKeyAlgorithmRSAEncryptionRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1205 { &kSecKeyAlgorithmRSAEncryptionPKCS1
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1206 { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1
, kSecRSAAlgorithmID
, kSecPaddingOAEP
},
1208 SecPadding padding
= (SecPadding
)-1;
1209 CFIndex keyAlg
= SecKeyGetAlgorithmIdentifier(context
->key
);
1210 for (size_t i
= 0; i
< array_size(paddingMap
); ++i
) {
1211 if (keyAlg
== paddingMap
[i
].keyAlg
&& CFEqual(algorithm
, *paddingMap
[i
].algorithm
)) {
1212 padding
= paddingMap
[i
].padding
;
1216 require_quiet(padding
!= (SecPadding
)-1, out
);
1218 // Check legacy virtual table entries.
1220 OSStatus status
= errSecSuccess
;
1221 switch (context
->operation
) {
1222 case kSecKeyOperationTypeSign
:
1223 if (context
->key
->key_class
->rawSign
!= NULL
) {
1224 result
= kCFBooleanTrue
;
1225 if (context
->mode
== kSecKeyOperationModePerform
) {
1226 size
= SecKeyGetSize(context
->key
, kSecKeySignatureSize
);
1227 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1228 status
= context
->key
->key_class
->rawSign(context
->key
, padding
,
1229 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1230 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1234 case kSecKeyOperationTypeVerify
:
1235 if (context
->key
->key_class
->rawVerify
!= NULL
) {
1236 result
= kCFBooleanTrue
;
1237 if (context
->mode
== kSecKeyOperationModePerform
) {
1238 status
= context
->key
->key_class
->rawVerify(context
->key
, padding
,
1239 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1240 CFDataGetBytePtr(in2
), CFDataGetLength(in2
));
1244 case kSecKeyOperationTypeEncrypt
:
1245 if (context
->key
->key_class
->encrypt
!= NULL
) {
1246 result
= kCFBooleanTrue
;
1247 if (context
->mode
== kSecKeyOperationModePerform
) {
1248 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1249 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1250 status
= context
->key
->key_class
->encrypt(context
->key
, padding
,
1251 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1252 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1256 case kSecKeyOperationTypeDecrypt
:
1257 if (context
->key
->key_class
->decrypt
!= NULL
) {
1258 result
= kCFBooleanTrue
;
1259 if (context
->mode
== kSecKeyOperationModePerform
) {
1260 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1261 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1262 status
= context
->key
->key_class
->decrypt(context
->key
, padding
,
1263 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1264 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1272 if (status
== errSecSuccess
) {
1273 if (CFGetTypeID(result
) == CFDataGetTypeID()) {
1274 CFDataSetLength((CFMutableDataRef
)result
, size
);
1277 SecError(status
, error
, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context
->operation
, (int)padding
);
1278 CFReleaseNull(result
);
1285 CFTypeRef
SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext
*context
, CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1287 // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error.
1288 CFIndex algorithmCount
= CFArrayGetCount(context
->algorithm
);
1289 for (CFIndex index
= 0; index
< algorithmCount
- 1; index
++) {
1290 SecKeyAlgorithm indexAlgorithm
= CFArrayGetValueAtIndex(context
->algorithm
, index
);
1291 for (CFIndex tested
= index
+ 1; tested
< algorithmCount
; tested
++) {
1292 require_quiet(!CFEqual(indexAlgorithm
, CFArrayGetValueAtIndex(context
->algorithm
, tested
)), fail
);
1296 SecKeyAlgorithm algorithm
= CFArrayGetValueAtIndex(context
->algorithm
, algorithmCount
- 1);
1297 CFTypeRef output
= SecKeyCopyBackendOperationResult(context
, algorithm
, in1
, in2
, error
);
1298 if (output
!= kCFNull
) {
1299 // Backend handled the operation, return result.
1303 // To silence static analyzer.
1304 CFReleaseSafe(output
);
1306 // Get adaptor which is able to handle requested algorithm.
1307 SecKeyAlgorithmAdaptor adaptor
= SecKeyGetAlgorithmAdaptor(context
->operation
, algorithm
);
1308 require_quiet(adaptor
!= NULL
, fail
);
1310 // Invoke the adaptor and return result.
1311 CFTypeRef result
= adaptor(context
, in1
, in2
, error
);
1312 require_quiet(result
!= kCFNull
, fail
);
1316 if (context
->mode
== kSecKeyOperationModePerform
) {
1317 SecError(errSecParam
, error
, CFSTR("%@: algorithm not supported by the key %@"),
1318 CFArrayGetValueAtIndex(context
->algorithm
, 0), context
->key
);
1325 #pragma mark Algorithm-related SecKey API entry points
1327 static CFMutableArrayRef
SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm
) {
1328 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1329 CFArrayAppendValue(result
, algorithm
);
1333 CFDataRef
SecKeyCreateSignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef dataToSign
, CFErrorRef
*error
) {
1334 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeSign
, SecKeyCreateAlgorithmArray(algorithm
) };
1335 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, dataToSign
, NULL
, error
);
1336 SecKeyOperationContextDestroy(&context
);
1340 Boolean
SecKeyVerifySignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef signedData
, CFDataRef signature
,
1341 CFErrorRef
*error
) {
1342 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeVerify
, SecKeyCreateAlgorithmArray(algorithm
) };
1343 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, signedData
, signature
, error
);
1344 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1346 SecKeyOperationContextDestroy(&context
);
1350 CFDataRef
SecKeyCreateEncryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plainText
, CFErrorRef
*error
) {
1351 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeEncrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1352 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, plainText
, NULL
, error
);
1353 SecKeyOperationContextDestroy(&context
);
1357 CFDataRef
SecKeyCreateDecryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef cipherText
, CFErrorRef
*error
) {
1358 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeDecrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1359 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, cipherText
, NULL
, error
);
1360 SecKeyOperationContextDestroy(&context
);
1364 CFDataRef
SecKeyCopyKeyExchangeResult(SecKeyRef key
, SecKeyAlgorithm algorithm
, SecKeyRef publicKey
,
1365 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1366 CFDataRef publicKeyData
= NULL
, result
= NULL
;
1367 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeKeyExchange
, SecKeyCreateAlgorithmArray(algorithm
) };
1368 require_quiet(publicKeyData
= SecKeyCopyExternalRepresentation(publicKey
, error
), out
);
1369 result
= SecKeyRunAlgorithmAndCopyResult(&context
, publicKeyData
, parameters
, error
);
1372 CFReleaseSafe(publicKeyData
);
1373 SecKeyOperationContextDestroy(&context
);
1377 Boolean
SecKeyIsAlgorithmSupported(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
) {
1378 SecKeyOperationContext context
= { key
, operation
, SecKeyCreateAlgorithmArray(algorithm
), kSecKeyOperationModeCheckIfSupported
};
1379 CFErrorRef error
= NULL
;
1380 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, NULL
, NULL
, &error
);
1381 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1383 CFReleaseSafe(error
);
1384 SecKeyOperationContextDestroy(&context
);