kc-27-key-non-extractable.c [plain text]
#import <Security/Security.h>
#import <Security/SecCertificatePriv.h>
#include "keychain_regressions.h"
#include "kc-helpers.h"
#include <stdlib.h>
#include <err.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <Security/SecItemPriv.h>
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
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 ); CFReleaseNull(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 (access) CFRelease(access);
return status;
}
static int testExtractable(
SecKeychainRef keychain,
Boolean extractable,
Boolean explicit)
{
OSStatus status;
SecKeyRef publicKeyRef = NULL;
SecKeyRef privateKeyRef = NULL;
CFStringRef label = (extractable) ? CFSTR("test-extractable-YES") : CFSTR("test-extractable-NO");
Boolean *extractablePtr = (explicit) ? &extractable : NULL;
status = GenerateRSAKeyPair(keychain,
label,
1024, extractablePtr,
&publicKeyRef,
&privateKeyRef);
if (status != noErr) {
return status;
}
const CSSM_KEY *cssmPrivKey;
status = SecKeyGetCSSMKey(privateKeyRef, &cssmPrivKey);
ok_status(status, "%s: SecKeyGetCSSMKey", testName);
if (status != noErr) {
return status;
}
if (extractable) {
ok(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE, "%s: check private key marked as extractable (as requested)", testName);
if (!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
return 1;
}
}
else {
ok(!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE), "%s: check private key marked as non-extractable (as requested)", testName);
if (cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE) {
return 1;
}
}
SecKeyImportExportParameters keyParams;
memset(&keyParams, 0, sizeof(keyParams));
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = CFSTR("borken");
CFDataRef exportedData = NULL;
status = SecKeychainItemExport(privateKeyRef, kSecFormatWrappedPKCS8, 0, &keyParams, &exportedData);
if(extractable) {
ok_status(status, "%s: SecKeychainItemExport (PKCS8) (and we expected it to succeed)", testName);
} else {
is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS8) (and we expected this to fail with errSecDataNotAvailable)", testName);
}
status = SecKeychainItemExport(privateKeyRef, kSecFormatPKCS12, 0, &keyParams, &exportedData);
if(extractable) {
ok_status(status, "%s: SecKeychainItemExport(and we expected it to succeed)", testName);
} else {
is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS12) (and we expected this to fail with errSecDataNotAvailable)", testName);
}
if (status != noErr) {
if (extractable) {
return 1;
}
else {
status = 0; }
}
else if (status == noErr && !extractable) {
return 1;
}
status = SecKeychainItemDelete((SecKeychainItemRef)publicKeyRef);
ok_status(status, "%s: SecKeychainItemDelete", testName);
if (status != noErr) {
warnx("Unable to delete created public key from keychain (err = %d)", (int)status);
}
status = SecKeychainItemDelete((SecKeychainItemRef)privateKeyRef);
ok_status(status, "%s: SecKeychainItemDelete", testName);
if (status != noErr) {
warnx("Unable to delete created private key from keychain (err = %d)", (int)status);
}
CFRelease(publicKeyRef);
CFRelease(privateKeyRef);
return 0;
}
int kc_27_key_non_extractable(int argc, char *const *argv)
{
plan_tests(24);
initializeKeychainTests(__FUNCTION__);
SecKeychainRef kc = getPopulatedTestKeychain();
startTest("Extract extractable key");
testExtractable(kc, TRUE, TRUE);
startTest("Extract non-extractable key");
testExtractable(kc, FALSE, TRUE);
startTest("Extract implicitly extractable key");
testExtractable(kc, TRUE, FALSE);
ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
CFRelease(kc);
deleteTestFiles();
return 0;
}