kc-30-xara-key-helpers.h [plain text]
#include "kc-30-xara-helpers.h"
#ifndef kc_30_xara_key_helpers_h
#define kc_30_xara_key_helpers_h
#if TARGET_OS_MAC
static CFMutableDictionaryRef makeBaseKeyDictionary() {
CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(query, kSecClass, kSecClassKey);
return query;
}
static CFMutableDictionaryRef makeQueryKeyDictionary(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 makeAddKeyDictionary(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label) {
CFMutableDictionaryRef query = makeBaseKeyDictionary();
CFDictionaryAddValue(query, kSecUseKeychain, kc);
CFDictionarySetValue(query, kSecAttrLabel, label);
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);
return query;
}
static SecKeyRef makeCustomKey(const char* name, SecKeychainRef kc, CFStringRef label) {
CFMutableDictionaryRef query = makeAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
CFErrorRef error = NULL;
SecKeyRef item = SecKeyGenerateSymmetric(query, &error);
ok(item != NULL, "%s: SecKeyGenerateSymmetric errored: %ld", name, error ? CFErrorGetCode(error) : -1);
CFReleaseNull(query);
return item;
}
#define makeCustomKeyTests 1
static SecKeyRef makeKey(const char* name, SecKeychainRef kc) {
return makeCustomKey(name, kc, CFSTR("test_key"));
}
#define makeKeyTests makeCustomKeyTests
static void makeCustomKeyWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef label, CFStringRef expectedHash) {
SecKeyRef key = makeCustomKey(name, kc, label);
checkIntegrityHash(name, (SecKeychainItemRef) key, expectedHash);
CFReleaseNull(key);
}
#define makeCustomKeyWithIntegrityTests (makeCustomKeyTests + checkIntegrityHashTests)
static void makeKeyWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef expectedHash) {
makeCustomKeyWithIntegrity(name, kc, CFSTR("test_key"), expectedHash);
}
#define makeKeyWithIntegrityTests makeCustomKeyWithIntegrityTests
static void makeCustomKeyPair(const char* name, SecKeychainRef kc, CFStringRef label, SecKeyRef* aPub, SecKeyRef* aPriv) {
CFMutableDictionaryRef query = makeAddKeyDictionary(kc, kSecAttrKeyClassPublic, label);
CFErrorRef error = NULL;
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 makeKeyPairWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef expectedPubHash, CFStringRef expectedPrivHash) {
SecKeyRef pub;
SecKeyRef priv;
makeKeyPair(name, kc, &pub, &priv);
checkIntegrityHash(name, (SecKeychainItemRef) pub, expectedPubHash);
checkIntegrityHash(name, (SecKeychainItemRef) priv, expectedPrivHash);
}
#define makeKeyPairWithIntegrityTests (makeKeyTests + checkIntegrityHashTests)
static void makeCustomDuplicateKey(const char* name, SecKeychainRef kc, CFStringRef label) {
CFMutableDictionaryRef query;
query = makeAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
CFErrorRef error = NULL;
SecKeyRef item = 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 = makeAddKeyDictionary(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 = makeAddKeyDictionary(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
static void testAddKey(CFStringRef expectedHash) {
char* name = "testAddKey";
SecKeychainRef kc = newKeychain(name);
makeKeyWithIntegrity(name, kc, expectedHash);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testAddKeyTests (newKeychainTests + makeKeyWithIntegrityTests + 1)
static void testAddFreeKey(CFStringRef expectedHash) {
}
#define testAddFreeKeyTests 0
static void testCopyMatchingKey(CFStringRef expectedHash) {
char* name = "testCopyMatchingKey";
secdebugfunc("integrity", "************************************* %s", name);
SecKeychainRef kc = newKeychain(name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
makeKeyWithIntegrity(name, kc, expectedHash);
SecKeyRef item = (SecKeyRef) checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
checkIntegrityHash(name, (SecKeychainItemRef) item, expectedHash);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testCopyMatchingKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
static void testUpdateKey(CFStringRef expectedHash, CFStringRef expectedHashAfter) {
char * name = "testUpdateKey";
secdebugfunc("integrity", "************************************* %s", name);
SecKeychainRef kc = newKeychain(name);
makeKeyWithIntegrity(name, kc, expectedHash);
SecKeychainItemRef item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
CFReleaseNull(item);
CFStringRef label = CFSTR("a modified label");
CFMutableDictionaryRef query = makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric);
CFMutableDictionaryRef update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(update, kSecAttrLabel, label);
ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
CFReleaseNull(query);
CFReleaseNull(update);
query = makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric);
CFDictionarySetValue(query, kSecAttrLabel, label);
item = checkN(name, query, 1);
checkIntegrityHash(name, item, expectedHashAfter);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testUpdateKeyTests (newKeychainTests + makeKeyWithIntegrityTests + checkNTests + 1 + checkNTests + checkIntegrityHashTests + 1)
static void testKeyPair() {
char* name = "testKeyPair";
secdebugfunc("integrity", "************************************* %s", name);
SecKeychainRef kc = newKeychain(name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
SecKeyRef pub;
SecKeyRef priv;
makeKeyPair(name, kc, &pub, &priv);
SecKeyRef item;
item = (SecKeyRef) checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
checkHashesMatch(name, (SecKeychainItemRef)pub, (SecKeychainItemRef)item);
item = (SecKeyRef) checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
checkHashesMatch(name, (SecKeychainItemRef)priv, (SecKeychainItemRef)item);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
+ checkNTests + checkHashesMatchTests \
+ checkNTests + checkHashesMatchTests + 1)
static void testAddDuplicateKey(CFStringRef expectedHash) {
char * name = "testAddDuplicateKey";
secdebugfunc("integrity", "************************************* %s", name);
SecKeychainRef kc = newKeychain(name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
makeKeyWithIntegrity(name, kc, expectedHash);
SecKeychainItemRef item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
makeDuplicateKey(name, kc);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testAddDuplicateKeyTests (newKeychainTests + checkNTests +makeKeyWithIntegrityTests + checkNTests + makeDuplicateKeyTests + checkNTests + 1)
static void testAddDuplicateFreeKey(CFStringRef expectedHash) {
}
#define testAddDuplicateFreeKeyTests 0
static void testExportImportKeyPair() {
char* name = "testExportImportKeyPair";
secdebugfunc("integrity", "************************************* %s", name);
SecKeychainRef kc = newKeychain(name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
SecKeyRef pub;
SecKeyRef priv;
makeKeyPair(name, kc, &pub, &priv);
SecKeyRef item;
item = (SecKeyRef) checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
checkHashesMatch(name, (SecKeychainItemRef)pub, (SecKeychainItemRef)item);
item = (SecKeyRef) checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
checkHashesMatch(name, (SecKeychainItemRef)priv, (SecKeychainItemRef)item);
CFMutableArrayRef applications = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
SecTrustedApplicationRef app = NULL;
ok_status(SecTrustedApplicationCreateFromPath(NULL, &app), "%s: SecTrustedApplicationCreateFromPath", name);
CFArrayAppendValue(applications, app);
ok_status(SecTrustedApplicationCreateFromPath("/usr/bin/codesign", &app), "%s: SecTrustedApplicationCreateFromPath", name);
CFArrayAppendValue(applications, app);
SecAccessRef accessRef = NULL;
ok_status(SecAccessCreate(CFSTR("accessDescription"), applications, &accessRef), "%s: SecAccessCreate", name);
const SecItemImportExportKeyParameters keyParams =
{
SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
0,
CFSTR( "" ),
CFSTR( "" ),
CFSTR( "" ),
accessRef, 0, 0
};
CFArrayRef items = NULL;
CFDataRef keyData = NULL;
ok_status(SecItemExport(pub, kSecFormatPEMSequence, kSecItemPemArmour, &keyParams, &keyData), "%s: SecItemExport", name);
ok_status(SecKeychainItemDelete((SecKeychainItemRef)pub), "%s: SecKeychainDelete", name);;
CFRelease(pub);
pub = NULL;
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
ok_status(SecItemImport(keyData, NULL, NULL, NULL, kSecItemPemArmour, &keyParams, kc, &items), "%s: SecItemImport", name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
ok_status(SecItemExport(priv, kSecFormatPEMSequence, kSecItemPemArmour, &keyParams, &keyData), "%s: SecItemExport", name);
ok_status(SecKeychainItemDelete((SecKeychainItemRef)priv), "%s: SecKeychainDelete", name);;
CFRelease(priv);
priv = NULL;
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
ok_status(SecItemImport(keyData, NULL, NULL, NULL, kSecItemPemArmour, &keyParams, kc, &items), "%s: SecItemImport", name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
SecAccessRef newRef = NULL;
ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef) CFArrayGetValueAtIndex(items, 0), &newRef), "%s:SecKeychainItemCopyAccess", name);
SecKeyRef importedKey = items && CFArrayGetCount(items) > 0 ? (SecKeyRef)CFArrayGetValueAtIndex(items, 0) : NULL;
if (importedKey) {
CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(query, kSecClass, kSecClassKey);
CFDictionaryAddValue(query, kSecValueRef, importedKey);
CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(attrs, kSecAttrLabel, CFSTR("private key custom label"));
ok_status( SecItemUpdate(query, attrs), "%s: SecItemUpdate", name);
} else {
fail("%s: Didn't have an item to update", name);
}
ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef) CFArrayGetValueAtIndex(items, 0), &newRef), "%s:SecKeychainItemCopyAccess", name);
checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
}
#define testExportImportKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
+ checkNTests + checkHashesMatchTests \
+ checkNTests + checkHashesMatchTests \
+ 5 + checkNTests + 1 + checkNTests \
+ 2 + checkNTests + 1 + checkNTests + 1 + 1 + 1 + checkNTests\
+ 1)
#else
#endif
#endif