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 "SecKeyPriv.h"
41 #include "SecRSAKeyPriv.h"
42 #include "SecECKeyPriv.h"
43 #include "SecCTKKeyPriv.h"
44 #include "SecBasePriv.h"
46 #include <CoreFoundation/CFNumber.h>
47 #include <CoreFoundation/CFString.h>
48 #include <CoreFoundation/CFPriv.h>
51 #include <AssertMacros.h>
52 #include <utilities/debugging.h>
53 #include <utilities/SecCFError.h>
54 #include <CommonCrypto/CommonDigest.h>
55 #include <Security/SecAsn1Coder.h>
56 #include <Security/oidsalg.h>
57 #include <Security/SecInternal.h>
58 #include <Security/SecRandom.h>
59 #include <Security/SecureTransport.h> /* For error codes. */
61 #include <corecrypto/ccrng_system.h>
67 #include <libDER/asn1Types.h>
68 #include <libDER/DER_Keys.h>
69 #include <libDER/DER_Encode.h>
71 CFDataRef
SecKeyCopyPublicKeyHash(SecKeyRef key
)
73 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
75 /* encode the public key. */
76 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
77 require_quiet(pubKeyBlob
, errOut
);
79 /* Calculate the digest of the public key. */
80 require_quiet(pubKeyDigest
= SecSHA1DigestCreate(CFGetAllocator(key
),
81 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
84 CFReleaseNull(pubKeyBlob
);
91 static CFDictionaryRef
SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key
,
93 CFDataRef privateBlob
)
95 CFAllocatorRef allocator
= CFGetAllocator(key
);
97 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
98 CFDictionaryRef dict
= NULL
;
100 size_t sizeValue
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
);
101 CFNumberRef sizeInBits
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
);
103 /* encode the public key. */
104 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
105 require_quiet(pubKeyBlob
, errOut
);
107 /* Calculate the digest of the public key. */
108 require_quiet(pubKeyDigest
= SecSHA1DigestCreate(allocator
,
109 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
112 DICT_ADDPAIR(kSecClass
, kSecClassKey
);
113 DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob
? kSecAttrKeyClassPrivate
: kSecAttrKeyClassPublic
);
114 DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
);
115 DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
);
116 DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
);
117 DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
);
118 DICT_ADDPAIR(kSecAttrKeyType
, keyType
);
119 DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
);
120 DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
);
121 DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
);
122 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
);
123 DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
);
124 DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
);
125 DICT_ADDPAIR(kSecAttrCanEncrypt
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
126 DICT_ADDPAIR(kSecAttrCanDecrypt
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
127 DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
);
128 DICT_ADDPAIR(kSecAttrCanSign
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
129 DICT_ADDPAIR(kSecAttrCanVerify
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
130 DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
);
131 DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
);
132 DICT_ADDPAIR(kSecAttrCanWrap
, privateBlob
? kCFBooleanFalse
: kCFBooleanTrue
);
133 DICT_ADDPAIR(kSecAttrCanUnwrap
, privateBlob
? kCFBooleanTrue
: kCFBooleanFalse
);
134 DICT_ADDPAIR(kSecValueData
, privateBlob
? privateBlob
: pubKeyBlob
);
135 dict
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
138 // @@@ Zero out key material.
139 CFReleaseSafe(pubKeyDigest
);
140 CFReleaseSafe(pubKeyBlob
);
141 CFReleaseSafe(sizeInBits
);
146 CFDictionaryRef
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
,
148 CFDataRef privateBlob
)
150 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, privateBlob
);
153 CFDictionaryRef
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
)
155 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, NULL
);
158 static CFStringRef
SecKeyCopyDescription(CFTypeRef cf
) {
159 SecKeyRef key
= (SecKeyRef
)cf
;
161 if(key
->key_class
->describe
)
162 return key
->key_class
->describe(key
);
164 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
);
167 static void SecKeyDestroy(CFTypeRef cf
) {
168 SecKeyRef key
= (SecKeyRef
)cf
;
170 CFReleaseNull(key
->cdsaKey
);
172 if (key
->key_class
->destroy
)
173 key
->key_class
->destroy(key
);
176 static Boolean
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
)
178 SecKeyRef key1
= (SecKeyRef
)cf1
;
179 SecKeyRef key2
= (SecKeyRef
)cf2
;
182 if (!key2
|| key1
->key_class
!= key2
->key_class
)
184 if (key1
->key_class
->version
>= 4 && key1
->key_class
->isEqual
)
185 return key1
->key_class
->isEqual(key1
, key2
);
186 if (key1
->key_class
->extraBytes
)
187 return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
);
189 /* TODO: Won't work when we get reference keys. */
190 CFDictionaryRef d1
, d2
;
191 d1
= SecKeyCopyAttributeDictionary(key1
);
192 d2
= SecKeyCopyAttributeDictionary(key2
);
193 // Returning NULL is an error; bail out of the equality check
199 Boolean result
= CFEqual(d1
, d2
);
205 struct ccrng_state
*ccrng_seckey
;
207 CFGiblisWithFunctions(SecKey
, NULL
, NULL
, SecKeyDestroy
, SecKeyEqual
, NULL
, NULL
, SecKeyCopyDescription
, NULL
, NULL
, ^{
208 static struct ccrng_system_state ccrng_system_state_seckey
;
209 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
210 ccrng_system_init(&ccrng_system_state_seckey
);
213 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
214 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
216 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
217 return CFBooleanGetValue(value
);
219 secwarning("Value %@ for key %@ is not bool", value
, key
);
223 return default_value
;
226 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
227 CFDictionarySetValue(dict
, kSecValueRef
, item
);
228 return SecItemAdd(dict
, NULL
);
231 static void merge_params_applier(const void *key
, const void *value
,
233 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
234 CFDictionaryAddValue(result
, key
, value
);
237 /* Create a mutable dictionary that is based on the subdictionary for key
238 with any attributes from the top level dict merged in. */
239 static CF_RETURNS_RETAINED CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
241 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
242 CFMutableDictionaryRef result
;
245 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
246 /* Add everything in dict not already in result to result. */
247 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
249 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
252 /* Remove values that only belong in the top level dict. */
253 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
254 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
255 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
256 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
261 CFIndex
SecKeyGetAlgorithmId(SecKeyRef key
) {
262 if (!key
|| !key
->key_class
) {
263 // TBD: somehow, a key can be created with a NULL key_class in the
264 // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path
265 return kSecNullAlgorithmID
;
267 /* This method was added to version 1 keys. */
268 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
) {
269 return key
->key_class
->getAlgorithmID(key
);
271 /* All version 0 keys were RSA. */
272 return kSecRSAAlgorithmID
;
275 /* Generate a private/public keypair. */
276 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
277 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
278 OSStatus result
= errSecUnsupportedAlgorithm
;
279 SecKeyRef privKey
= NULL
;
280 SecKeyRef pubKey
= NULL
;
281 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
282 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
283 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
284 CFStringRef tokenID
= CFDictionaryGetValue(parameters
, kSecAttrTokenID
);
286 require_quiet(ktype
, errOut
);
288 if (tokenID
!= NULL
) {
289 result
= SecCTKKeyGeneratePair(parameters
, &pubKey
, &privKey
);
290 } else if (CFEqual(ktype
, kSecAttrKeyTypeECSECPrimeRandom
)) {
291 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
292 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
293 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
296 require_noerr_quiet(result
, errOut
);
298 // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default
299 // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys).
300 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
301 CFDictionaryRemoveValue(pubParams
, kSecAttrTokenID
);
302 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
304 if (getBoolForKey(privParams
, kSecAttrIsPermanent
, CFDictionaryContainsKey(privParams
, kSecAttrTokenID
))) {
305 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
313 *privateKey
= privKey
;
318 CFReleaseSafe(pubParams
);
319 CFReleaseSafe(privParams
);
320 CFReleaseSafe(pubKey
);
321 CFReleaseSafe(privKey
);
326 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
327 return SecKeyCopyPublicKey(privateKey
);
330 CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
332 const CFTypeRef refType
= (returnPersistentRef
) ? kSecReturnPersistentRef
: kSecReturnRef
;
334 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
336 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
337 kSecClass
, kSecClassKey
,
338 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
339 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
340 kSecAttrApplicationLabel
, public_key_hash
,
341 refType
, kCFBooleanTrue
,
343 CFReleaseNull(public_key_hash
);
348 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
349 CFTypeRef persistentRef
= NULL
;
350 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
352 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
353 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
355 CFReleaseNull(query
);
356 return (CFDataRef
)persistentRef
;
359 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
360 SecKeyRef privateKey
= NULL
;
361 CFTypeRef queryResult
= NULL
;
362 CFDictionaryRef query
= NULL
;
364 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, CFSTR("Null Public Key")));
366 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
368 require_quiet(SecError(SecItemCopyMatching(query
, &queryResult
), error
,
369 CFSTR("Error finding private key from public: %@"), publicKey
), errOut
);
371 if (CFGetTypeID(queryResult
) == SecKeyGetTypeID()) {
372 privateKey
= (SecKeyRef
) queryResult
;
377 CFReleaseNull(query
);
378 CFReleaseNull(queryResult
);
382 OSStatus
SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey
, CFErrorRef
*error
) {
383 OSStatus retval
= errSecParam
;
384 CFTypeRef private_key
= NULL
;
385 CFDictionaryRef query
= NULL
;
387 require_action_quiet(publicKey
!= NULL
, errOut
, SecError(errSecParam
, error
, NULL
, CFSTR("Null Public Key")));
389 query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
391 retval
= SecItemCopyMatching(query
, &private_key
);
393 if (!retval
&& CFGetTypeID(private_key
) != SecKeyGetTypeID()) {
394 retval
= errSecInternalComponent
;
398 CFReleaseNull(query
);
399 CFReleaseNull(private_key
);
404 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
405 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
406 const SecAsn1Item
*keyData
) {
407 SecKeyRef publicKey
= NULL
;
408 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
410 /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of
411 SecKeyCreateRSAPublicKey, since on OS X the latter function will return
412 a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here.
414 publicKey
= SecKeyCreateRSAPublicKey_ios(allocator
,
415 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
416 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
419 .oidLength
= oid
->Length
,
420 .key
= keyData
->Data
,
421 .keyLength
= keyData
->Length
,
424 derKey
.parameters
= params
->Data
;
425 derKey
.parametersLength
= params
->Length
;
427 publicKey
= SecKeyCreateECPublicKey(allocator
,
428 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
430 secwarning("Unsupported algorithm oid");
437 SecKeyRef
SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator
, CFDataRef subjectPublicKeyInfoData
)
441 DERItem subjectPublicKeyInfoDER
= {
442 .data
= (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData
),
443 .length
= (DERSize
)CFDataGetLength(subjectPublicKeyInfoData
),
445 DERSubjPubKeyInfo subjectPublicKeyInfo
;
446 DERAlgorithmId algorithmId
;
449 drtn
= DERParseSequence(&subjectPublicKeyInfoDER
,
450 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
451 &subjectPublicKeyInfo
, sizeof(subjectPublicKeyInfo
));
453 require_noerr_quiet(drtn
, out
);
455 drtn
= DERParseSequenceContent(&subjectPublicKeyInfo
.algId
,
456 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
457 &algorithmId
, sizeof(algorithmId
));
458 require_noerr_quiet(drtn
, out
);
461 drtn
= DERParseBitString(&subjectPublicKeyInfo
.pubKey
, &pubKeyBytes
, &unusedBits
);
462 require_noerr_quiet(drtn
, out
);
464 /* Convert DERItem to SecAsn1Item : */
465 const SecAsn1Oid oid
= { .Data
= algorithmId
.oid
.data
, .Length
= algorithmId
.oid
.length
};
466 const SecAsn1Item params
= { .Data
= algorithmId
.params
.data
, .Length
= algorithmId
.params
.length
};
467 const SecAsn1Item pubKey
= { .Data
= pubKeyBytes
.data
, .Length
= pubKeyBytes
.length
};
469 return SecKeyCreatePublicFromDER(allocator
, &oid
, ¶ms
, &pubKey
);
476 static const DERByte oidRSA
[] = {
477 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
479 static const DERByte oidECsecp256
[] = {
480 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
482 static const DERByte oidECsecp384
[] = {
483 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
485 static const DERByte oidECsecp521
[] = {
486 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
490 CFDataRef
SecKeyCopySubjectPublicKeyInfo(SecKeyRef key
)
492 CFMutableDataRef data
= NULL
;
493 CFDataRef publicKey
= NULL
;
494 CFDataRef dataret
= NULL
;
495 DERSubjPubKeyInfo spki
;
499 memset(&spki
, 0, sizeof(spki
));
501 /* encode the public key. */
502 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &publicKey
), errOut
);
503 require_quiet(publicKey
, errOut
);
505 require_quiet(CFDataGetLength(publicKey
) != 0, errOut
);
507 // Add prefix 00 is needed to avoid creating negative bit strings
508 if (((uint8_t *)CFDataGetBytePtr(publicKey
))[0] & 0x80)
512 CFMutableDataRef paddedKey
= CFDataCreateMutable(NULL
, 0);
513 /* the bit strings bits used field first */
514 CFDataAppendBytes(paddedKey
, (const UInt8
*)"\x00", 1);
516 CFDataAppendBytes(paddedKey
, (const UInt8
*)"\x00", 1);
518 CFDataAppendBytes(paddedKey
, CFDataGetBytePtr(publicKey
), CFDataGetLength(publicKey
));
519 CFTransferRetained(publicKey
, paddedKey
);
521 spki
.pubKey
.data
= (DERByte
*)CFDataGetBytePtr(publicKey
);
522 spki
.pubKey
.length
= CFDataGetLength(publicKey
);
524 // Encode algId according to algorithm used.
525 CFIndex algorithm
= SecKeyGetAlgorithmId(key
);
526 if (algorithm
== kSecRSAAlgorithmID
) {
527 spki
.algId
.data
= (DERByte
*)oidRSA
;
528 spki
.algId
.length
= sizeof(oidRSA
);
529 } else if (algorithm
== kSecECDSAAlgorithmID
) {
530 SecECNamedCurve curve
= SecECKeyGetNamedCurve(key
);
532 case kSecECCurveSecp256r1
:
533 spki
.algId
.data
= (DERByte
*)oidECsecp256
;
534 spki
.algId
.length
= sizeof(oidECsecp256
);
536 case kSecECCurveSecp384r1
:
537 spki
.algId
.data
= (DERByte
*)oidECsecp384
;
538 spki
.algId
.length
= sizeof(oidECsecp384
);
540 case kSecECCurveSecp521r1
:
541 spki
.algId
.data
= (DERByte
*)oidECsecp521
;
542 spki
.algId
.length
= sizeof(oidECsecp521
);
551 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &spki
,
552 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
553 data
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
554 CFDataSetLength(data
, size
);
556 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &spki
,
557 DERNumSubjPubKeyInfoItemSpecs
,
558 DERSubjPubKeyInfoItemSpecs
,
559 CFDataGetMutableBytePtr(data
), &size
);
560 require_quiet(drtn
== DR_Success
, errOut
);
561 CFDataSetLength(data
, size
);
563 dataret
= CFRetain(data
);
566 CFReleaseNull(publicKey
);
573 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
574 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
575 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
576 if (!key_class
) return NULL
;
577 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
578 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
579 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
581 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
582 result
->key_class
= key_class
;
583 if (key_class
->extraBytes
) {
584 /* Make result->key point to the extraBytes we allocated. */
585 result
->key
= ((char*)result
) + sizeof(*result
);
587 if (key_class
->init
) {
589 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
591 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
600 static SecKeyAlgorithm
SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
601 switch (SecKeyGetAlgorithmId(key
)) {
602 case kSecRSAAlgorithmID
: {
604 if (!_CFMZEnabled()) {
605 // On CSSM-based implementation, these functions actually did hash its input,
606 // so keep doing that for backward compatibility.
608 case kSecPaddingNone
:
609 return kSecKeyAlgorithmRSASignatureRaw
;
610 case kSecPaddingPKCS1
:
611 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
612 case kSecPaddingPKCS1SHA1
:
613 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
614 case kSecPaddingPKCS1SHA224
:
615 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
;
616 case kSecPaddingPKCS1SHA256
:
617 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
618 case kSecPaddingPKCS1SHA384
:
619 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
620 case kSecPaddingPKCS1SHA512
:
621 return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
629 case kSecPaddingNone
:
630 return kSecKeyAlgorithmRSASignatureRaw
;
631 case kSecPaddingPKCS1
:
632 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
;
633 case kSecPaddingPKCS1SHA1
:
634 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
;
635 case kSecPaddingPKCS1SHA224
:
636 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
;
637 case kSecPaddingPKCS1SHA256
:
638 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
;
639 case kSecPaddingPKCS1SHA384
:
640 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
;
641 case kSecPaddingPKCS1SHA512
:
642 return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
;
648 case kSecECDSAAlgorithmID
:
650 case kSecPaddingSigRaw
:
651 return kSecKeyAlgorithmECDSASignatureRFC4754
;
653 // Although it is not very logical, previous SecECKey implementation really considered
654 // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour
655 // for backward compatibility.
656 return kSecKeyAlgorithmECDSASignatureDigestX962
;
663 // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments
664 // used by legacy RawSign-style functions.
665 static OSStatus
SecKeyPerformLegacyOperation(SecKeyRef key
,
666 const uint8_t *in1Ptr
, size_t in1Len
,
667 const uint8_t *in2Ptr
, size_t in2Len
,
668 uint8_t *outPtr
, size_t *outLen
,
669 CFTypeRef (^operation
)(CFDataRef in1
, CFDataRef in2
, CFRange
*resultRange
, CFErrorRef
*error
)) {
670 CFErrorRef error
= NULL
;
671 OSStatus status
= errSecSuccess
;
672 CFDataRef in1
= CFDataCreateWithBytesNoCopy(NULL
, in1Ptr
, in1Len
, kCFAllocatorNull
);
673 CFDataRef in2
= CFDataCreateWithBytesNoCopy(NULL
, in2Ptr
, in2Len
, kCFAllocatorNull
);
674 CFRange range
= { 0, -1 };
675 CFTypeRef output
= operation(in1
, in2
, &range
, &error
);
676 require_quiet(output
, out
);
677 if (CFGetTypeID(output
) == CFDataGetTypeID() && outLen
!= NULL
) {
678 if (range
.length
== -1) {
679 range
.length
= CFDataGetLength(output
);
681 require_action_quiet((size_t)range
.length
<= *outLen
, out
,
682 SecError(errSecParam
, &error
, CFSTR("buffer too small")));
683 *outLen
= range
.length
;
684 CFDataGetBytes(output
, range
, outPtr
);
690 CFReleaseSafe(output
);
692 status
= SecErrorGetOSStatus(error
);
693 if (status
== errSecVerifyFailed
) {
694 // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed.
695 status
= errSSLCrypto
;
702 OSStatus
SecKeyRawSign(
703 SecKeyRef key
, /* Private key */
704 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
705 const uint8_t *dataToSign
, /* signature over this data */
706 size_t dataToSignLen
, /* length of dataToSign */
707 uint8_t *sig
, /* signature, RETURNED */
708 size_t *sigLen
) { /* IN/OUT */
709 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
710 if (algorithm
== NULL
) {
713 return SecKeyPerformLegacyOperation(key
, dataToSign
, dataToSignLen
, NULL
, 0, sig
, sigLen
,
714 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
715 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
719 OSStatus
SecKeyRawVerify(
720 SecKeyRef key
, /* Public key */
721 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
722 const uint8_t *signedData
, /* signature over this data */
723 size_t signedDataLen
, /* length of dataToSign */
724 const uint8_t *sig
, /* signature */
725 size_t sigLen
) { /* length of signature */
726 SecKeyAlgorithm algorithm
= SecKeyGetSignatureAlgorithmForPadding(key
, padding
);
727 if (algorithm
== NULL
) {
730 OSStatus status
= SecKeyPerformLegacyOperation(key
, signedData
, signedDataLen
, sig
, sigLen
, NULL
, NULL
,
731 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
732 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
)
733 ? kCFBooleanTrue
: NULL
;
738 static SecKeyAlgorithm
SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key
, SecPadding padding
) {
739 switch (SecKeyGetAlgorithmId(key
)) {
740 case kSecRSAAlgorithmID
:
742 case kSecPaddingNone
:
743 return kSecKeyAlgorithmRSAEncryptionRaw
;
744 case kSecPaddingPKCS1
:
745 return kSecKeyAlgorithmRSAEncryptionPKCS1
;
746 case kSecPaddingOAEP
:
747 return kSecKeyAlgorithmRSAEncryptionOAEPSHA1
;
756 OSStatus
SecKeyEncrypt(
757 SecKeyRef key
, /* Public key */
758 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
759 const uint8_t *plainText
,
760 size_t plainTextLen
, /* length of plainText */
762 size_t *cipherTextLen
) { /* IN/OUT */
763 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
764 if (algorithm
== NULL
) {
768 return SecKeyPerformLegacyOperation(key
, plainText
, plainTextLen
, NULL
, 0, cipherText
, cipherTextLen
,
769 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
770 return SecKeyCreateEncryptedData(key
, algorithm
, in1
, error
);
774 OSStatus
SecKeyDecrypt(
775 SecKeyRef key
, /* Private key */
776 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
777 const uint8_t *cipherText
,
778 size_t cipherTextLen
, /* length of cipherText */
780 size_t *plainTextLen
) { /* IN/OUT */
781 SecKeyAlgorithm algorithm
= SecKeyGetEncryptionAlgorithmForPadding(key
, padding
);
782 if (algorithm
== NULL
) {
785 return SecKeyPerformLegacyOperation(key
, cipherText
, cipherTextLen
, NULL
, 0, plainText
, plainTextLen
,
786 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
787 CFDataRef decrypted
= SecKeyCreateDecryptedData(key
, algorithm
, in1
, error
);
789 if (decrypted
!= NULL
&& algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
&&
790 *(data
= CFDataGetBytePtr(decrypted
)) == 0x00) {
791 // Strip zero-padding from the beginning of the block, as the contract of this
793 range
->length
= CFDataGetLength(decrypted
);
794 while (*data
== 0x00 && range
->length
> 0) {
804 size_t SecKeyGetBlockSize(SecKeyRef key
) {
805 if (key
->key_class
->blockSize
)
806 return key
->key_class
->blockSize(key
);
810 /* Private API functions. */
812 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
813 return SecKeyCopyAttributes(key
);
816 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
817 CFErrorRef error
= NULL
;
818 SecKeyRef key
= SecKeyCreateWithData(CFDictionaryGetValue(refAttributes
, kSecValueData
), refAttributes
, &error
);
820 CFStringRef description
= CFErrorCopyDescription(error
);
821 secwarning("%@", description
);
822 CFRelease(description
);
828 static SecKeyAlgorithm
SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key
, const SecAsn1AlgId
*algId
, bool digestData
) {
829 static const struct TableItem
{
830 const SecAsn1Oid
*oid1
, *oid2
;
831 const SecKeyAlgorithm
*algorithms
[2];
832 } translationTableRSA
[] = {
833 { &CSSMOID_SHA1WithRSA
, &CSSMOID_SHA1
, {
834 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
,
835 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
,
837 { &CSSMOID_SHA224WithRSA
, &CSSMOID_SHA224
, {
838 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
,
839 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
,
841 { &CSSMOID_SHA256WithRSA
, &CSSMOID_SHA256
, {
842 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
,
843 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
,
845 { &CSSMOID_SHA384WithRSA
, &CSSMOID_SHA384
, {
846 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
,
847 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
,
849 { &CSSMOID_SHA512WithRSA
, &CSSMOID_SHA512
, {
850 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
,
851 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
,
853 { &CSSMOID_MD5
, NULL
, {
854 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
855 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
857 { &CSSMOID_MD5WithRSA
, NULL
, {
858 [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
,
859 [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5
,
862 }, translationTableECDSA
[] = {
863 { &CSSMOID_ECDSA_WithSHA1
, &CSSMOID_SHA1
, {
864 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
865 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1
,
867 { &CSSMOID_ECDSA_WithSHA224
, &CSSMOID_SHA224
, {
868 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
869 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224
,
871 { &CSSMOID_ECDSA_WithSHA256
, &CSSMOID_SHA256
, {
872 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
873 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256
,
875 { &CSSMOID_ECDSA_WithSHA384
, &CSSMOID_SHA384
, {
876 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
877 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384
,
879 { &CSSMOID_ECDSA_WithSHA512
, &CSSMOID_SHA512
, {
880 [false] = &kSecKeyAlgorithmECDSASignatureDigestX962
,
881 [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512
,
886 const struct TableItem
*table
;
887 switch (SecKeyGetAlgorithmId(key
)) {
888 case kSecRSAAlgorithmID
:
889 table
= translationTableRSA
;
891 case kSecECDSAAlgorithmID
:
892 table
= translationTableECDSA
;
898 for (; table
->oid1
!= NULL
; table
++) {
899 if (SecAsn1OidCompare(table
->oid1
, &algId
->algorithm
) ||
900 (table
->oid2
!= NULL
&& SecAsn1OidCompare(table
->oid2
, &algId
->algorithm
))) {
901 return *table
->algorithms
[digestData
];
907 OSStatus
SecKeyDigestAndVerify(
908 SecKeyRef key
, /* Private key */
909 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
910 const uint8_t *dataToDigest
, /* signature over this data */
911 size_t dataToDigestLen
,/* length of dataToDigest */
912 const uint8_t *sig
, /* signature to verify */
913 size_t sigLen
) { /* length of sig */
915 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
916 if (algorithm
== NULL
) {
917 return errSecUnimplemented
;
920 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, sig
, sigLen
, NULL
, NULL
,
921 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
922 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
923 kCFBooleanTrue
: NULL
;
927 OSStatus
SecKeyDigestAndSign(
928 SecKeyRef key
, /* Private key */
929 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
930 const uint8_t *dataToDigest
, /* signature over this data */
931 size_t dataToDigestLen
,/* length of dataToDigest */
932 uint8_t *sig
, /* signature, RETURNED */
933 size_t *sigLen
) { /* IN/OUT */
934 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, true);
935 if (algorithm
== NULL
) {
936 return errSecUnimplemented
;
939 return SecKeyPerformLegacyOperation(key
, dataToDigest
, dataToDigestLen
, NULL
, 0, sig
, sigLen
,
940 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
941 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
945 OSStatus
SecKeyVerifyDigest(
946 SecKeyRef key
, /* Private key */
947 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
948 const uint8_t *digestData
, /* signature over this digest */
949 size_t digestDataLen
,/* length of dataToDigest */
950 const uint8_t *sig
, /* signature to verify */
951 size_t sigLen
) { /* length of sig */
952 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
953 if (algorithm
== NULL
) {
954 return errSecUnimplemented
;
957 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, sig
, sigLen
, NULL
, NULL
,
958 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
959 return SecKeyVerifySignature(key
, algorithm
, in1
, in2
, error
) ?
960 kCFBooleanTrue
: NULL
;
964 OSStatus
SecKeySignDigest(
965 SecKeyRef key
, /* Private key */
966 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
967 const uint8_t *digestData
, /* signature over this digest */
968 size_t digestDataLen
,/* length of digestData */
969 uint8_t *sig
, /* signature, RETURNED */
970 size_t *sigLen
) { /* IN/OUT */
971 SecKeyAlgorithm algorithm
= SecKeyGetAlgorithmForSecAsn1AlgId(key
, algId
, false);
972 if (algorithm
== NULL
) {
973 return errSecUnimplemented
;
976 return SecKeyPerformLegacyOperation(key
, digestData
, digestDataLen
, NULL
, 0, sig
, sigLen
,
977 ^CFTypeRef(CFDataRef in1
, CFDataRef in2
, CFRange
*range
, CFErrorRef
*error
) {
978 return SecKeyCreateSignature(key
, algorithm
, in1
, error
);
983 /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments,
984 with output in the second argument). Therefore, avoid implementing this function here
985 if compiling for OS X.
988 // Export original SecKeyGetAlgorithmID symbol for backward binary compatibility.
989 #undef SecKeyGetAlgorithmID
990 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
);
991 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
992 return SecKeyGetAlgorithmId(key
);
996 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
997 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
998 return key
->key_class
->copyPublic(key
, serializedPublic
);
999 return errSecUnimplemented
;
1002 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
1004 switch (algorithmID
)
1006 case kSecRSAAlgorithmID
:
1007 return SecKeyCreateRSAPublicKey(allocator
,
1008 keyData
, keyDataLength
,
1009 kSecKeyEncodingBytes
);
1010 case kSecECDSAAlgorithmID
:
1011 return SecKeyCreateECPublicKey(allocator
,
1012 keyData
, keyDataLength
,
1013 kSecKeyEncodingBytes
);
1019 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
1021 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
1024 // This is a bit icky hack to avoid changing the vtable for
1026 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
1028 size_t result
= SecKeyGetBlockSize(key
);
1030 if (whichSize
== 0 || whichSize
== 10) {
1031 // kSecKeyKeySizeInBits is declared as 0 on iOS (SPI) and 10 on macOS (API). Unified implementation
1032 // here deals with both values.
1033 whichSize
= kSecKeyKeySizeInBits
;
1036 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmId(key
)) {
1037 switch (whichSize
) {
1038 case kSecKeyEncryptedDataSize
:
1041 case kSecKeySignatureSize
:
1042 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
1044 case kSecKeyKeySizeInBits
:
1050 if (whichSize
== kSecKeyKeySizeInBits
)
1057 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
1059 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1060 kSecReturnRef
, kCFBooleanTrue
,
1061 kSecClass
, kSecClassKey
,
1062 kSecValuePersistentRef
, persistentRef
,
1064 CFTypeRef foundRef
= NULL
;
1065 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1067 if (status
== errSecSuccess
) {
1068 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
1069 *lookedUpData
= (SecKeyRef
) foundRef
;
1071 status
= errSecSuccess
;
1073 status
= errSecItemNotFound
;
1077 CFReleaseSafe(foundRef
);
1078 CFReleaseSafe(query
);
1083 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
1086 secerror("SecKeyCopyPersistentRef: Need a key reference for this to work");
1089 if (!persistentRef
) {
1090 secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work");
1094 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1095 kSecReturnPersistentRef
, kCFBooleanTrue
,
1097 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
1099 CFTypeRef foundRef
= NULL
;
1100 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1102 if (status
== errSecSuccess
) {
1103 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
1104 *persistentRef
= foundRef
;
1107 secerror("SecKeyCopyPersistentRef: SecItemCopyMatching returned success, but we got type %lu instead of CFData for key %@.", CFGetTypeID(foundRef
), key
);
1108 status
= errSecItemNotFound
;
1111 secerror("SecKeyCopyPersistentRef: received status %i for key %@", (int)status
, key
);
1112 CFStringRef str
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Expected to find persistentref for key %@"), key
);
1113 __security_stackshotreport(str
, (int)status
);
1117 CFReleaseSafe(foundRef
);
1118 CFReleaseSafe(query
);
1127 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
1129 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg");
1130 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint");
1131 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg");
1132 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags");
1133 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1134 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1136 #undef SEC_CONST_DECL
1139 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1145 if (key
->key_class
->version
> 2 && key
->key_class
->copyWrapKey
)
1146 return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
);
1147 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
);
1152 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1158 if (key
->key_class
->version
> 2 && key
->key_class
->copyUnwrapKey
)
1159 return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
);
1161 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
);
1165 static CFIndex
SecKeyParamsGetCFIndex(CFTypeRef value
, CFStringRef errName
, CFErrorRef
*error
) {
1166 CFIndex result
= -1;
1167 CFNumberRef localValue
= NULL
;
1169 if (isString(value
)) {
1170 CFNumberFormatterRef formatter
= CFNumberFormatterCreate(kCFAllocatorDefault
, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle
);
1171 localValue
= CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault
, formatter
, value
, NULL
, kCFNumberFormatterParseIntegersOnly
);
1172 CFReleaseSafe(formatter
);
1175 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue
);
1176 if (CFEqual(t
, value
)) {
1183 if (value
!= NULL
&& CFGetTypeID(value
) == CFNumberGetTypeID()) {
1184 if (!CFNumberGetValue(value
, kCFNumberCFIndexType
, &result
) || result
< 0) {
1185 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1188 SecError(errSecParam
, error
, CFSTR("Unsupported %@: %@"), errName
, value
);
1191 CFReleaseSafe(localValue
);
1195 SecKeyRef
SecKeyCreateWithData(CFDataRef keyData
, CFDictionaryRef parameters
, CFErrorRef
*error
) {
1197 SecKeyRef key
= NULL
;
1198 CFAllocatorRef allocator
= NULL
;
1200 if (CFDictionaryGetValue(parameters
, kSecAttrTokenID
) != NULL
) {
1201 return SecKeyCreateCTKKey(allocator
, parameters
, error
);
1203 else if (!keyData
) {
1204 SecError(errSecParam
, error
, CFSTR("Failed to provide key data to SecKeyCreateWithData"));
1207 /* First figure out the key type (algorithm). */
1208 CFIndex algorithm
, class;
1209 CFTypeRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1210 require_quiet((algorithm
= SecKeyParamsGetCFIndex(ktype
, CFSTR("key type"), error
)) >= 0, out
);
1211 CFTypeRef kclass
= CFDictionaryGetValue(parameters
, kSecAttrKeyClass
);
1212 require_quiet((class = SecKeyParamsGetCFIndex(kclass
, CFSTR("key class"), error
)) >= 0, out
);
1215 case 0: // kSecAttrKeyClassPublic
1216 switch (algorithm
) {
1217 case 42: // kSecAlgorithmRSA
1218 key
= SecKeyCreateRSAPublicKey(allocator
,
1219 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1220 kSecKeyEncodingBytes
);
1222 SecError(errSecParam
, error
, CFSTR("RSA public key creation from data failed"));
1225 case 43: // kSecAlgorithmECDSA
1226 case 73: // kSecAlgorithmEC
1227 key
= SecKeyCreateECPublicKey(allocator
,
1228 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1229 kSecKeyEncodingBytes
);
1231 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1235 SecError(errSecParam
, error
, CFSTR("Unsupported public key type: %@"), ktype
);
1239 case 1: // kSecAttrKeyClassPrivate
1240 switch (algorithm
) {
1241 case 42: // kSecAlgorithmRSA
1242 key
= SecKeyCreateRSAPrivateKey(allocator
,
1243 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1244 kSecKeyEncodingBytes
);
1246 SecError(errSecParam
, error
, CFSTR("RSA private key creation from data failed"));
1249 case 43: // kSecAlgorithmECDSA
1250 case 73: // kSecAlgorithmEC
1251 key
= SecKeyCreateECPrivateKey(allocator
,
1252 CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
),
1253 kSecKeyEncodingBytes
);
1255 SecError(errSecParam
, error
, CFSTR("EC public key creation from data failed"));
1259 SecError(errSecParam
, error
, CFSTR("Unsupported private key type: %@"), ktype
);
1263 case 2: // kSecAttrKeyClassSymmetric
1264 SecError(errSecUnimplemented
, error
, CFSTR("Unsupported symmetric key type: %@"), ktype
);
1267 SecError(errSecParam
, error
, CFSTR("Unsupported key class: %@"), kclass
);
1275 // Similar to CFErrorPropagate, but does not consult input value of *error, it can contain any garbage and if overwritten, previous value is never released.
1276 static inline bool SecKeyErrorPropagate(bool succeeded
, CFErrorRef possibleError CF_CONSUMED
, CFErrorRef
*error
) {
1281 *error
= possibleError
;
1283 CFRelease(possibleError
);
1289 CFDataRef
SecKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
1290 if (!key
->key_class
->copyExternalRepresentation
) {
1291 if (error
!= NULL
) {
1294 SecError(errSecUnimplemented
, error
, CFSTR("export not implemented for key %@"), key
);
1298 CFErrorRef localError
= NULL
;
1299 CFDataRef result
= key
->key_class
->copyExternalRepresentation(key
, &localError
);
1300 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1304 CFDictionaryRef
SecKeyCopyAttributes(SecKeyRef key
) {
1305 if (key
->key_class
->copyDictionary
) {
1306 return key
->key_class
->copyDictionary(key
);
1308 // Create dictionary with basic values derived from other known information of the key.
1309 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1310 CFIndex blockSize
= SecKeyGetBlockSize(key
) * 8;
1311 if (blockSize
> 0) {
1312 CFNumberRef blockSizeRef
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &blockSize
);
1313 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, blockSizeRef
);
1314 CFRelease(blockSizeRef
);
1317 switch (SecKeyGetAlgorithmId(key
)) {
1318 case kSecRSAAlgorithmID
:
1319 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
1321 case kSecECDSAAlgorithmID
:
1322 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECSECPrimeRandom
);
1326 if (key
->key_class
->rawSign
!= NULL
|| key
->key_class
->decrypt
!= NULL
) {
1327 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1328 } else if (key
->key_class
->rawVerify
!= NULL
|| key
->key_class
->encrypt
!= NULL
) {
1329 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1336 SecKeyRef
SecKeyCopyPublicKey(SecKeyRef key
) {
1337 SecKeyRef result
= NULL
;
1338 if (key
->key_class
->version
>= 4 && key
->key_class
->copyPublicKey
) {
1339 result
= key
->key_class
->copyPublicKey(key
);
1340 if (result
!= NULL
) {
1345 CFDataRef serializedPublic
= NULL
;
1347 require_noerr_quiet(SecKeyCopyPublicBytes(key
, &serializedPublic
), fail
);
1348 require_quiet(serializedPublic
, fail
);
1350 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmId(key
), serializedPublic
);
1353 CFReleaseSafe(serializedPublic
);
1357 SecKeyRef
SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1358 SecKeyRef privKey
= NULL
, pubKey
= NULL
;
1359 OSStatus status
= SecKeyGeneratePair(parameters
, &pubKey
, &privKey
);
1360 if (status
!= errSecSuccess
) {
1361 if (error
!= NULL
) {
1364 SecError(status
, error
, CFSTR("Key generation failed, error %d"), (int)status
);
1366 CFReleaseSafe(pubKey
);
1370 SecKeyRef
SecKeyCreateDuplicate(SecKeyRef key
) {
1371 if (key
->key_class
->version
>= 4 && key
->key_class
->createDuplicate
) {
1372 return key
->key_class
->createDuplicate(key
);
1374 return (SecKeyRef
)CFRetain(key
);
1378 Boolean
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
1379 if (key
->key_class
->version
>= 4 && key
->key_class
->setParameter
) {
1380 CFErrorRef localError
= NULL
;
1381 Boolean result
= key
->key_class
->setParameter(key
, name
, value
, &localError
);
1382 SecKeyErrorPropagate(result
, localError
, error
);
1385 if (error
!= NULL
) {
1388 return SecError(errSecUnimplemented
, error
, CFSTR("setParameter not implemented for %@"), key
);
1392 #pragma mark Generic algorithm adaptor lookup and invocation
1394 static CFTypeRef
SecKeyCopyBackendOperationResult(SecKeyOperationContext
*context
, SecKeyAlgorithm algorithm
,
1395 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1396 CFTypeRef result
= kCFNull
;
1397 assert(CFArrayGetCount(context
->algorithm
) > 0);
1398 if (context
->key
->key_class
->version
>= 4 && context
->key
->key_class
->copyOperationResult
!= NULL
) {
1399 return context
->key
->key_class
->copyOperationResult(context
->key
, context
->operation
, algorithm
,
1400 context
->algorithm
, context
->mode
, in1
, in2
, error
);
1403 // Mapping from algorithms to legacy SecPadding values.
1404 static const struct {
1405 const SecKeyAlgorithm
*algorithm
;
1409 { &kSecKeyAlgorithmRSASignatureRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1410 { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1411 { &kSecKeyAlgorithmECDSASignatureRFC4754
, kSecECDSAAlgorithmID
, kSecPaddingSigRaw
},
1412 { &kSecKeyAlgorithmECDSASignatureDigestX962
, kSecECDSAAlgorithmID
, kSecPaddingPKCS1
},
1413 { &kSecKeyAlgorithmRSAEncryptionRaw
, kSecRSAAlgorithmID
, kSecPaddingNone
},
1414 { &kSecKeyAlgorithmRSAEncryptionPKCS1
, kSecRSAAlgorithmID
, kSecPaddingPKCS1
},
1415 { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1
, kSecRSAAlgorithmID
, kSecPaddingOAEP
},
1417 SecPadding padding
= (SecPadding
)-1;
1418 CFIndex keyAlg
= SecKeyGetAlgorithmId(context
->key
);
1419 for (size_t i
= 0; i
< array_size(paddingMap
); ++i
) {
1420 if (keyAlg
== paddingMap
[i
].keyAlg
&& CFEqual(algorithm
, *paddingMap
[i
].algorithm
)) {
1421 padding
= paddingMap
[i
].padding
;
1425 require_quiet(padding
!= (SecPadding
)-1, out
);
1427 // Check legacy virtual table entries.
1429 OSStatus status
= errSecSuccess
;
1430 switch (context
->operation
) {
1431 case kSecKeyOperationTypeSign
:
1432 if (context
->key
->key_class
->rawSign
!= NULL
) {
1433 result
= kCFBooleanTrue
;
1434 if (context
->mode
== kSecKeyOperationModePerform
) {
1435 size
= SecKeyGetSize(context
->key
, kSecKeySignatureSize
);
1436 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1437 status
= context
->key
->key_class
->rawSign(context
->key
, padding
,
1438 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1439 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1443 case kSecKeyOperationTypeVerify
:
1444 if (context
->key
->key_class
->rawVerify
!= NULL
) {
1445 result
= kCFBooleanTrue
;
1446 if (context
->mode
== kSecKeyOperationModePerform
) {
1447 status
= context
->key
->key_class
->rawVerify(context
->key
, padding
,
1448 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1449 CFDataGetBytePtr(in2
), CFDataGetLength(in2
));
1453 case kSecKeyOperationTypeEncrypt
:
1454 if (context
->key
->key_class
->encrypt
!= NULL
) {
1455 result
= kCFBooleanTrue
;
1456 if (context
->mode
== kSecKeyOperationModePerform
) {
1457 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1458 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1459 status
= context
->key
->key_class
->encrypt(context
->key
, padding
,
1460 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1461 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1465 case kSecKeyOperationTypeDecrypt
:
1466 if (context
->key
->key_class
->decrypt
!= NULL
) {
1467 result
= kCFBooleanTrue
;
1468 if (context
->mode
== kSecKeyOperationModePerform
) {
1469 size
= SecKeyGetSize(context
->key
, kSecKeyEncryptedDataSize
);
1470 result
= CFDataCreateMutableWithScratch(NULL
, size
);
1471 status
= context
->key
->key_class
->decrypt(context
->key
, padding
,
1472 CFDataGetBytePtr(in1
), CFDataGetLength(in1
),
1473 CFDataGetMutableBytePtr((CFMutableDataRef
)result
), &size
);
1481 if (status
== errSecSuccess
) {
1482 if (CFGetTypeID(result
) == CFDataGetTypeID()) {
1483 CFDataSetLength((CFMutableDataRef
)result
, size
);
1486 SecError(status
, error
, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context
->operation
, (int)padding
);
1487 CFReleaseNull(result
);
1494 CFTypeRef
SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext
*context
, CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
1496 // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error.
1497 CFIndex algorithmCount
= CFArrayGetCount(context
->algorithm
);
1498 for (CFIndex index
= 0; index
< algorithmCount
- 1; index
++) {
1499 SecKeyAlgorithm indexAlgorithm
= CFArrayGetValueAtIndex(context
->algorithm
, index
);
1500 for (CFIndex tested
= index
+ 1; tested
< algorithmCount
; tested
++) {
1501 require_quiet(!CFEqual(indexAlgorithm
, CFArrayGetValueAtIndex(context
->algorithm
, tested
)), fail
);
1505 SecKeyAlgorithm algorithm
= CFArrayGetValueAtIndex(context
->algorithm
, algorithmCount
- 1);
1506 CFTypeRef output
= SecKeyCopyBackendOperationResult(context
, algorithm
, in1
, in2
, error
);
1507 if (output
!= kCFNull
) {
1508 // Backend handled the operation, return result.
1512 // To silence static analyzer.
1513 CFReleaseSafe(output
);
1515 // Get adaptor which is able to handle requested algorithm.
1516 SecKeyAlgorithmAdaptor adaptor
= SecKeyGetAlgorithmAdaptor(context
->operation
, algorithm
);
1517 require_quiet(adaptor
!= NULL
, fail
);
1519 // Invoke the adaptor and return result.
1520 CFTypeRef result
= adaptor(context
, in1
, in2
, error
);
1521 require_quiet(result
!= kCFNull
, fail
);
1525 if (context
->mode
== kSecKeyOperationModePerform
) {
1526 SecError(errSecParam
, error
, CFSTR("%@: algorithm not supported by the key %@"),
1527 CFArrayGetValueAtIndex(context
->algorithm
, 0), context
->key
);
1534 #pragma mark Algorithm-related SecKey API entry points
1536 static CFMutableArrayRef
SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm
) {
1537 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1538 CFArrayAppendValue(result
, algorithm
);
1542 CFDataRef
SecKeyCreateSignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef dataToSign
, CFErrorRef
*error
) {
1543 CFErrorRef localError
= NULL
;
1544 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeSign
, SecKeyCreateAlgorithmArray(algorithm
) };
1545 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, dataToSign
, NULL
, &localError
);
1546 SecKeyOperationContextDestroy(&context
);
1547 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1551 Boolean
SecKeyVerifySignature(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef signedData
, CFDataRef signature
,
1552 CFErrorRef
*error
) {
1553 CFErrorRef localError
= NULL
;
1554 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeVerify
, SecKeyCreateAlgorithmArray(algorithm
) };
1555 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, signedData
, signature
, &localError
);
1556 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1558 SecKeyOperationContextDestroy(&context
);
1559 SecKeyErrorPropagate(result
, localError
, error
);
1563 CFDataRef
SecKeyCreateEncryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef plainText
, CFErrorRef
*error
) {
1564 CFErrorRef localError
= NULL
;
1565 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeEncrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1566 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, plainText
, NULL
, &localError
);
1567 SecKeyOperationContextDestroy(&context
);
1568 SecKeyErrorPropagate(result
, localError
, error
);
1572 CFDataRef
SecKeyCreateDecryptedData(SecKeyRef key
, SecKeyAlgorithm algorithm
, CFDataRef cipherText
, CFErrorRef
*error
) {
1573 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeDecrypt
, SecKeyCreateAlgorithmArray(algorithm
) };
1574 CFDataRef result
= SecKeyRunAlgorithmAndCopyResult(&context
, cipherText
, NULL
, error
);
1575 SecKeyOperationContextDestroy(&context
);
1579 CFDataRef
SecKeyCopyKeyExchangeResult(SecKeyRef key
, SecKeyAlgorithm algorithm
, SecKeyRef publicKey
,
1580 CFDictionaryRef parameters
, CFErrorRef
*error
) {
1581 CFErrorRef localError
= NULL
;
1582 CFDataRef publicKeyData
= NULL
, result
= NULL
;
1583 SecKeyOperationContext context
= { key
, kSecKeyOperationTypeKeyExchange
, SecKeyCreateAlgorithmArray(algorithm
) };
1584 require_quiet(publicKeyData
= SecKeyCopyExternalRepresentation(publicKey
, error
), out
);
1585 result
= SecKeyRunAlgorithmAndCopyResult(&context
, publicKeyData
, parameters
, &localError
);
1586 SecKeyErrorPropagate(result
!= NULL
, localError
, error
);
1589 CFReleaseSafe(publicKeyData
);
1590 SecKeyOperationContextDestroy(&context
);
1594 Boolean
SecKeyIsAlgorithmSupported(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
) {
1595 SecKeyOperationContext context
= { key
, operation
, SecKeyCreateAlgorithmArray(algorithm
), kSecKeyOperationModeCheckIfSupported
};
1596 CFErrorRef error
= NULL
;
1597 CFTypeRef res
= SecKeyRunAlgorithmAndCopyResult(&context
, NULL
, NULL
, &error
);
1598 Boolean result
= CFEqualSafe(res
, kCFBooleanTrue
);
1600 CFReleaseSafe(error
);
1601 SecKeyOperationContextDestroy(&context
);