X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/sec/Security/SecKey.c diff --git a/sec/Security/SecKey.c b/sec/Security/SecKey.c deleted file mode 100644 index 227a6c07..00000000 --- a/sec/Security/SecKey.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * Copyright (c) 2006-2011 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * SecKey.c - CoreFoundation based key object - */ - - -#include -#include -#include -#include - -#include - -#include - -#include "SecRSAKeyPriv.h" -#include "SecECKey.h" -#include "SecBasePriv.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static pthread_once_t kSecKeyRegisterClass = PTHREAD_ONCE_INIT; -static CFTypeID kSecKeyTypeID = _kCFRuntimeNotATypeID; - -/* Forward declartions of static functions. */ -static CFStringRef SecKeyCopyDescription(CFTypeRef cf); -static void SecKeyDestroy(CFTypeRef cf); - -/* Static functions. */ -#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH) - -/* Currently length of SHA512 oid + 1 */ -#define MAX_OID_LEN (10) - -#define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN) - -/* Encode the digestInfo header into digestInfo and return the offset from - digestInfo at which to put the actual digest. Returns 0 if digestInfo - won't fit within digestInfoLength bytes. - - 0x30, topLen, - 0x30, algIdLen, - 0x06, oid.Len, oid.Data, - 0x05, 0x00 - 0x04, digestLen - digestData - */ - -static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid, - size_t digestLength, uint8_t *digestInfo, size_t digestInfoLength) { - size_t algIdLen = oid->Length + 4; - size_t topLen = algIdLen + digestLength + 4; - size_t totalLen = topLen + 2; - - if (totalLen > digestInfoLength) { - return 0; - } - - size_t ix = 0; - digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); - digestInfo[ix++] = topLen; - digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); - digestInfo[ix++] = algIdLen; - digestInfo[ix++] = SEC_ASN1_OBJECT_ID; - digestInfo[ix++] = oid->Length; - memcpy(&digestInfo[ix], oid->Data, oid->Length); - ix += oid->Length; - digestInfo[ix++] = SEC_ASN1_NULL; - digestInfo[ix++] = 0; - digestInfo[ix++] = SEC_ASN1_OCTET_STRING; - digestInfo[ix++] = digestLength; - - return ix; -} - -static struct ccrng_system_state ccrng_system_state_seckey; - -static void register_algs(void) { - ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey; - ccrng_system_init(&ccrng_system_state_seckey); -} - - -static CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key) -{ - CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; - - /* encode the public key. */ - require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); - require(pubKeyBlob, errOut); - - /* Calculate the digest of the public key. */ - require(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key), - CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), - errOut); -errOut: - CFReleaseNull(pubKeyBlob); - return pubKeyDigest; -} - - -/* - */ -static CF_RETURNS_RETAINED CFDictionaryRef SecKeyGenerateAttributeDictionaryFor(SecKeyRef key, - CFTypeRef keyType, - CFDataRef privateBlob) -{ - CFAllocatorRef allocator = CFGetAllocator(key); - DICT_DECLARE(25); - CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; - CFDictionaryRef dict = NULL; - - size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits); - CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue); - - /* encode the public key. */ - require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); - require(pubKeyBlob, errOut); - - /* Calculate the digest of the public key. */ - require(pubKeyDigest = SecSHA1DigestCreate(allocator, - CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), - errOut); - - DICT_ADDPAIR(kSecClass, kSecClassKey); - DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic); - DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest); - DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrKeyType, keyType); - DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits); - DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits); - DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanEncrypt, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanDecrypt, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanSign, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanVerify, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanWrap, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanUnwrap, kCFBooleanTrue); - DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); - dict = DICT_CREATE(allocator); - -errOut: - // @@@ Zero out key material. - CFReleaseSafe(pubKeyDigest); - CFReleaseSafe(pubKeyBlob); - CFReleaseSafe(sizeInBits); - - return dict; -} - -CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, - CFTypeRef keyType, - CFDataRef privateBlob) -{ - return SecKeyGenerateAttributeDictionaryFor(key, keyType, privateBlob); -} - -CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType) -{ - return SecKeyGenerateAttributeDictionaryFor(key, keyType, NULL); -} - -/* - */ - -static CFStringRef SecKeyCopyDescription(CFTypeRef cf) { - SecKeyRef key = (SecKeyRef)cf; - - if(key->key_class->describe) - return key->key_class->describe(key); - else - return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR(""), key); -} - -static void SecKeyDestroy(CFTypeRef cf) { - SecKeyRef key = (SecKeyRef)cf; - if (key->key_class->destroy) - key->key_class->destroy(key); -} - -static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2) -{ - SecKeyRef key1 = (SecKeyRef)cf1; - SecKeyRef key2 = (SecKeyRef)cf2; - if (key1 == key2) - return true; - if (!key2 || key1->key_class != key2->key_class) - return false; - if (key1->key_class->extraBytes) - return !memcmp(key1->key, key2->key, key1->key_class->extraBytes); - - /* TODO: Won't work when we get reference keys. */ - CFDictionaryRef d1, d2; - d1 = SecKeyCopyAttributeDictionary(key1); - d2 = SecKeyCopyAttributeDictionary(key2); - Boolean result = CFEqual(d1, d2); - CFReleaseSafe(d1); - CFReleaseSafe(d2); - return result; -} - -static void SecKeyRegisterClass(void) { - static const CFRuntimeClass kSecKeyClass = { - 0, /* version */ - "SecKey", /* class name */ - NULL, /* init */ - NULL, /* copy */ - SecKeyDestroy, /* dealloc */ - SecKeyEqual, /* equal */ - NULL, /* hash */ - NULL, /* copyFormattingDesc */ - SecKeyCopyDescription /* copyDebugDesc */ - }; - - kSecKeyTypeID = _CFRuntimeRegisterClass(&kSecKeyClass); - register_algs(); -} - -/* Public API functions. */ -CFTypeID SecKeyGetTypeID(void) { - pthread_once(&kSecKeyRegisterClass, SecKeyRegisterClass); - return kSecKeyTypeID; -} - -static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) { - CFTypeRef value = CFDictionaryGetValue(dict, key); - if (value) { - if (CFGetTypeID(value) == CFBooleanGetTypeID()) { - return CFBooleanGetValue(value); - } else { - secwarning("Value %@ for key %@ is not bool", value, key); - } - } - - return default_value; -} - -static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) { - CFDictionarySetValue(dict, kSecValueRef, item); - return SecItemAdd(dict, NULL); -} - -static void merge_params_applier(const void *key, const void *value, - void *context) { - CFMutableDictionaryRef result = (CFMutableDictionaryRef)context; - CFDictionaryAddValue(result, key, value); -} - -/* Create a mutable dictionary that is based on the subdictionary for key - with any attributes from the top level dict merged in. */ -static CFMutableDictionaryRef merge_params(CFDictionaryRef dict, - CFStringRef key) { - CFDictionaryRef subdict = CFDictionaryGetValue(dict, key); - CFMutableDictionaryRef result; - - if (subdict) { - result = CFDictionaryCreateMutableCopy(NULL, 0, subdict); - /* Add everything in dict not already in result to result. */ - CFDictionaryApplyFunction(dict, merge_params_applier, result); - } else { - result = CFDictionaryCreateMutableCopy(NULL, 0, dict); - } - - /* Remove values that only belong in the top level dict. */ - CFDictionaryRemoveValue(result, kSecPublicKeyAttrs); - CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs); - CFDictionaryRemoveValue(result, kSecAttrKeyType); - CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits); - - return result; -} - -/* Generate a private/public keypair. */ -OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, - SecKeyRef *publicKey, SecKeyRef *privateKey) { - OSStatus result = errSecUnsupportedAlgorithm; - SecKeyRef privKey = NULL; - SecKeyRef pubKey = NULL; - CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs), - privParams = merge_params(parameters, kSecPrivateKeyAttrs); - CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); - - require(ktype, errOut); - - if (CFEqual(ktype, kSecAttrKeyTypeEC)) { - result = SecECKeyGeneratePair(parameters, &pubKey, &privKey); - } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { - result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey); - } - - require_noerr(result, errOut); - - /* Store the keys in the keychain if they are marked as permanent. */ - if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { - require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut); - } - if (getBoolForKey(privParams, kSecAttrIsPermanent, false)) { - require_noerr_quiet(result = add_ref(privKey, privParams), errOut); - } - - if (publicKey) { - *publicKey = pubKey; - pubKey = NULL; - } - if (privateKey) { - *privateKey = privKey; - privKey = NULL; - } - -errOut: - CFReleaseSafe(pubParams); - CFReleaseSafe(privParams); - CFReleaseSafe(pubKey); - CFReleaseSafe(privKey); - - return result; -} - -SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { - CFDataRef serializedPublic = NULL; - SecKeyRef result = NULL; - - require_noerr_quiet(SecKeyCopyPublicBytes(privateKey, &serializedPublic), fail); - require_quiet(serializedPublic, fail); - - result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmID(privateKey), serializedPublic); - -fail: - CFReleaseSafe(serializedPublic); - - return result; -} - -static CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef) -{ - CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); - - CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassKey, - kSecAttrKeyClass, kSecAttrKeyClassPrivate, - kSecAttrSynchronizable, kSecAttrSynchronizableAny, - kSecAttrApplicationLabel, public_key_hash, - kSecReturnPersistentRef, kCFBooleanTrue, - NULL); - CFReleaseNull(public_key_hash); - - return query; -} - -CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { - CFTypeRef persistentRef = NULL; - CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true); - - require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error , - CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail); -fail: - CFReleaseNull(query); - return (CFDataRef)persistentRef; -} - -SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { - CFTypeRef private_key = NULL; - - CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false); - - require_quiet(SecError(SecItemCopyMatching(query, &private_key), error, - CFSTR("Error finding private key from public: %@"), publicKey), fail); -fail: - CFReleaseNull(query); - return (SecKeyRef)private_key; -} - -SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, - const SecAsn1Oid *oid, const SecAsn1Item *params, - const SecAsn1Item *keyData) { - SecKeyRef publicKey = NULL; - if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) { - /* pkcs1 1 */ - publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault, - keyData->Data, keyData->Length, kSecKeyEncodingPkcs1); - } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) { - SecDERKey derKey = { - .oid = oid->Data, - .oidLength = oid->Length, - .key = keyData->Data, - .keyLength = keyData->Length, - }; - if (params) { - derKey.parameters = params->Data; - derKey.parametersLength = params->Length; - } - publicKey = SecKeyCreateECPublicKey(kCFAllocatorDefault, - (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding); - } else { - secwarning("Unsupported algorithm oid"); - } - - return publicKey; -} - -SecKeyRef SecKeyCreate(CFAllocatorRef allocator, - const SecKeyDescriptor *key_class, const uint8_t *keyData, - CFIndex keyDataLength, SecKeyEncoding encoding) { - check(key_class); - - size_t size = sizeof(struct __SecKey) + key_class->extraBytes; - SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator, - SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL); - if (result) { - memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); - result->key_class = key_class; - if (key_class->extraBytes) { - /* Make result->key point to the extraBytes we allocated. */ - result->key = ((char*)result) + sizeof(*result); - } - if (key_class->init) { - OSStatus status; - status = key_class->init(result, keyData, keyDataLength, encoding); - if (status) { - secwarning("init %s key: %" PRIdOSStatus, key_class->name, status); - CFRelease(result); - result = NULL; - } - } - } - return result; -} - -enum { - kSecKeyDigestInfoSign, - kSecKeyDigestInfoVerify -}; - -static OSStatus SecKeyDigestInfoSignVerify( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingPKCS1@@@ */ - const uint8_t *dataToSign, /* signature over this data */ - size_t dataToSignLen, /* length of dataToSign */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen, /* IN/OUT */ - int mode) { - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - const SecAsn1Oid *digestOid; - size_t digestLen; - - switch (padding) { -#if 0 - case kSecPaddingPKCS1MD2: - digestLen = CC_MD2_DIGEST_LENGTH; - digestOid = &CSSMOID_MD2; - break; - case kSecPaddingPKCS1MD4: - digestLen = CC_MD4_DIGEST_LENGTH; - digestOid = &CSSMOID_MD4; - break; - case kSecPaddingPKCS1MD5: - digestLen = CC_MD5_DIGEST_LENGTH; - digestOid = &CSSMOID_MD5; - break; -#endif - case kSecPaddingPKCS1SHA1: - digestLen = CC_SHA1_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA1; - break; - case kSecPaddingPKCS1SHA224: - digestLen = CC_SHA224_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA224; - break; - case kSecPaddingPKCS1SHA256: - digestLen = CC_SHA256_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA256; - break; - case kSecPaddingPKCS1SHA384: - digestLen = CC_SHA384_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA384; - break; - case kSecPaddingPKCS1SHA512: - digestLen = CC_SHA512_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA512; - break; - default: - return errSecUnsupportedPadding; - } - - if (dataToSignLen != digestLen) - return errSecParam; - - size_t offset = DEREncodeDigestInfoPrefix(digestOid, digestLen, - digestInfo, digestInfoLength); - if (!offset) - return errSecBufferTooSmall; - - /* Append the digest to the digestInfo prefix and adjust the length. */ - memcpy(&digestInfo[offset], dataToSign, digestLen); - digestInfoLength = offset + digestLen; - - if (mode == kSecKeyDigestInfoSign) { - return key->key_class->rawSign(key, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); - } else { - return key->key_class->rawVerify(key, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, *sigLen); - } - - return errSecSuccess; -} - -OSStatus SecKeyRawSign( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ - const uint8_t *dataToSign, /* signature over this data */ - size_t dataToSignLen, /* length of dataToSign */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen) { /* IN/OUT */ - if (!key->key_class->rawSign) - return errSecUnsupportedOperation; - - if (padding < kSecPaddingPKCS1MD2) { - return key->key_class->rawSign(key, padding, dataToSign, dataToSignLen, - sig, sigLen); - } else { - return SecKeyDigestInfoSignVerify(key, padding, dataToSign, dataToSignLen, - sig, sigLen, kSecKeyDigestInfoSign); - } -} - -OSStatus SecKeyRawVerify( - SecKeyRef key, /* Public key */ - SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ - const uint8_t *signedData, /* signature over this data */ - size_t signedDataLen, /* length of dataToSign */ - const uint8_t *sig, /* signature */ - size_t sigLen) { /* length of signature */ - if (!key->key_class->rawVerify) - return errSecUnsupportedOperation; - - if (padding < kSecPaddingPKCS1MD2) { - return key->key_class->rawVerify(key, padding, signedData, signedDataLen, - sig, sigLen); - } else { - /* Casting away the constness of sig is safe since - SecKeyDigestInfoSignVerify only modifies sig if - mode == kSecKeyDigestInfoSign. */ - return SecKeyDigestInfoSignVerify(key, padding, - signedData, signedDataLen, (uint8_t *)sig, &sigLen, - kSecKeyDigestInfoVerify); - } -} - -OSStatus SecKeyEncrypt( - SecKeyRef key, /* Public key */ - SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ - const uint8_t *plainText, - size_t plainTextLen, /* length of plainText */ - uint8_t *cipherText, - size_t *cipherTextLen) { /* IN/OUT */ - if (key->key_class->encrypt) - return key->key_class->encrypt(key, padding, plainText, plainTextLen, - cipherText, cipherTextLen); - return errSecUnsupportedOperation; -} - -OSStatus SecKeyDecrypt( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ - const uint8_t *cipherText, - size_t cipherTextLen, /* length of cipherText */ - uint8_t *plainText, - size_t *plainTextLen) { /* IN/OUT */ - if (key->key_class->decrypt) - return key->key_class->decrypt(key, padding, cipherText, cipherTextLen, - plainText, plainTextLen); - return errSecUnsupportedOperation; -} - -size_t SecKeyGetBlockSize(SecKeyRef key) { - if (key->key_class->blockSize) - return key->key_class->blockSize(key); - return 0; -} - -/* Private API functions. */ - -CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) { - if (key->key_class->copyDictionary) - return key->key_class->copyDictionary(key); - return NULL; -} - -SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { - /* TODO: Support having an allocator in refAttributes. */ - CFAllocatorRef allocator = NULL; - CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData); - CFTypeRef ktype = CFDictionaryGetValue(refAttributes, kSecAttrKeyType); - SInt32 algorithm; - SecKeyRef ref; - - /* First figure out the key type (algorithm). */ - if (CFGetTypeID(ktype) == CFNumberGetTypeID()) { - CFNumberGetValue(ktype, kCFNumberSInt32Type, &algorithm); - } else if (isString(ktype)) { - algorithm = CFStringGetIntValue(ktype); - CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm); - if (!CFEqual(t, ktype)) { - secwarning("Unsupported key class: %@", ktype); - CFReleaseSafe(t); - return NULL; - } - CFReleaseSafe(t); - } else { - secwarning("Unsupported key type: %@", ktype); - return NULL; - } - - /* TODO: The code below won't scale well, consider moving to something - table driven. */ - SInt32 class; - CFTypeRef kclass = CFDictionaryGetValue(refAttributes, kSecAttrKeyClass); - if (CFGetTypeID(kclass) == CFNumberGetTypeID()) { - CFNumberGetValue(kclass, kCFNumberSInt32Type, &class); - } else if (isString(kclass)) { - class = CFStringGetIntValue(kclass); - CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class); - if (!CFEqual(t, kclass)) { - CFReleaseSafe(t); - secwarning("Unsupported key class: %@", kclass); - return NULL; - } - CFReleaseSafe(t); - } else { - secwarning("Unsupported key class: %@", kclass); - return NULL; - } - - switch (class) { - case 0: // kSecAttrKeyClassPublic - switch (algorithm) { - case 42: // kSecAlgorithmRSA - ref = SecKeyCreateRSAPublicKey(allocator, - CFDataGetBytePtr(data), CFDataGetLength(data), - kSecKeyEncodingBytes); - break; - case 43: // kSecAlgorithmECDSA - case 73: // kSecAlgorithmEC - ref = SecKeyCreateECPublicKey(allocator, - CFDataGetBytePtr(data), CFDataGetLength(data), - kSecKeyEncodingBytes); - break; - default: - secwarning("Unsupported public key type: %@", ktype); - ref = NULL; - break; - }; - break; - case 1: // kSecAttrKeyClassPrivate - switch (algorithm) { - case 42: // kSecAlgorithmRSA - ref = SecKeyCreateRSAPrivateKey(allocator, - CFDataGetBytePtr(data), CFDataGetLength(data), - kSecKeyEncodingBytes); - break; - case 43: // kSecAlgorithmECDSA - case 73: // kSecAlgorithmEC - ref = SecKeyCreateECPrivateKey(allocator, - CFDataGetBytePtr(data), CFDataGetLength(data), - kSecKeyEncodingBytes); - break; - default: - secwarning("Unsupported private key type: %@", ktype); - ref = NULL; - break; - }; - break; - case 2: // kSecAttrKeyClassSymmetric - secwarning("Unsupported symmetric key type: %@", ktype); - ref = NULL; - break; - default: - secwarning("Unsupported key class: %@", kclass); - ref = NULL; - } - - return ref; -} - -/* TODO: This function should ensure that this keys algorithm matches the - signature algorithm. */ -static OSStatus SecKeyGetDigestInfo(SecKeyRef this, const SecAsn1AlgId *algId, - const uint8_t *data, size_t dataLen, bool digestData, - uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */) { - unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *); - CFIndex keyAlgID = kSecNullAlgorithmID; - const SecAsn1Oid *digestOid; - size_t digestLen; - size_t offset = 0; - - /* Since these oids all have the same prefix, use switch. */ - if ((algId->algorithm.Length == CSSMOID_RSA.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data, - algId->algorithm.Length - 1)) { - keyAlgID = kSecRSAAlgorithmID; - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { -#if 0 - case 2: /* oidMD2WithRSA */ - digestFcn = CC_MD2; - digestLen = CC_MD2_DIGEST_LENGTH; - digestOid = &CSSMOID_MD2; - break; - case 3: /* oidMD4WithRSA */ - digestFcn = CC_MD4; - digestLen = CC_MD4_DIGEST_LENGTH; - digestOid = &CSSMOID_MD4; - break; - case 4: /* oidMD5WithRSA */ - digestFcn = CC_MD5; - digestLen = CC_MD5_DIGEST_LENGTH; - digestOid = &CSSMOID_MD5; - break; -#endif /* 0 */ - case 5: /* oidSHA1WithRSA */ - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA1; - break; - case 11: /* oidSHA256WithRSA */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA256; - break; - case 12: /* oidSHA384WithRSA */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA384; - break; - case 13: /* oidSHA512WithRSA */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA512; - break; - case 14: /* oidSHA224WithRSA */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA224; - break; - default: - secdebug("key", "unsupported rsa signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data, - algId->algorithm.Length - 1)) { - keyAlgID = kSecECDSAAlgorithmID; - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { - case 1: /* oidSHA224WithECDSA */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - break; - case 2: /* oidSHA256WithECDSA */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - break; - case 3: /* oidSHA384WithECDSA */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - break; - case 4: /* oidSHA512WithECDSA */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - break; - default: - secdebug("key", "unsupported ecdsa signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) { - keyAlgID = kSecECDSAAlgorithmID; - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) { - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA1; - } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1)) - { - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { - case 4: /* OID_SHA224 */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA224; - break; - case 1: /* OID_SHA256 */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA256; - break; - case 2: /* OID_SHA384 */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA384; - break; - case 3: /* OID_SHA512 */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA512; - break; - default: - secdebug("key", "unsupported sha-2 signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) { - digestFcn = CC_MD5; - digestLen = CC_MD5_DIGEST_LENGTH; - digestOid = &CSSMOID_MD5; - } else { - secdebug("key", "unsupported digesting algorithm"); - return errSecUnsupportedAlgorithm; - } - - /* check key is appropriate for signature (superfluous for digest only oid) */ - if (keyAlgID == kSecNullAlgorithmID) - keyAlgID = SecKeyGetAlgorithmID(this); - else if (keyAlgID != SecKeyGetAlgorithmID(this)) - return errSecUnsupportedAlgorithm; - - switch(keyAlgID) { - case kSecRSAAlgorithmID: - offset = DEREncodeDigestInfoPrefix(digestOid, digestLen, - digestInfo, *digestInfoLen); - if (!offset) - return errSecBufferTooSmall; - break; - case kSecDSAAlgorithmID: - if (digestOid != &CSSMOID_SHA1) - return errSecUnsupportedAlgorithm; - break; - case kSecECDSAAlgorithmID: - break; - default: - secdebug("key", "unsupported signature algorithm"); - return errSecUnsupportedAlgorithm; - } - - if (digestData) { - if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */ - return errSecParam; - digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]); - *digestInfoLen = offset + digestLen; - } else { - if (dataLen != digestLen) - return errSecParam; - memcpy(&digestInfo[offset], data, dataLen); - *digestInfoLen = offset + dataLen; - } - - return errSecSuccess; -} - -OSStatus SecKeyDigestAndVerify( - SecKeyRef this, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *dataToDigest, /* signature over this data */ - size_t dataToDigestLen,/* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen) { /* length of sig */ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - if (this == NULL) - return errSecParam; - - status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawVerify(this, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -OSStatus SecKeyDigestAndSign( - SecKeyRef this, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *dataToDigest, /* signature over this data */ - size_t dataToDigestLen,/* length of dataToDigest */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen) { /* IN/OUT */ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true /* digest data */, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawSign(this, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -OSStatus SecKeyVerifyDigest( - SecKeyRef this, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen,/* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen) { /* length of sig */ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false /* data is digest */, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawVerify(this, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -OSStatus SecKeySignDigest( - SecKeyRef this, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen,/* length of digestData */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen) { /* IN/OUT */ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawSign(this, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -CFIndex SecKeyGetAlgorithmID(SecKeyRef key) { - /* This method was added to version 1 keys. */ - if (key->key_class->version > 0 && key->key_class->getAlgorithmID) - return key->key_class->getAlgorithmID(key); - /* All version 0 key were RSA. */ - return kSecRSAAlgorithmID; -} - - -OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) { - if (key->key_class->version > 1 && key->key_class->copyPublic) - return key->key_class->copyPublic(key, serializedPublic); - return errSecUnimplemented; -} - -SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength) -{ - switch (algorithmID) - { - case kSecRSAAlgorithmID: - return SecKeyCreateRSAPublicKey(allocator, - keyData, keyDataLength, - kSecKeyEncodingBytes); - case kSecECDSAAlgorithmID: - return SecKeyCreateECPublicKey(allocator, - keyData, keyDataLength, - kSecKeyEncodingBytes); - default: - return NULL; - } -} - -SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized) -{ - return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized)); -} - -// This is a bit icky hack to avoid changing the vtable for -// SecKey. -size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) -{ - size_t result = SecKeyGetBlockSize(key); - - if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmID(key)) { - switch (whichSize) { - case kSecKeyEncryptedDataSize: - result = 0; - break; - case kSecKeySignatureSize: - result = (result >= 66 ? 9 : 8) + 2 * result; - break; - case kSecKeyKeySizeInBits: - if (result >= 66) - return 521; - } - } - - if (whichSize == kSecKeyKeySizeInBits) - result *= 8; - - return result; - -} - -OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) -{ - CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecReturnRef, kCFBooleanTrue, - kSecClass, kSecClassKey, - kSecValuePersistentRef, persistentRef, - NULL); - CFTypeRef foundRef = NULL; - OSStatus status = SecItemCopyMatching(query, &foundRef); - - if (status == errSecSuccess) { - if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) { - *lookedUpData = (SecKeyRef) foundRef; - foundRef = NULL; - status = errSecSuccess; - } else { - status = errSecItemNotFound; - } - } - - CFReleaseSafe(foundRef); - CFReleaseSafe(query); - - return status; -} - -OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) -{ - CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecReturnPersistentRef, kCFBooleanTrue, - kSecValueRef, key, - kSecAttrSynchronizable, kSecAttrSynchronizableAny, - NULL); - CFTypeRef foundRef = NULL; - OSStatus status = SecItemCopyMatching(query, &foundRef); - - if (status == errSecSuccess) { - if (CFGetTypeID(foundRef) == CFDataGetTypeID()) { - *persistentRef = foundRef; - foundRef = NULL; - } else { - status = errSecItemNotFound; - } - } - - CFReleaseSafe(foundRef); - CFReleaseSafe(query); - - return status; -}