kc-24-key-copy-keychains.c [plain text]
#import <Security/Security.h>
#include "keychain_regressions.h"
#include "kc-helpers.h"
#include "kc-key-helpers.h"
#include "kc-keychain-file-helpers.h"
#include <stdlib.h>
#include <err.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
static OSStatus GenerateRSAKeyPair(
SecKeychainRef keychain,
CFStringRef keyLabel,
int keySizeValue,
Boolean *extractable,
SecKeyRef *publicKeyRef,
SecKeyRef *privateKeyRef)
{
OSStatus status;
CFNumberRef keySize = CFNumberCreate(NULL, kCFNumberIntType, &keySizeValue);
SecAccessRef access = NULL;
status = SecAccessCreate(keyLabel, NULL, &access);
CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue( params, kSecUseKeychain, keychain );
CFDictionaryAddValue( params, kSecAttrAccess, access );
CFDictionaryAddValue( params, kSecAttrKeyType, kSecAttrKeyTypeRSA );
CFDictionaryAddValue( params, kSecAttrKeySizeInBits, keySize );
CFDictionaryAddValue( params, kSecAttrIsPermanent, kCFBooleanTrue );
if (extractable)
CFDictionaryAddValue( params, kSecAttrIsExtractable, (*extractable) ? kCFBooleanTrue : kCFBooleanFalse );
if (keyLabel)
CFDictionaryAddValue( params, kSecAttrLabel, keyLabel );
status = SecKeyGeneratePair(params, publicKeyRef, privateKeyRef);
ok_status(status, "%s: SecKeyGeneratePair", testName);
if (params) CFRelease(params);
if (keychain) CFRelease(keychain);
if (access) CFRelease(access);
return status;
}
static SecAccessRef MakeNewAccess(SecKeychainItemRef item, CFStringRef accessLabel, Boolean allowAny)
{
OSStatus status;
SecAccessRef access = NULL;
CFMutableArrayRef trustedApplications = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!allowAny) {
SecTrustedApplicationRef myself = NULL, someOther = NULL;
status = SecTrustedApplicationCreateFromPath(NULL, &myself);
ok_status(status, "%s: MakeNewAccess: SecTrustedApplicationCreateFromPath (self)", testName);
if (!status && myself) {
CFArrayAppendValue(trustedApplications, myself);
CFRelease(myself);
}
status = SecTrustedApplicationCreateFromPath("/Applications/Mail.app", &someOther);
ok_status(status, "%s: MakeNewAccess: SecTrustedApplicationCreateFromPath (Mail.app)", testName);
if (!status && someOther) {
CFArrayAppendValue(trustedApplications, someOther);
CFRelease(someOther);
}
}
if (item) {
status = SecKeychainItemCopyAccess(item, &access);
ok_status(status, "%s: MakeNewAccess: SecKeychainItemCopyAccess", testName);
} else {
status = SecAccessCreate(accessLabel, trustedApplications, &access);
ok_status(status, "%s: MakeNewAccess: SecAccessCreate", testName);
}
if (status) return NULL;
CFArrayRef aclList = NULL;
status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
ok_status(status, "%s: MakeNewAccess: SecAccessCopySelectedACLList", testName);
if (!status)
{
SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
CFArrayRef appList = NULL;
CFStringRef promptDescription = NULL;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
ok_status(status, "%s: MakeNewAccess: SecAccessCopySimpleContents", testName);
if (allowAny) {
promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
status = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
ok_status(status, "%s: MakeNewAccess: SecACLSetSimpleContents", testName);
}
else {
status = SecACLSetSimpleContents(aclRef, trustedApplications, promptDescription, &promptSelector);
ok_status(status, "%s: MakeNewAccess: SecACLSetSimpleContents", testName);
}
if (appList) CFRelease(appList);
if (promptDescription) CFRelease(promptDescription);
}
if (aclList) CFRelease(aclList);
if (trustedApplications) CFRelease(trustedApplications);
return access;
}
static int testCopyKey(SecKeychainRef userKeychain, SecKeychainRef tempKeychain)
{
OSStatus status;
SecAccessRef access = NULL;
SecKeyRef publicKeyRef = NULL;
SecKeyRef privateKeyRef = NULL;
CFStringRef label = CFSTR("Test Key Copied To Keychain");
if (!tempKeychain) {
warnc(EXIT_FAILURE, "Failed to make a new temporary keychain!");
}
status = GenerateRSAKeyPair(tempKeychain,
label,
2048, NULL, &publicKeyRef,
&privateKeyRef);
if (status != errSecSuccess) {
warnc(EXIT_FAILURE, "Unable to get key pair (error %d)", (int)status);
}
CFDataRef exportedData = NULL;
CFStringRef tempPassword = CFSTR("MY_TEMPORARY_PASSWORD");
SecItemImportExportKeyParameters keyParams;
memset(&keyParams, 0, sizeof(keyParams));
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = tempPassword;
status = SecItemExport(privateKeyRef, kSecFormatWrappedPKCS8, 0, &keyParams, &exportedData);
ok_status(status, "%s: SecItemExport", testName);
if (!exportedData || status != noErr) {
warnc(EXIT_FAILURE, "Unable to export key! (error %d)", (int)status);
}
access = MakeNewAccess(NULL, label, true);
keyParams.accessRef = access;
SecExternalFormat format = kSecFormatWrappedPKCS8;
SecExternalItemType itemType = kSecItemTypePrivateKey;
CFArrayRef importedItems = NULL;
status = SecItemImport(exportedData, NULL, &format, &itemType, 0, &keyParams, userKeychain, &importedItems);
ok_status(status, "%s: SecItemImport", testName);
if (status != noErr) {
warnc(EXIT_FAILURE, "Unable to import key! (error %d)", (int)status);
}
if (importedItems) {
SecKeyRef importedKey = (SecKeyRef) CFArrayGetValueAtIndex(importedItems, 0);
if (CFGetTypeID(importedKey) == SecKeyGetTypeID()) {
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, label );
status = SecItemUpdate( query, attrs );
ok_status(status, "%s: SecItemUpdate", testName);
if (status != errSecSuccess) {
warnc(EXIT_FAILURE, "Failed to update label of imported key! (error %d)", (int)status);
}
CFRelease(query);
CFRelease(attrs);
}
CFRelease(importedItems);
}
checkN(testName, makeQueryKeyDictionaryWithLabel(userKeychain, kSecAttrKeyClassPrivate, label), 1);
if (access) CFRelease(access);
return 0;
}
int kc_24_key_copy_keychain(int argc, char *const *argv)
{
plan_tests(18);
initializeKeychainTests(__FUNCTION__);
SecKeychainRef keychain = getPopulatedTestKeychain();
SecKeychainRef blankKeychain = createNewKeychain("forKeys", "password");
testCopyKey(keychain, blankKeychain);
ok_status(SecKeychainDelete(keychain), "%s: SecKeychainDelete", testName);
ok_status(SecKeychainDelete(blankKeychain), "%s: SecKeychainDelete", testName);
CFReleaseNull(keychain);
CFReleaseNull(blankKeychain);
checkPrompts(0, "No prompts while importing items");
deleteTestFiles();
return 0;
}