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 "SecRSAKeyPriv.h"
36 #include "SecBasePriv.h"
38 #include <CoreFoundation/CFNumber.h>
39 #include <CoreFoundation/CFString.h>
40 #include <MacErrors.h>
43 #include <AssertMacros.h>
44 #include <security_utilities/debugging.h>
45 #include <CommonCrypto/CommonDigest.h>
46 #include <Security/SecAsn1Coder.h>
47 #include <Security/oidsalg.h>
48 #include <Security/SecInternal.h>
49 #include <Security/SecRandom.h>
50 #include <corecrypto/ccrng_system.h>
53 static pthread_once_t kSecKeyRegisterClass
= PTHREAD_ONCE_INIT
;
54 static CFTypeID kSecKeyTypeID
= _kCFRuntimeNotATypeID
;
56 /* Forward declartions of static functions. */
57 static CFStringRef
SecKeyDescribe(CFTypeRef cf
);
58 static void SecKeyDestroy(CFTypeRef cf
);
60 /* Static functions. */
61 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
63 /* Currently length of SHA512 oid + 1 */
64 #define MAX_OID_LEN (10)
66 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
68 /* Encode the digestInfo header into digestInfo and return the offset from
69 digestInfo at which to put the actual digest. Returns 0 if digestInfo
70 won't fit within digestInfoLength bytes.
74 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 struct ccrng_system_state ccrng_system_state_seckey
;
108 static void register_algs(void) {
109 ccrng_seckey
= (struct ccrng_state
*)&ccrng_system_state_seckey
;
110 ccrng_system_init(&ccrng_system_state_seckey
);
116 static CFDictionaryRef
SecKeyGenerateAttributeDictionaryFor(SecKeyRef key
,
118 CFDataRef privateBlob
)
120 CFAllocatorRef allocator
= CFGetAllocator(key
);
122 CFDataRef pubKeyDigest
= NULL
, pubKeyBlob
= NULL
;
123 CFDictionaryRef dict
= NULL
;
125 size_t sizeValue
= SecKeyGetSize(key
, kSecKeyKeySizeInBits
);
126 CFNumberRef sizeInBits
= CFNumberCreate(allocator
, kCFNumberLongType
, &sizeValue
);
128 /* encode the public key. */
129 require_noerr(SecKeyCopyPublicBytes(key
, &pubKeyBlob
), errOut
);
130 require(pubKeyBlob
, errOut
);
132 /* Calculate the digest of the public key. */
133 require(pubKeyDigest
= SecSHA1DigestCreate(allocator
,
134 CFDataGetBytePtr(pubKeyBlob
), CFDataGetLength(pubKeyBlob
)),
137 DICT_ADDPAIR(kSecClass
, kSecClassKey
);
138 DICT_ADDPAIR(kSecAttrKeyClass
, privateBlob
? kSecAttrKeyClassPrivate
: kSecAttrKeyClassPublic
);
139 DICT_ADDPAIR(kSecAttrApplicationLabel
, pubKeyDigest
);
140 DICT_ADDPAIR(kSecAttrIsPermanent
, kCFBooleanTrue
);
141 DICT_ADDPAIR(kSecAttrIsPrivate
, kCFBooleanTrue
);
142 DICT_ADDPAIR(kSecAttrIsModifiable
, kCFBooleanTrue
);
143 DICT_ADDPAIR(kSecAttrKeyType
, keyType
);
144 DICT_ADDPAIR(kSecAttrKeySizeInBits
, sizeInBits
);
145 DICT_ADDPAIR(kSecAttrEffectiveKeySize
, sizeInBits
);
146 DICT_ADDPAIR(kSecAttrIsSensitive
, kCFBooleanFalse
);
147 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive
, kCFBooleanFalse
);
148 DICT_ADDPAIR(kSecAttrIsExtractable
, kCFBooleanTrue
);
149 DICT_ADDPAIR(kSecAttrWasNeverExtractable
, kCFBooleanFalse
);
150 DICT_ADDPAIR(kSecAttrCanEncrypt
, kCFBooleanFalse
);
151 DICT_ADDPAIR(kSecAttrCanDecrypt
, kCFBooleanTrue
);
152 DICT_ADDPAIR(kSecAttrCanDerive
, kCFBooleanTrue
);
153 DICT_ADDPAIR(kSecAttrCanSign
, kCFBooleanTrue
);
154 DICT_ADDPAIR(kSecAttrCanVerify
, kCFBooleanFalse
);
155 DICT_ADDPAIR(kSecAttrCanSignRecover
, kCFBooleanFalse
);
156 DICT_ADDPAIR(kSecAttrCanVerifyRecover
, kCFBooleanFalse
);
157 DICT_ADDPAIR(kSecAttrCanWrap
, kCFBooleanFalse
);
158 DICT_ADDPAIR(kSecAttrCanUnwrap
, kCFBooleanTrue
);
159 DICT_ADDPAIR(kSecValueData
, privateBlob
? privateBlob
: pubKeyBlob
);
160 dict
= DICT_CREATE(allocator
);
163 // @@@ Zero out key material.
164 CFReleaseSafe(pubKeyDigest
);
165 CFReleaseSafe(pubKeyBlob
);
166 CFReleaseSafe(sizeInBits
);
171 CFDictionaryRef
SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key
,
173 CFDataRef privateBlob
)
175 return SecKeyGenerateAttributeDictionaryFor(key
, keyType
, privateBlob
);
178 CFDictionaryRef
SecKeyGeneratePublicAttributeDictionary(SecKeyRef key
, CFTypeRef keyType
)
180 return SecKeyGenerateAttributeDictionaryFor(key
, keyType
, NULL
);
186 static CFStringRef
SecKeyDescribe(CFTypeRef cf
) {
187 SecKeyRef key
= (SecKeyRef
)cf
;
188 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecKeyRef: %p>"), key
);
191 static void SecKeyDestroy(CFTypeRef cf
) {
192 SecKeyRef key
= (SecKeyRef
)cf
;
193 if (key
->key_class
->destroy
)
194 key
->key_class
->destroy(key
);
197 static Boolean
SecKeyEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
198 SecKeyRef key1
= (SecKeyRef
)cf1
;
199 SecKeyRef key2
= (SecKeyRef
)cf2
;
202 if (!key2
|| key1
->key_class
!= key2
->key_class
)
204 if (key1
->key_class
->extraBytes
)
205 return !memcmp(key1
->key
, key2
->key
, key1
->key_class
->extraBytes
);
207 /* TODO: Won't work when we get reference keys. */
208 CFDictionaryRef d1
, d2
;
209 d1
= SecKeyCopyAttributeDictionary(key1
);
210 d2
= SecKeyCopyAttributeDictionary(key2
);
211 Boolean result
= CFEqual(d1
, d2
);
217 static void SecKeyRegisterClass(void) {
218 static const CFRuntimeClass kSecKeyClass
= {
220 "SecKey", /* class name */
223 SecKeyDestroy
, /* dealloc */
224 SecKeyEqual
, /* equal */
226 NULL
, /* copyFormattingDesc */
227 SecKeyDescribe
/* copyDebugDesc */
230 kSecKeyTypeID
= _CFRuntimeRegisterClass(&kSecKeyClass
);
234 /* Public API functions. */
235 CFTypeID
SecKeyGetTypeID(void) {
236 pthread_once(&kSecKeyRegisterClass
, SecKeyRegisterClass
);
237 return kSecKeyTypeID
;
240 static bool getBoolForKey(CFDictionaryRef dict
, CFStringRef key
, bool default_value
) {
241 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
243 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
244 return CFBooleanGetValue(value
);
246 secwarning("Value %@ for key %@ is not bool", value
, key
);
250 return default_value
;
253 static OSStatus
add_ref(CFTypeRef item
, CFMutableDictionaryRef dict
) {
254 CFDictionarySetValue(dict
, kSecValueRef
, item
);
255 return SecItemAdd(dict
, NULL
);
258 static void merge_params_applier(const void *key
, const void *value
,
260 CFMutableDictionaryRef result
= (CFMutableDictionaryRef
)context
;
261 CFDictionaryAddValue(result
, key
, value
);
264 /* Create a mutable dictionary that is based on the subdictionary for key
265 with any attributes from the top level dict merged in. */
266 static CFMutableDictionaryRef
merge_params(CFDictionaryRef dict
,
268 CFDictionaryRef subdict
= CFDictionaryGetValue(dict
, key
);
269 CFMutableDictionaryRef result
;
272 result
= CFDictionaryCreateMutableCopy(NULL
, 0, subdict
);
273 /* Add everything in dict not already in result to result. */
274 CFDictionaryApplyFunction(dict
, merge_params_applier
, result
);
276 result
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
279 /* Remove values that only belong in the top level dict. */
280 CFDictionaryRemoveValue(result
, kSecPublicKeyAttrs
);
281 CFDictionaryRemoveValue(result
, kSecPrivateKeyAttrs
);
282 CFDictionaryRemoveValue(result
, kSecAttrKeyType
);
283 CFDictionaryRemoveValue(result
, kSecAttrKeySizeInBits
);
288 /* Generate a private/public keypair. */
289 OSStatus
SecKeyGeneratePair(CFDictionaryRef parameters
,
290 SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
291 OSStatus result
= errSecUnsupportedAlgorithm
;
292 SecKeyRef privKey
= NULL
;
293 SecKeyRef pubKey
= NULL
;
294 CFMutableDictionaryRef pubParams
= merge_params(parameters
, kSecPublicKeyAttrs
),
295 privParams
= merge_params(parameters
, kSecPrivateKeyAttrs
);
296 CFStringRef ktype
= CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
298 require(ktype
, errOut
);
300 if (CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
301 result
= SecECKeyGeneratePair(parameters
, &pubKey
, &privKey
);
302 } else if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
303 result
= SecRSAKeyGeneratePair(parameters
, &pubKey
, &privKey
);
306 require_noerr(result
, errOut
);
308 /* Store the keys in the keychain if they are marked as permanent. */
309 if (getBoolForKey(pubParams
, kSecAttrIsPermanent
, false)) {
310 require_noerr(result
= add_ref(pubKey
, pubParams
), errOut
);
312 if (getBoolForKey(privParams
, kSecAttrIsPermanent
, false)) {
313 require_noerr(result
= add_ref(privKey
, privParams
), errOut
);
321 *privateKey
= privKey
;
326 CFReleaseSafe(pubParams
);
327 CFReleaseSafe(privParams
);
328 CFReleaseSafe(pubKey
);
329 CFReleaseSafe(privKey
);
334 SecKeyRef
SecKeyCreatePublicFromDER(CFAllocatorRef allocator
,
335 const SecAsn1Oid
*oid
, const SecAsn1Item
*params
,
336 const SecAsn1Item
*keyData
) {
337 SecKeyRef publicKey
= NULL
;
338 if (SecAsn1OidCompare(oid
, &CSSMOID_RSA
)) {
340 publicKey
= SecKeyCreateRSAPublicKey(kCFAllocatorDefault
,
341 keyData
->Data
, keyData
->Length
, kSecKeyEncodingPkcs1
);
342 } else if (SecAsn1OidCompare(oid
, &CSSMOID_ecPublicKey
)) {
345 .oidLength
= oid
->Length
,
346 .key
= keyData
->Data
,
347 .keyLength
= keyData
->Length
,
350 derKey
.parameters
= params
->Data
;
351 derKey
.parametersLength
= params
->Length
;
353 publicKey
= SecKeyCreateECPublicKey(kCFAllocatorDefault
,
354 (const uint8_t *)&derKey
, sizeof(derKey
), kSecDERKeyEncoding
);
356 secwarning("Unsupported algorithm oid");
362 SecKeyRef
SecKeyCreate(CFAllocatorRef allocator
,
363 const SecKeyDescriptor
*key_class
, const uint8_t *keyData
,
364 CFIndex keyDataLength
, SecKeyEncoding encoding
) {
367 size_t size
= sizeof(struct __SecKey
) + key_class
->extraBytes
;
368 SecKeyRef result
= (SecKeyRef
)_CFRuntimeCreateInstance(allocator
,
369 SecKeyGetTypeID(), size
- sizeof(CFRuntimeBase
), NULL
);
371 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
372 result
->key_class
= key_class
;
373 if (key_class
->extraBytes
) {
374 /* Make result->key point to the extraBytes we allocated. */
375 result
->key
= ((char*)result
) + sizeof(*result
);
377 if (key_class
->init
) {
379 status
= key_class
->init(result
, keyData
, keyDataLength
, encoding
);
381 secwarning("init %s key: %d", key_class
->name
, status
);
391 kSecKeyDigestInfoSign
,
392 kSecKeyDigestInfoVerify
395 static OSStatus
SecKeyDigestInfoSignVerify(
396 SecKeyRef key
, /* Private key */
397 SecPadding padding
, /* kSecPaddingPKCS1@@@ */
398 const uint8_t *dataToSign
, /* signature over this data */
399 size_t dataToSignLen
, /* length of dataToSign */
400 uint8_t *sig
, /* signature, RETURNED */
401 size_t *sigLen
, /* IN/OUT */
403 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
404 uint8_t digestInfo
[digestInfoLength
];
405 const SecAsn1Oid
*digestOid
;
410 case kSecPaddingPKCS1MD2
:
411 digestLen
= CC_MD2_DIGEST_LENGTH
;
412 digestOid
= &CSSMOID_MD2
;
414 case kSecPaddingPKCS1MD4
:
415 digestLen
= CC_MD4_DIGEST_LENGTH
;
416 digestOid
= &CSSMOID_MD4
;
418 case kSecPaddingPKCS1MD5
:
419 digestLen
= CC_MD5_DIGEST_LENGTH
;
420 digestOid
= &CSSMOID_MD5
;
423 case kSecPaddingPKCS1SHA1
:
424 digestLen
= CC_SHA1_DIGEST_LENGTH
;
425 digestOid
= &CSSMOID_SHA1
;
428 case kSecPaddingPKCS1SHA224
:
429 digestLen
= CC_SHA224_DIGEST_LENGTH
;
430 digestOid
= &CSSMOID_SHA224
;
432 case kSecPaddingPKCS1SHA256
:
433 digestLen
= CCSHA256_OUTPUT_SIZE
;
434 digestOid
= &CSSMOID_SHA256
;
436 case kSecPaddingPKCS1SHA384
:
437 digestLen
= CC_SHA384_DIGEST_LENGTH
;
438 digestOid
= &CSSMOID_SHA384
;
440 case kSecPaddingPKCS1SHA512
:
441 digestLen
= CC_SHA512_DIGEST_LENGTH
;
442 digestOid
= &CSSMOID_SHA512
;
446 return errSecUnsupportedPadding
;
449 if (dataToSignLen
!= digestLen
)
452 size_t offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
453 digestInfo
, digestInfoLength
);
455 return errSecBufferTooSmall
;
457 /* Append the digest to the digestInfo prefix and adjust the length. */
458 memcpy(&digestInfo
[offset
], dataToSign
, digestLen
);
459 digestInfoLength
= offset
+ digestLen
;
461 if (mode
== kSecKeyDigestInfoSign
) {
462 return key
->key_class
->rawSign(key
, kSecPaddingPKCS1
,
463 digestInfo
, digestInfoLength
, sig
, sigLen
);
465 return key
->key_class
->rawVerify(key
, kSecPaddingPKCS1
,
466 digestInfo
, digestInfoLength
, sig
, *sigLen
);
472 OSStatus
SecKeyRawSign(
473 SecKeyRef key
, /* Private key */
474 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
475 const uint8_t *dataToSign
, /* signature over this data */
476 size_t dataToSignLen
, /* length of dataToSign */
477 uint8_t *sig
, /* signature, RETURNED */
478 size_t *sigLen
) { /* IN/OUT */
479 if (!key
->key_class
->rawSign
)
480 return errSecUnsupportedOperation
;
482 if (padding
< kSecPaddingPKCS1MD2
) {
483 return key
->key_class
->rawSign(key
, padding
, dataToSign
, dataToSignLen
,
486 return SecKeyDigestInfoSignVerify(key
, padding
, dataToSign
, dataToSignLen
,
487 sig
, sigLen
, kSecKeyDigestInfoSign
);
491 OSStatus
SecKeyRawVerify(
492 SecKeyRef key
, /* Public key */
493 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
494 const uint8_t *signedData
, /* signature over this data */
495 size_t signedDataLen
, /* length of dataToSign */
496 const uint8_t *sig
, /* signature */
497 size_t sigLen
) { /* length of signature */
498 if (!key
->key_class
->rawVerify
)
499 return errSecUnsupportedOperation
;
501 if (padding
< kSecPaddingPKCS1MD2
) {
502 return key
->key_class
->rawVerify(key
, padding
, signedData
, signedDataLen
,
505 /* Casting away the constness of sig is safe since
506 SecKeyDigestInfoSignVerify only modifies sig if
507 mode == kSecKeyDigestInfoSign. */
508 return SecKeyDigestInfoSignVerify(key
, padding
,
509 signedData
, signedDataLen
, (uint8_t *)sig
, &sigLen
,
510 kSecKeyDigestInfoVerify
);
514 OSStatus
SecKeyEncrypt(
515 SecKeyRef key
, /* Public key */
516 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
517 const uint8_t *plainText
,
518 size_t plainTextLen
, /* length of plainText */
520 size_t *cipherTextLen
) { /* IN/OUT */
521 if (key
->key_class
->encrypt
)
522 return key
->key_class
->encrypt(key
, padding
, plainText
, plainTextLen
,
523 cipherText
, cipherTextLen
);
524 return errSecUnsupportedOperation
;
527 OSStatus
SecKeyDecrypt(
528 SecKeyRef key
, /* Private key */
529 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
530 const uint8_t *cipherText
,
531 size_t cipherTextLen
, /* length of cipherText */
533 size_t *plainTextLen
) { /* IN/OUT */
534 if (key
->key_class
->decrypt
)
535 return key
->key_class
->decrypt(key
, padding
, cipherText
, cipherTextLen
,
536 plainText
, plainTextLen
);
537 return errSecUnsupportedOperation
;
540 size_t SecKeyGetBlockSize(SecKeyRef key
) {
541 if (key
->key_class
->blockSize
)
542 return key
->key_class
->blockSize(key
);
546 /* Private API functions. */
548 CFDictionaryRef
SecKeyCopyAttributeDictionary(SecKeyRef key
) {
549 if (key
->key_class
->copyDictionary
)
550 return key
->key_class
->copyDictionary(key
);
554 SecKeyRef
SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) {
555 /* TODO: Support having an allocator in refAttributes. */
556 CFAllocatorRef allocator
= NULL
;
557 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
558 CFTypeRef ktype
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyType
);
562 /* First figure out the key type (algorithm). */
563 if (CFGetTypeID(ktype
) == CFNumberGetTypeID()) {
564 CFNumberGetValue(ktype
, kCFNumberSInt32Type
, &algorithm
);
566 secwarning("Unsupported key type: %@", ktype
);
570 /* TODO: The code below won't scale well, consider moving to something
573 CFTypeRef kclass
= CFDictionaryGetValue(refAttributes
, kSecAttrKeyClass
);
574 if (CFGetTypeID(kclass
) == CFNumberGetTypeID()) {
575 CFNumberGetValue(kclass
, kCFNumberSInt32Type
, &class);
577 secwarning("Unsupported key class: %@", kclass
);
582 case 0: // kSecAttrKeyClassPublic
584 case 42: // kSecAlgorithmRSA
585 ref
= SecKeyCreateRSAPublicKey(allocator
,
586 CFDataGetBytePtr(data
), CFDataGetLength(data
),
587 kSecKeyEncodingBytes
);
589 case 43: // kSecAlgorithmECDSA
590 ref
= SecKeyCreateECPublicKey(allocator
,
591 CFDataGetBytePtr(data
), CFDataGetLength(data
),
592 kSecKeyEncodingBytes
);
595 secwarning("Unsupported public key type: %@", ktype
);
600 case 1: // kSecAttrKeyClassPrivate
602 case 42: // kSecAlgorithmRSA
603 ref
= SecKeyCreateRSAPrivateKey(allocator
,
604 CFDataGetBytePtr(data
), CFDataGetLength(data
),
605 kSecKeyEncodingBytes
);
607 case 43: // kSecAlgorithmECDSA
608 ref
= SecKeyCreateECPrivateKey(allocator
,
609 CFDataGetBytePtr(data
), CFDataGetLength(data
),
610 kSecKeyEncodingBytes
);
613 secwarning("Unsupported private key type: %@", ktype
);
618 case 2: // kSecAttrKeyClassSymmetric
619 secwarning("Unsupported symmetric key type: %@", ktype
);
623 secwarning("Unsupported key class: %@", kclass
);
630 /* TODO: This function should ensure that this keys algorithm matches the
631 signature algorithm. */
632 static OSStatus
SecKeyGetDigestInfo(SecKeyRef
this, const SecAsn1AlgId
*algId
,
633 const uint8_t *data
, size_t dataLen
, bool digestData
,
634 uint8_t *digestInfo
, size_t *digestInfoLen
/* IN/OUT */) {
635 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
636 CFIndex keyAlgID
= kSecNullAlgorithmID
;
637 const SecAsn1Oid
*digestOid
;
641 /* Since these oids all have the same prefix, use switch. */
642 if ((algId
->algorithm
.Length
== CSSMOID_RSA
.Length
) &&
643 !memcmp(algId
->algorithm
.Data
, CSSMOID_RSA
.Data
,
644 algId
->algorithm
.Length
- 1)) {
645 keyAlgID
= kSecRSAAlgorithmID
;
646 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
648 case 2: /* oidMD2WithRSA */
650 digestLen
= CC_MD2_DIGEST_LENGTH
;
651 digestOid
= &CSSMOID_MD2
;
653 case 3: /* oidMD4WithRSA */
655 digestLen
= CC_MD4_DIGEST_LENGTH
;
656 digestOid
= &CSSMOID_MD4
;
658 case 4: /* oidMD5WithRSA */
660 digestLen
= CC_MD5_DIGEST_LENGTH
;
661 digestOid
= &CSSMOID_MD5
;
664 case 5: /* oidSHA1WithRSA */
666 digestLen
= CC_SHA1_DIGEST_LENGTH
;
667 digestOid
= &CSSMOID_SHA1
;
669 case 11: /* oidSHA256WithRSA */
670 digestFcn
= CC_SHA256
;
671 digestLen
= CC_SHA256_DIGEST_LENGTH
;
672 digestOid
= &CSSMOID_SHA256
;
674 case 12: /* oidSHA384WithRSA */
676 digestFcn
= CC_SHA384
;
677 digestLen
= CC_SHA384_DIGEST_LENGTH
;
678 digestOid
= &CSSMOID_SHA384
;
680 case 13: /* oidSHA512WithRSA */
681 digestFcn
= CC_SHA512
;
682 digestLen
= CC_SHA512_DIGEST_LENGTH
;
683 digestOid
= &CSSMOID_SHA512
;
685 case 14: /* oidSHA224WithRSA */
686 digestFcn
= CC_SHA224
;
687 digestLen
= CC_SHA224_DIGEST_LENGTH
;
688 digestOid
= &CSSMOID_SHA224
;
691 secdebug("key", "unsupported rsa signature algorithm");
692 return errSecUnsupportedAlgorithm
;
694 } else if ((algId
->algorithm
.Length
== CSSMOID_ECDSA_WithSHA224
.Length
) &&
695 !memcmp(algId
->algorithm
.Data
, CSSMOID_ECDSA_WithSHA224
.Data
,
696 algId
->algorithm
.Length
- 1)) {
697 keyAlgID
= kSecECDSAAlgorithmID
;
698 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
699 case 1: /* oidSHA224WithECDSA */
700 digestFcn
= CC_SHA224
;
701 digestLen
= CC_SHA224_DIGEST_LENGTH
;
703 case 2: /* oidSHA256WithECDSA */
704 digestFcn
= CC_SHA256
;
705 digestLen
= CC_SHA256_DIGEST_LENGTH
;
707 case 3: /* oidSHA384WithECDSA */
709 digestFcn
= CC_SHA384
;
710 digestLen
= CC_SHA384_DIGEST_LENGTH
;
712 case 4: /* oidSHA512WithECDSA */
713 digestFcn
= CC_SHA512
;
714 digestLen
= CC_SHA512_DIGEST_LENGTH
;
717 secdebug("key", "unsupported ecdsa signature algorithm");
718 return errSecUnsupportedAlgorithm
;
720 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_ECDSA_WithSHA1
)) {
721 keyAlgID
= kSecECDSAAlgorithmID
;
723 digestLen
= CC_SHA1_DIGEST_LENGTH
;
724 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_SHA1
)) {
726 digestLen
= CC_SHA1_DIGEST_LENGTH
;
727 digestOid
= &CSSMOID_SHA1
;
728 } else if ((algId
->algorithm
.Length
== CSSMOID_SHA224
.Length
) &&
729 !memcmp(algId
->algorithm
.Data
, CSSMOID_SHA224
.Data
, algId
->algorithm
.Length
- 1))
731 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
732 case 4: /* OID_SHA224 */
733 digestFcn
= CC_SHA224
;
734 digestLen
= CC_SHA224_DIGEST_LENGTH
;
735 digestOid
= &CSSMOID_SHA224
;
737 case 1: /* OID_SHA256 */
738 digestFcn
= CC_SHA256
;
739 digestLen
= CC_SHA256_DIGEST_LENGTH
;
740 digestOid
= &CSSMOID_SHA256
;
742 case 2: /* OID_SHA384 */
744 digestFcn
= CC_SHA384
;
745 digestLen
= CC_SHA384_DIGEST_LENGTH
;
746 digestOid
= &CSSMOID_SHA384
;
748 case 3: /* OID_SHA512 */
749 digestFcn
= CC_SHA512
;
750 digestLen
= CC_SHA512_DIGEST_LENGTH
;
751 digestOid
= &CSSMOID_SHA512
;
754 secdebug("key", "unsupported sha-2 signature algorithm");
755 return errSecUnsupportedAlgorithm
;
757 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
759 digestLen
= CC_MD5_DIGEST_LENGTH
;
760 digestOid
= &CSSMOID_MD5
;
762 secdebug("key", "unsupported digesting algorithm");
763 return errSecUnsupportedAlgorithm
;
766 /* check key is appropriate for signature (superfluous for digest only oid) */
767 if (keyAlgID
== kSecNullAlgorithmID
)
768 keyAlgID
= SecKeyGetAlgorithmID(this);
769 else if (keyAlgID
!= SecKeyGetAlgorithmID(this))
770 return errSecUnsupportedAlgorithm
;
773 case kSecRSAAlgorithmID
:
774 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
775 digestInfo
, *digestInfoLen
);
777 return errSecBufferTooSmall
;
779 case kSecDSAAlgorithmID
:
780 if (digestOid
!= &CSSMOID_SHA1
)
781 return errSecUnsupportedAlgorithm
;
783 case kSecECDSAAlgorithmID
:
786 secdebug("key", "unsupported signature algorithm");
787 return errSecUnsupportedAlgorithm
;
791 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
793 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
794 *digestInfoLen
= offset
+ digestLen
;
796 if (dataLen
!= digestLen
)
798 memcpy(&digestInfo
[offset
], data
, dataLen
);
799 *digestInfoLen
= offset
+ dataLen
;
805 OSStatus
SecKeyDigestAndVerify(
806 SecKeyRef
this, /* Private key */
807 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
808 const uint8_t *dataToDigest
, /* signature over this data */
809 size_t dataToDigestLen
,/* length of dataToDigest */
810 const uint8_t *sig
, /* signature to verify */
811 size_t sigLen
) { /* length of sig */
812 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
813 uint8_t digestInfo
[digestInfoLength
];
816 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true,
817 digestInfo
, &digestInfoLength
);
820 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
821 digestInfo
, digestInfoLength
, sig
, sigLen
);
824 OSStatus
SecKeyDigestAndSign(
825 SecKeyRef
this, /* Private key */
826 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
827 const uint8_t *dataToDigest
, /* signature over this data */
828 size_t dataToDigestLen
,/* length of dataToDigest */
829 uint8_t *sig
, /* signature, RETURNED */
830 size_t *sigLen
) { /* IN/OUT */
831 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
832 uint8_t digestInfo
[digestInfoLength
];
835 status
= SecKeyGetDigestInfo(this, algId
, dataToDigest
, dataToDigestLen
, true /* digest data */,
836 digestInfo
, &digestInfoLength
);
839 return SecKeyRawSign(this, kSecPaddingPKCS1
,
840 digestInfo
, digestInfoLength
, sig
, sigLen
);
843 OSStatus
SecKeyVerifyDigest(
844 SecKeyRef
this, /* Private key */
845 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
846 const uint8_t *digestData
, /* signature over this digest */
847 size_t digestDataLen
,/* length of dataToDigest */
848 const uint8_t *sig
, /* signature to verify */
849 size_t sigLen
) { /* length of sig */
850 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
851 uint8_t digestInfo
[digestInfoLength
];
854 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false /* data is digest */,
855 digestInfo
, &digestInfoLength
);
858 return SecKeyRawVerify(this, kSecPaddingPKCS1
,
859 digestInfo
, digestInfoLength
, sig
, sigLen
);
862 OSStatus
SecKeySignDigest(
863 SecKeyRef
this, /* Private key */
864 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
865 const uint8_t *digestData
, /* signature over this digest */
866 size_t digestDataLen
,/* length of digestData */
867 uint8_t *sig
, /* signature, RETURNED */
868 size_t *sigLen
) { /* IN/OUT */
869 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
870 uint8_t digestInfo
[digestInfoLength
];
873 status
= SecKeyGetDigestInfo(this, algId
, digestData
, digestDataLen
, false,
874 digestInfo
, &digestInfoLength
);
877 return SecKeyRawSign(this, kSecPaddingPKCS1
,
878 digestInfo
, digestInfoLength
, sig
, sigLen
);
881 CFIndex
SecKeyGetAlgorithmID(SecKeyRef key
) {
882 /* This method was added to version 1 keys. */
883 if (key
->key_class
->version
> 0 && key
->key_class
->getAlgorithmID
)
884 return key
->key_class
->getAlgorithmID(key
);
885 /* All version 0 key were RSA. */
886 return kSecRSAAlgorithmID
;
890 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* serializedPublic
) {
891 if (key
->key_class
->version
> 1 && key
->key_class
->copyPublic
)
892 return key
->key_class
->copyPublic(key
, serializedPublic
);
893 return errSecUnimplemented
;
896 SecKeyRef
SecKeyCreateFromPublicBytes(CFAllocatorRef allocator
, CFIndex algorithmID
, const uint8_t *keyData
, CFIndex keyDataLength
)
900 case kSecRSAAlgorithmID
:
901 return SecKeyCreateRSAPublicKey(allocator
,
902 keyData
, keyDataLength
,
903 kSecKeyEncodingBytes
);
904 case kSecECDSAAlgorithmID
:
905 return SecKeyCreateECPublicKey(allocator
,
906 keyData
, keyDataLength
,
907 kSecKeyEncodingBytes
);
913 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef serialized
)
915 return SecKeyCreateFromPublicBytes(allocator
, algorithmID
, CFDataGetBytePtr(serialized
), CFDataGetLength(serialized
));
918 // This is a bit icky hack to avoid changing the vtable for
920 size_t SecKeyGetSize(SecKeyRef key
, SecKeySize whichSize
)
922 size_t result
= SecKeyGetBlockSize(key
);
924 if (kSecECDSAAlgorithmID
== SecKeyGetAlgorithmID(key
)) {
926 case kSecKeyEncryptedDataSize
:
929 case kSecKeySignatureSize
:
930 result
= 2 * result
+ 6;
934 case kSecKeyKeySizeInBits
:
940 if (whichSize
== kSecKeyKeySizeInBits
)