int
main(int argc, char *const *argv)
{
	plan_tests(6);

	ok(tests_begin(argc, argv), "setup");

	UInt32 didGetNotification = 0;
	ok_status(SecKeychainAddCallback(callbackFunction, kSecAddEventMask,
		&didGetNotification), "add callback");

	SecKeychainRef keychain;
	ok_status(SecKeychainCreate("test", 4, "test", FALSE, NULL, &keychain),
			"create keychain");
	SecKeychainItemRef itemRef;
	ok_status(SecKeychainAddGenericPassword(keychain,
		sizeof(account), account,
		sizeof(service), service,
		sizeof(password), password,
		&itemRef),
		"add generic password, release and wait for callback");
	//checkContent(itemRef);
	CFRelease(itemRef);
	CFRelease(keychain);

	if (argc > 1 && !strcmp(argv[1], "-l")) {
		printf("pid: %d\n", getpid());
		sleep(100);
	}
	ok(tests_end(1), "cleanup");
	ok_leaks("leaks");

	return 0;
}
void tests(void)
{
	SecKeychainRef keychain;
	ok_status(SecKeychainCreate("test", 4, "test", FALSE, NULL, &keychain),
		"create keychain");
	SecKeyRef pub_crypt = NULL, prv_crypt = NULL;
	ok_status(SecKeyCreatePair(keychain, CSSM_ALGID_RSA, 256,
		0 /* contextHandle */,
		CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP,
		CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE,
		CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP,
		CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
			CSSM_KEYATTR_SENSITIVE,
		NULL /* initialAccess */, &pub_crypt, &prv_crypt),
		"generate encryption keypair");

	SecKeyRef pub_sign = NULL, prv_sign = NULL;
	ok_status(SecKeyCreatePair(keychain, CSSM_ALGID_RSA, 256,
		0 /* contextHandle */,
		CSSM_KEYUSE_VERIFY,
		CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE,
		CSSM_KEYUSE_SIGN,
		CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
			CSSM_KEYATTR_SENSITIVE,
		NULL /* initialAccess */, &pub_sign, &prv_sign),
		"generate signing keypair");

	uint32 btrue = 1;
	uint32 bfalse = 0;
	/* uint32 prv_class = CSSM_KEYCLASS_PRIVATE_KEY; */
	SecKeychainAttribute attrs[] = 
	{
		{ kSecKeyDecrypt, sizeof(uint32), &btrue },
		{ kSecKeyEncrypt, sizeof(uint32), &bfalse },
		/* { kSecKeyKeyClass, sizeof(uint32), &prv_class } */
	};
	SecKeychainAttributeList attrList = { sizeof(attrs) / sizeof(*attrs), attrs };
	SecKeychainSearchRef search;
	OSStatus result;
	SecKeychainItemRef item;
	
	ok_status((result = SecKeychainSearchCreateFromAttributes(keychain,
		CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &search)), "create key search");
	if (result == noErr)
	{
		ok_status(SecKeychainSearchCopyNext(search, &item), "get first key");
		cmp_ok((intptr_t)prv_crypt, ==, (intptr_t)item, "is key found the right one?");
		CFRelease(item);
		item = NULL;
		is_status(SecKeychainSearchCopyNext(search, &item),
			errSecItemNotFound, "get next key");
		is((intptr_t)item, 0, "no item returned");
		CFRelease(search);
	}
OSStatus makeMasterPassword(const char *fvmkcName, const char *masterPasswordPassword, uint32 keySizeInBits, SecKeychainRef *keychainRef)
{
    /*
        OSStatus SecFileVaultMakeMasterPassword(CFStringRef masterPasswordPassword);

        *** In the real code, this will be done directly rather than exec'ing a tool, since there are too many parameters to specify
        *** this needs to be done as root, since the keychain will be a system keychain
        /usr/bin/certtool y c k=/Library/Keychains/FileVaultMaster.keychain p=<masterPasswordPassword>
        /usr/bin/certtool c   k=/Library/Keychains/FileVaultMaster.keychain o=/Library/Keychains/FileVaultMaster.cer
        Two steps: create the keychain, then create the keypair
    */

    SecAccessRef initialAccess = NULL;

    if (!masterPasswordPassword)
    {
        sec_error("You must supply a non-empty password");
        return -2;
    }

    //  We return an error if the keychain already exists
    OSStatus status = SecKeychainCreate(fvmkcName, (UInt32) strlen(masterPasswordPassword), masterPasswordPassword, false, initialAccess, keychainRef);
    if (status!=noErr)
    {
		if (status==errSecDuplicateKeychain || status==CSSMERR_DL_DATASTORE_ALREADY_EXISTS)
            sec_error("The keychain file %s already exists", fvmkcName);
        return status;
    }

    // Create the key pair
    char host[PATH_MAX];
	int rx = gethostname(host, sizeof(host));
    if (rx)
        strcpy(host, "localhost");

    CFStringRef hostName = CFSTR("FileVault Recovery Key");		// This is what shows up in Keychain Access display
    CFStringRef userName = CFStringCreateWithCString(kCFAllocatorDefault, host, kCFStringEncodingUTF8);
    CFDataRef certData = NULL;
    printf("Generating a %d bit key pair; this may take several minutes\n", keySizeInBits);
    status = createPair(hostName,userName,*keychainRef,keySizeInBits, &certData);
    if (status)
        sec_error("Error in createPair: %s", sec_errstr(status));
    if (certData)
        CFRelease(certData);

    return status;
}
Exemple #4
0
static VALUE rb_create_keychain(int argc, VALUE *argv, VALUE self){
  VALUE password, path;
  rb_scan_args(argc, argv, "11", &path, &password);

  char * c_password = NULL;
  UInt32 passwordLength = 0;
  if(!NIL_P(password)){
    password = rb_str_conv_enc(password, (rb_encoding*)rb_obj_encoding(password), rb_utf8_encoding());
    c_password = StringValueCStr(password);
    passwordLength = (UInt32)strlen(c_password);
  }

  SecKeychainRef keychain;
  OSStatus result =SecKeychainCreate(StringValueCStr(path), passwordLength, c_password, c_password == NULL, NULL, &keychain);
  CheckOSStatusOrRaise(result);

  return KeychainFromSecKeychainRef(keychain);

}
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");
}
void tests(void)
{
	SecKeychainRef keychain = NULL;
	ok_status(SecKeychainCreate("test", 4, "test", FALSE, NULL, &keychain),
		"create keychain");
	ok_status(test_sec_event_register(kSecEveryEventMask),
		"register for all events");
	int item_num;
	int item_count = 9;
	for (item_num = 0; item_num < item_count; ++item_num)
	{
		char account[64];
		sprintf(account, "account-%d", item_num);
		ok_status(SecKeychainAddGenericPassword(keychain, 7, "service",
			strlen(account), account, 4, "test", NULL),
			"add generic password");
	}
	SecKeychainAttribute attrs[] =
	{ { kSecAccountItemAttr } };
	SecKeychainAttributeList attrList =
	{ sizeof(attrs) / sizeof(*attrs), attrs };

	for (item_num = 0; item_num < item_count - 2; ++item_num)
	{
		char account[64];
		sprintf(account, "account-%d", item_num);
		SecKeychainItemRef item = NULL;
		is_sec_event(kSecAddEvent, NULL, &item, NULL, "got add event");

		SKIP: {
			skip("no item", 3, item != NULL);

			ok_status(SecKeychainItemCopyContent(item, NULL, &attrList, NULL,
				NULL), "get content");
			
			eq_stringn(account, strlen(account), attrs[0].data, attrs[0].length,
				"account name in notification matches");
			ok_status(SecKeychainItemFreeContent(&attrList, NULL),
				"free content");
		}
	}

	for (; item_num < item_count; ++item_num)
	{
		char account[64];
		sprintf(account, "account-%d", item_num);
		SecKeychainItemRef item = NULL;
		is_sec_event(kSecAddEvent, NULL, &item, NULL, "got add event");

		SKIP: {
			skip("no item", 3, item != NULL);

			ok_status(SecKeychainItemCopyContent(item, NULL, &attrList, NULL,
				NULL), "get content");
			eq_stringn(account, strlen(account), attrs[0].data, attrs[0].length,
				"account name in notification matches");
			ok_status(SecKeychainItemFreeContent(&attrList, NULL),
				"free content");
		}
	}
	
	ok(tests_end(1), "cleanup");
}