#ifndef kc_key_helpers_h
#define kc_key_helpers_h
#include "kc-helpers.h"
#include "utilities/SecCFRelease.h"
#if TARGET_OS_MAC
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunused-function"
static CFMutableDictionaryRef makeBaseKeyDictionary() {
CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(query, kSecClass, kSecClassKey);
return query;
}
static CFMutableDictionaryRef createQueryKeyDictionary(SecKeychainRef kc, CFStringRef keyClass) {
CFMutableDictionaryRef query = makeBaseKeyDictionary();
CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue((CFMutableArrayRef)searchList, kc);
CFDictionarySetValue(query, kSecMatchSearchList, searchList);
CFDictionarySetValue(query, kSecAttrKeyClass, keyClass);
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
return query;
}
static CFMutableDictionaryRef createQueryKeyDictionaryWithLabel(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label) {
CFMutableDictionaryRef query = createQueryKeyDictionary(kc, keyClass);
CFDictionarySetValue(query, kSecAttrLabel, label);
return query;
}
static CFMutableDictionaryRef createAddKeyDictionaryWithApplicationLabel(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label, CFStringRef applicationLabel) {
CFMutableDictionaryRef query = makeBaseKeyDictionary();
CFDictionaryAddValue(query, kSecUseKeychain, kc);
CFDictionarySetValue(query, kSecAttrLabel, label);
if(applicationLabel) {
CFDictionarySetValue(query, kSecAttrApplicationLabel, applicationLabel);
} else {
CFDictionarySetValue(query, kSecAttrApplicationLabel, CFSTR("test_application")); }
int32_t n = 0;
if(CFEqual(keyClass, kSecAttrKeyClassSymmetric)) {
CFDictionarySetValue(query, kSecAttrKeyType, kSecAttrKeyTypeAES);
n = 128;
} else if(CFEqual(keyClass, kSecAttrKeyClassPublic) ||
CFEqual(keyClass, kSecAttrKeyClassPrivate)) {
CFDictionarySetValue(query, kSecAttrKeyType, kSecAttrKeyTypeRSA);
n = 1024;
}
CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &n);
CFDictionarySetValue(query, kSecAttrKeySizeInBits, num);
CFReleaseNull(num);
return query;
}
static CFMutableDictionaryRef createAddKeyDictionary(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label) {
return createAddKeyDictionaryWithApplicationLabel(kc, keyClass, label, NULL);
}
static SecKeyRef createCustomKeyWithApplicationLabel(const char* name, SecKeychainRef kc, CFStringRef label, CFStringRef applicationLabel) {
CFMutableDictionaryRef query = createAddKeyDictionaryWithApplicationLabel(kc, kSecAttrKeyClassSymmetric, label, applicationLabel);
CFErrorRef error = NULL;
SecKeyRef item = SecKeyGenerateSymmetric(query, &error);
ok(item != NULL, "%s: SecKeyGenerateSymmetric: %ld", name, error ? CFErrorGetCode(error) : 0);
CFReleaseNull(query);
return item;
}
#define createCustomKeyWithApplicationLabelTests 1
static SecKeyRef createCustomKey(const char* name, SecKeychainRef kc, CFStringRef label) {
return createCustomKeyWithApplicationLabel(name, kc, label, NULL);
}
#define createCustomKeyTests createCustomKeyWithApplicationLabelTests
static SecKeyRef makeKey(const char* name, SecKeychainRef kc) {
return createCustomKey(name, kc, CFSTR("test_key"));
}
#define makeKeyTests createCustomKeyTests
static void makeCustomKeyPair(const char* name, SecKeychainRef kc, CFStringRef label, SecKeyRef* aPub, SecKeyRef* aPriv) {
CFMutableDictionaryRef query = createAddKeyDictionary(kc, kSecAttrKeyClassPublic, label);
SecKeyRef pub;
SecKeyRef priv;
ok_status(SecKeyGeneratePair(query, &pub, &priv), "%s: SecKeyGeneratePair returned a result", name);
if(aPub) {
*aPub = pub;
}
if(aPriv) {
*aPriv = priv;
}
CFReleaseNull(query);
}
#define makeCustomKeyPairTests 1
static void makeKeyPair(const char* name, SecKeychainRef kc, SecKeyRef* aPub, SecKeyRef* aPriv) {
makeCustomKeyPair(name, kc, CFSTR("test_key"), aPub, aPriv);
}
#define makeKeyPairTests makeCustomKeyPairTests
static void makeCustomDuplicateKey(const char* name, SecKeychainRef kc, CFStringRef label) {
CFMutableDictionaryRef query;
query = createAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
CFErrorRef error = NULL;
CFReleaseSafe(SecKeyGenerateSymmetric(query, &error));
is(CFErrorGetCode(error), errSecDuplicateItem, "%s: SecKeyGenerateSymmetric (duplicate) errored: %ld", name, error ? CFErrorGetCode(error) : -1);
CFReleaseNull(query);
}
#define makeCustomDuplicateKeyTests 1
static void makeDuplicateKey(const char* name, SecKeychainRef kc) {
makeCustomDuplicateKey(name, kc, CFSTR("test_key"));
}
#define makeDuplicateKeyTests makeCustomDuplicateKeyTests
static SecKeyRef makeCustomFreeKey(const char* name, SecKeychainRef kc, CFStringRef label) {
SecKeyRef symkey;
ok_status(SecKeyGenerate(
NULL,
CSSM_ALGID_AES, 128,
0,
CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
CSSM_KEYATTR_EXTRACTABLE,
NULL,
&symkey), "%s: SecKeyGenerate", name);;
CFMutableDictionaryRef query = createAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue((CFMutableArrayRef)itemList, symkey);
CFDictionarySetValue(query, kSecUseItemList, itemList);
CFTypeRef result = NULL;
ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
ok(result != NULL, "%s: SecItemAdd returned a result", name);
CFReleaseNull(symkey);
return (SecKeyRef) result;
}
#define makeCustomFreeKeyTests 3
static SecKeyRef makeFreeKey(const char* name, SecKeychainRef kc) {
return makeCustomFreeKey(name, kc, CFSTR("test_free_key"));
}
#define makeFreeKeyTests makeCustomFreeKeyTests
static SecKeyRef makeCustomDuplicateFreeKey(const char* name, SecKeychainRef kc, CFStringRef label) {
SecKeyRef symkey;
ok_status(SecKeyGenerate(
NULL,
CSSM_ALGID_AES, 128,
0,
CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
CSSM_KEYATTR_EXTRACTABLE,
NULL,
&symkey), "%s: SecKeyGenerate", name);;
CFMutableDictionaryRef query = createAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
CFArrayAppendValue((CFMutableArrayRef)itemList, symkey);
CFDictionarySetValue(query, kSecUseItemList, itemList);
CFTypeRef result = NULL;
is(SecItemAdd(query, &result), errSecDuplicateItem, "%s: SecItemAdd (duplicate)", name);
CFReleaseNull(symkey);
return (SecKeyRef) result;
}
#define makeCustomDuplicateFreeKeyTests 2
static SecKeyRef makeDuplicateFreeKey(const char* name, SecKeychainRef kc) {
return makeCustomFreeKey(name, kc, CFSTR("test_free_key"));
}
#define makeDuplicateFreeKeyTests makeCustomDuplicateFreeKeyTests
#define checkKeyUseTests 4
static void checkKeyUse(SecKeyRef key, OSStatus expectedStatus) {
CFStringRef plaintext = CFSTR("A short story: the string goes into the encryptor, and returns unrecognizable. The decryptor reverses.");
CFDataRef plaintextData = CFDataCreate(NULL, (uint8_t*) CFStringGetCStringPtr(plaintext, kCFStringEncodingUTF8), CFStringGetLength(plaintext));
SecTransformRef transform = SecEncryptTransformCreate(key, NULL);
SecTransformSetAttribute(transform, kSecPaddingKey, kSecPaddingPKCS7Key, NULL);
SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, NULL);
SecTransformSetAttribute(transform, kSecTransformInputAttributeName, plaintextData, NULL);
CFErrorRef error = NULL;
CFDataRef ciphertextData = SecTransformExecute(transform, &error);
CFDataRef roundtripData = NULL;
if(error) {
CFStringRef errorStr = CFErrorCopyDescription(error);
is(CFErrorGetCode(error), expectedStatus, "%s: Encrypting data failed: %d %s (and expected %d)", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(errorStr, kCFStringEncodingUTF8), (int) expectedStatus);
CFReleaseSafe(errorStr);
if(expectedStatus != errSecSuccess) {
for(int i = 1; i < checkKeyUseTests; i++) {
pass("test numbers match");
}
goto cleanup;
}
} else {
pass("%s: transform executed", testName);
}
CFReleaseSafe(transform);
transform = SecDecryptTransformCreate(key, NULL);
SecTransformSetAttribute(transform, kSecPaddingKey, kSecPaddingPKCS7Key, NULL);
SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, NULL);
SecTransformSetAttribute(transform, kSecTransformInputAttributeName, ciphertextData, NULL);
roundtripData = SecTransformExecute(transform, &error);
is(error, NULL, "%s: checkKeyUse: SecTransformExecute (decrypt)", testName);
if(error) {
CFStringRef errorStr = CFErrorCopyDescription(error);
fail("%s: Decrypting data failed: %d %s", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(errorStr, kCFStringEncodingUTF8));
CFReleaseSafe(errorStr);
} else {
pass("%s: make test numbers match", testName);
}
eq_cf(plaintextData, roundtripData, "%s: checkKeyUse: roundtripped data is input data", testName);
cleanup:
CFReleaseSafe(transform);
CFReleaseSafe(plaintext);
CFReleaseSafe(plaintextData);
CFReleaseSafe(ciphertextData);
CFReleaseSafe(roundtripData);
}
#pragma clang diagnostic pop
#else
#endif
#endif