2 * Copyright (c) 2006-2014 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/SecFramework.h>
34 #include <utilities/SecIOFormat.h>
36 #include <utilities/SecCFWrappers.h>
38 #include "SecRSAKeyPriv.h"
39 #include "SecECKeyPriv.h"
40 #include "SecBasePriv.h"
42 #include <CoreFoundation/CFNumber.h>
43 #include <CoreFoundation/CFString.h>
44 #include <Security/SecBase.h>
47 #include <AssertMacros.h>
48 #include <utilities/debugging.h>
49 #include <utilities/SecCFError.h>
50 #include <CommonCrypto/CommonDigest.h>
51 #include <Security/SecAsn1Coder.h>
52 #include <Security/oidsalg.h>
53 #include <Security/SecInternal.h>
54 #include <Security/SecRandom.h>
55 #include <corecrypto/ccrng_system.h>
59 /* Static functions. */
60 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
62 /* Currently length of SHA512 oid + 1 */
63 #define MAX_OID_LEN (10)
65 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
67 /* Encode the digestInfo header into digestInfo and return the offset from
68 digestInfo at which to put the actual digest. Returns 0 if digestInfo
69 won't fit within digestInfoLength bytes.
73 0x06, oid.Len, oid.Data,
79 static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid
*oid
,
80 size_t digestLength
, uint8_t *digestInfo
, size_t digestInfoLength
) {
81 size_t algIdLen
= oid
->Length
+ 4;
82 size_t topLen
= algIdLen
+ digestLength
+ 4;
83 size_t totalLen
= topLen
+ 2;
85 if (totalLen
> digestInfoLength
) {
90 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
91 digestInfo
[ix
++] = topLen
;
92 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
93 digestInfo
[ix
++] = algIdLen
;
94 digestInfo
[ix
++] = SEC_ASN1_OBJECT_ID
;
95 digestInfo
[ix
++] = oid
->Length
;
96 memcpy(&digestInfo
[ix
], oid
->Data
, oid
->Length
);
98 digestInfo
[ix
++] = SEC_ASN1_NULL
;
100 digestInfo
[ix
++] = SEC_ASN1_OCTET_STRING
;
101 digestInfo
[ix
++] = digestLength
;
106 static CFDataRef
SecKeyCopyPublicKeyHash(SecKeyRef key
)
108 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
110 /* encode the public key. */
111 require_noerr(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
112 require(pubKeyBlob
, errOut
);
114 /* Calculate the digest of the public key. */
115 require(pubKeyDigest
= SecSHA1DigestCreate(CFGetAllocator(key
),
116 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
119 CFReleaseNull(pubKeyBlob
);
126 static CFDictionaryRef
SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key
,
128 CFDataRef privateBlob
)
130 CFAllocatorRef allocator
= CFGetAllocator(key
);
132 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
133 CFDictionaryRef dict
= NULL
;
135 size_t sizeValue
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
);
136 CFNumberRef sizeInBits
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
);
138 /* encode the public key. */
139 require_noerr(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
140 require(pubKeyBlob
, errOut
);
142 /* Calculate the digest of the public key. */
143 require(pubKeyDigest
= SecSHA1DigestCreate(allocator
,
144 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
147 DICT_ADDPAIR(kSecClass
, kSecClassKey
);
148 DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob
? kSecAttrKeyClassPrivate
: kSecAttrKeyClassPublic
);
149 DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
);
150 DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
);
151 DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
);
152 DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
);
153 DICT_ADDPAIR(kSecAttrKeyType
, keyType
);
154 DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
);
155 DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
);
156 DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
);
157 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
);
158 DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
);
159 DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
);
160 DICT_ADDPAIR(kSecAttrCanEncrypt
, kCFBooleanFalse
);
161 DICT_ADDPAIR(kSecAttrCanDecrypt
, kCFBooleanTrue
);
162 DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
);
163 DICT_ADDPAIR(kSecAttrCanSign
, kCFBooleanTrue
);
164 DICT_ADDPAIR(kSecAttrCanVerify
, kCFBooleanFalse
);
165 DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
);
166 DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
);
167 DICT_ADDPAIR(kSecAttrCanWrap
, kCFBooleanFalse
);
168 DICT_ADDPAIR(kSecAttrCanUnwrap
, kCFBooleanTrue
);
169 DICT_ADDPAIR(kSecValueData
, privateBlob
? privateBlob
: pubKeyBlob
);
170 dict
= DICT_CREATE(allocator
);
173 // @@@ Zero out key material.
174 CFReleaseSafe(pubKeyDigest
);
175 CFReleaseSafe(pubKeyBlob
);
176 CFReleaseSafe(sizeInBits
);
181 CFDictionaryRef
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
,
183 CFDataRef privateBlob
)
185 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, privateBlob
);
188 CFDictionaryRef
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
)
190 return SecKeyCopyAttributeDictionaryWithLocalKey(key
, keyType
, NULL
);
193 static CFStringRef
SecKeyCopyDescription(CFTypeRef cf
) {
194 SecKeyRef key
= (SecKeyRef
)cf
;
196 if(key
->key_class
->describe
)
197 return key
->key_class
->describe(key
);
199 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
);
202 static void SecKeyDestroy(CFTypeRef cf
) {
203 SecKeyRef key
= (SecKeyRef
)cf
;
204 if (key
->key_class
->destroy
)
205 key
->key_class
->destroy(key
);
208 static Boolean
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
)
210 SecKeyRef key1
= (SecKeyRef
)cf1
;
211 SecKeyRef key2
= (SecKeyRef
)cf2
;
214 if (!key2
|| key1
->key_class
!= key2
->key_class
)
216 if (key1
->key_class
->extraBytes
)
217 return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
);
219 /* TODO: Won't work when we get reference keys. */
220 CFDictionaryRef d1
, d2
;
221 d1
= SecKeyCopyAttributeDictionary(key1
);
222 d2
= SecKeyCopyAttributeDictionary(key2
);
223 Boolean result
= CFEqual(d1
, d2
);
229 struct ccrng_state
*ccrng_seckey
;
231 CFGiblisWithFunctions(SecKey
, NULL
, NULL
, SecKeyDestroy
, SecKeyEqual
, NULL
, NULL
, SecKeyCopyDescription
, NULL
, NULL
, ^{
232 static struct ccrng_system_state ccrng_system_state_seckey
;
233 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
234 ccrng_system_init(&ccrng_system_state_seckey
);
237 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
238 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
240 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
241 return CFBooleanGetValue(value
);
243 secwarning("Value %@ for key %@ is not bool", value
, key
);
247 return default_value
;
250 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
251 CFDictionarySetValue(dict
, kSecValueRef
, item
);
252 return SecItemAdd(dict
, NULL
);
255 static void merge_params_applier(const void *key
, const void *value
,
257 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
258 CFDictionaryAddValue(result
, key
, value
);
261 /* Create a mutable dictionary that is based on the subdictionary for key
262 with any attributes from the top level dict merged in. */
263 static CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
265 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
266 CFMutableDictionaryRef result
;
269 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
270 /* Add everything in dict not already in result to result. */
271 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
273 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
276 /* Remove values that only belong in the top level dict. */
277 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
278 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
279 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
280 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
285 /* Generate a private/public keypair. */
286 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
287 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
288 OSStatus result
= errSecUnsupportedAlgorithm
;
289 SecKeyRef privKey
= NULL
;
290 SecKeyRef pubKey
= NULL
;
291 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
292 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
293 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
295 require(ktype
, errOut
);
297 if (CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
298 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
299 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
300 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
303 require_noerr(result
, errOut
);
305 /* Store the keys in the keychain if they are marked as permanent. */
306 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
307 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
309 if (getBoolForKey(privParams
, kSecAttrIsPermanent
, false)) {
310 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
318 *privateKey
= privKey
;
323 CFReleaseSafe(pubParams
);
324 CFReleaseSafe(privParams
);
325 CFReleaseSafe(pubKey
);
326 CFReleaseSafe(privKey
);
331 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
332 CFDataRef serializedPublic
= NULL
;
333 SecKeyRef result
= NULL
;
335 require_noerr_quiet(SecKeyCopyPublicBytes(privateKey
, &serializedPublic
), fail
);
336 require_quiet(serializedPublic
, fail
);
338 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmID(privateKey
), serializedPublic
);
341 CFReleaseSafe(serializedPublic
);
346 static CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
348 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
350 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
351 kSecClass
, kSecClassKey
,
352 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
353 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
354 kSecAttrApplicationLabel
, public_key_hash
,
355 kSecReturnPersistentRef
, kCFBooleanTrue
,
357 CFReleaseNull(public_key_hash
);
362 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
363 CFTypeRef persistentRef
= NULL
;
364 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
366 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
367 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
369 CFReleaseNull(query
);
370 return (CFDataRef
)persistentRef
;
373 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
374 CFTypeRef private_key
= NULL
;
376 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
378 require_quiet(SecError(SecItemCopyMatching(query
, &private_key
), error
,
379 CFSTR("Error finding private key from public: %@"), publicKey
), fail
);
381 CFReleaseNull(query
);
382 return (SecKeyRef
)private_key
;
385 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
386 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
387 const SecAsn1Item
*keyData
) {
388 SecKeyRef publicKey
= NULL
;
389 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
391 publicKey
= SecKeyCreateRSAPublicKey(kCFAllocatorDefault
,
392 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
393 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
396 .oidLength
= oid
->Length
,
397 .key
= keyData
->Data
,
398 .keyLength
= keyData
->Length
,
401 derKey
.parameters
= params
->Data
;
402 derKey
.parametersLength
= params
->Length
;
404 publicKey
= SecKeyCreateECPublicKey(kCFAllocatorDefault
,
405 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
407 secwarning("Unsupported algorithm oid");
413 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
414 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
415 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
416 if (!key_class
) return NULL
;
417 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
418 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
419 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
421 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
422 result
->key_class
= key_class
;
423 if (key_class
->extraBytes
) {
424 /* Make result->key point to the extraBytes we allocated. */
425 result
->key
= ((char*)result
) + sizeof(*result
);
427 if (key_class
->init
) {
429 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
431 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
441 kSecKeyDigestInfoSign
,
442 kSecKeyDigestInfoVerify
445 static OSStatus
SecKeyDigestInfoSignVerify(
446 SecKeyRef key
, /* Private key */
447 SecPadding padding
, /* kSecPaddingPKCS1@@@ */
448 const uint8_t *dataToSign
, /* signature over this data */
449 size_t dataToSignLen
, /* length of dataToSign */
450 uint8_t *sig
, /* signature, RETURNED */
451 size_t *sigLen
, /* IN/OUT */
453 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
454 uint8_t digestInfo
[digestInfoLength
];
455 const SecAsn1Oid
*digestOid
;
460 case kSecPaddingPKCS1MD2
:
461 digestLen
= CC_MD2_DIGEST_LENGTH
;
462 digestOid
= &CSSMOID_MD2
;
464 case kSecPaddingPKCS1MD4
:
465 digestLen
= CC_MD4_DIGEST_LENGTH
;
466 digestOid
= &CSSMOID_MD4
;
468 case kSecPaddingPKCS1MD5
:
469 digestLen
= CC_MD5_DIGEST_LENGTH
;
470 digestOid
= &CSSMOID_MD5
;
473 case kSecPaddingPKCS1SHA1
:
474 digestLen
= CC_SHA1_DIGEST_LENGTH
;
475 digestOid
= &CSSMOID_SHA1
;
477 case kSecPaddingPKCS1SHA224
:
478 digestLen
= CC_SHA224_DIGEST_LENGTH
;
479 digestOid
= &CSSMOID_SHA224
;
481 case kSecPaddingPKCS1SHA256
:
482 digestLen
= CC_SHA256_DIGEST_LENGTH
;
483 digestOid
= &CSSMOID_SHA256
;
485 case kSecPaddingPKCS1SHA384
:
486 digestLen
= CC_SHA384_DIGEST_LENGTH
;
487 digestOid
= &CSSMOID_SHA384
;
489 case kSecPaddingPKCS1SHA512
:
490 digestLen
= CC_SHA512_DIGEST_LENGTH
;
491 digestOid
= &CSSMOID_SHA512
;
494 return errSecUnsupportedPadding
;
497 if (dataToSignLen
!= digestLen
)
500 size_t offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
501 digestInfo
, digestInfoLength
);
503 return errSecBufferTooSmall
;
505 /* Append the digest to the digestInfo prefix and adjust the length. */
506 memcpy(&digestInfo
[offset
], dataToSign
, digestLen
);
507 digestInfoLength
= offset
+ digestLen
;
509 if (mode
== kSecKeyDigestInfoSign
) {
510 return key
->key_class
->rawSign(key
, kSecPaddingPKCS1
,
511 digestInfo
, digestInfoLength
, sig
, sigLen
);
513 return key
->key_class
->rawVerify(key
, kSecPaddingPKCS1
,
514 digestInfo
, digestInfoLength
, sig
, *sigLen
);
517 return errSecSuccess
;
520 OSStatus
SecKeyRawSign(
521 SecKeyRef key
, /* Private key */
522 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
523 const uint8_t *dataToSign
, /* signature over this data */
524 size_t dataToSignLen
, /* length of dataToSign */
525 uint8_t *sig
, /* signature, RETURNED */
526 size_t *sigLen
) { /* IN/OUT */
527 if (!key
->key_class
->rawSign
)
528 return errSecUnsupportedOperation
;
530 if (padding
< kSecPaddingPKCS1MD2
) {
531 return key
->key_class
->rawSign(key
, padding
, dataToSign
, dataToSignLen
,
534 return SecKeyDigestInfoSignVerify(key
, padding
, dataToSign
, dataToSignLen
,
535 sig
, sigLen
, kSecKeyDigestInfoSign
);
539 OSStatus
SecKeyRawVerify(
540 SecKeyRef key
, /* Public key */
541 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
542 const uint8_t *signedData
, /* signature over this data */
543 size_t signedDataLen
, /* length of dataToSign */
544 const uint8_t *sig
, /* signature */
545 size_t sigLen
) { /* length of signature */
546 if (!key
->key_class
->rawVerify
)
547 return errSecUnsupportedOperation
;
549 if (padding
< kSecPaddingPKCS1MD2
) {
550 return key
->key_class
->rawVerify(key
, padding
, signedData
, signedDataLen
,
553 /* Casting away the constness of sig is safe since
554 SecKeyDigestInfoSignVerify only modifies sig if
555 mode == kSecKeyDigestInfoSign. */
556 return SecKeyDigestInfoSignVerify(key
, padding
,
557 signedData
, signedDataLen
, (uint8_t *)sig
, &sigLen
,
558 kSecKeyDigestInfoVerify
);
562 OSStatus
SecKeyEncrypt(
563 SecKeyRef key
, /* Public key */
564 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
565 const uint8_t *plainText
,
566 size_t plainTextLen
, /* length of plainText */
568 size_t *cipherTextLen
) { /* IN/OUT */
569 if (key
->key_class
->encrypt
)
570 return key
->key_class
->encrypt(key
, padding
, plainText
, plainTextLen
,
571 cipherText
, cipherTextLen
);
572 return errSecUnsupportedOperation
;
575 OSStatus
SecKeyDecrypt(
576 SecKeyRef key
, /* Private key */
577 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
578 const uint8_t *cipherText
,
579 size_t cipherTextLen
, /* length of cipherText */
581 size_t *plainTextLen
) { /* IN/OUT */
582 if (key
->key_class
->decrypt
)
583 return key
->key_class
->decrypt(key
, padding
, cipherText
, cipherTextLen
,
584 plainText
, plainTextLen
);
585 return errSecUnsupportedOperation
;
588 size_t SecKeyGetBlockSize(SecKeyRef key
) {
589 if (key
->key_class
->blockSize
)
590 return key
->key_class
->blockSize(key
);
594 /* Private API functions. */
596 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
597 if (key
->key_class
->copyDictionary
)
598 return key
->key_class
->copyDictionary(key
);
602 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
603 /* TODO: Support having an allocator in refAttributes. */
604 CFAllocatorRef allocator
= NULL
;
605 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
606 CFTypeRef ktype
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyType
);
610 /* First figure out the key type (algorithm). */
611 if (CFGetTypeID(ktype
) == CFNumberGetTypeID()) {
612 CFNumberGetValue(ktype
, kCFNumberSInt32Type
, &algorithm
);
613 } else if (isString(ktype
)) {
614 algorithm
= CFStringGetIntValue(ktype
);
615 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm
);
616 if (!CFEqual(t
, ktype
)) {
617 secwarning("Unsupported key class: %@", ktype
);
623 secwarning("Unsupported key type: %@", ktype
);
627 /* TODO: The code below won't scale well, consider moving to something
630 CFTypeRef kclass
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyClass
);
631 if (CFGetTypeID(kclass
) == CFNumberGetTypeID()) {
632 CFNumberGetValue(kclass
, kCFNumberSInt32Type
, &class);
633 } else if (isString(kclass
)) {
634 class = CFStringGetIntValue(kclass
);
635 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class);
636 if (!CFEqual(t
, kclass
)) {
638 secwarning("Unsupported key class: %@", kclass
);
643 secwarning("Unsupported key class: %@", kclass
);
648 case 0: // kSecAttrKeyClassPublic
650 case 42: // kSecAlgorithmRSA
651 ref
= SecKeyCreateRSAPublicKey(allocator
,
652 CFDataGetBytePtr(data
), CFDataGetLength(data
),
653 kSecKeyEncodingBytes
);
655 case 43: // kSecAlgorithmECDSA
656 case 73: // kSecAlgorithmEC
657 ref
= SecKeyCreateECPublicKey(allocator
,
658 CFDataGetBytePtr(data
), CFDataGetLength(data
),
659 kSecKeyEncodingBytes
);
662 secwarning("Unsupported public key type: %@", ktype
);
667 case 1: // kSecAttrKeyClassPrivate
669 case 42: // kSecAlgorithmRSA
670 ref
= SecKeyCreateRSAPrivateKey(allocator
,
671 CFDataGetBytePtr(data
), CFDataGetLength(data
),
672 kSecKeyEncodingBytes
);
674 case 43: // kSecAlgorithmECDSA
675 case 73: // kSecAlgorithmEC
676 ref
= SecKeyCreateECPrivateKey(allocator
,
677 CFDataGetBytePtr(data
), CFDataGetLength(data
),
678 kSecKeyEncodingBytes
);
681 secwarning("Unsupported private key type: %@", ktype
);
686 case 2: // kSecAttrKeyClassSymmetric
687 secwarning("Unsupported symmetric key type: %@", ktype
);
691 secwarning("Unsupported key class: %@", kclass
);
698 /* TODO: This function should ensure that this keys algorithm matches the
699 signature algorithm. */
700 static OSStatus
SecKeyGetDigestInfo(SecKeyRef
this, const SecAsn1AlgId
*algId
,
701 const uint8_t *data
, size_t dataLen
, bool digestData
,
702 uint8_t *digestInfo
, size_t *digestInfoLen
/* IN/OUT */) {
703 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
704 CFIndex keyAlgID
= kSecNullAlgorithmID
;
705 const SecAsn1Oid
*digestOid
;
709 /* Since these oids all have the same prefix, use switch. */
710 if ((algId
->algorithm
.Length
== CSSMOID_RSA
.Length
) &&
711 !memcmp(algId
->algorithm
.Data
, CSSMOID_RSA
.Data
,
712 algId
->algorithm
.Length
- 1)) {
713 keyAlgID
= kSecRSAAlgorithmID
;
714 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
716 case 2: /* oidMD2WithRSA */
718 digestLen
= CC_MD2_DIGEST_LENGTH
;
719 digestOid
= &CSSMOID_MD2
;
721 case 3: /* oidMD4WithRSA */
723 digestLen
= CC_MD4_DIGEST_LENGTH
;
724 digestOid
= &CSSMOID_MD4
;
726 case 4: /* oidMD5WithRSA */
728 digestLen
= CC_MD5_DIGEST_LENGTH
;
729 digestOid
= &CSSMOID_MD5
;
732 case 5: /* oidSHA1WithRSA */
734 digestLen
= CC_SHA1_DIGEST_LENGTH
;
735 digestOid
= &CSSMOID_SHA1
;
737 case 11: /* oidSHA256WithRSA */
738 digestFcn
= CC_SHA256
;
739 digestLen
= CC_SHA256_DIGEST_LENGTH
;
740 digestOid
= &CSSMOID_SHA256
;
742 case 12: /* oidSHA384WithRSA */
744 digestFcn
= CC_SHA384
;
745 digestLen
= CC_SHA384_DIGEST_LENGTH
;
746 digestOid
= &CSSMOID_SHA384
;
748 case 13: /* oidSHA512WithRSA */
749 digestFcn
= CC_SHA512
;
750 digestLen
= CC_SHA512_DIGEST_LENGTH
;
751 digestOid
= &CSSMOID_SHA512
;
753 case 14: /* oidSHA224WithRSA */
754 digestFcn
= CC_SHA224
;
755 digestLen
= CC_SHA224_DIGEST_LENGTH
;
756 digestOid
= &CSSMOID_SHA224
;
759 secdebug("key", "unsupported rsa signature algorithm");
760 return errSecUnsupportedAlgorithm
;
762 } else if ((algId
->algorithm
.Length
== CSSMOID_ECDSA_WithSHA224
.Length
) &&
763 !memcmp(algId
->algorithm
.Data
, CSSMOID_ECDSA_WithSHA224
.Data
,
764 algId
->algorithm
.Length
- 1)) {
765 keyAlgID
= kSecECDSAAlgorithmID
;
766 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
767 case 1: /* oidSHA224WithECDSA */
768 digestFcn
= CC_SHA224
;
769 digestLen
= CC_SHA224_DIGEST_LENGTH
;
771 case 2: /* oidSHA256WithECDSA */
772 digestFcn
= CC_SHA256
;
773 digestLen
= CC_SHA256_DIGEST_LENGTH
;
775 case 3: /* oidSHA384WithECDSA */
777 digestFcn
= CC_SHA384
;
778 digestLen
= CC_SHA384_DIGEST_LENGTH
;
780 case 4: /* oidSHA512WithECDSA */
781 digestFcn
= CC_SHA512
;
782 digestLen
= CC_SHA512_DIGEST_LENGTH
;
785 secdebug("key", "unsupported ecdsa signature algorithm");
786 return errSecUnsupportedAlgorithm
;
788 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_ECDSA_WithSHA1
)) {
789 keyAlgID
= kSecECDSAAlgorithmID
;
791 digestLen
= CC_SHA1_DIGEST_LENGTH
;
792 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_SHA1
)) {
794 digestLen
= CC_SHA1_DIGEST_LENGTH
;
795 digestOid
= &CSSMOID_SHA1
;
796 } else if ((algId
->algorithm
.Length
== CSSMOID_SHA224
.Length
) &&
797 !memcmp(algId
->algorithm
.Data
, CSSMOID_SHA224
.Data
, algId
->algorithm
.Length
- 1))
799 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
800 case 4: /* OID_SHA224 */
801 digestFcn
= CC_SHA224
;
802 digestLen
= CC_SHA224_DIGEST_LENGTH
;
803 digestOid
= &CSSMOID_SHA224
;
805 case 1: /* OID_SHA256 */
806 digestFcn
= CC_SHA256
;
807 digestLen
= CC_SHA256_DIGEST_LENGTH
;
808 digestOid
= &CSSMOID_SHA256
;
810 case 2: /* OID_SHA384 */
812 digestFcn
= CC_SHA384
;
813 digestLen
= CC_SHA384_DIGEST_LENGTH
;
814 digestOid
= &CSSMOID_SHA384
;
816 case 3: /* OID_SHA512 */
817 digestFcn
= CC_SHA512
;
818 digestLen
= CC_SHA512_DIGEST_LENGTH
;
819 digestOid
= &CSSMOID_SHA512
;
822 secdebug("key", "unsupported sha-2 signature algorithm");
823 return errSecUnsupportedAlgorithm
;
825 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
827 digestLen
= CC_MD5_DIGEST_LENGTH
;
828 digestOid
= &CSSMOID_MD5
;
830 secdebug("key", "unsupported digesting algorithm");
831 return errSecUnsupportedAlgorithm
;
834 /* check key is appropriate for signature (superfluous for digest only oid) */
835 if (keyAlgID
== kSecNullAlgorithmID
)
836 keyAlgID
= SecKeyGetAlgorithmID(this);
837 else if (keyAlgID
!= SecKeyGetAlgorithmID(this))
838 return errSecUnsupportedAlgorithm
;
841 case kSecRSAAlgorithmID
:
842 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
843 digestInfo
, *digestInfoLen
);
845 return errSecBufferTooSmall
;
847 case kSecDSAAlgorithmID
:
848 if (digestOid
!= &CSSMOID_SHA1
)
849 return errSecUnsupportedAlgorithm
;
851 case kSecECDSAAlgorithmID
:
854 secdebug("key", "unsupported signature algorithm");
855 return errSecUnsupportedAlgorithm
;
859 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
861 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
862 *digestInfoLen
= offset
+ digestLen
;
864 if (dataLen
!= digestLen
)
866 memcpy(&digestInfo
[offset
], data
, dataLen
);
867 *digestInfoLen
= offset
+ dataLen
;
870 return errSecSuccess
;
873 OSStatus
SecKeyDigestAndVerify(
874 SecKeyRef
this, /* Private key */
875 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
876 const uint8_t *dataToDigest
, /* signature over this data */
877 size_t dataToDigestLen
,/* length of dataToDigest */
878 const uint8_t *sig
, /* signature to verify */
879 size_t sigLen
) { /* length of sig */
880 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
881 uint8_t digestInfo
[digestInfoLength
];
887 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true,
888 digestInfo
, &digestInfoLength
);
891 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
892 digestInfo
, digestInfoLength
, sig
, sigLen
);
895 OSStatus
SecKeyDigestAndSign(
896 SecKeyRef
this, /* Private key */
897 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
898 const uint8_t *dataToDigest
, /* signature over this data */
899 size_t dataToDigestLen
,/* length of dataToDigest */
900 uint8_t *sig
, /* signature, RETURNED */
901 size_t *sigLen
) { /* IN/OUT */
902 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
903 uint8_t digestInfo
[digestInfoLength
];
906 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true /* digest data */,
907 digestInfo
, &digestInfoLength
);
910 return SecKeyRawSign(this, kSecPaddingPKCS1
,
911 digestInfo
, digestInfoLength
, sig
, sigLen
);
914 OSStatus
SecKeyVerifyDigest(
915 SecKeyRef
this, /* Private key */
916 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
917 const uint8_t *digestData
, /* signature over this digest */
918 size_t digestDataLen
,/* length of dataToDigest */
919 const uint8_t *sig
, /* signature to verify */
920 size_t sigLen
) { /* length of sig */
921 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
922 uint8_t digestInfo
[digestInfoLength
];
925 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false /* data is digest */,
926 digestInfo
, &digestInfoLength
);
929 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
930 digestInfo
, digestInfoLength
, sig
, sigLen
);
933 OSStatus
SecKeySignDigest(
934 SecKeyRef
this, /* Private key */
935 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
936 const uint8_t *digestData
, /* signature over this digest */
937 size_t digestDataLen
,/* length of digestData */
938 uint8_t *sig
, /* signature, RETURNED */
939 size_t *sigLen
) { /* IN/OUT */
940 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
941 uint8_t digestInfo
[digestInfoLength
];
944 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false,
945 digestInfo
, &digestInfoLength
);
948 return SecKeyRawSign(this, kSecPaddingPKCS1
,
949 digestInfo
, digestInfoLength
, sig
, sigLen
);
952 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
953 /* This method was added to version 1 keys. */
954 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
)
955 return key
->key_class
->getAlgorithmID(key
);
956 /* All version 0 key were RSA. */
957 return kSecRSAAlgorithmID
;
961 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
962 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
963 return key
->key_class
->copyPublic(key
, serializedPublic
);
964 return errSecUnimplemented
;
967 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
971 case kSecRSAAlgorithmID
:
972 return SecKeyCreateRSAPublicKey(allocator
,
973 keyData
, keyDataLength
,
974 kSecKeyEncodingBytes
);
975 case kSecECDSAAlgorithmID
:
976 return SecKeyCreateECPublicKey(allocator
,
977 keyData
, keyDataLength
,
978 kSecKeyEncodingBytes
);
984 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
986 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
989 // This is a bit icky hack to avoid changing the vtable for
991 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
993 size_t result
= SecKeyGetBlockSize(key
);
995 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmID(key
)) {
997 case kSecKeyEncryptedDataSize
:
1000 case kSecKeySignatureSize
:
1001 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
1003 case kSecKeyKeySizeInBits
:
1009 if (whichSize
== kSecKeyKeySizeInBits
)
1016 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
1018 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1019 kSecReturnRef
, kCFBooleanTrue
,
1020 kSecClass
, kSecClassKey
,
1021 kSecValuePersistentRef
, persistentRef
,
1023 CFTypeRef foundRef
= NULL
;
1024 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1026 if (status
== errSecSuccess
) {
1027 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
1028 *lookedUpData
= (SecKeyRef
) foundRef
;
1030 status
= errSecSuccess
;
1032 status
= errSecItemNotFound
;
1036 CFReleaseSafe(foundRef
);
1037 CFReleaseSafe(query
);
1042 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
1044 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1045 kSecReturnPersistentRef
, kCFBooleanTrue
,
1047 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
1049 CFTypeRef foundRef
= NULL
;
1050 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1052 if (status
== errSecSuccess
) {
1053 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
1054 *persistentRef
= foundRef
;
1057 status
= errSecItemNotFound
;
1061 CFReleaseSafe(foundRef
);
1062 CFReleaseSafe(query
);
1071 #define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
1073 SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg
, "kSecKeyWrapPGPSymAlg");
1074 SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint
, "kSecKeyWrapPGPFingerprint");
1075 SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg
, "kSecKeyWrapPGPWrapAlg");
1076 SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags
, "kSecKeyWrapPGPECFlags");
1077 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128
, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1078 SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256
, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1080 #undef SEC_CONST_DECL
1083 _SecKeyCopyWrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef unwrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1089 if (key
->key_class
->version
> 2 && key
->key_class
->copyWrapKey
)
1090 return key
->key_class
->copyWrapKey(key
, type
, unwrappedKey
, parameters
, outParam
, error
);
1091 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key wrap supported for key %@"), key
);
1096 _SecKeyCopyUnwrapKey(SecKeyRef key
, SecKeyWrapType type
, CFDataRef wrappedKey
, CFDictionaryRef parameters
, CFDictionaryRef
*outParam
, CFErrorRef
*error
)
1102 if (key
->key_class
->version
> 2 && key
->key_class
->copyUnwrapKey
)
1103 return key
->key_class
->copyUnwrapKey(key
, type
, wrappedKey
, parameters
, outParam
, error
);
1105 SecError(errSecUnsupportedOperation
, error
, CFSTR("No key unwrap for key %@"), key
);