]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/regressions/kc-30-xara-item-helpers.h
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-30-xara-item-helpers.h
diff --git a/OSX/libsecurity_keychain/regressions/kc-30-xara-item-helpers.h b/OSX/libsecurity_keychain/regressions/kc-30-xara-item-helpers.h
new file mode 100644 (file)
index 0000000..e2f523c
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "kc-30-xara-helpers.h"
+
+#ifndef kc_30_xara_item_helpers_h
+#define kc_30_xara_item_helpers_h
+
+#if TARGET_OS_MAC
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-function"
+
+
+static CFMutableDictionaryRef makeBaseItemDictionary(CFStringRef itemclass) {
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
+    CFDictionarySetValue(query, kSecClass, itemclass);
+
+    if(CFEqual(itemclass, kSecClassInternetPassword)) {
+        CFDictionarySetValue(query, kSecAttrServer, CFSTR("test_service"));
+        CFDictionarySetValue(query, kSecAttrAuthenticationType, CFSTR("dflt")); // Default, I guess?
+    } else {
+        // Generic passwords have services
+        CFDictionarySetValue(query, kSecAttrService, CFSTR("test_service"));
+    }
+    return query;
+}
+
+static CFMutableDictionaryRef makeQueryItemDictionary(SecKeychainRef kc, CFStringRef itemclass) {
+    CFMutableDictionaryRef query = makeBaseItemDictionary(itemclass);
+
+    CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)searchList, kc);
+    CFDictionarySetValue(query, kSecMatchSearchList, searchList);
+
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    return query;
+}
+
+static CFMutableDictionaryRef makeQueryCustomItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
+    CFMutableDictionaryRef query = makeQueryItemDictionary(kc, itemclass);
+    CFDictionarySetValue(query, kSecAttrLabel, label);
+    return query;
+}
+
+static CFMutableDictionaryRef makeAddCustomItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label, CFStringRef account) {
+    CFMutableDictionaryRef query = makeBaseItemDictionary(itemclass);
+
+    CFDictionaryAddValue(query, kSecUseKeychain, kc);
+    CFDictionarySetValue(query, kSecAttrAccount, account);
+    CFDictionarySetValue(query, kSecAttrComment, CFSTR("a comment"));
+    CFDictionarySetValue(query, kSecAttrLabel, label);
+    CFDictionarySetValue(query, kSecValueData, CFDataCreate(NULL, (void*)"data", 4));
+    return query;
+}
+
+static CFMutableDictionaryRef makeAddItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
+    return makeAddCustomItemDictionary(kc, itemclass, label, CFSTR("test_account"));
+}
+
+static SecKeychainItemRef makeCustomItem(const char* name, SecKeychainRef kc, CFDictionaryRef addDictionary) {
+    CFTypeRef result = NULL;
+    ok_status(SecItemAdd(addDictionary, &result), "%s: SecItemAdd", name);
+    ok(result != NULL, "%s: SecItemAdd returned a result", name);
+
+    SecKeychainItemRef item = (SecKeychainItemRef) result;
+    ok(item != NULL, "%s: Couldn't convert into SecKeychainItemRef", name);
+
+    return item;
+}
+#define makeCustomItemTests 3
+
+static SecKeychainItemRef makeItem(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
+    CFMutableDictionaryRef query = makeAddItemDictionary(kc, itemclass, label);
+
+    SecKeychainItemRef item = makeCustomItem(name, kc, query);
+
+    CFReleaseNull(query);
+    return item;
+}
+#define makeItemTests makeCustomItemTests
+
+static void makeCustomDuplicateItem(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
+    CFMutableDictionaryRef query = makeAddItemDictionary(kc, itemclass, label);
+
+    CFTypeRef result = NULL;
+    is(SecItemAdd(query, &result), errSecDuplicateItem, "%s: SecItemAdd (duplicate)", name);
+
+    CFReleaseNull(query);
+}
+#define makeCustomDuplicateItemTests 1
+
+static void makeDuplicateItem(const char* name, SecKeychainRef kc, CFStringRef itemclass) {
+    return makeCustomDuplicateItem(name, kc, itemclass, CFSTR("test_label"));
+}
+#define makeDuplicateItemTests makeCustomDuplicateItemTests
+
+static void makeCustomItemWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label, CFStringRef expectedHash) {
+    SecKeychainItemRef item = makeItem(name, kc, itemclass, label);
+    checkIntegrityHash(name, item, expectedHash);
+    CFReleaseNull(item);
+}
+#define makeCustomItemWithIntegrityTests (makeItemTests + checkIntegrityHashTests)
+
+static void makeItemWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef expectedHash) {
+    makeCustomItemWithIntegrity(name, kc, itemclass, CFSTR("test_label"), expectedHash);
+}
+#define makeItemWithIntegrityTests (makeCustomItemWithIntegrityTests)
+
+static void testAddItem(CFStringRef itemclass, CFStringRef expectedHash) {
+    char name[100];
+    sprintf(name, "testAddItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    SecKeychainRef kc = newKeychain(name);
+    makeItemWithIntegrity(name, kc, itemclass, expectedHash);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testAddItemTests (newKeychainTests + makeItemWithIntegrityTests + 1)
+
+static void testCopyMatchingItem(CFStringRef itemclass, CFStringRef expectedHash) {
+    char name[100];
+    sprintf(name, "testCopyMatchingItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    SecKeychainRef kc = newKeychain(name);
+    makeItemWithIntegrity(name, kc, itemclass, expectedHash);
+
+    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
+    checkIntegrityHash(name, item, expectedHash);
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testCopyMatchingItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
+
+static void testUpdateItem(CFStringRef itemclass, CFStringRef expectedHashOrig, CFStringRef expectedHashAfter) {
+    char name[100];
+    sprintf(name, "testUpdateItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    SecKeychainRef kc = newKeychain(name);
+    makeItemWithIntegrity(name, kc, itemclass, expectedHashOrig);
+
+    CFMutableDictionaryRef query = makeQueryItemDictionary(kc, itemclass);
+    CFMutableDictionaryRef update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(update, kSecAttrComment, CFSTR("a modification"));
+    CFDictionarySetValue(update, kSecAttrAccount, CFSTR("a account modification"));
+    CFDictionarySetValue(update, kSecAttrLabel, CFSTR("a label modification"));
+    ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
+
+    CFReleaseNull(update);
+
+    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
+    checkIntegrityHash(name, item, expectedHashAfter);
+    CFReleaseNull(item);
+
+    // Check that updating data works
+    update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(update, kSecValueData, CFDataCreate(NULL, (void*)"data", 4));
+    ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
+
+    item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
+    checkIntegrityHash(name, item, expectedHashAfter);
+
+    CFReleaseNull(query);
+    CFReleaseNull(update);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testUpdateItemTests (newKeychainTests + makeItemWithIntegrityTests \
+        + 1 + checkNTests + checkIntegrityHashTests \
+        + 1 + checkNTests + checkIntegrityHashTests \
+        + 1)
+
+static void testAddDuplicateItem(CFStringRef itemclass, CFStringRef expectedHash) {
+    char name[100];
+    sprintf(name, "testAddDuplicateItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    SecKeychainRef kc = newKeychain(name);
+    makeItemWithIntegrity(name, kc, itemclass, expectedHash);
+
+    makeDuplicateItem(name, kc, itemclass);
+
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testAddDuplicateItemTests (newKeychainTests + makeItemWithIntegrityTests + makeDuplicateItemTests + 1)
+
+static void testDeleteItem(CFStringRef itemclass, CFStringRef expectedHash) {
+    char name[100];
+    sprintf(name, "testDeleteItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    SecKeychainRef kc = newKeychain(name);
+    makeItemWithIntegrity(name, kc, itemclass, expectedHash);
+
+    SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
+    checkIntegrityHash(name, item, expectedHash);
+
+    ok_status(SecKeychainItemDelete(item), "%s: SecKeychainItemDelete", name);
+    checkN(name, makeQueryItemDictionary(kc, itemclass), 0);
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testDeleteItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1 + checkNTests + 1)
+
+static void writeEmptyV512Keychain(const char* name, const char* keychainFile);
+
+// This test is to find <rdar://problem/23515265> CrashTracer: accountsd at …curity: Security::KeychainCore::CCallbackMgr::consume + 387
+//
+// The issue was that items could remain in the Keychain cache, even after the
+// actual object was freed. The main path involved updating an item so that it
+// had the same primary key as an item which was in the cache but not in the
+// database (this could be caused by another process deleting the item and us
+// not receiving the notification).
+//
+// This test should pass. Failure is shown by crashing.
+//
+static void testUpdateRetainedItem(CFStringRef itemclass) {
+    char name[100];
+    sprintf(name, "testUpdateRetainedItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
+    secdebugfunc("integrity", "************************************* %s", name);
+
+    writeEmptyV512Keychain(name, keychainFile);
+    SecKeychainRef kc = openCustomKeychain(name, "test.keychain", "password");
+
+    SecKeychainItemRef item = makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("test_label"), CFSTR("account1")));
+
+    CFRelease(checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("test_label")), 1));
+
+    is(CFGetRetainCount(item), 1, "%s: CFGetRetainCount(item)", name);
+
+    // Bump our local database version number a few times, so we'll re-read the database when we reset it later
+    CFReleaseSafe(makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("version"), CFSTR("version"))));
+    CFReleaseSafe(makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("bump"), CFSTR("bump"))));
+
+    // Simulate another process deleting the items we just made, and us not receiving the notification
+    writeEmptyV512Keychain(name, keychainFile);
+
+    // Generate some keychain notifications on a different keychain so the AppleDatabase will reload test.keychain
+    SecKeychainRef kc2 = newCustomKeychain(name, "unrelated.keychain", "password");
+    CFReleaseSafe(makeCustomItem(name, kc2, makeAddCustomItemDictionary(kc, itemclass, CFSTR("unrelated1_label"), CFSTR("unrelated1"))));
+    ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", name);
+
+    secdebugfunc("integrity", "************************************* should reload database\n");
+
+    SecKeychainItemRef item2 = makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label"), CFSTR("account2")));
+    CFReleaseSafe(checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label")), 1));
+    is(CFGetRetainCount(item2), 1, "%s: CFGetRetainCount(item2)", name);
+
+    // Now, update the second item so it would collide with the first
+    CFMutableDictionaryRef query = makeQueryCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label"));
+    CFMutableDictionaryRef update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(update, kSecAttrAccount, CFSTR("account1"));
+    CFDictionarySetValue(update, kSecAttrLabel, CFSTR("test_label"));
+    ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
+
+    is(CFGetRetainCount(item), 1, "%s: CFGetRetainCount(item)", name);
+    CFReleaseNull(item);
+
+    SecKeychainItemRef result = checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("test_label")), 1);
+    CFReleaseNull(result);
+    ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
+}
+#define testUpdateRetainedItemTests (openCustomKeychainTests + makeCustomItemTests + checkNTests \
+        + 1 + makeCustomItemTests + makeCustomItemTests \
+        + newCustomKeychainTests + makeCustomItemTests + 1 \
+        + makeCustomItemTests + checkNTests + 1 \
+        + 1 + 1 + checkNTests + 1)
+
+#pragma clang pop
+#else
+
+#endif /* TARGET_OS_MAC */
+
+
+#endif /* kc_30_xara_item_helpers_h */