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; }
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 item"); SecKeychainAttribute copyAttrs[] = { { kSecCreationDateItemAttr }, { kSecModDateItemAttr } }; SecKeychainAttributeList copyAttrList = { sizeof(copyAttrs) / sizeof(*copyAttrs), copyAttrs }; ok_status(SecKeychainItemCopyContent(copy, NULL, ©AttrList, 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(©AttrList, 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"); }