X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/84aacf34eae6543be9f0280b2015385f91e5c2c6..b54c578e17e9bcbd74aa30ea75e25e955b9a6205:/OSX/sec/Security/SecKey.c?ds=inline diff --git a/OSX/sec/Security/SecKey.c b/OSX/sec/Security/SecKey.c deleted file mode 100644 index 545900fa..00000000 --- a/OSX/sec/Security/SecKey.c +++ /dev/null @@ -1,1617 +0,0 @@ -/* - * Copyright (c) 2006-2015 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 - -#include - -#include -#include - -#include "SecKeyPriv.h" -#include "SecRSAKeyPriv.h" -#include "SecECKeyPriv.h" -#include "SecCTKKeyPriv.h" -#include "SecBasePriv.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For error codes. */ - -#include - -#include -#include -#include - -#include -#include -#include - -CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key) -{ - CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; - - /* encode the public key. */ - require_noerr_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); - require_quiet(pubKeyBlob, errOut); - - /* Calculate the digest of the public key. */ - require_quiet(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key), - CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), - errOut); -errOut: - CFReleaseNull(pubKeyBlob); - return pubKeyDigest; -} - - -/* - */ -static CFDictionaryRef SecKeyCopyAttributeDictionaryWithLocalKey(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_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); - require_quiet(pubKeyBlob, errOut); - - /* Calculate the digest of the public key. */ - require_quiet(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, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanDecrypt, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanSign, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanVerify, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse); - DICT_ADDPAIR(kSecAttrCanWrap, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); - DICT_ADDPAIR(kSecAttrCanUnwrap, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); - DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); - dict = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - -errOut: - // @@@ Zero out key material. - CFReleaseSafe(pubKeyDigest); - CFReleaseSafe(pubKeyBlob); - CFReleaseSafe(sizeInBits); - - return dict; -} - -CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, - CFTypeRef keyType, - CFDataRef privateBlob) -{ - return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, privateBlob); -} - -CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType) -{ - return SecKeyCopyAttributeDictionaryWithLocalKey(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 TARGET_OS_OSX - CFReleaseNull(key->cdsaKey); -#endif - 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->version >= 4 && key1->key_class->isEqual) - return key1->key_class->isEqual(key1, key2); - 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); - // Returning NULL is an error; bail out of the equality check - if(!d1 || !d2) { - CFReleaseSafe(d1); - CFReleaseSafe(d2); - return false; - } - Boolean result = CFEqual(d1, d2); - CFReleaseSafe(d1); - CFReleaseSafe(d2); - return result; -} - -struct ccrng_state *ccrng_seckey; - -CFGiblisWithFunctions(SecKey, NULL, NULL, SecKeyDestroy, SecKeyEqual, NULL, NULL, SecKeyCopyDescription, NULL, NULL, ^{ - static struct ccrng_system_state ccrng_system_state_seckey; - ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey; - ccrng_system_init(&ccrng_system_state_seckey); -}) - -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 CF_RETURNS_RETAINED 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; -} - -CFIndex SecKeyGetAlgorithmId(SecKeyRef key) { - if (!key || !key->key_class) { - // TBD: somehow, a key can be created with a NULL key_class in the - // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path - return kSecNullAlgorithmID; - } - /* 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 keys were RSA. */ - return kSecRSAAlgorithmID; -} - -/* 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); - CFStringRef tokenID = CFDictionaryGetValue(parameters, kSecAttrTokenID); - - require_quiet(ktype, errOut); - - if (tokenID != NULL) { - result = SecCTKKeyGeneratePair(parameters, &pubKey, &privKey); - } else if (CFEqual(ktype, kSecAttrKeyTypeECSECPrimeRandom)) { - result = SecECKeyGeneratePair(parameters, &pubKey, &privKey); - } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { - result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey); - } - - require_noerr_quiet(result, errOut); - - // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default - // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys). - if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { - CFDictionaryRemoveValue(pubParams, kSecAttrTokenID); - require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut); - } - if (getBoolForKey(privParams, kSecAttrIsPermanent, CFDictionaryContainsKey(privParams, kSecAttrTokenID))) { - 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) { - return SecKeyCopyPublicKey(privateKey); -} - -CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef) -{ - const CFTypeRef refType = (returnPersistentRef) ? kSecReturnPersistentRef: kSecReturnRef; - - CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); - - CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassKey, - kSecAttrKeyClass, kSecAttrKeyClassPrivate, - kSecAttrSynchronizable, kSecAttrSynchronizableAny, - kSecAttrApplicationLabel, public_key_hash, - refType, 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) { - SecKeyRef privateKey = NULL; - CFTypeRef queryResult = NULL; - CFDictionaryRef query = NULL; - - require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, CFSTR("Null Public Key"))); - - query = CreatePrivateKeyMatchingQuery(publicKey, false); - - require_quiet(SecError(SecItemCopyMatching(query, &queryResult), error, - CFSTR("Error finding private key from public: %@"), publicKey), errOut); - - if (CFGetTypeID(queryResult) == SecKeyGetTypeID()) { - privateKey = (SecKeyRef) queryResult; - queryResult = NULL; - } - -errOut: - CFReleaseNull(query); - CFReleaseNull(queryResult); - return privateKey; -} - -OSStatus SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey, CFErrorRef *error) { - OSStatus retval = errSecParam; - CFTypeRef private_key = NULL; - CFDictionaryRef query = NULL; - - require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, NULL, CFSTR("Null Public Key"))); - - query = CreatePrivateKeyMatchingQuery(publicKey, false); - - retval = SecItemCopyMatching(query, &private_key); - - if (!retval && CFGetTypeID(private_key) != SecKeyGetTypeID()) { - retval = errSecInternalComponent; - } - -errOut: - CFReleaseNull(query); - CFReleaseNull(private_key); - return retval; -} - - -SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, - const SecAsn1Oid *oid, const SecAsn1Item *params, - const SecAsn1Item *keyData) { - SecKeyRef publicKey = NULL; - if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) { - /* pkcs1 1 */ - /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of - SecKeyCreateRSAPublicKey, since on OS X the latter function will return - a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here. - */ - publicKey = SecKeyCreateRSAPublicKey_ios(allocator, - 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(allocator, - (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding); - } else { - secwarning("Unsupported algorithm oid"); - } - - return publicKey; -} - - -SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, CFDataRef subjectPublicKeyInfoData) -{ - DERReturn drtn; - - DERItem subjectPublicKeyInfoDER = { - .data = (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData), - .length = (DERSize)CFDataGetLength(subjectPublicKeyInfoData), - }; - DERSubjPubKeyInfo subjectPublicKeyInfo; - DERAlgorithmId algorithmId; - DERItem pubKeyBytes; - - drtn = DERParseSequence(&subjectPublicKeyInfoDER, - DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, - &subjectPublicKeyInfo, sizeof(subjectPublicKeyInfo)); - - require_noerr_quiet(drtn, out); - - drtn = DERParseSequenceContent(&subjectPublicKeyInfo.algId, - DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, - &algorithmId, sizeof(algorithmId)); - require_noerr_quiet(drtn, out); - - DERByte unusedBits; - drtn = DERParseBitString(&subjectPublicKeyInfo.pubKey, &pubKeyBytes, &unusedBits); - require_noerr_quiet(drtn, out); - - /* Convert DERItem to SecAsn1Item : */ - const SecAsn1Oid oid = { .Data = algorithmId.oid.data, .Length = algorithmId.oid.length }; - const SecAsn1Item params = { .Data = algorithmId.params.data, .Length = algorithmId.params.length }; - const SecAsn1Item pubKey = { .Data = pubKeyBytes.data, .Length = pubKeyBytes.length }; - - return SecKeyCreatePublicFromDER(allocator, &oid, ¶ms, &pubKey); - -out: - - return NULL; -} - -static const DERByte oidRSA[] = { - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, -}; -static const DERByte oidECsecp256[] = { - 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, -}; -static const DERByte oidECsecp384[] = { - 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, -}; -static const DERByte oidECsecp521[] = { - 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, -}; - - -CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key) -{ - CFMutableDataRef data = NULL; - CFDataRef publicKey = NULL; - CFDataRef dataret = NULL; - DERSubjPubKeyInfo spki; - DERReturn drtn; - size_t zeroPad = 0; - - memset(&spki, 0, sizeof(spki)); - - /* encode the public key. */ - require_noerr_quiet(SecKeyCopyPublicBytes(key, &publicKey), errOut); - require_quiet(publicKey, errOut); - - require_quiet(CFDataGetLength(publicKey) != 0, errOut); - - // Add prefix 00 is needed to avoid creating negative bit strings - if (((uint8_t *)CFDataGetBytePtr(publicKey))[0] & 0x80) - zeroPad = 1; - - - CFMutableDataRef paddedKey = CFDataCreateMutable(NULL, 0); - /* the bit strings bits used field first */ - CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); - if (zeroPad) - CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); - - CFDataAppendBytes(paddedKey, CFDataGetBytePtr(publicKey), CFDataGetLength(publicKey)); - CFTransferRetained(publicKey, paddedKey); - - spki.pubKey.data = (DERByte *)CFDataGetBytePtr(publicKey); - spki.pubKey.length = CFDataGetLength(publicKey); - - // Encode algId according to algorithm used. - CFIndex algorithm = SecKeyGetAlgorithmId(key); - if (algorithm == kSecRSAAlgorithmID) { - spki.algId.data = (DERByte *)oidRSA; - spki.algId.length = sizeof(oidRSA); - } else if (algorithm == kSecECDSAAlgorithmID) { - SecECNamedCurve curve = SecECKeyGetNamedCurve(key); - switch(curve) { - case kSecECCurveSecp256r1: - spki.algId.data = (DERByte *)oidECsecp256; - spki.algId.length = sizeof(oidECsecp256); - break; - case kSecECCurveSecp384r1: - spki.algId.data = (DERByte *)oidECsecp384; - spki.algId.length = sizeof(oidECsecp384); - break; - case kSecECCurveSecp521r1: - spki.algId.data = (DERByte *)oidECsecp521; - spki.algId.length = sizeof(oidECsecp521); - break; - default: - goto errOut; - } - } else { - goto errOut; - } - - DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &spki, - DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs); - data = CFDataCreateMutable(kCFAllocatorDefault, size); - CFDataSetLength(data, size); - - drtn = DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &spki, - DERNumSubjPubKeyInfoItemSpecs, - DERSubjPubKeyInfoItemSpecs, - CFDataGetMutableBytePtr(data), &size); - require_quiet(drtn == DR_Success, errOut); - CFDataSetLength(data, size); - - dataret = CFRetain(data); -errOut: - CFReleaseNull(data); - CFReleaseNull(publicKey); - - return dataret; -} - - - -SecKeyRef SecKeyCreate(CFAllocatorRef allocator, - const SecKeyDescriptor *key_class, const uint8_t *keyData, - CFIndex keyDataLength, SecKeyEncoding encoding) { - if (!key_class) return NULL; - 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; -} - -static SecKeyAlgorithm SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key, SecPadding padding) { - switch (SecKeyGetAlgorithmId(key)) { - case kSecRSAAlgorithmID: { -#if TARGET_OS_OSX - if (!_CFMZEnabled()) { - // On CSSM-based implementation, these functions actually did hash its input, - // so keep doing that for backward compatibility. - switch (padding) { - case kSecPaddingNone: - return kSecKeyAlgorithmRSASignatureRaw; - case kSecPaddingPKCS1: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; - case kSecPaddingPKCS1SHA1: - return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; - case kSecPaddingPKCS1SHA224: - return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224; - case kSecPaddingPKCS1SHA256: - return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; - case kSecPaddingPKCS1SHA384: - return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384; - case kSecPaddingPKCS1SHA512: - return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; - default: - return NULL; - } - } else -#endif - { - switch (padding) { - case kSecPaddingNone: - return kSecKeyAlgorithmRSASignatureRaw; - case kSecPaddingPKCS1: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; - case kSecPaddingPKCS1SHA1: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1; - case kSecPaddingPKCS1SHA224: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224; - case kSecPaddingPKCS1SHA256: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256; - case kSecPaddingPKCS1SHA384: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384; - case kSecPaddingPKCS1SHA512: - return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512; - default: - return NULL; - } - } - } - case kSecECDSAAlgorithmID: - switch (padding) { - case kSecPaddingSigRaw: - return kSecKeyAlgorithmECDSASignatureRFC4754; - default: - // Although it is not very logical, previous SecECKey implementation really considered - // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour - // for backward compatibility. - return kSecKeyAlgorithmECDSASignatureDigestX962; - } - default: - return NULL; - } -} - -// Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments -// used by legacy RawSign-style functions. -static OSStatus SecKeyPerformLegacyOperation(SecKeyRef key, - const uint8_t *in1Ptr, size_t in1Len, - const uint8_t *in2Ptr, size_t in2Len, - uint8_t *outPtr, size_t *outLen, - CFTypeRef (^operation)(CFDataRef in1, CFDataRef in2, CFRange *resultRange, CFErrorRef *error)) { - CFErrorRef error = NULL; - OSStatus status = errSecSuccess; - CFDataRef in1 = CFDataCreateWithBytesNoCopy(NULL, in1Ptr, in1Len, kCFAllocatorNull); - CFDataRef in2 = CFDataCreateWithBytesNoCopy(NULL, in2Ptr, in2Len, kCFAllocatorNull); - CFRange range = { 0, -1 }; - CFTypeRef output = operation(in1, in2, &range, &error); - require_quiet(output, out); - if (CFGetTypeID(output) == CFDataGetTypeID() && outLen != NULL) { - if (range.length == -1) { - range.length = CFDataGetLength(output); - } - require_action_quiet((size_t)range.length <= *outLen, out, - SecError(errSecParam, &error, CFSTR("buffer too small"))); - *outLen = range.length; - CFDataGetBytes(output, range, outPtr); - } - -out: - CFReleaseSafe(in1); - CFReleaseSafe(in2); - CFReleaseSafe(output); - if (error != NULL) { - status = SecErrorGetOSStatus(error); - if (status == errSecVerifyFailed) { - // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed. - status = errSSLCrypto; - } - CFRelease(error); - } - return status; -} - -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 */ - SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); - if (algorithm == NULL) { - return errSecParam; - } - return SecKeyPerformLegacyOperation(key, dataToSign, dataToSignLen, NULL, 0, sig, sigLen, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyCreateSignature(key, algorithm, in1, error); - }); -} - -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 */ - SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); - if (algorithm == NULL) { - return errSecParam; - } - OSStatus status = SecKeyPerformLegacyOperation(key, signedData, signedDataLen, sig, sigLen, NULL, NULL, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyVerifySignature(key, algorithm, in1, in2, error) - ? kCFBooleanTrue : NULL; - }); - return status; -} - -static SecKeyAlgorithm SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key, SecPadding padding) { - switch (SecKeyGetAlgorithmId(key)) { - case kSecRSAAlgorithmID: - switch (padding) { - case kSecPaddingNone: - return kSecKeyAlgorithmRSAEncryptionRaw; - case kSecPaddingPKCS1: - return kSecKeyAlgorithmRSAEncryptionPKCS1; - case kSecPaddingOAEP: - return kSecKeyAlgorithmRSAEncryptionOAEPSHA1; - default: - return NULL; - } - default: - return NULL; - } -} - -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 */ - SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); - if (algorithm == NULL) { - return errSecParam; - } - - return SecKeyPerformLegacyOperation(key, plainText, plainTextLen, NULL, 0, cipherText, cipherTextLen, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyCreateEncryptedData(key, algorithm, in1, error); - }); -} - -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 */ - SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); - if (algorithm == NULL) { - return errSecParam; - } - return SecKeyPerformLegacyOperation(key, cipherText, cipherTextLen, NULL, 0, plainText, plainTextLen, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - CFDataRef decrypted = SecKeyCreateDecryptedData(key, algorithm, in1, error); - const UInt8 *data; - if (decrypted != NULL && algorithm == kSecKeyAlgorithmRSAEncryptionRaw && - *(data = CFDataGetBytePtr(decrypted)) == 0x00) { - // Strip zero-padding from the beginning of the block, as the contract of this - // function says. - range->length = CFDataGetLength(decrypted); - while (*data == 0x00 && range->length > 0) { - range->location++; - range->length--; - data++; - } - } - return decrypted; - }); -} - -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) { - return SecKeyCopyAttributes(key); -} - -SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { - CFErrorRef error = NULL; - SecKeyRef key = SecKeyCreateWithData(CFDictionaryGetValue(refAttributes, kSecValueData), refAttributes, &error); - if (key == NULL) { - CFStringRef description = CFErrorCopyDescription(error); - secwarning("%@", description); - CFRelease(description); - CFRelease(error); - } - return key; -} - -static SecKeyAlgorithm SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key, const SecAsn1AlgId *algId, bool digestData) { - static const struct TableItem { - const SecAsn1Oid *oid1, *oid2; - const SecKeyAlgorithm *algorithms[2]; - } translationTableRSA[] = { - { &CSSMOID_SHA1WithRSA, &CSSMOID_SHA1, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1, - } }, - { &CSSMOID_SHA224WithRSA, &CSSMOID_SHA224, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224, - } }, - { &CSSMOID_SHA256WithRSA, &CSSMOID_SHA256, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, - } }, - { &CSSMOID_SHA384WithRSA, &CSSMOID_SHA384, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384, - } }, - { &CSSMOID_SHA512WithRSA, &CSSMOID_SHA512, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512, - } }, - { &CSSMOID_MD5, NULL, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, - } }, - { &CSSMOID_MD5WithRSA, NULL, { - [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, - [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, - } }, - { NULL }, - }, translationTableECDSA[] = { - { &CSSMOID_ECDSA_WithSHA1, &CSSMOID_SHA1, { - [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, - [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1, - } }, - { &CSSMOID_ECDSA_WithSHA224, &CSSMOID_SHA224, { - [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, - [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224, - } }, - { &CSSMOID_ECDSA_WithSHA256, &CSSMOID_SHA256, { - [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, - [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256, - } }, - { &CSSMOID_ECDSA_WithSHA384, &CSSMOID_SHA384, { - [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, - [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384, - } }, - { &CSSMOID_ECDSA_WithSHA512, &CSSMOID_SHA512, { - [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, - [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512, - } }, - { NULL }, - }; - - const struct TableItem *table; - switch (SecKeyGetAlgorithmId(key)) { - case kSecRSAAlgorithmID: - table = translationTableRSA; - break; - case kSecECDSAAlgorithmID: - table = translationTableECDSA; - break; - default: - return NULL; - } - - for (; table->oid1 != NULL; table++) { - if (SecAsn1OidCompare(table->oid1, &algId->algorithm) || - (table->oid2 != NULL && SecAsn1OidCompare(table->oid2, &algId->algorithm))) { - return *table->algorithms[digestData]; - } - } - return NULL; -} - -OSStatus SecKeyDigestAndVerify( - SecKeyRef key, /* 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 */ - - SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); - if (algorithm == NULL) { - return errSecUnimplemented; - } - - return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, sig, sigLen, NULL, NULL, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? - kCFBooleanTrue : NULL; - }); -} - -OSStatus SecKeyDigestAndSign( - SecKeyRef key, /* 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 */ - SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); - if (algorithm == NULL) { - return errSecUnimplemented; - } - - return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, NULL, 0, sig, sigLen, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyCreateSignature(key, algorithm, in1, error); - }); -} - -OSStatus SecKeyVerifyDigest( - SecKeyRef key, /* 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 */ - SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); - if (algorithm == NULL) { - return errSecUnimplemented; - } - - return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, sig, sigLen, NULL, NULL, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? - kCFBooleanTrue : NULL; - }); -} - -OSStatus SecKeySignDigest( - SecKeyRef key, /* 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 */ - SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); - if (algorithm == NULL) { - return errSecUnimplemented; - } - - return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, NULL, 0, sig, sigLen, - ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { - return SecKeyCreateSignature(key, algorithm, in1, error); - }); -} - -#if TARGET_OS_OSX -/* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments, - with output in the second argument). Therefore, avoid implementing this function here - if compiling for OS X. - */ -#else -// Export original SecKeyGetAlgorithmID symbol for backward binary compatibility. -#undef SecKeyGetAlgorithmID -CFIndex SecKeyGetAlgorithmID(SecKeyRef key); -CFIndex SecKeyGetAlgorithmID(SecKeyRef key) { - return SecKeyGetAlgorithmId(key); -} -#endif - -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 (whichSize == 0 || whichSize == 10) { - // kSecKeyKeySizeInBits is declared as 0 on iOS (SPI) and 10 on macOS (API). Unified implementation - // here deals with both values. - whichSize = kSecKeyKeySizeInBits; - } - - 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) -{ - if (!key) { - secerror("SecKeyCopyPersistentRef: Need a key reference for this to work"); - return errSecParam; - } - if (!persistentRef) { - secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work"); - return errSecParam; - } - - 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 { - secerror("SecKeyCopyPersistentRef: SecItemCopyMatching returned success, but we got type %lu instead of CFData for key %@.", CFGetTypeID(foundRef), key); - status = errSecItemNotFound; - } - } else { - secerror("SecKeyCopyPersistentRef: received status %i for key %@", (int)status, key); - CFStringRef str = CFStringCreateWithFormat(NULL, NULL, CFSTR("Expected to find persistentref for key %@"), key); - __security_stackshotreport(str, (int)status); - CFReleaseNull(str); - } - - CFReleaseSafe(foundRef); - CFReleaseSafe(query); - - return status; -} - -/* - * - */ - -#define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); - -SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg, "kSecKeyWrapPGPSymAlg"); -SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint, "kSecKeyWrapPGPFingerprint"); -SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg, "kSecKeyWrapPGPWrapAlg"); -SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags, "kSecKeyWrapPGPECFlags"); -SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128"); -SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256"); - -#undef SEC_CONST_DECL - -CFDataRef -_SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) -{ - if (error) - *error = NULL; - if (outParam) - *outParam = NULL; - if (key->key_class->version > 2 && key->key_class->copyWrapKey) - return key->key_class->copyWrapKey(key, type, unwrappedKey, parameters, outParam, error); - SecError(errSecUnsupportedOperation, error, CFSTR("No key wrap supported for key %@"), key); - return NULL; -} - -CFDataRef -_SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) -{ - if (error) - *error = NULL; - if (outParam) - *outParam = NULL; - if (key->key_class->version > 2 && key->key_class->copyUnwrapKey) - return key->key_class->copyUnwrapKey(key, type, wrappedKey, parameters, outParam, error); - - SecError(errSecUnsupportedOperation, error, CFSTR("No key unwrap for key %@"), key); - return NULL; -} - -static CFIndex SecKeyParamsGetCFIndex(CFTypeRef value, CFStringRef errName, CFErrorRef *error) { - CFIndex result = -1; - CFNumberRef localValue = NULL; - - if (isString(value)) { - CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle); - localValue = CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault, formatter, value, NULL, kCFNumberFormatterParseIntegersOnly); - CFReleaseSafe(formatter); - - if (localValue) { - CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue); - if (CFEqual(t, value)) { - value = localValue; - } - CFReleaseSafe(t); - } - } - - if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) { - if (!CFNumberGetValue(value, kCFNumberCFIndexType, &result) || result < 0) { - SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); - } - } else { - SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); - } - - CFReleaseSafe(localValue); - return result; -} - -SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CFErrorRef *error) { - - SecKeyRef key = NULL; - CFAllocatorRef allocator = NULL; - - if (CFDictionaryGetValue(parameters, kSecAttrTokenID) != NULL) { - return SecKeyCreateCTKKey(allocator, parameters, error); - } - else if (!keyData) { - SecError(errSecParam, error, CFSTR("Failed to provide key data to SecKeyCreateWithData")); - return NULL; - } - /* First figure out the key type (algorithm). */ - CFIndex algorithm, class; - CFTypeRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); - require_quiet((algorithm = SecKeyParamsGetCFIndex(ktype, CFSTR("key type"), error)) >= 0, out); - CFTypeRef kclass = CFDictionaryGetValue(parameters, kSecAttrKeyClass); - require_quiet((class = SecKeyParamsGetCFIndex(kclass, CFSTR("key class"), error)) >= 0, out); - - switch (class) { - case 0: // kSecAttrKeyClassPublic - switch (algorithm) { - case 42: // kSecAlgorithmRSA - key = SecKeyCreateRSAPublicKey(allocator, - CFDataGetBytePtr(keyData), CFDataGetLength(keyData), - kSecKeyEncodingBytes); - if (key == NULL) { - SecError(errSecParam, error, CFSTR("RSA public key creation from data failed")); - } - break; - case 43: // kSecAlgorithmECDSA - case 73: // kSecAlgorithmEC - key = SecKeyCreateECPublicKey(allocator, - CFDataGetBytePtr(keyData), CFDataGetLength(keyData), - kSecKeyEncodingBytes); - if (key == NULL) { - SecError(errSecParam, error, CFSTR("EC public key creation from data failed")); - } - break; - default: - SecError(errSecParam, error, CFSTR("Unsupported public key type: %@"), ktype); - break; - }; - break; - case 1: // kSecAttrKeyClassPrivate - switch (algorithm) { - case 42: // kSecAlgorithmRSA - key = SecKeyCreateRSAPrivateKey(allocator, - CFDataGetBytePtr(keyData), CFDataGetLength(keyData), - kSecKeyEncodingBytes); - if (key == NULL) { - SecError(errSecParam, error, CFSTR("RSA private key creation from data failed")); - } - break; - case 43: // kSecAlgorithmECDSA - case 73: // kSecAlgorithmEC - key = SecKeyCreateECPrivateKey(allocator, - CFDataGetBytePtr(keyData), CFDataGetLength(keyData), - kSecKeyEncodingBytes); - if (key == NULL) { - SecError(errSecParam, error, CFSTR("EC public key creation from data failed")); - } - break; - default: - SecError(errSecParam, error, CFSTR("Unsupported private key type: %@"), ktype); - break; - }; - break; - case 2: // kSecAttrKeyClassSymmetric - SecError(errSecUnimplemented, error, CFSTR("Unsupported symmetric key type: %@"), ktype); - break; - default: - SecError(errSecParam, error, CFSTR("Unsupported key class: %@"), kclass); - break; - } - -out: - return key; -} - -// Similar to CFErrorPropagate, but does not consult input value of *error, it can contain any garbage and if overwritten, previous value is never released. -static inline bool SecKeyErrorPropagate(bool succeeded, CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) { - if (succeeded) { - return true; - } else { - if (error) { - *error = possibleError; - } else { - CFRelease(possibleError); - } - return false; - } -} - -CFDataRef SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { - if (!key->key_class->copyExternalRepresentation) { - if (error != NULL) { - *error = NULL; - } - SecError(errSecUnimplemented, error, CFSTR("export not implemented for key %@"), key); - return NULL; - } - - CFErrorRef localError = NULL; - CFDataRef result = key->key_class->copyExternalRepresentation(key, &localError); - SecKeyErrorPropagate(result != NULL, localError, error); - return result; -} - -CFDictionaryRef SecKeyCopyAttributes(SecKeyRef key) { - if (key->key_class->copyDictionary) { - return key->key_class->copyDictionary(key); - } else { - // Create dictionary with basic values derived from other known information of the key. - CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFIndex blockSize = SecKeyGetBlockSize(key) * 8; - if (blockSize > 0) { - CFNumberRef blockSizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &blockSize); - CFDictionarySetValue(dict, kSecAttrKeySizeInBits, blockSizeRef); - CFRelease(blockSizeRef); - } - - switch (SecKeyGetAlgorithmId(key)) { - case kSecRSAAlgorithmID: - CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA); - break; - case kSecECDSAAlgorithmID: - CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); - break; - } - - if (key->key_class->rawSign != NULL || key->key_class->decrypt != NULL) { - CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate); - } else if (key->key_class->rawVerify != NULL || key->key_class->encrypt != NULL) { - CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic); - } - - return dict; - } -} - -SecKeyRef SecKeyCopyPublicKey(SecKeyRef key) { - SecKeyRef result = NULL; - if (key->key_class->version >= 4 && key->key_class->copyPublicKey) { - result = key->key_class->copyPublicKey(key); - if (result != NULL) { - return result; - } - } - - CFDataRef serializedPublic = NULL; - - require_noerr_quiet(SecKeyCopyPublicBytes(key, &serializedPublic), fail); - require_quiet(serializedPublic, fail); - - result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmId(key), serializedPublic); - -fail: - CFReleaseSafe(serializedPublic); - return result; -} - -SecKeyRef SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) { - SecKeyRef privKey = NULL, pubKey = NULL; - OSStatus status = SecKeyGeneratePair(parameters, &pubKey, &privKey); - if (status != errSecSuccess) { - if (error != NULL) { - *error = NULL; - } - SecError(status, error, CFSTR("Key generation failed, error %d"), (int)status); - } - CFReleaseSafe(pubKey); - return privKey; -} - -SecKeyRef SecKeyCreateDuplicate(SecKeyRef key) { - if (key->key_class->version >= 4 && key->key_class->createDuplicate) { - return key->key_class->createDuplicate(key); - } else { - return (SecKeyRef)CFRetain(key); - } -} - -Boolean SecKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) { - if (key == NULL) { - SecCTKKeySetTestMode(name, value); - return true; - } else if (key->key_class->version >= 4 && key->key_class->setParameter) { - CFErrorRef localError = NULL; - Boolean result = key->key_class->setParameter(key, name, value, &localError); - SecKeyErrorPropagate(result, localError, error); - return result; - } else { - if (error != NULL) { - *error = NULL; - } - return SecError(errSecUnimplemented, error, CFSTR("setParameter not implemented for %@"), key); - } -} - -#pragma mark Generic algorithm adaptor lookup and invocation - -static CFTypeRef SecKeyCopyBackendOperationResult(SecKeyOperationContext *context, SecKeyAlgorithm algorithm, - CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { - CFTypeRef result = kCFNull; - assert(CFArrayGetCount(context->algorithm) > 0); - if (context->key->key_class->version >= 4 && context->key->key_class->copyOperationResult != NULL) { - return context->key->key_class->copyOperationResult(context->key, context->operation, algorithm, - context->algorithm, context->mode, in1, in2, error); - } - - // Mapping from algorithms to legacy SecPadding values. - static const struct { - const SecKeyAlgorithm *algorithm; - CFIndex keyAlg; - SecPadding padding; - } paddingMap[] = { - { &kSecKeyAlgorithmRSASignatureRaw, kSecRSAAlgorithmID, kSecPaddingNone }, - { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, - { &kSecKeyAlgorithmECDSASignatureRFC4754, kSecECDSAAlgorithmID, kSecPaddingSigRaw }, - { &kSecKeyAlgorithmECDSASignatureDigestX962, kSecECDSAAlgorithmID, kSecPaddingPKCS1 }, - { &kSecKeyAlgorithmRSAEncryptionRaw, kSecRSAAlgorithmID, kSecPaddingNone }, - { &kSecKeyAlgorithmRSAEncryptionPKCS1, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, - { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1, kSecRSAAlgorithmID, kSecPaddingOAEP }, - }; - SecPadding padding = (SecPadding)-1; - CFIndex keyAlg = SecKeyGetAlgorithmId(context->key); - for (size_t i = 0; i < array_size(paddingMap); ++i) { - if (keyAlg == paddingMap[i].keyAlg && CFEqual(algorithm, *paddingMap[i].algorithm)) { - padding = paddingMap[i].padding; - break; - } - } - require_quiet(padding != (SecPadding)-1, out); - - // Check legacy virtual table entries. - size_t size = 0; - OSStatus status = errSecSuccess; - switch (context->operation) { - case kSecKeyOperationTypeSign: - if (context->key->key_class->rawSign != NULL) { - result = kCFBooleanTrue; - if (context->mode == kSecKeyOperationModePerform) { - size = SecKeyGetSize(context->key, kSecKeySignatureSize); - result = CFDataCreateMutableWithScratch(NULL, size); - status = context->key->key_class->rawSign(context->key, padding, - CFDataGetBytePtr(in1), CFDataGetLength(in1), - CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); - } - } - break; - case kSecKeyOperationTypeVerify: - if (context->key->key_class->rawVerify != NULL) { - result = kCFBooleanTrue; - if (context->mode == kSecKeyOperationModePerform) { - status = context->key->key_class->rawVerify(context->key, padding, - CFDataGetBytePtr(in1), CFDataGetLength(in1), - CFDataGetBytePtr(in2), CFDataGetLength(in2)); - } - } - break; - case kSecKeyOperationTypeEncrypt: - if (context->key->key_class->encrypt != NULL) { - result = kCFBooleanTrue; - if (context->mode == kSecKeyOperationModePerform) { - size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); - result = CFDataCreateMutableWithScratch(NULL, size); - status = context->key->key_class->encrypt(context->key, padding, - CFDataGetBytePtr(in1), CFDataGetLength(in1), - CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); - } - } - break; - case kSecKeyOperationTypeDecrypt: - if (context->key->key_class->decrypt != NULL) { - result = kCFBooleanTrue; - if (context->mode == kSecKeyOperationModePerform) { - size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); - result = CFDataCreateMutableWithScratch(NULL, size); - status = context->key->key_class->decrypt(context->key, padding, - CFDataGetBytePtr(in1), CFDataGetLength(in1), - CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); - } - } - break; - default: - goto out; - } - - if (status == errSecSuccess) { - if (CFGetTypeID(result) == CFDataGetTypeID()) { - CFDataSetLength((CFMutableDataRef)result, size); - } - } else { - SecError(status, error, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context->operation, (int)padding); - CFReleaseNull(result); - } - -out: - return result; -} - -CFTypeRef SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { - - // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error. - CFIndex algorithmCount = CFArrayGetCount(context->algorithm); - for (CFIndex index = 0; index < algorithmCount - 1; index++) { - SecKeyAlgorithm indexAlgorithm = CFArrayGetValueAtIndex(context->algorithm, index); - for (CFIndex tested = index + 1; tested < algorithmCount; tested++) { - require_quiet(!CFEqual(indexAlgorithm, CFArrayGetValueAtIndex(context->algorithm, tested)), fail); - } - } - - SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(context->algorithm, algorithmCount - 1); - CFTypeRef output = SecKeyCopyBackendOperationResult(context, algorithm, in1, in2, error); - if (output != kCFNull) { - // Backend handled the operation, return result. - return output; - } - - // To silence static analyzer. - CFReleaseSafe(output); - - // Get adaptor which is able to handle requested algorithm. - SecKeyAlgorithmAdaptor adaptor = SecKeyGetAlgorithmAdaptor(context->operation, algorithm); - require_quiet(adaptor != NULL, fail); - - // Invoke the adaptor and return result. - CFTypeRef result = adaptor(context, in1, in2, error); - require_quiet(result != kCFNull, fail); - return result; - -fail: - if (context->mode == kSecKeyOperationModePerform) { - SecError(errSecParam, error, CFSTR("%@: algorithm not supported by the key %@"), - CFArrayGetValueAtIndex(context->algorithm, 0), context->key); - return NULL; - } else { - return kCFNull; - } -} - -#pragma mark Algorithm-related SecKey API entry points - -static CFMutableArrayRef SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm) { - CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayAppendValue(result, algorithm); - return result; -} - -CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error) { - CFErrorRef localError = NULL; - SecKeyOperationContext context = { key, kSecKeyOperationTypeSign, SecKeyCreateAlgorithmArray(algorithm) }; - CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, dataToSign, NULL, &localError); - SecKeyOperationContextDestroy(&context); - SecKeyErrorPropagate(result != NULL, localError, error); - return result; -} - -Boolean SecKeyVerifySignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef signedData, CFDataRef signature, - CFErrorRef *error) { - CFErrorRef localError = NULL; - SecKeyOperationContext context = { key, kSecKeyOperationTypeVerify, SecKeyCreateAlgorithmArray(algorithm) }; - CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, signedData, signature, &localError); - Boolean result = CFEqualSafe(res, kCFBooleanTrue); - CFReleaseSafe(res); - SecKeyOperationContextDestroy(&context); - SecKeyErrorPropagate(result, localError, error); - return result; -} - -CFDataRef SecKeyCreateEncryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, - CFDictionaryRef parameters, CFErrorRef *error) { - CFErrorRef localError = NULL; - SecKeyOperationContext context = { key, kSecKeyOperationTypeEncrypt, SecKeyCreateAlgorithmArray(algorithm) }; - CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, plaintext, parameters, &localError); - SecKeyOperationContextDestroy(&context); - SecKeyErrorPropagate(result, localError, error); - return result; -} - -CFDataRef SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, CFErrorRef *error) { - return SecKeyCreateEncryptedDataWithParameters(key, algorithm, plaintext, NULL, error); -} - -CFDataRef SecKeyCreateDecryptedDataWithParameters(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, - CFDictionaryRef parameters, CFErrorRef *error) { - SecKeyOperationContext context = { key, kSecKeyOperationTypeDecrypt, SecKeyCreateAlgorithmArray(algorithm) }; - CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, ciphertext, parameters, error); - SecKeyOperationContextDestroy(&context); - return result; -} - -CFDataRef SecKeyCreateDecryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef ciphertext, CFErrorRef *error) { - return SecKeyCreateDecryptedDataWithParameters(key, algorithm, ciphertext, NULL, error); -} - -CFDataRef SecKeyCopyKeyExchangeResult(SecKeyRef key, SecKeyAlgorithm algorithm, SecKeyRef publicKey, - CFDictionaryRef parameters, CFErrorRef *error) { - CFErrorRef localError = NULL; - CFDataRef publicKeyData = NULL, result = NULL; - SecKeyOperationContext context = { key, kSecKeyOperationTypeKeyExchange, SecKeyCreateAlgorithmArray(algorithm) }; - require_quiet(publicKeyData = SecKeyCopyExternalRepresentation(publicKey, error), out); - result = SecKeyRunAlgorithmAndCopyResult(&context, publicKeyData, parameters, &localError); - SecKeyErrorPropagate(result != NULL, localError, error); - -out: - CFReleaseSafe(publicKeyData); - SecKeyOperationContextDestroy(&context); - return result; -} - -Boolean SecKeyIsAlgorithmSupported(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm) { - SecKeyOperationContext context = { key, operation, SecKeyCreateAlgorithmArray(algorithm), kSecKeyOperationModeCheckIfSupported }; - CFErrorRef error = NULL; - CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, NULL, NULL, &error); - Boolean result = CFEqualSafe(res, kCFBooleanTrue); - CFReleaseSafe(res); - CFReleaseSafe(error); - SecKeyOperationContextDestroy(&context); - return result; -}