]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/regressions/kc-helpers.h
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-helpers.h
diff --git a/OSX/libsecurity_keychain/regressions/kc-helpers.h b/OSX/libsecurity_keychain/regressions/kc-helpers.h
new file mode 100644 (file)
index 0000000..f5402b3
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2016 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@
+ */
+
+#ifndef kc_helpers_h
+#define kc_helpers_h
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <Security/Security.h>
+#include <Security/SecKeychainPriv.h>
+#include "utilities/SecCFRelease.h"
+
+#include "kc-keychain-file-helpers.h"
+
+/* redefine this since the headers are mixed up */
+static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
+{
+    if (left == NULL || right == NULL)
+        return left == right;
+    else
+        return CFEqual(left, right);
+}
+
+static char keychainFile[1000];
+static char keychainDbFile[1000];
+static char keychainTempFile[1000];
+static char keychainName[1000];
+static char testName[1000];
+static uint32_t promptAttempts;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-function"
+
+static void startTest(const char* thisTestName) {
+    strlcpy(testName, thisTestName, sizeof(testName));
+}
+
+static void initializeKeychainTests(const char* thisTestName) {
+    const char *home_dir = getenv("HOME");
+    sprintf(keychainName, "test-%s.asdf", thisTestName);
+    sprintf(keychainFile, "%s/Library/Keychains/%s", home_dir, keychainName);
+    sprintf(keychainDbFile, "%s/Library/Keychains/%s-db", home_dir, keychainName);
+    sprintf(keychainTempFile, "%s/Library/Keychains/test_temp", home_dir);
+
+    deleteKeychainFiles(keychainFile);
+
+    startTest(thisTestName);
+
+    SecKeychainGetUserPromptAttempts(&promptAttempts);
+    SecKeychainSetUserInteractionAllowed(FALSE);
+}
+
+// Use this at the bottom of every test to make sure everything is gone
+static void deleteTestFiles() {
+    deleteKeychainFiles(keychainFile);
+}
+
+static SecKeychainRef getPopulatedTestKeychain() {
+    deleteKeychainFiles(keychainFile);
+
+    writeFile(keychainFile, test_keychain, sizeof(test_keychain));
+
+    SecKeychainRef kc = NULL;
+    ok_status(SecKeychainOpen(keychainFile, &kc), "%s: getPopulatedTestKeychain: SecKeychainOpen", testName);
+    ok_status(SecKeychainUnlock(kc, (UInt32) strlen(test_keychain_password), test_keychain_password, true), "%s: getPopulatedTestKeychain: SecKeychainUnlock", testName);
+    return kc;
+}
+#define getPopulatedTestKeychainTests 2
+
+static void addToSearchList(SecKeychainRef keychain) {
+    CFArrayRef searchList = NULL;
+    SecKeychainCopySearchList(&searchList);
+    CFMutableArrayRef mutableSearchList = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(searchList) + 1, searchList);
+    CFArrayAppendValue(mutableSearchList, keychain);
+    SecKeychainSetSearchList(mutableSearchList);
+    CFRelease(searchList);
+    CFRelease(mutableSearchList);
+}
+
+
+/* Checks to be sure there are N elements in this search, and returns the first
+ * if it exists. */
+static SecKeychainItemRef checkN(char* testName, const CFDictionaryRef query, uint32_t n) {
+    CFArrayRef results = NULL;
+    if(n > 0) {
+        ok_status(SecItemCopyMatching(query, (CFTypeRef*) &results), "%s: SecItemCopyMatching", testName);
+    } else {
+        is(SecItemCopyMatching(query, (CFTypeRef*) &results), errSecItemNotFound, "%s: SecItemCopyMatching (for no items)", testName);
+    }
+
+    SecKeychainItemRef item = NULL;
+    if(results) {
+        is(CFArrayGetCount(results), n, "%s: Wrong number of results", testName);
+        if(n >= 1) {
+            ok(item = (SecKeychainItemRef) CFArrayGetValueAtIndex(results, 0), "%s: Couldn't get item", testName);
+        } else {
+            pass("make test numbers match");
+        }
+    } else if((!results) && n == 0) {
+        pass("%s: no results found (and none expected)", testName);
+        pass("make test numbers match");
+    } else {
+        fail("%s: no results found (and %d expected)", testName, n);
+        fflush(stdout); CFShow(query); fflush(stdout);
+        pass("make test numbers match");
+    }
+
+    CFRelease(query);
+    return item;
+}
+#define checkNTests 3
+
+
+static void readPasswordContentsWithResult(SecKeychainItemRef item, OSStatus expectedResult, CFStringRef expectedContents) {
+    if(!item) {
+        fail("no item passed to readPasswordContentsWithResult");
+        fail("Match test numbers");
+        fail("Match test numbers");
+        return;
+    }
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
+    CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
+
+    CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)itemList, item);
+    CFDictionarySetValue(query, kSecUseItemList, itemList);
+
+    CFTypeRef results = NULL;
+    if(expectedContents) {
+        is(SecItemCopyMatching(query, (CFTypeRef*) &results), expectedResult, "%s: readPasswordContents: SecItemCopyMatching", testName);
+        CFReleaseNull(query);
+
+        if(results) {
+            ok(CFGetTypeID(results) == CFDataGetTypeID(), "%s: result is not a data", testName);
+
+            CFDataRef data = (CFDataRef) results;
+            CFStringRef str = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(data), CFDataGetLength(data), kCFStringEncodingUTF8, false);
+            eq_cf(str, expectedContents, "%s: contents do not match", testName);
+            CFReleaseNull(str);
+            CFReleaseNull(results);
+        } else {
+            fail("Didn't get any results");
+            fail("Match test numbers");
+        }
+    } else {
+        is(SecItemCopyMatching(query, (CFTypeRef*) &results), expectedResult, "%s: readPasswordContents: expecting error %d", testName, (int) expectedResult);
+        pass("Match test numbers");
+        pass("Match test numbers");
+    }
+}
+#define readPasswordContentsWithResultTests 3
+
+static void readPasswordContents(SecKeychainItemRef item, CFStringRef expectedContents) {
+    return readPasswordContentsWithResult(item, errSecSuccess, expectedContents);
+}
+#define readPasswordContentsTests readPasswordContentsWithResultTests
+
+static void changePasswordContents(SecKeychainItemRef item, CFStringRef newPassword) {
+    if(!item) {
+        fail("no item passed to changePasswordContents");
+        return;
+    }
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
+
+    CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)itemList, item);
+    CFDictionarySetValue(query, kSecUseItemList, itemList);
+
+    CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(attrs, kSecValueData, CFDataCreate(NULL, (const UInt8*) CFStringGetCStringPtr(newPassword, kCFStringEncodingUTF8), CFStringGetLength(newPassword)));
+
+    ok_status(SecItemUpdate(query, attrs), "%s: SecItemUpdate", testName);
+}
+#define changePasswordContentsTests 1
+
+static void deleteItem(SecKeychainItemRef item) {
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+    CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)itemList, item);
+    CFDictionarySetValue(query, kSecUseItemList, itemList);
+
+    ok_status(SecItemDelete(query), "%s: SecItemDelete single item", testName);
+    CFReleaseNull(query);
+}
+#define deleteItemTests 1
+
+static void deleteItems(CFArrayRef items) {
+    if(!items) {
+        fail("no items passed to deleteItems");
+        return;
+    }
+
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(query, kSecUseItemList, items);
+
+    size_t count = (size_t) CFArrayGetCount(items);
+    if(count > 0) {
+        ok_status(SecItemDelete(query), "%s: SecItemDelete %ld items", testName, count);
+    } else {
+        is(SecItemDelete(query), errSecItemNotFound, "%s: SecItemDelete no items", testName);
+    }
+    CFReleaseNull(query);
+}
+#define deleteItemsTests 1
+
+/* Checks in with securityd to see how many prompts were generated since the last call to this function, and tests against the number expected.
+ Returns the number generated since the last call. */
+static uint32_t checkPrompts(uint32_t expectedSinceLastCall, char* explanation) {
+    uint32_t currentPrompts = UINT_MAX;
+    uint32_t newPrompts = UINT_MAX;
+    ok_status(SecKeychainGetUserPromptAttempts(&currentPrompts), "%s: SecKeychainGetUserPromptAttempts", testName);
+
+    newPrompts = currentPrompts - promptAttempts;
+
+    is(newPrompts, expectedSinceLastCall, "%s: wrong number of prompts: %s", testName, explanation);
+    promptAttempts = currentPrompts;
+
+    return newPrompts;
+}
+#define checkPromptsTests 2
+
+#pragma clang diagnostic pop
+
+#endif /* kc_helpers_h */