int kc_27_key_non_extractable(int argc, char *const *argv)
{
    plan_tests(24);
    initializeKeychainTests(__FUNCTION__);

    SecKeychainRef kc = getPopulatedTestKeychain();

	// test case 1: extractable
    startTest("Extract extractable key");
    testExtractable(kc, TRUE, TRUE);

	// test case 2: non-extractable
    startTest("Extract non-extractable key");
    testExtractable(kc, FALSE, TRUE);

	// test case 3: extractable (when not explicitly specified)
    startTest("Extract implicitly extractable key");
    testExtractable(kc, TRUE, FALSE);

    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
    CFRelease(kc);

    deleteTestFiles();
    return 0;
}
Exemple #2
0
static VALUE rb_keychain_delete(VALUE self){

  SecKeychainRef keychain=NULL;
  Data_Get_Struct(self, struct OpaqueSecKeychainRef, keychain);
  OSStatus result = SecKeychainDelete(keychain);
  CheckOSStatusOrRaise(result);
  return self;
}
int main(int argc, char **argv)
{
	bool verbose = false;
	
	int arg;
	while ((arg = getopt(argc, argv, "vh")) != -1) {
		switch (arg) {
			case 'v':
				verbose = true;
				break;
			case 'h':
				usage(argv);
		}
	}
	if(optind != argc) {
		usage(argv);
	}
	
	printNoDialog();
	
	/* initial setup */
	verboseDisp(verbose, "deleting keychain");
	unlink(KEYCHAIN_NAME);
	
	verboseDisp(verbose, "creating keychain");
	SecKeychainRef kcRef = NULL;
	OSStatus ortn = SecKeychainCreate(KEYCHAIN_NAME, 
		strlen(KEYCHAIN_PWD), KEYCHAIN_PWD,
		false, NULL, &kcRef);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}

	/* 
	 * 1. Generate key pair with cleartext public key.
	 *    Ensure we can use the public key when keychain is locked with no
	 *    user interaction.  
	 */
	 
	/* generate key pair, cleartext public key */
	verboseDisp(verbose, "creating key pair, cleartext public key");
	SecKeyRef pubKeyRef = NULL;
	SecKeyRef privKeyRef = NULL;
	if(genKeyPair(false, kcRef, &pubKeyRef, &privKeyRef)) {
		exit(1);
	}
	
	/* Use generated cleartext public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	CFDataRef exportData = NULL;
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}
	CFRelease(exportData);
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}

	/* reset */
	verboseDisp(verbose, "deleting keys");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	CFRelease(privKeyRef);

	/* 
	 * 2. Generate key pair with encrypted public key.
	 *    Ensure that user interaction is required when we use the public key 
	 *    when keychain is locked.
	 */

	verboseDisp(verbose, "programmatically unlocking keychain");
	ortn = SecKeychainUnlock(kcRef, strlen(KEYCHAIN_PWD), KEYCHAIN_PWD, TRUE);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	
	/* generate key pair, encrypted public key */
	verboseDisp(verbose, "creating key pair, encrypted public key");
	if(genKeyPair(true, kcRef, &pubKeyRef, &privKeyRef)) {
		exit(1);
	}

	/* Use generated encrypted public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}
	/* we'll use that exported blob later to test import */
	if(!didGetDialog()) {
		exit(1);
	}
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}

	/* reset */
	printNoDialog();
	verboseDisp(verbose, "locking keychain");
	SecKeychainLock(kcRef);
	verboseDisp(verbose, "deleting keys");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	CFRelease(privKeyRef);

	/* 
	 * 3. Import public key, storing in cleartext. Ensure that the import
	 *    doesn't require unlock, and ensure we can use the public key 
	 *    when keychain is locked with no user interaction.  
	 */

	printNoDialog();
	verboseDisp(verbose, "locking keychain");
	SecKeychainLock(kcRef);

	/* import public key - default is in the clear */
	verboseDisp(verbose, "importing public key, store in the clear (default)");
	CFArrayRef outArray = NULL;
	SecExternalFormat format = kSecFormatOpenSSL;
	SecExternalItemType type = kSecItemTypePublicKey;
	ortn = SecKeychainItemImport(exportData, 
		NULL, &format, &type,
		0, NULL,
		kcRef, &outArray);
	if(ortn) {
		cssmPerror("SecKeychainItemImport", ortn);
		exit(1);
	}
	CFRelease(exportData);
	if(CFArrayGetCount(outArray) != 1) {
		printf("***Unexpected outArray size (%ld) after import\n",
			(long)CFArrayGetCount(outArray));
		exit(1);
	}
	pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
	if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
		printf("***Unexpected item type after import\n");
		exit(1);
	}
	
	/* Use imported cleartext public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	exportData = NULL;
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainItemExport", ortn);
		exit(1);
	}
	/* we'll use exportData again */
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}

	/* reset */
	verboseDisp(verbose, "deleting key");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	
	/* 
	 * Import public key, storing in encrypted form.
	 * Ensure that user interaction is required when we use the public key 
	 * when keychain is locked.
	 */

	/* import public key, encrypted in the keychain */
	SecKeyImportExportParameters impExpParams;
	memset(&impExpParams, 0, sizeof(impExpParams));
	impExpParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
	impExpParams.keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | 
								 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
	verboseDisp(verbose, "importing public key, store encrypted");
	printExpectDialog();
	outArray = NULL;
	format = kSecFormatOpenSSL;
	type = kSecItemTypePublicKey;
	ortn = SecKeychainItemImport(exportData, 
		NULL, &format, &type,
		0, &impExpParams,
		kcRef, &outArray);
	if(ortn) {
		cssmPerror("SecKeychainItemImport", ortn);
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}
	CFRelease(exportData);
	if(CFArrayGetCount(outArray) != 1) {
		printf("***Unexpected outArray size (%ld) after import\n",
			(long)CFArrayGetCount(outArray));
		exit(1);
	}
	pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
	if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
		printf("***Unexpected item type after import\n");
		exit(1);
	}
					
	/* Use imported encrypted public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainItemExport", ortn);
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}
	CFRelease(exportData);
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}

	SecKeychainDelete(kcRef);
	printf("...test succeeded.\n");
	return 0;
}
void tests(int dont_skip)
{
	SecKeychainRef source, dest;
	ok_status(SecKeychainCreate("source", 4, "test", FALSE, NULL, &source),
		"create source keychain");
	ok_status(SecKeychainCreate("dest", 4, "test", FALSE, NULL, &dest),
		"create dest keychain");
	SecKeychainItemRef original = NULL;
	ok_status(SecKeychainAddInternetPassword(source,
		19, "members.spamcop.net",
		0, NULL,
		5, "smith",
		0, NULL,
		80, kSecProtocolTypeHTTP,
		kSecAuthenticationTypeDefault,
		4, "test", &original), "add internet password");
	SecKeychainAttribute origAttrs[] = 
	{
		{ kSecCreationDateItemAttr },
		{ kSecModDateItemAttr }
	};
	SecKeychainAttributeList origAttrList =
	{
		sizeof(origAttrs) / sizeof(*origAttrs),
		origAttrs
	};
	ok_status(SecKeychainItemCopyContent(original, NULL, &origAttrList,
		NULL, NULL), "SecKeychainItemCopyContent");

	/* Must sleep 1 second to trigger mod date bug. */
	sleep(1);
	SecKeychainItemRef copy;
	ok_status(SecKeychainItemCreateCopy(original, dest, NULL, &copy),
		"copy item");

	SecKeychainAttribute copyAttrs[] = 
	{
		{ kSecCreationDateItemAttr },
		{ kSecModDateItemAttr }
	};
	SecKeychainAttributeList copyAttrList =
	{
		sizeof(copyAttrs) / sizeof(*copyAttrs),
		copyAttrs
	};
	ok_status(SecKeychainItemCopyContent(copy, NULL, &copyAttrList,
		NULL, NULL), "SecKeychainItemCopyContent");

	is(origAttrs[0].length, 16, "creation date length 16");
	is(origAttrs[1].length, 16, "mod date length 16");
	is(origAttrs[0].length, copyAttrs[0].length, "creation date length same");
	is(origAttrs[1].length, copyAttrs[1].length, "mod date length same");

	TODO: {
		todo("<rdar://problem/3731664> Moving/copying a keychain item "
			"between keychains erroneously updates dates");

		diag("original creation: %.*s copy creation: %.*s",
			(int)origAttrs[0].length, (const char *)origAttrs[0].data,
			(int)copyAttrs[0].length, (const char *)copyAttrs[0].data);
		ok(!memcmp(origAttrs[0].data, copyAttrs[0].data, origAttrs[0].length),
			"creation date same");

		diag("original mod: %.*s copy mod: %.*s",
			(int)origAttrs[1].length, (const char *)origAttrs[1].data,
			(int)copyAttrs[1].length, (const char *)copyAttrs[1].data);
		ok(!memcmp(origAttrs[1].data, copyAttrs[1].data, origAttrs[1].length),
			"mod date same");
	}

	ok_status(SecKeychainItemFreeContent(&origAttrList, NULL),
		"SecKeychainItemCopyContent");
	ok_status(SecKeychainItemFreeContent(&copyAttrList, NULL),
		"SecKeychainItemCopyContent");

	is(CFGetRetainCount(original), 1, "original retaincount is 1");
	CFRelease(original);
	is(CFGetRetainCount(copy), 1, "copy retaincount is 1");
	CFRelease(copy);
	is(CFGetRetainCount(source), 1, "source retaincount is 1");
	ok_status(SecKeychainDelete(source), "delete keychain source");
	CFRelease(source);
	ok_status(SecKeychainDelete(dest), "delete keychain dest");
	is(CFGetRetainCount(dest), 1, "dest retaincount is 1");
	CFRelease(dest);

	ok(tests_end(1), "cleanup");
}
static void tests(void)
{
	char *home = getenv("HOME");
	char kcname1[256], kcname2[256];
	SecKeychainStatus status1, status2;

	if (!home || strlen(home) > 200)
		plan_skip_all("home too big");

	sprintf(kcname1, "%s/kctests/kc1/kc1", home);
	SecKeychainRef kc1 = NULL, kc2 = NULL;
    kc1 = createNewKeychainAt(kcname1, "test");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");
	ok_status(SecKeychainLock(kc1), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecReadPermStatus|kSecWritePermStatus,
			"status (locked) readable writable");
	}

	/* Make keychain non writable. */
	char kcdir1[256];
	sprintf(kcdir1, "%s/kctests/kc1", home);
	ok_unix(chmod(kcdir1, 0555), "chmod kcdir1 0555");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecReadPermStatus, "status (locked) readable");
	ok_status(SecKeychainUnlock(kc1, 4, "test", TRUE), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	/* Reopen the keychain. */
	CFRelease(kc1);
	ok_status(SecKeychainOpen(kcname1, &kc1), "SecKeychainOpen kc1");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	sprintf(kcname2, "%s/kctests/kc2/kc2", home);
    kc2 = createNewKeychainAt(kcname2, "test");
	ok_unix(chmod(kcname2, 0444), "chmod kc2 0444");
	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Reopen the keychain. */
	CFRelease(kc2);
	ok_status(SecKeychainOpen(kcname2, &kc2), "SecKeychainOpen kc2");

	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Restore dir to writable so cleanup code will work ok. */
	ok_unix(chmod(kcdir1, 0755), "chmod kcdir1 0755");
    ok_status(SecKeychainDelete(kc1), "%s: SecKeychainDelete", testName);
	CFRelease(kc1);
    ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", testName);
	CFRelease(kc2);

	bool testWithFreshlyCreatedKeychain = true;
	SecKeychainRef keychain = createNewKeychain("test", "test");
	ok_status(SecKeychainLock(keychain), "SecKeychainLock");

	do {
		SecKeychainStatus keychainStatus = 0;
		is_status(SecKeychainUnlock(keychain, 0, NULL, true), -25293, "SecKeychainUnlock with NULL password (incorrect)");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), 0, "Check it's not unlocked");

		keychainStatus = 0;
		ok_status(SecKeychainUnlock(keychain, strlen("test"), "test", true), "SecKeychainUnlock with correct password");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), kSecUnlockStateStatus, "Check it's unlocked");
		
		ok_status(SecKeychainLock(keychain), "SecKeychainLock");

		if (testWithFreshlyCreatedKeychain)
		{
        CFRelease(keychain);
			testWithFreshlyCreatedKeychain = false;
			ok_status(SecKeychainOpen("test", &keychain), "SecKeychainOpen");
		}
        else {
			testWithFreshlyCreatedKeychain = true;

            ok_status(SecKeychainDelete(keychain), "%s: SecKeychainDelete", testName);
            CFReleaseNull(keychain);
        }
		
	}
	while(!testWithFreshlyCreatedKeychain);

}