2 * Copyright (c) 2006-2011 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"
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 pthread_once_t kSecKeyRegisterClass
= PTHREAD_ONCE_INIT
;
60 static CFTypeID kSecKeyTypeID
= _kCFRuntimeNotATypeID
;
62 /* Forward declartions of static functions. */
63 static CFStringRef
SecKeyCopyDescription(CFTypeRef cf
);
64 static void SecKeyDestroy(CFTypeRef cf
);
66 /* Static functions. */
67 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
69 /* Currently length of SHA512 oid + 1 */
70 #define MAX_OID_LEN (10)
72 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
74 /* Encode the digestInfo header into digestInfo and return the offset from
75 digestInfo at which to put the actual digest. Returns 0 if digestInfo
76 won't fit within digestInfoLength bytes.
80 0x06, oid.Len, oid.Data,
86 static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid
*oid
,
87 size_t digestLength
, uint8_t *digestInfo
, size_t digestInfoLength
) {
88 size_t algIdLen
= oid
->Length
+ 4;
89 size_t topLen
= algIdLen
+ digestLength
+ 4;
90 size_t totalLen
= topLen
+ 2;
92 if (totalLen
> digestInfoLength
) {
97 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
98 digestInfo
[ix
++] = topLen
;
99 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
100 digestInfo
[ix
++] = algIdLen
;
101 digestInfo
[ix
++] = SEC_ASN1_OBJECT_ID
;
102 digestInfo
[ix
++] = oid
->Length
;
103 memcpy(&digestInfo
[ix
], oid
->Data
, oid
->Length
);
105 digestInfo
[ix
++] = SEC_ASN1_NULL
;
106 digestInfo
[ix
++] = 0;
107 digestInfo
[ix
++] = SEC_ASN1_OCTET_STRING
;
108 digestInfo
[ix
++] = digestLength
;
113 static struct ccrng_system_state ccrng_system_state_seckey
;
115 static void register_algs(void) {
116 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
117 ccrng_system_init(&ccrng_system_state_seckey
);
121 static CFDataRef
SecKeyCopyPublicKeyHash(SecKeyRef key
)
123 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
125 /* encode the public key. */
126 require_noerr(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
127 require(pubKeyBlob
, errOut
);
129 /* Calculate the digest of the public key. */
130 require(pubKeyDigest
= SecSHA1DigestCreate(CFGetAllocator(key
),
131 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
134 CFReleaseNull(pubKeyBlob
);
141 static CF_RETURNS_RETAINED CFDictionaryRef
SecKeyGenerateAttributeDictionaryFor(SecKeyRef key
,
143 CFDataRef privateBlob
)
145 CFAllocatorRef allocator
= CFGetAllocator(key
);
147 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
148 CFDictionaryRef dict
= NULL
;
150 size_t sizeValue
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
);
151 CFNumberRef sizeInBits
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
);
153 /* encode the public key. */
154 require_noerr(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
155 require(pubKeyBlob
, errOut
);
157 /* Calculate the digest of the public key. */
158 require(pubKeyDigest
= SecSHA1DigestCreate(allocator
,
159 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
162 DICT_ADDPAIR(kSecClass
, kSecClassKey
);
163 DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob
? kSecAttrKeyClassPrivate
: kSecAttrKeyClassPublic
);
164 DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
);
165 DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
);
166 DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
);
167 DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
);
168 DICT_ADDPAIR(kSecAttrKeyType
, keyType
);
169 DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
);
170 DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
);
171 DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
);
172 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
);
173 DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
);
174 DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
);
175 DICT_ADDPAIR(kSecAttrCanEncrypt
, kCFBooleanFalse
);
176 DICT_ADDPAIR(kSecAttrCanDecrypt
, kCFBooleanTrue
);
177 DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
);
178 DICT_ADDPAIR(kSecAttrCanSign
, kCFBooleanTrue
);
179 DICT_ADDPAIR(kSecAttrCanVerify
, kCFBooleanFalse
);
180 DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
);
181 DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
);
182 DICT_ADDPAIR(kSecAttrCanWrap
, kCFBooleanFalse
);
183 DICT_ADDPAIR(kSecAttrCanUnwrap
, kCFBooleanTrue
);
184 DICT_ADDPAIR(kSecValueData
, privateBlob
? privateBlob
: pubKeyBlob
);
185 dict
= DICT_CREATE(allocator
);
188 // @@@ Zero out key material.
189 CFReleaseSafe(pubKeyDigest
);
190 CFReleaseSafe(pubKeyBlob
);
191 CFReleaseSafe(sizeInBits
);
196 CFDictionaryRef
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
,
198 CFDataRef privateBlob
)
200 return SecKeyGenerateAttributeDictionaryFor(key
, keyType
, privateBlob
);
203 CFDictionaryRef
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
)
205 return SecKeyGenerateAttributeDictionaryFor(key
, keyType
, NULL
);
211 static CFStringRef
SecKeyCopyDescription(CFTypeRef cf
) {
212 SecKeyRef key
= (SecKeyRef
)cf
;
214 if(key
->key_class
->describe
)
215 return key
->key_class
->describe(key
);
217 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
);
220 static void SecKeyDestroy(CFTypeRef cf
) {
221 SecKeyRef key
= (SecKeyRef
)cf
;
222 if (key
->key_class
->destroy
)
223 key
->key_class
->destroy(key
);
226 static Boolean
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
)
228 SecKeyRef key1
= (SecKeyRef
)cf1
;
229 SecKeyRef key2
= (SecKeyRef
)cf2
;
232 if (!key2
|| key1
->key_class
!= key2
->key_class
)
234 if (key1
->key_class
->extraBytes
)
235 return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
);
237 /* TODO: Won't work when we get reference keys. */
238 CFDictionaryRef d1
, d2
;
239 d1
= SecKeyCopyAttributeDictionary(key1
);
240 d2
= SecKeyCopyAttributeDictionary(key2
);
241 Boolean result
= CFEqual(d1
, d2
);
247 static void SecKeyRegisterClass(void) {
248 static const CFRuntimeClass kSecKeyClass
= {
250 "SecKey", /* class name */
253 SecKeyDestroy
, /* dealloc */
254 SecKeyEqual
, /* equal */
256 NULL
, /* copyFormattingDesc */
257 SecKeyCopyDescription
/* copyDebugDesc */
260 kSecKeyTypeID
= _CFRuntimeRegisterClass(&kSecKeyClass
);
264 /* Public API functions. */
265 CFTypeID
SecKeyGetTypeID(void) {
266 pthread_once(&kSecKeyRegisterClass
, SecKeyRegisterClass
);
267 return kSecKeyTypeID
;
270 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
271 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
273 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
274 return CFBooleanGetValue(value
);
276 secwarning("Value %@ for key %@ is not bool", value
, key
);
280 return default_value
;
283 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
284 CFDictionarySetValue(dict
, kSecValueRef
, item
);
285 return SecItemAdd(dict
, NULL
);
288 static void merge_params_applier(const void *key
, const void *value
,
290 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
291 CFDictionaryAddValue(result
, key
, value
);
294 /* Create a mutable dictionary that is based on the subdictionary for key
295 with any attributes from the top level dict merged in. */
296 static CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
298 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
299 CFMutableDictionaryRef result
;
302 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
303 /* Add everything in dict not already in result to result. */
304 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
306 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
309 /* Remove values that only belong in the top level dict. */
310 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
311 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
312 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
313 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
318 /* Generate a private/public keypair. */
319 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
320 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
321 OSStatus result
= errSecUnsupportedAlgorithm
;
322 SecKeyRef privKey
= NULL
;
323 SecKeyRef pubKey
= NULL
;
324 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
325 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
326 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
328 require(ktype
, errOut
);
330 if (CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
331 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
332 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
333 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
336 require_noerr(result
, errOut
);
338 /* Store the keys in the keychain if they are marked as permanent. */
339 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
340 require_noerr_quiet(result
= add_ref(pubKey
, pubParams
), errOut
);
342 if (getBoolForKey(privParams
, kSecAttrIsPermanent
, false)) {
343 require_noerr_quiet(result
= add_ref(privKey
, privParams
), errOut
);
351 *privateKey
= privKey
;
356 CFReleaseSafe(pubParams
);
357 CFReleaseSafe(privParams
);
358 CFReleaseSafe(pubKey
);
359 CFReleaseSafe(privKey
);
364 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
365 CFDataRef serializedPublic
= NULL
;
366 SecKeyRef result
= NULL
;
368 require_noerr_quiet(SecKeyCopyPublicBytes(privateKey
, &serializedPublic
), fail
);
369 require_quiet(serializedPublic
, fail
);
371 result
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmID(privateKey
), serializedPublic
);
374 CFReleaseSafe(serializedPublic
);
379 static CFDictionaryRef
CreatePrivateKeyMatchingQuery(SecKeyRef publicKey
, bool returnPersistentRef
)
381 CFDataRef public_key_hash
= SecKeyCopyPublicKeyHash(publicKey
);
383 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
384 kSecClass
, kSecClassKey
,
385 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
386 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
387 kSecAttrApplicationLabel
, public_key_hash
,
388 kSecReturnPersistentRef
, kCFBooleanTrue
,
390 CFReleaseNull(public_key_hash
);
395 CFDataRef
SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
396 CFTypeRef persistentRef
= NULL
;
397 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, true);
399 require_quiet(SecError(SecItemCopyMatching(query
, &persistentRef
),error
,
400 CFSTR("Error finding persistent ref to key from public: %@"), publicKey
), fail
);
402 CFReleaseNull(query
);
403 return (CFDataRef
)persistentRef
;
406 SecKeyRef
SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey
, CFErrorRef
*error
) {
407 CFTypeRef private_key
= NULL
;
409 CFDictionaryRef query
= CreatePrivateKeyMatchingQuery(publicKey
, false);
411 require_quiet(SecError(SecItemCopyMatching(query
, &private_key
), error
,
412 CFSTR("Error finding private key from public: %@"), publicKey
), fail
);
414 CFReleaseNull(query
);
415 return (SecKeyRef
)private_key
;
418 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
419 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
420 const SecAsn1Item
*keyData
) {
421 SecKeyRef publicKey
= NULL
;
422 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
424 publicKey
= SecKeyCreateRSAPublicKey(kCFAllocatorDefault
,
425 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
426 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
429 .oidLength
= oid
->Length
,
430 .key
= keyData
->Data
,
431 .keyLength
= keyData
->Length
,
434 derKey
.parameters
= params
->Data
;
435 derKey
.parametersLength
= params
->Length
;
437 publicKey
= SecKeyCreateECPublicKey(kCFAllocatorDefault
,
438 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
440 secwarning("Unsupported algorithm oid");
446 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
447 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
448 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
451 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
452 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
453 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
455 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
456 result
->key_class
= key_class
;
457 if (key_class
->extraBytes
) {
458 /* Make result->key point to the extraBytes we allocated. */
459 result
->key
= ((char*)result
) + sizeof(*result
);
461 if (key_class
->init
) {
463 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
465 secwarning("init %s key: %" PRIdOSStatus
, key_class
->name
, status
);
475 kSecKeyDigestInfoSign
,
476 kSecKeyDigestInfoVerify
479 static OSStatus
SecKeyDigestInfoSignVerify(
480 SecKeyRef key
, /* Private key */
481 SecPadding padding
, /* kSecPaddingPKCS1@@@ */
482 const uint8_t *dataToSign
, /* signature over this data */
483 size_t dataToSignLen
, /* length of dataToSign */
484 uint8_t *sig
, /* signature, RETURNED */
485 size_t *sigLen
, /* IN/OUT */
487 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
488 uint8_t digestInfo
[digestInfoLength
];
489 const SecAsn1Oid
*digestOid
;
494 case kSecPaddingPKCS1MD2
:
495 digestLen
= CC_MD2_DIGEST_LENGTH
;
496 digestOid
= &CSSMOID_MD2
;
498 case kSecPaddingPKCS1MD4
:
499 digestLen
= CC_MD4_DIGEST_LENGTH
;
500 digestOid
= &CSSMOID_MD4
;
502 case kSecPaddingPKCS1MD5
:
503 digestLen
= CC_MD5_DIGEST_LENGTH
;
504 digestOid
= &CSSMOID_MD5
;
507 case kSecPaddingPKCS1SHA1
:
508 digestLen
= CC_SHA1_DIGEST_LENGTH
;
509 digestOid
= &CSSMOID_SHA1
;
511 case kSecPaddingPKCS1SHA224
:
512 digestLen
= CC_SHA224_DIGEST_LENGTH
;
513 digestOid
= &CSSMOID_SHA224
;
515 case kSecPaddingPKCS1SHA256
:
516 digestLen
= CC_SHA256_DIGEST_LENGTH
;
517 digestOid
= &CSSMOID_SHA256
;
519 case kSecPaddingPKCS1SHA384
:
520 digestLen
= CC_SHA384_DIGEST_LENGTH
;
521 digestOid
= &CSSMOID_SHA384
;
523 case kSecPaddingPKCS1SHA512
:
524 digestLen
= CC_SHA512_DIGEST_LENGTH
;
525 digestOid
= &CSSMOID_SHA512
;
528 return errSecUnsupportedPadding
;
531 if (dataToSignLen
!= digestLen
)
534 size_t offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
535 digestInfo
, digestInfoLength
);
537 return errSecBufferTooSmall
;
539 /* Append the digest to the digestInfo prefix and adjust the length. */
540 memcpy(&digestInfo
[offset
], dataToSign
, digestLen
);
541 digestInfoLength
= offset
+ digestLen
;
543 if (mode
== kSecKeyDigestInfoSign
) {
544 return key
->key_class
->rawSign(key
, kSecPaddingPKCS1
,
545 digestInfo
, digestInfoLength
, sig
, sigLen
);
547 return key
->key_class
->rawVerify(key
, kSecPaddingPKCS1
,
548 digestInfo
, digestInfoLength
, sig
, *sigLen
);
551 return errSecSuccess
;
554 OSStatus
SecKeyRawSign(
555 SecKeyRef key
, /* Private key */
556 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
557 const uint8_t *dataToSign
, /* signature over this data */
558 size_t dataToSignLen
, /* length of dataToSign */
559 uint8_t *sig
, /* signature, RETURNED */
560 size_t *sigLen
) { /* IN/OUT */
561 if (!key
->key_class
->rawSign
)
562 return errSecUnsupportedOperation
;
564 if (padding
< kSecPaddingPKCS1MD2
) {
565 return key
->key_class
->rawSign(key
, padding
, dataToSign
, dataToSignLen
,
568 return SecKeyDigestInfoSignVerify(key
, padding
, dataToSign
, dataToSignLen
,
569 sig
, sigLen
, kSecKeyDigestInfoSign
);
573 OSStatus
SecKeyRawVerify(
574 SecKeyRef key
, /* Public key */
575 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
576 const uint8_t *signedData
, /* signature over this data */
577 size_t signedDataLen
, /* length of dataToSign */
578 const uint8_t *sig
, /* signature */
579 size_t sigLen
) { /* length of signature */
580 if (!key
->key_class
->rawVerify
)
581 return errSecUnsupportedOperation
;
583 if (padding
< kSecPaddingPKCS1MD2
) {
584 return key
->key_class
->rawVerify(key
, padding
, signedData
, signedDataLen
,
587 /* Casting away the constness of sig is safe since
588 SecKeyDigestInfoSignVerify only modifies sig if
589 mode == kSecKeyDigestInfoSign. */
590 return SecKeyDigestInfoSignVerify(key
, padding
,
591 signedData
, signedDataLen
, (uint8_t *)sig
, &sigLen
,
592 kSecKeyDigestInfoVerify
);
596 OSStatus
SecKeyEncrypt(
597 SecKeyRef key
, /* Public key */
598 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
599 const uint8_t *plainText
,
600 size_t plainTextLen
, /* length of plainText */
602 size_t *cipherTextLen
) { /* IN/OUT */
603 if (key
->key_class
->encrypt
)
604 return key
->key_class
->encrypt(key
, padding
, plainText
, plainTextLen
,
605 cipherText
, cipherTextLen
);
606 return errSecUnsupportedOperation
;
609 OSStatus
SecKeyDecrypt(
610 SecKeyRef key
, /* Private key */
611 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
612 const uint8_t *cipherText
,
613 size_t cipherTextLen
, /* length of cipherText */
615 size_t *plainTextLen
) { /* IN/OUT */
616 if (key
->key_class
->decrypt
)
617 return key
->key_class
->decrypt(key
, padding
, cipherText
, cipherTextLen
,
618 plainText
, plainTextLen
);
619 return errSecUnsupportedOperation
;
622 size_t SecKeyGetBlockSize(SecKeyRef key
) {
623 if (key
->key_class
->blockSize
)
624 return key
->key_class
->blockSize(key
);
628 /* Private API functions. */
630 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
631 if (key
->key_class
->copyDictionary
)
632 return key
->key_class
->copyDictionary(key
);
636 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
637 /* TODO: Support having an allocator in refAttributes. */
638 CFAllocatorRef allocator
= NULL
;
639 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
640 CFTypeRef ktype
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyType
);
644 /* First figure out the key type (algorithm). */
645 if (CFGetTypeID(ktype
) == CFNumberGetTypeID()) {
646 CFNumberGetValue(ktype
, kCFNumberSInt32Type
, &algorithm
);
647 } else if (isString(ktype
)) {
648 algorithm
= CFStringGetIntValue(ktype
);
649 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm
);
650 if (!CFEqual(t
, ktype
)) {
651 secwarning("Unsupported key class: %@", ktype
);
657 secwarning("Unsupported key type: %@", ktype
);
661 /* TODO: The code below won't scale well, consider moving to something
664 CFTypeRef kclass
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyClass
);
665 if (CFGetTypeID(kclass
) == CFNumberGetTypeID()) {
666 CFNumberGetValue(kclass
, kCFNumberSInt32Type
, &class);
667 } else if (isString(kclass
)) {
668 class = CFStringGetIntValue(kclass
);
669 CFStringRef t
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class);
670 if (!CFEqual(t
, kclass
)) {
672 secwarning("Unsupported key class: %@", kclass
);
677 secwarning("Unsupported key class: %@", kclass
);
682 case 0: // kSecAttrKeyClassPublic
684 case 42: // kSecAlgorithmRSA
685 ref
= SecKeyCreateRSAPublicKey(allocator
,
686 CFDataGetBytePtr(data
), CFDataGetLength(data
),
687 kSecKeyEncodingBytes
);
689 case 43: // kSecAlgorithmECDSA
690 case 73: // kSecAlgorithmEC
691 ref
= SecKeyCreateECPublicKey(allocator
,
692 CFDataGetBytePtr(data
), CFDataGetLength(data
),
693 kSecKeyEncodingBytes
);
696 secwarning("Unsupported public key type: %@", ktype
);
701 case 1: // kSecAttrKeyClassPrivate
703 case 42: // kSecAlgorithmRSA
704 ref
= SecKeyCreateRSAPrivateKey(allocator
,
705 CFDataGetBytePtr(data
), CFDataGetLength(data
),
706 kSecKeyEncodingBytes
);
708 case 43: // kSecAlgorithmECDSA
709 case 73: // kSecAlgorithmEC
710 ref
= SecKeyCreateECPrivateKey(allocator
,
711 CFDataGetBytePtr(data
), CFDataGetLength(data
),
712 kSecKeyEncodingBytes
);
715 secwarning("Unsupported private key type: %@", ktype
);
720 case 2: // kSecAttrKeyClassSymmetric
721 secwarning("Unsupported symmetric key type: %@", ktype
);
725 secwarning("Unsupported key class: %@", kclass
);
732 /* TODO: This function should ensure that this keys algorithm matches the
733 signature algorithm. */
734 static OSStatus
SecKeyGetDigestInfo(SecKeyRef
this, const SecAsn1AlgId
*algId
,
735 const uint8_t *data
, size_t dataLen
, bool digestData
,
736 uint8_t *digestInfo
, size_t *digestInfoLen
/* IN/OUT */) {
737 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
738 CFIndex keyAlgID
= kSecNullAlgorithmID
;
739 const SecAsn1Oid
*digestOid
;
743 /* Since these oids all have the same prefix, use switch. */
744 if ((algId
->algorithm
.Length
== CSSMOID_RSA
.Length
) &&
745 !memcmp(algId
->algorithm
.Data
, CSSMOID_RSA
.Data
,
746 algId
->algorithm
.Length
- 1)) {
747 keyAlgID
= kSecRSAAlgorithmID
;
748 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
750 case 2: /* oidMD2WithRSA */
752 digestLen
= CC_MD2_DIGEST_LENGTH
;
753 digestOid
= &CSSMOID_MD2
;
755 case 3: /* oidMD4WithRSA */
757 digestLen
= CC_MD4_DIGEST_LENGTH
;
758 digestOid
= &CSSMOID_MD4
;
760 case 4: /* oidMD5WithRSA */
762 digestLen
= CC_MD5_DIGEST_LENGTH
;
763 digestOid
= &CSSMOID_MD5
;
766 case 5: /* oidSHA1WithRSA */
768 digestLen
= CC_SHA1_DIGEST_LENGTH
;
769 digestOid
= &CSSMOID_SHA1
;
771 case 11: /* oidSHA256WithRSA */
772 digestFcn
= CC_SHA256
;
773 digestLen
= CC_SHA256_DIGEST_LENGTH
;
774 digestOid
= &CSSMOID_SHA256
;
776 case 12: /* oidSHA384WithRSA */
778 digestFcn
= CC_SHA384
;
779 digestLen
= CC_SHA384_DIGEST_LENGTH
;
780 digestOid
= &CSSMOID_SHA384
;
782 case 13: /* oidSHA512WithRSA */
783 digestFcn
= CC_SHA512
;
784 digestLen
= CC_SHA512_DIGEST_LENGTH
;
785 digestOid
= &CSSMOID_SHA512
;
787 case 14: /* oidSHA224WithRSA */
788 digestFcn
= CC_SHA224
;
789 digestLen
= CC_SHA224_DIGEST_LENGTH
;
790 digestOid
= &CSSMOID_SHA224
;
793 secdebug("key", "unsupported rsa signature algorithm");
794 return errSecUnsupportedAlgorithm
;
796 } else if ((algId
->algorithm
.Length
== CSSMOID_ECDSA_WithSHA224
.Length
) &&
797 !memcmp(algId
->algorithm
.Data
, CSSMOID_ECDSA_WithSHA224
.Data
,
798 algId
->algorithm
.Length
- 1)) {
799 keyAlgID
= kSecECDSAAlgorithmID
;
800 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
801 case 1: /* oidSHA224WithECDSA */
802 digestFcn
= CC_SHA224
;
803 digestLen
= CC_SHA224_DIGEST_LENGTH
;
805 case 2: /* oidSHA256WithECDSA */
806 digestFcn
= CC_SHA256
;
807 digestLen
= CC_SHA256_DIGEST_LENGTH
;
809 case 3: /* oidSHA384WithECDSA */
811 digestFcn
= CC_SHA384
;
812 digestLen
= CC_SHA384_DIGEST_LENGTH
;
814 case 4: /* oidSHA512WithECDSA */
815 digestFcn
= CC_SHA512
;
816 digestLen
= CC_SHA512_DIGEST_LENGTH
;
819 secdebug("key", "unsupported ecdsa signature algorithm");
820 return errSecUnsupportedAlgorithm
;
822 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_ECDSA_WithSHA1
)) {
823 keyAlgID
= kSecECDSAAlgorithmID
;
825 digestLen
= CC_SHA1_DIGEST_LENGTH
;
826 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_SHA1
)) {
828 digestLen
= CC_SHA1_DIGEST_LENGTH
;
829 digestOid
= &CSSMOID_SHA1
;
830 } else if ((algId
->algorithm
.Length
== CSSMOID_SHA224
.Length
) &&
831 !memcmp(algId
->algorithm
.Data
, CSSMOID_SHA224
.Data
, algId
->algorithm
.Length
- 1))
833 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
834 case 4: /* OID_SHA224 */
835 digestFcn
= CC_SHA224
;
836 digestLen
= CC_SHA224_DIGEST_LENGTH
;
837 digestOid
= &CSSMOID_SHA224
;
839 case 1: /* OID_SHA256 */
840 digestFcn
= CC_SHA256
;
841 digestLen
= CC_SHA256_DIGEST_LENGTH
;
842 digestOid
= &CSSMOID_SHA256
;
844 case 2: /* OID_SHA384 */
846 digestFcn
= CC_SHA384
;
847 digestLen
= CC_SHA384_DIGEST_LENGTH
;
848 digestOid
= &CSSMOID_SHA384
;
850 case 3: /* OID_SHA512 */
851 digestFcn
= CC_SHA512
;
852 digestLen
= CC_SHA512_DIGEST_LENGTH
;
853 digestOid
= &CSSMOID_SHA512
;
856 secdebug("key", "unsupported sha-2 signature algorithm");
857 return errSecUnsupportedAlgorithm
;
859 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
861 digestLen
= CC_MD5_DIGEST_LENGTH
;
862 digestOid
= &CSSMOID_MD5
;
864 secdebug("key", "unsupported digesting algorithm");
865 return errSecUnsupportedAlgorithm
;
868 /* check key is appropriate for signature (superfluous for digest only oid) */
869 if (keyAlgID
== kSecNullAlgorithmID
)
870 keyAlgID
= SecKeyGetAlgorithmID(this);
871 else if (keyAlgID
!= SecKeyGetAlgorithmID(this))
872 return errSecUnsupportedAlgorithm
;
875 case kSecRSAAlgorithmID
:
876 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
877 digestInfo
, *digestInfoLen
);
879 return errSecBufferTooSmall
;
881 case kSecDSAAlgorithmID
:
882 if (digestOid
!= &CSSMOID_SHA1
)
883 return errSecUnsupportedAlgorithm
;
885 case kSecECDSAAlgorithmID
:
888 secdebug("key", "unsupported signature algorithm");
889 return errSecUnsupportedAlgorithm
;
893 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
895 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
896 *digestInfoLen
= offset
+ digestLen
;
898 if (dataLen
!= digestLen
)
900 memcpy(&digestInfo
[offset
], data
, dataLen
);
901 *digestInfoLen
= offset
+ dataLen
;
904 return errSecSuccess
;
907 OSStatus
SecKeyDigestAndVerify(
908 SecKeyRef
this, /* 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 */
914 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
915 uint8_t digestInfo
[digestInfoLength
];
921 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true,
922 digestInfo
, &digestInfoLength
);
925 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
926 digestInfo
, digestInfoLength
, sig
, sigLen
);
929 OSStatus
SecKeyDigestAndSign(
930 SecKeyRef
this, /* Private key */
931 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
932 const uint8_t *dataToDigest
, /* signature over this data */
933 size_t dataToDigestLen
,/* length of dataToDigest */
934 uint8_t *sig
, /* signature, RETURNED */
935 size_t *sigLen
) { /* IN/OUT */
936 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
937 uint8_t digestInfo
[digestInfoLength
];
940 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true /* digest data */,
941 digestInfo
, &digestInfoLength
);
944 return SecKeyRawSign(this, kSecPaddingPKCS1
,
945 digestInfo
, digestInfoLength
, sig
, sigLen
);
948 OSStatus
SecKeyVerifyDigest(
949 SecKeyRef
this, /* Private key */
950 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
951 const uint8_t *digestData
, /* signature over this digest */
952 size_t digestDataLen
,/* length of dataToDigest */
953 const uint8_t *sig
, /* signature to verify */
954 size_t sigLen
) { /* length of sig */
955 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
956 uint8_t digestInfo
[digestInfoLength
];
959 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false /* data is digest */,
960 digestInfo
, &digestInfoLength
);
963 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
964 digestInfo
, digestInfoLength
, sig
, sigLen
);
967 OSStatus
SecKeySignDigest(
968 SecKeyRef
this, /* Private key */
969 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
970 const uint8_t *digestData
, /* signature over this digest */
971 size_t digestDataLen
,/* length of digestData */
972 uint8_t *sig
, /* signature, RETURNED */
973 size_t *sigLen
) { /* IN/OUT */
974 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
975 uint8_t digestInfo
[digestInfoLength
];
978 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false,
979 digestInfo
, &digestInfoLength
);
982 return SecKeyRawSign(this, kSecPaddingPKCS1
,
983 digestInfo
, digestInfoLength
, sig
, sigLen
);
986 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
987 /* This method was added to version 1 keys. */
988 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
)
989 return key
->key_class
->getAlgorithmID(key
);
990 /* All version 0 key were RSA. */
991 return kSecRSAAlgorithmID
;
995 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
996 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
997 return key
->key_class
->copyPublic(key
, serializedPublic
);
998 return errSecUnimplemented
;
1001 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
1003 switch (algorithmID
)
1005 case kSecRSAAlgorithmID
:
1006 return SecKeyCreateRSAPublicKey(allocator
,
1007 keyData
, keyDataLength
,
1008 kSecKeyEncodingBytes
);
1009 case kSecECDSAAlgorithmID
:
1010 return SecKeyCreateECPublicKey(allocator
,
1011 keyData
, keyDataLength
,
1012 kSecKeyEncodingBytes
);
1018 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
1020 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
1023 // This is a bit icky hack to avoid changing the vtable for
1025 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
1027 size_t result
= SecKeyGetBlockSize(key
);
1029 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmID(key
)) {
1030 switch (whichSize
) {
1031 case kSecKeyEncryptedDataSize
:
1034 case kSecKeySignatureSize
:
1035 result
= (result
>= 66 ? 9 : 8) + 2 * result
;
1037 case kSecKeyKeySizeInBits
:
1043 if (whichSize
== kSecKeyKeySizeInBits
)
1050 OSStatus
SecKeyFindWithPersistentRef(CFDataRef persistentRef
, SecKeyRef
* lookedUpData
)
1052 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1053 kSecReturnRef
, kCFBooleanTrue
,
1054 kSecClass
, kSecClassKey
,
1055 kSecValuePersistentRef
, persistentRef
,
1057 CFTypeRef foundRef
= NULL
;
1058 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1060 if (status
== errSecSuccess
) {
1061 if (CFGetTypeID(foundRef
) == SecKeyGetTypeID()) {
1062 *lookedUpData
= (SecKeyRef
) foundRef
;
1064 status
= errSecSuccess
;
1066 status
= errSecItemNotFound
;
1070 CFReleaseSafe(foundRef
);
1071 CFReleaseSafe(query
);
1076 OSStatus
SecKeyCopyPersistentRef(SecKeyRef key
, CFDataRef
* persistentRef
)
1078 CFDictionaryRef query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
1079 kSecReturnPersistentRef
, kCFBooleanTrue
,
1081 kSecAttrSynchronizable
, kSecAttrSynchronizableAny
,
1083 CFTypeRef foundRef
= NULL
;
1084 OSStatus status
= SecItemCopyMatching(query
, &foundRef
);
1086 if (status
== errSecSuccess
) {
1087 if (CFGetTypeID(foundRef
) == CFDataGetTypeID()) {
1088 *persistentRef
= foundRef
;
1091 status
= errSecItemNotFound
;
1095 CFReleaseSafe(foundRef
);
1096 CFReleaseSafe(query
);