]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/regressions/kc-30-xara.c
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-30-xara.c
index 469aab6593e9d3dbb304395020bbc2baa5e62af5..e10f600a0d1da551442255647af391530ff1cc6d 100644 (file)
@@ -31,6 +31,9 @@
 #include <TargetConditionals.h>
 #include <Security/cssmapi.h>
 #include <stdlib.h>
 #include <TargetConditionals.h>
 #include <Security/cssmapi.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <copyfile.h>
+#include <unistd.h>
 
 #include "kc-30-xara-item-helpers.h"
 #include "kc-30-xara-key-helpers.h"
 
 #include "kc-30-xara-item-helpers.h"
 #include "kc-30-xara-key-helpers.h"
@@ -54,7 +57,7 @@ static CSSM_API_MEMORY_FUNCS memFuncs = { cssmMalloc, cssmFree, cssmRealloc, css
 
 static CSSM_DL_DB_HANDLE initializeDL() {
     CSSM_VERSION version = { 2, 0 };
 
 static CSSM_DL_DB_HANDLE initializeDL() {
     CSSM_VERSION version = { 2, 0 };
-    CSSM_DL_DB_HANDLE dldbHandle;
+    CSSM_DL_DB_HANDLE dldbHandle = { 0, 0 };
     CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
     CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
 
     CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
     CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
 
@@ -121,86 +124,100 @@ static void modifyAttributeInKeychain(char * name, CSSM_DL_DB_HANDLE dldbHandle,
 
 static void testAttackItem(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAttackItem";
 
 static void testAttackItem(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAttackItem";
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     SecKeychainRef kc = newKeychain(name);
 
     SecKeychainRef kc = newKeychain(name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
 
     makeItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
 
     makeItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
-    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    CFReleaseNull(item);
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
 
     kc = openKeychain(name);
 
     kc = openKeychain(name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL);
+
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 }
-#define testAttackItemTests (newKeychainTests + checkNTests + makeItemWithIntegrityTests + checkNTests + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + 1)
+#define testAttackItemTests (newKeychainTests + checkNTests + makeItemWithIntegrityTests + checkNTests + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + readPasswordContentsWithResultTests + 1)
 
 static void testAttackKey(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAttackKey";
 
 static void testAttackKey(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAttackKey";
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     SecKeychainRef kc = newKeychain(name);
 
     SecKeychainRef kc = newKeychain(name);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
 
     makeKeyWithIntegrity(name, kc, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
 
     makeKeyWithIntegrity(name, kc, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
-    SecKeychainItemRef item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    SecKeychainItemRef item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+
+    checkKeyUse((SecKeyRef) item, errSecSuccess);
+
+    CFReleaseNull(item);
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "Label", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "Label", modification, strlen(modification));
 
     kc = openKeychain(name);
 
     kc = openKeychain(name);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    checkKeyUse((SecKeyRef) item, errSecInvalidItemRef);
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 }
-#define testAttackKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + 1)
+#define testAttackKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkKeyUseTests + modifyAttributeInKeychainTests \
+        + openKeychainTests + checkNTests + checkKeyUseTests + 1)
 
 
 static void testAddAfterCorruptItem(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAddAfterCorruptItem";
 
 
 static void testAddAfterCorruptItem(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAddAfterCorruptItem";
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     SecKeychainRef kc = newKeychain(name);
 
     SecKeychainRef kc = newKeychain(name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
 
     makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("test_label"), CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
 
     makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("test_label"), CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
-    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
-    CFReleaseNull(item);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
 
     makeDuplicateItem(name, kc, kSecClassGenericPassword);
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
 
     makeDuplicateItem(name, kc, kSecClassGenericPassword);
     CFReleaseNull(kc);
 
     char * modification = "evil_application";
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
 
     kc = openKeychain(name);
 
     kc = openKeychain(name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+    SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    deleteItem(item);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
 
     makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("evil_application"), CFSTR("d2aa97b30a1f96f9e61fcade2b00d9f4284976a83a5b68392251ee5ec827f8cc"));
 
     makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("evil_application"), CFSTR("d2aa97b30a1f96f9e61fcade2b00d9f4284976a83a5b68392251ee5ec827f8cc"));
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("evil_application"));
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("evil_application"));
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 #define testAddAfterCorruptItemTests (newKeychainTests + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeDuplicateItemTests \
 }
 #define testAddAfterCorruptItemTests (newKeychainTests + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeDuplicateItemTests \
-        + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeCustomDuplicateItemTests + 1)
+        + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + deleteItemTests \
+        + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeCustomDuplicateItemTests + 1)
 
 static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAddAfterCorruptKey";
 
 static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle) {
     char * name = "testAddAfterCorruptKey";
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     SecKeychainRef kc = newKeychain(name);
 
     SecKeychainRef kc = newKeychain(name);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
 
     // Make a symmetric key
     makeCustomKeyWithIntegrity(name, kc, CFSTR("test_key"), CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
 
 
     // Make a symmetric key
     makeCustomKeyWithIntegrity(name, kc, CFSTR("test_key"), CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
 
-    SecKeychainItemRef item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    SecKeychainItemRef item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
     makeCustomDuplicateKey(name, kc, CFSTR("test_key"));
     CFReleaseNull(item);
 
     makeCustomDuplicateKey(name, kc, CFSTR("test_key"));
     CFReleaseNull(item);
 
@@ -208,36 +225,46 @@ static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle) {
     SecKeyRef pub;
     SecKeyRef priv;
     makeCustomKeyPair(name, kc, CFSTR("test_key_pair"), &pub, &priv);
     SecKeyRef pub;
     SecKeyRef priv;
     makeCustomKeyPair(name, kc, CFSTR("test_key_pair"), &pub, &priv);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
     CFReleaseNull(pub);
     CFReleaseNull(priv);
 
     ok_status(SecKeychainListRemoveKeychain(&kc), "%s: SecKeychainListRemoveKeychain", name);
 
     char * modification = "evil_application";
     CFReleaseNull(pub);
     CFReleaseNull(priv);
 
     ok_status(SecKeychainListRemoveKeychain(&kc), "%s: SecKeychainListRemoveKeychain", name);
 
     char * modification = "evil_application";
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "PrintName", modification, strlen(modification));
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_PUBLIC_KEY, "PrintName", modification, strlen(modification));
-    modifyAttributeInKeychain(name, dldbHandle, keychainFile, CSSM_DL_DB_RECORD_PRIVATE_KEY, "PrintName", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "PrintName", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_PUBLIC_KEY, "PrintName", modification, strlen(modification));
+    modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_PRIVATE_KEY, "PrintName", modification, strlen(modification));
 
     kc = openKeychain(name);
 
     kc = openKeychain(name);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    deleteItem(item);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    deleteItem(item);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+    deleteItem(item);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
 
     makeCustomKeyWithIntegrity(name, kc, CFSTR("evil_application"), CFSTR("ca6d90a0b053113e43bbb67f64030230c96537f77601f66bdf821d8684431dfc"));
 
     makeCustomKeyWithIntegrity(name, kc, CFSTR("evil_application"), CFSTR("ca6d90a0b053113e43bbb67f64030230c96537f77601f66bdf821d8684431dfc"));
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
 
     makeCustomDuplicateKey(name, kc, CFSTR("evil_application"));
 
     makeCustomKeyPair(name, kc, CFSTR("evil_application"), &pub, &priv);
 
     makeCustomDuplicateKey(name, kc, CFSTR("evil_application"));
 
     makeCustomKeyPair(name, kc, CFSTR("evil_application"), &pub, &priv);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
-    checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
 
     // We cannot create a duplicate key pair, so don't try.
 
     CFReleaseNull(item);
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
 
     // We cannot create a duplicate key pair, so don't try.
 
     CFReleaseNull(item);
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 #define testAddAfterCorruptKeyTests (newKeychainTests \
         + checkNTests + checkNTests + checkNTests \
 }
 #define testAddAfterCorruptKeyTests (newKeychainTests \
         + checkNTests + checkNTests + checkNTests \
@@ -248,76 +275,460 @@ static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle) {
         + modifyAttributeInKeychainTests \
         + modifyAttributeInKeychainTests \
         + openKeychainTests \
         + modifyAttributeInKeychainTests \
         + modifyAttributeInKeychainTests \
         + openKeychainTests \
-        + checkNTests + checkNTests + checkNTests \
+        + checkNTests + deleteItemTests + checkNTests \
+        + checkNTests + deleteItemTests + checkNTests \
+        + checkNTests + deleteItemTests + checkNTests \
         + makeCustomKeyWithIntegrityTests + checkNTests \
         + makeCustomDuplicateKeyTests \
         + makeCustomKeyPairTests + checkNTests + checkNTests \
         + 1)
 
 
         + makeCustomKeyWithIntegrityTests + checkNTests \
         + makeCustomDuplicateKeyTests \
         + makeCustomKeyPairTests + checkNTests + checkNTests \
         + 1)
 
 
+// These constants are in CommonBlob, but we're in C and can't access them
+#define version_MacOS_10_0 0x00000100
+#define version_partition 0x00000200
+
 static void testKeychainUpgrade() {
     char name[100];
     sprintf(name, "testKeychainUpgrade");
 static void testKeychainUpgrade() {
     char name[100];
     sprintf(name, "testKeychainUpgrade");
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
+    UInt32 version;
+    char* path = malloc(sizeof(char) * 400);
+    UInt32 len = 400;
+
+    // To test multi-threading, we want the upgrade to take a while. Add a bunch of passwords...
+    char oldkcFile[MAXPATHLEN];
+    snprintf(oldkcFile, sizeof(oldkcFile), "%s/Library/test.keychain", getenv("HOME"));
+    unlink(oldkcFile);
+    writeOldKeychain(name, oldkcFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, oldkcFile, "password");
+
+    for(int i = 0; i < 200; i++) {
+        CFTypeRef result = NULL;
+        CFStringRef cflabel = CFStringCreateWithFormat(NULL, NULL, CFSTR("item%d"), i);
+        CFMutableDictionaryRef query = createAddCustomItemDictionaryWithService(kc, kSecClassInternetPassword, cflabel, cflabel, CFSTR("no service"));
+        SecItemAdd(query, &result); // don't particuluarly care if this fails...
+        CFReleaseNull(query);
+        CFReleaseNull(cflabel);
+        CFReleaseNull(result);
+    }
 
 
-    writeOldKeychain(name, keychainFile);
-    SecKeychainRef kc = openCustomKeychain(name, "test.keychain", "password");
+    CFReleaseNull(kc);
+
+    ok_status(copyfile(oldkcFile, keychainFile, NULL, COPYFILE_UNLINK | COPYFILE_ALL), "%s: copyfile", name);
+    unlink(oldkcFile);
+    unlink(keychainDbFile);
 
 
+    static dispatch_once_t onceToken = 0;
+    static dispatch_queue_t release_queue = NULL;
+    dispatch_once(&onceToken, ^{
+        release_queue = dispatch_queue_create("com.apple.security.keychain-upgrade-queue", DISPATCH_QUEUE_CONCURRENT);
+    });
+
+    dispatch_group_t g = dispatch_group_create();
     SecKeychainItemRef item;
 
     SecKeychainItemRef item;
 
-    item = checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    char* __block blockName = NULL;
+    asprintf(&blockName, "%s", name);
+
+    kc = openCustomKeychain(name, keychainName, "password");
+
+    // Directly after an upgrade, no items should have partition ID lists
+    dispatch_group_async(g, release_queue, ^() {
+        secerror("beginning 1\n");
+        SecKeychainRef blockKc;
+        SecKeychainOpen(keychainName, &blockKc);
+        SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryItemDictionary(blockKc, kSecClassGenericPassword), 1);
+        checkIntegrityHash(blockName, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
+        checkPartitionIDs(blockName, item, 0);
+        CFReleaseSafe(blockKc);
+        CFReleaseSafe(item);
+        secerror("ending 1\n");
+    });
+
+    dispatch_group_async(g, release_queue, ^() {
+        usleep(0.1 * USEC_PER_SEC); // use different timings to try to find multithreaded upgrade bugs
+        secerror("beginning 2\n");
+        SecKeychainRef blockKc;
+        SecKeychainOpen(keychainName, &blockKc);
+        SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryItemDictionaryWithService(blockKc, kSecClassInternetPassword, CFSTR("test_service")), 1);
+        checkIntegrityHash(blockName, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
+        checkPartitionIDs(blockName, item, 0);
+        CFReleaseSafe(blockKc);
+        CFReleaseSafe(item);
+        secerror("ending 2\n");
+    });
+
+    dispatch_group_async(g, release_queue, ^() {
+        usleep(0.3 * USEC_PER_SEC);
+        secerror("beginning 3\n");
+        SecKeychainRef blockKc;
+        SecKeychainOpen(keychainName, &blockKc);
+        SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassSymmetric), 1);
+        checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
+        checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
+        CFReleaseSafe(blockKc);
+        CFReleaseSafe(item);
+        secerror("ending 3\n");
+    });
+
+    dispatch_group_async(g, release_queue, ^() {
+        usleep(0.5 * USEC_PER_SEC);
+        secerror("beginning 4\n");
+        SecKeychainRef blockKc;
+        SecKeychainOpen(keychainName, &blockKc);
+        SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassPublic), 1);
+        checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
+        checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
+        CFReleaseSafe(blockKc);
+        CFReleaseSafe(item);
+        secerror("ending 4\n");
+    });
+
+    dispatch_group_async(g, release_queue, ^() {
+        usleep(1 * USEC_PER_SEC);
+        secerror("beginning 5\n");
+        SecKeychainRef blockKc;
+        SecKeychainOpen(keychainName, &blockKc);
+        SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassPrivate), 1);
+        checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
+        checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
+        CFReleaseSafe(blockKc);
+        CFReleaseSafe(item);
+        secerror("ending 5\n");
+    });
+
+    dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
+
+    // @@@ I'm worried that there are still some thread issues in AppleDatabase; if these are run in the blocks above
+    //     you can sometimes get CSSMERR_DL_INVALID_RECORD_UID/errSecInvalidRecord instead of errSecDuplicateItem
+    //     <rdar://problem/27085024> Multi-threading duplicate item creation sometimes returns -67701
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+    makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
+
+    // Check the keychain's version and path
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_partition, "%s: version of upgraded keychain is incorrect", name);
+    ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetKeychainPath", name);
+    eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
+    free(path);
+
+    // Now close the keychain and open it again
+    CFReleaseNull(kc);
+    kc = openCustomKeychain(name, keychainName, "password");
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
     checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
     checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
+    checkPartitionIDs(name, item, 0);
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
 
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
 
-    item = checkN(name, makeQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
     checkIntegrityHash(name, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
     checkIntegrityHash(name, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
+    checkPartitionIDs(name, item, 0);
     makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
 
     makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
+    checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
 
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
+    checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
 
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
+    checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
 
 
-    // Now close the keychain and open it again
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
     CFReleaseNull(kc);
     CFReleaseNull(kc);
-    kc = openCustomKeychain(name, "test.keychain", "password");
 
 
-    item = checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    // make sure we clean up any files left over
+    unlink(keychainDbFile);
+    unlink(keychainFile);
+    unlink(oldkcFile);
+}
+#define testKeychainUpgradeTests (openCustomKeychainTests + 1 + openCustomKeychainTests + 4 \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + openCustomKeychainTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
+        + 1)
+
+// tests that SecKeychainCreate over an old .keychain file returns an empty keychain
+static void testKeychainCreateOver() {
+    char name[100];
+    sprintf(name, "testKeychainCreateOver");
+    secnotice("integrity", "************************************* %s", name);
+    UInt32 version;
+    char* path = malloc(sizeof(char) * 400);
+    UInt32 len = 400;
+
+    writeOldKeychain(name, keychainFile);
+    unlink(keychainDbFile);
+
+    SecKeychainItemRef item = NULL;
+
+    // Check that we upgrade on SecKeychainOpen
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
     checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
     checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
+    CFReleaseNull(item);
+
+    ok_status(SecKeychainDelete(kc));
+    CFReleaseNull(kc);
+
+    // the old file should still exist, but the -db file should not.
+    struct stat filebuf;
+    is(stat(keychainFile, &filebuf), 0, "%s: check %s exists", name, keychainFile);
+    isnt(stat(keychainDbFile, &filebuf), 0, "%s: check %s does not exist", name, keychainDbFile);
+
+    // Now create a new keychain over the old remnants.
+    ok_status(SecKeychainCreate(keychainFile, (UInt32) strlen("password"), "password", false, NULL, &kc), "%s: SecKeychainCreate", name);
+
+    // Directly after creating a keychain, there shouldn't be any items (even though an old keychain exists underneath)
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+    checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
+
+    // Check the keychain's version and path
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_partition, "%s: version of upgraded keychain is incorrect", name);
+    ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetKeychainPath", name);
+    eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
+    free(path);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+
+    // final check that the files on-disk are as we expect
+    is(stat(keychainFile, &filebuf), 0, "%s: check %s exists", name, keychainFile);
+    isnt(stat(keychainDbFile, &filebuf), 0, "%s: check %s does not exist", name, keychainDbFile);
+
+    // make sure we clean up any files left over
+    unlink(keychainDbFile);
+    unlink(keychainFile);
+}
+#define testKeychainCreateOverTests (openCustomKeychainTests + \
++ checkNTests + checkIntegrityHashTests \
++ 1 + 2 + 1 \
++ checkNTests \
++ checkNTests \
++ checkNTests \
++ checkNTests \
++ checkNTests \
++ 4 + 1 + 2)
+
+static void testKeychainDowngrade() {
+    char *name = "testKeychainDowngrade";
+    secnotice("integrity", "************************************* %s", name);
+
+    // For now, don't worry about filenames
+    writeFullV512Keychain(name, keychainDbFile);
+    unlink(keychainFile);
+    writeFullV512Keyfile(name, keychainTempFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+    UInt32 version;
+
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_partition, "%s: version of initial keychain is incorrect", name);
+
+    SecKeychainItemRef item;
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    checkIntegrityHash(name, item, CFSTR("6ba8d9f77ddba54d9373b11ae5c8f7b55a5e81da27e05e86723eeceb0a9a8e0c"));
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
 
     makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
 
-    item = checkN(name, makeQueryItemDictionary(kc, kSecClassInternetPassword), 1);
-    checkIntegrityHash(name, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    checkIntegrityHash(name, item, CFSTR("630a9fe4f0191db8a99d6e8455e7114f628ce8f0f9eb3559efa572a98877a2b2"));
     makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
 
     makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
 
     checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
-    checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("d27ee2be4920d5b6f47f6b19696d09c9a6c1a5d80c6f148f778db27b4ba99d9a"));
 
 
-    item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
-    checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+    checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("4b3f7bd7f9e48dc71006ce670990aed9dba6d5089b84d4113121bab41d0a3228"));
+
+
+
+    ok_status(SecKeychainAttemptMigrationWithMasterKey(kc, version_MacOS_10_0, keychainTempFile), "%s: SecKeychainAttemptKeychainMigrationWithMasterKey", name);
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_MacOS_10_0, "%s: version of downgraded keychain is incorrect", name);
+
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+    checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
+
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+
+    // make sure we clean up
+    unlink(keychainTempFile);
+    unlink(keychainDbFile);
+    unlink(keychainFile);
 }
 }
-#define testKeychainUpgradeTests (openCustomKeychainTests \
-        + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
-        + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
-        + checkNTests + checkIntegrityHashTests + \
-        + checkNTests + checkIntegrityHashTests + \
-        + checkNTests + checkIntegrityHashTests + \
-        + openCustomKeychainTests \
+#define testKeychainDowngradeTests (openCustomKeychainTests + 2 \
         + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
         + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
         + checkNTests + checkIntegrityHashTests +\
         + checkNTests + checkIntegrityHashTests +\
         + checkNTests + checkIntegrityHashTests +\
         + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
         + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
         + checkNTests + checkIntegrityHashTests +\
         + checkNTests + checkIntegrityHashTests +\
         + checkNTests + checkIntegrityHashTests +\
-        1)
+        + 3 + \
+        + checkNTests + makeCustomDuplicateItemTests \
+        + checkNTests + makeCustomDuplicateItemTests \
+        + checkNTests \
+        + checkNTests \
+        + checkNTests \
+        + 1)\
+
+// Test opening and upgrading a v256 keychain at a -db filename.
+static void testKeychainWrongFile256() {
+    char name[100];
+    sprintf(name, "testKeychainWrongFile256");
+    secnotice("integrity", "************************************* %s", name);
+    UInt32 version;
+
+    unlink(keychainFile);
+    writeOldKeychain(name, keychainDbFile);
+
+    // Only keychainDb file should exist
+    struct stat filebuf;
+    isnt(stat(keychainFile, &filebuf), 0, "%s: %s exists and shouldn't", name, keychainFile);
+    is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+
+    SecKeychainItemRef item;
+
+    // Iterate over the keychain to trigger upgrade
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+
+    // We should have created keychainFile, check for it
+    is(stat(keychainFile, &filebuf), 0, "%s: %s does not exist", name, keychainFile);
+    is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
+
+    // Check the keychain's version and path
+    char path[400];
+    UInt32 len = sizeof(path);
+
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_partition, "%s: version of re-upgraded keychain is incorrect", name);
+    ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetPath", name);
+    eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+
+    // make sure we clean up any files left over
+    unlink(keychainDbFile);
+    unlink(keychainFile);
+}
+#define testKeychainWrongFile256Tests (2 + openCustomKeychainTests \
+        + checkNTests + makeCustomDuplicateItemTests \
+        + 2 + 4 \
+        + checkNTests + makeCustomDuplicateItemTests \
+        + checkNTests + makeCustomDuplicateItemTests \
+        + checkNTests \
+        + checkNTests \
+        + checkNTests \
+        + 1)
+
+// Test opening and upgrading a v512 keychain at a .keychain filename.
+static void testKeychainWrongFile512() {
+    char name[100];
+    sprintf(name, "testKeychainWrongFile512");
+    secnotice("integrity", "************************************* %s", name);
+    UInt32 version;
+
+    writeFullV512Keychain(name, keychainFile);
+    unlink(keychainDbFile);
+
+    // Only keychain file should exist
+    struct stat filebuf;
+    isnt(stat(keychainDbFile, &filebuf), 0, "%s: %s exists and shouldn't", name, keychainFile);
+    is(stat(keychainFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+
+    SecKeychainItemRef item;
+
+    // Iterate over the keychain to trigger upgrade
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+
+    // We should have move the keychain to keychainDbFile, check for it
+    isnt(stat(keychainFile, &filebuf), 0, "%s: %s still exists", name, keychainFile);
+    is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
+
+    // Check the keychain's version and path
+    char path[400];
+    UInt32 len = sizeof(path);
+
+    ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
+    is(version, version_partition, "%s: version of moved keychain is incorrect", name);
+    ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetPath", name);
+    eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+
+    // make sure we clean up any files left over
+    unlink(keychainDbFile);
+    unlink(keychainFile);
+}
+#define testKeychainWrongFile512Tests (2 + openCustomKeychainTests \
++ checkNTests + makeCustomDuplicateItemTests \
++ 2 + 4 \
++ checkNTests + makeCustomDuplicateItemTests \
++ checkNTests + makeCustomDuplicateItemTests \
++ checkNTests \
++ checkNTests \
++ checkNTests \
++ 1)
+
+
+#undef version_partition
+#undef version_MacOS_10_0
 
 static SecAccessRef makeUidAccess(uid_t uid)
 {
 
 static SecAccessRef makeUidAccess(uid_t uid)
 {
@@ -399,22 +810,23 @@ static void checkAccessLength(const char * name, SecAccessRef access, int expect
 static void testUidAccess() {
     char name[100];
     sprintf(name, "testUidAccess");
 static void testUidAccess() {
     char name[100];
     sprintf(name, "testUidAccess");
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     SecAccessRef access = makeUidAccess(getuid());
 
     SecKeychainRef kc = newKeychain(name);
 
     SecAccessRef access = makeUidAccess(getuid());
 
     SecKeychainRef kc = newKeychain(name);
-    CFMutableDictionaryRef query = makeAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
+    CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
+    CFReleaseNull(query);
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
-    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
 
     ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
 
     ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
 
     // Check to make sure the ACL stays
     access = NULL;
 
     // Check to make sure the ACL stays
     access = NULL;
@@ -429,6 +841,7 @@ static void testUidAccess() {
     checkAccessLength(name, access, 2);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
     checkAccessLength(name, access, 2);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 #define testUidAccessTests (newKeychainTests + 2 + checkNTests + 1 + checkNTests + 1 + checkAccessLengthTests \
         + 2 + checkAccessLengthTests + 1)
 }
 #define testUidAccessTests (newKeychainTests + 2 + checkNTests + 1 + checkNTests + 1 + checkAccessLengthTests \
         + 2 + checkAccessLengthTests + 1)
@@ -495,7 +908,7 @@ static SecAccessRef makeMultipleUidAccess(uid_t* uids, uint32 count)
 static void testMultipleUidAccess() {
     char name[100];
     sprintf(name, "testMultipleUidAccess");
 static void testMultipleUidAccess() {
     char name[100];
     sprintf(name, "testMultipleUidAccess");
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
 
     uid_t uids[5];
     uids[0] = getuid();
 
     uid_t uids[5];
     uids[0] = getuid();
@@ -507,44 +920,142 @@ static void testMultipleUidAccess() {
     SecAccessRef access = makeMultipleUidAccess(uids, 5);
 
     SecKeychainRef kc = newKeychain(name);
     SecAccessRef access = makeMultipleUidAccess(uids, 5);
 
     SecKeychainRef kc = newKeychain(name);
-    CFMutableDictionaryRef query = makeAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
+    CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
+    CFReleaseNull(query);
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 #define testMultipleUidAccessTests (newKeychainTests + checkNTests + 3)
 
 static void testRootUidAccess() {
     char name[100];
     sprintf(name, "testRootUidAccess");
 }
 #define testMultipleUidAccessTests (newKeychainTests + checkNTests + 3)
 
 static void testRootUidAccess() {
     char name[100];
     sprintf(name, "testRootUidAccess");
-    secdebugfunc("integrity", "************************************* %s", name);
+    secnotice("integrity", "************************************* %s", name);
+
+    CFErrorRef error = NULL;
 
 
-    SecAccessRef access = SecAccessCreateWithOwnerAndACL(getuid(), 0, (kSecUseOnlyUID | kSecHonorRoot), NULL, NULL);
+    SecAccessRef access = SecAccessCreateWithOwnerAndACL(getuid(), 0, (kSecUseOnlyUID | kSecHonorRoot), NULL, &error);
+    ok(access, "%s: SecAccessCreateWithOwnerAndACL returned an access", name);
+    CFStringRef errorDesc = error ? CFErrorCopyDescription(error) : NULL;
+    is(error, NULL, "%s: SecAccessCreateWithOwnerAndACL did not return an error: %@", name, errorDesc ? errorDesc : CFSTR("no error"));
+    CFReleaseNull(errorDesc);
 
     SecKeychainRef kc = newKeychain(name);
 
     SecKeychainRef kc = newKeychain(name);
-    CFMutableDictionaryRef query = makeAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
+    CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
     CFDictionarySetValue(query, kSecAttrAccess, access);
 
     CFTypeRef result = NULL;
     ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
+    CFReleaseNull(query);
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
     ok(result != NULL, "%s: SecItemAdd returned a result", name);
 
-    query = makeQueryItemDictionary(kc, kSecClassGenericPassword);
+    query = createQueryItemDictionary(kc, kSecClassGenericPassword);
 
 
-    SecKeychainItemRef item = checkN(name, query, 1);
+    SecKeychainItemRef item = checkNCopyFirst(name, query, 1);
 
     ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
 
     ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
-    checkN(name, makeQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    CFReleaseNull(access);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
 
     ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
 }
 }
-#define testRootUidAccessTests (newKeychainTests + checkNTests + 4 + checkNTests)
+#define testRootUidAccessTests (newKeychainTests + 2 + checkNTests + 4 + checkNTests)
+
+static void testBadACL() {
+    char name[100];
+    sprintf(name, "testBadACL");
+    secnotice("integrity", "************************************* %s", name);
+
+    SecKeychainItemRef item = NULL;
+
+    unlink(keychainFile);
+    writeFullV512Keychain(name, keychainDbFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+
+    // Check that these exist in this keychain...
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFRelease(kc);
+
+    // Corrupt all the ACLs, by changing the partition id plist entry
+    uint8_t * fileBuffer = (uint8_t*) malloc(FULL_V512_SIZE);
+    memcpy(fileBuffer, full_v512, FULL_V512_SIZE);
+
+    void* p;
+    char * str = "<key>Partitions</key>";
+    while( (p = memmem(fileBuffer, FULL_V512_SIZE, (void*) str, strlen(str))) ) {
+        *(uint8_t*) p = 0;
+    }
+    writeFile(keychainDbFile, fileBuffer, FULL_V512_SIZE);
+    free(fileBuffer);
+
+    kc = openCustomKeychain(name, keychainName, "password");
+
+    // These items exist in this keychain, but their ACL is corrupted. We should be able to find them, but not fetch data.
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL); // we don't expect to be able to read this
+    deleteItem(item);
+    checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL); // we don't expect to be able to read this
+    deleteItem(item);
+    checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 0);
+
+    // These should work
+    makeItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
+    makeItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
+
+    // And now the items should exist
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    readPasswordContents(item, CFSTR("data"));
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+    readPasswordContents(item, CFSTR("data"));
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+}
+#define testBadACLTests (openCustomKeychainTests + checkNTests * 2 + 1 + openCustomKeychainTests \
+       + 2*(checkNTests + readPasswordContentsWithResultTests + deleteItemTests + checkNTests) \
+       + makeItemTests*2 + checkNTests*2 + readPasswordContentsTests*2 + 1)
+
+static void testIterateLockedKeychain() {
+    char name[100];
+    sprintf(name, "testIterateLockedKeychain");
+    secnotice("integrity", "************************************* %s", name);
+
+    SecKeychainItemRef item = NULL;
+
+    unlink(keychainFile);
+    writeFullV512Keychain(name, keychainDbFile);
+
+    SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
+
+    ok_status(SecKeychainLock(kc), "%s: SecKeychainLock", name);
+
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
+    item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
+
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
+    item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+    CFReleaseNull(kc);
+}
+#define testIterateLockedKeychainTests (openCustomKeychainTests + 1 + checkNTests*5 + 1)
 
 #define kTestCount (0 \
        + testAddItemTests \
 
 #define kTestCount (0 \
        + testAddItemTests \
@@ -576,16 +1087,31 @@ static void testRootUidAccess() {
        + unloadDLTests \
        \
        + testKeychainUpgradeTests \
        + unloadDLTests \
        \
        + testKeychainUpgradeTests \
+       + testKeychainCreateOverTests \
+       + testKeychainDowngradeTests \
+       + testKeychainWrongFile256Tests \
+       + testKeychainWrongFile512Tests \
        + testUidAccessTests \
        + testMultipleUidAccessTests \
        + testRootUidAccessTests \
        + testUidAccessTests \
        + testMultipleUidAccessTests \
        + testRootUidAccessTests \
+       + testBadACLTests \
+       + testIterateLockedKeychainTests \
        )
 
 static void tests(void)
 {
        )
 
 static void tests(void)
 {
-    const char *home_dir = getenv("HOME");
-    sprintf(keychainFile, "%s/Library/Keychains/test.keychain", home_dir);
-    sprintf(keychainName, "test.keychain");
+    initializeKeychainTests("kc-30-xara");
+
+    testKeychainUpgrade();
+    testKeychainCreateOver();
+    testKeychainDowngrade();
+    testKeychainWrongFile256();
+    testKeychainWrongFile512();
+    testUidAccess();
+    testMultipleUidAccess();
+    testRootUidAccess();
+    testBadACL();
+    testIterateLockedKeychain();
 
     testAddItem(kSecClassGenericPassword,  CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
     testAddItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
 
     testAddItem(kSecClassGenericPassword,  CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
     testAddItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
@@ -626,15 +1152,10 @@ static void tests(void)
     testAddAfterCorruptKey(dldbHandle);
     unloadDL(&dldbHandle);
 
     testAddAfterCorruptKey(dldbHandle);
     unloadDL(&dldbHandle);
 
-    testKeychainUpgrade();
-    testUidAccess();
-    testMultipleUidAccess();
-    testRootUidAccess();
-
     //makeOldKeychainBlob();
 }
 
     //makeOldKeychainBlob();
 }
 
-#pragma clang pop
+#pragma clang diagnostic pop
 #else
 
 #define kTestCount (0)
 #else
 
 #define kTestCount (0)
@@ -653,5 +1174,6 @@ int kc_30_xara(int argc, char *const *argv)
 
     tests();
 
 
     tests();
 
+    deleteTestFiles();
     return 0;
 }
     return 0;
 }