Esempio n. 1
0
static int
do_keychain_export(const char *backupPath, const char *keybagPath, const char *passwordString)
{
    CFDataRef backup=NULL;
    CFDataRef keybag=NULL;
    CFDataRef password=NULL;
    bool ok=false;

    if(passwordString) {
        require(password = CFDataCreate(NULL, (UInt8 *)passwordString, strlen(passwordString)), out);
    }
    require(keybag=copyFileContents(keybagPath), out);
    require(backup=_SecKeychainCopyBackup(keybag, password), out);

    ok=writeFileContents(backupPath, backup);

out:
    CFReleaseSafe(backup);
    CFReleaseSafe(keybag);
    CFReleaseSafe(password);

    return ok?0:1;
}
/* Test low level keychain migration from device to device interface. */
static void tests(void)
{
    int v_eighty = 80;
    CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
    const char *v_data = "test";
    CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
    CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net"));
    CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith"));
    CFDictionaryAddValue(query, kSecAttrPort, eighty);
    CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP);
    CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault);
    CFDictionaryAddValue(query, kSecValueData, pwdata);
    // NUKE anything we might have left around from a previous test run so we don't crash.
    SecItemDelete(query);
    ok_status(SecItemAdd(query, NULL), "add internet password");
    is_status(SecItemAdd(query, NULL), errSecDuplicateItem,
	"add internet password again");

    ok_status(SecItemCopyMatching(query, NULL), "Found the item we added");

    struct test_persistent_s p = {};
    test_persistent(&p);

    CFDataRef backup = NULL, keybag = NULL, password = NULL;

    test_add_lockdown_identity_items();

#if USE_KEYSTORE
    keybag = create_keybag(kAppleKeyStoreBackupBag, password);
#else
    keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0);
#endif

    ok(backup = _SecKeychainCopyBackup(keybag, password),
        "_SecKeychainCopyBackup");

    test_add_managedconfiguration_item();
    test_remove_lockdown_identity_items();

    ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
        "_SecKeychainRestoreBackup");
    CFReleaseSafe(backup);

    test_no_find_lockdown_identity_item();
    test_find_managedconfiguration_item();

    ok_status(SecItemCopyMatching(query, NULL),
        "Found the item we added after restore");

    test_persistent2(&p);

#if USE_KEYSTORE
    CFReleaseNull(keybag);
    keybag = create_keybag(kAppleKeyStoreOTABackupBag, password);
#endif

    ok(backup = _SecKeychainCopyBackup(keybag, password),
       "_SecKeychainCopyBackup");
    ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
              "_SecKeychainRestoreBackup");
    ok_status(SecItemCopyMatching(query, NULL),
              "Found the item we added after restore");
    CFReleaseNull(backup);

    // force tombstone to be added, since it's not the default behavior per rdar://14680869
    CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue);

    ok_status(SecItemDelete(query), "Deleted item we added");

#if USE_KEYSTORE
    CFReleaseNull(keybag);
    keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password);
#endif

    // add syncable item
    CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue);
    ok_status(SecItemAdd(query, NULL), "add internet password");

    // and non-syncable item
    test_add_managedconfiguration_item();

    CFDictionaryRef syncableBackup = NULL;

    CFErrorRef error = NULL;
    CFDictionaryRef scratch = NULL;
    SKIP: {
        skip("skipping syncable backup tests", 7,
             ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items"));

        // TODO: add item, call SecServerCopyTruthInTheCloud again

        // CFShow(syncableBackup);

        // find and delete
        skip("skipping syncable backup tests", 6,
             ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy"));

        skip("skipping syncable backup tests", 5,
             ok_status(SecItemDelete(query), "delete item we backed up"));

        // ensure we added a tombstone
        CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue);
        skip("skipping syncable backup tests", 4,
             ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted"));
        CFDictionaryRemoveValue(query, kSecAttrTombstone);

        test_find_managedconfiguration_item(); // <- 2 tests here

        // TODO: add a different new item - delete what's not in the syncableBackup?

        // Do another backup after some changes
        skip("skipping syncable backup tests", 1,
             ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes"));

        skip("skipping syncable backup tests", 0,
             ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items"));
    }
    CFReleaseNull(scratch);
    CFReleaseNull(error);

    // non-syncable item should (still) be gone -> add should work
    test_add_managedconfiguration_item();
    test_find_managedconfiguration_item();

    // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail
    is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL),
              "find restored item");
    is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item");

    CFReleaseSafe(syncableBackup);
    CFReleaseSafe(keybag);
    CFReleaseSafe(eighty);
    CFReleaseSafe(pwdata);
    CFReleaseSafe(query);
}