]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/regressions/kc-key-helpers.h
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-key-helpers.h
diff --git a/OSX/libsecurity_keychain/regressions/kc-key-helpers.h b/OSX/libsecurity_keychain/regressions/kc-key-helpers.h
new file mode 100644 (file)
index 0000000..08095c8
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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_key_helpers_h
+#define kc_key_helpers_h
+
+#include "kc-helpers.h"
+#include "utilities/SecCFRelease.h"
+
+#if TARGET_OS_MAC
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-function"
+
+static CFMutableDictionaryRef makeBaseKeyDictionary() {
+    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFDictionarySetValue(query, kSecClass, kSecClassKey);
+    return query;
+}
+
+static CFMutableDictionaryRef makeQueryKeyDictionary(SecKeychainRef kc, CFStringRef keyClass) {
+    CFMutableDictionaryRef query = makeBaseKeyDictionary();
+
+    CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)searchList, kc);
+    CFDictionarySetValue(query, kSecMatchSearchList, searchList);
+
+    CFDictionarySetValue(query, kSecAttrKeyClass, keyClass);
+
+    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+    return query;
+}
+
+static CFMutableDictionaryRef makeQueryKeyDictionaryWithLabel(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label) {
+    CFMutableDictionaryRef query = makeQueryKeyDictionary(kc, keyClass);
+    CFDictionarySetValue(query, kSecAttrLabel, label);
+    return query;
+}
+
+static CFMutableDictionaryRef makeAddKeyDictionaryWithApplicationLabel(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label, CFStringRef applicationLabel) {
+    CFMutableDictionaryRef query = makeBaseKeyDictionary();
+    CFDictionaryAddValue(query, kSecUseKeychain, kc);
+
+    CFDictionarySetValue(query, kSecAttrLabel, label);
+    if(applicationLabel) {
+        CFDictionarySetValue(query, kSecAttrApplicationLabel, applicationLabel);
+    } else {
+        CFDictionarySetValue(query, kSecAttrApplicationLabel, CFSTR("test_application")); // without setting this, it uses the current datetime.
+    }
+
+    int32_t n = 0;
+    if(CFEqual(keyClass, kSecAttrKeyClassSymmetric)) {
+        CFDictionarySetValue(query, kSecAttrKeyType, kSecAttrKeyTypeAES);
+        n = 128;
+    } else if(CFEqual(keyClass, kSecAttrKeyClassPublic) ||
+              CFEqual(keyClass, kSecAttrKeyClassPrivate)) {
+        CFDictionarySetValue(query, kSecAttrKeyType, kSecAttrKeyTypeRSA);
+        n = 1024;
+    }
+    CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &n);
+    CFDictionarySetValue(query, kSecAttrKeySizeInBits, num);
+
+    return query;
+}
+static CFMutableDictionaryRef makeAddKeyDictionary(SecKeychainRef kc, CFStringRef keyClass, CFStringRef label) {
+    return makeAddKeyDictionaryWithApplicationLabel(kc, keyClass, label, NULL);
+}
+
+static SecKeyRef makeCustomKeyWithApplicationLabel(const char* name, SecKeychainRef kc, CFStringRef label, CFStringRef applicationLabel) {
+    CFMutableDictionaryRef query = makeAddKeyDictionaryWithApplicationLabel(kc, kSecAttrKeyClassSymmetric, label, applicationLabel);
+
+    CFErrorRef error = NULL;
+    SecKeyRef item = SecKeyGenerateSymmetric(query, &error);
+    ok(item != NULL, "%s: SecKeyGenerateSymmetric: %ld", name, error ? CFErrorGetCode(error) : 0);
+
+    CFReleaseNull(query);
+    return item;
+}
+#define makeCustomKeyWithApplicationLabelTests 1
+
+static SecKeyRef makeCustomKey(const char* name, SecKeychainRef kc, CFStringRef label) {
+    return makeCustomKeyWithApplicationLabel(name, kc, label, NULL);
+}
+#define makeCustomKeyTests makeCustomKeyWithApplicationLabelTests
+
+static SecKeyRef makeKey(const char* name, SecKeychainRef kc) {
+    return makeCustomKey(name, kc, CFSTR("test_key"));
+}
+#define makeKeyTests makeCustomKeyTests
+
+static void makeCustomKeyPair(const char* name, SecKeychainRef kc, CFStringRef label, SecKeyRef* aPub, SecKeyRef* aPriv) {
+    CFMutableDictionaryRef query = makeAddKeyDictionary(kc, kSecAttrKeyClassPublic, label);
+
+    SecKeyRef pub;
+    SecKeyRef priv;
+    ok_status(SecKeyGeneratePair(query, &pub, &priv), "%s: SecKeyGeneratePair returned a result", name);
+
+    if(aPub) {
+        *aPub = pub;
+    }
+    if(aPriv) {
+        *aPriv = priv;
+    }
+
+    CFReleaseNull(query);
+}
+#define makeCustomKeyPairTests 1
+
+static void makeKeyPair(const char* name, SecKeychainRef kc, SecKeyRef* aPub, SecKeyRef* aPriv) {
+    makeCustomKeyPair(name, kc, CFSTR("test_key"), aPub, aPriv);
+}
+#define makeKeyPairTests makeCustomKeyPairTests
+
+// This only works for symmetric keys; key pairs cannot ever generate a duplicate (due to setting kSecKeyLabel to the hash of the public key)
+static void makeCustomDuplicateKey(const char* name, SecKeychainRef kc, CFStringRef label) {
+    CFMutableDictionaryRef query;
+
+    query = makeAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
+    CFErrorRef error = NULL;
+    CFReleaseSafe(SecKeyGenerateSymmetric(query, &error));
+    is(CFErrorGetCode(error), errSecDuplicateItem, "%s: SecKeyGenerateSymmetric (duplicate) errored: %ld", name, error ? CFErrorGetCode(error) : -1);
+
+    CFReleaseNull(query);
+}
+#define makeCustomDuplicateKeyTests 1
+
+static void makeDuplicateKey(const char* name, SecKeychainRef kc) {
+    makeCustomDuplicateKey(name, kc, CFSTR("test_key"));
+}
+#define makeDuplicateKeyTests makeCustomDuplicateKeyTests
+
+static SecKeyRef makeCustomFreeKey(const char* name, SecKeychainRef kc, CFStringRef label) {
+    SecKeyRef symkey;
+
+    ok_status(SecKeyGenerate(
+                             NULL,
+                             CSSM_ALGID_AES, 128,
+                             0, /* contextHandle */
+                             CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+                             CSSM_KEYATTR_EXTRACTABLE,
+                             NULL, /* initialAccess */
+                             &symkey), "%s: SecKeyGenerate", name);;
+
+    CFMutableDictionaryRef query = makeAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
+
+    CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)itemList, symkey);
+
+    CFDictionarySetValue(query, kSecUseItemList, itemList);
+
+    CFTypeRef result = NULL;
+    ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
+    ok(result != NULL, "%s: SecItemAdd returned a result", name);
+    CFReleaseNull(symkey);
+    return (SecKeyRef) result;
+}
+#define makeCustomFreeKeyTests 3
+
+static SecKeyRef makeFreeKey(const char* name, SecKeychainRef kc) {
+    return makeCustomFreeKey(name, kc, CFSTR("test_free_key"));
+}
+#define makeFreeKeyTests makeCustomFreeKeyTests
+
+static SecKeyRef makeCustomDuplicateFreeKey(const char* name, SecKeychainRef kc, CFStringRef label) {
+    SecKeyRef symkey;
+
+    ok_status(SecKeyGenerate(
+                             NULL,
+                             CSSM_ALGID_AES, 128,
+                             0, /* contextHandle */
+                             CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+                             CSSM_KEYATTR_EXTRACTABLE,
+                             NULL, /* initialAccess */
+                             &symkey), "%s: SecKeyGenerate", name);;
+
+    CFMutableDictionaryRef query = makeAddKeyDictionary(kc, kSecAttrKeyClassSymmetric, label);
+
+    CFMutableArrayRef itemList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+    CFArrayAppendValue((CFMutableArrayRef)itemList, symkey);
+
+    CFDictionarySetValue(query, kSecUseItemList, itemList);
+
+    CFTypeRef result = NULL;
+    is(SecItemAdd(query, &result), errSecDuplicateItem, "%s: SecItemAdd (duplicate)", name);
+    CFReleaseNull(symkey);
+    return (SecKeyRef) result;
+}
+#define makeCustomDuplicateFreeKeyTests 2
+
+static SecKeyRef makeDuplicateFreeKey(const char* name, SecKeychainRef kc) {
+    return makeCustomFreeKey(name, kc, CFSTR("test_free_key"));
+}
+#define makeDuplicateFreeKeyTests makeCustomDuplicateFreeKeyTests
+
+#define checkKeyUseTests 4
+static void checkKeyUse(SecKeyRef key, OSStatus expectedStatus) {
+    CFStringRef plaintext = CFSTR("A short story: the string goes into the encryptor, and returns unrecognizable. The decryptor reverses.");
+    CFDataRef plaintextData = CFDataCreate(NULL, (uint8_t*) CFStringGetCStringPtr(plaintext, kCFStringEncodingUTF8), CFStringGetLength(plaintext));
+
+    /* encrypt first */
+    SecTransformRef transform = SecEncryptTransformCreate(key, NULL);
+    SecTransformSetAttribute(transform, kSecPaddingKey, kSecPaddingPKCS7Key, NULL);
+    SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, NULL);
+    SecTransformSetAttribute(transform, kSecTransformInputAttributeName, plaintextData, NULL);
+
+    CFErrorRef error = NULL;
+    CFDataRef ciphertextData = SecTransformExecute(transform, &error);
+
+    if(error) {
+        is(CFErrorGetCode(error), expectedStatus, "%s: Encrypting data failed: %d %s (and expected %d)", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(CFErrorCopyDescription(error), kCFStringEncodingUTF8), (int) expectedStatus);
+
+        if(expectedStatus != errSecSuccess) {
+            // make test numbers match and quit
+            for(int i = 1; i < checkKeyUseTests; i++) {
+                pass("test numbers match");
+            }
+            return;
+        }
+
+    } else {
+        pass("%s: transform executed", testName);
+    }
+
+    CFReleaseSafe(transform);
+
+    /* and now decrypt */
+    transform = SecDecryptTransformCreate(key, NULL);
+    SecTransformSetAttribute(transform, kSecPaddingKey, kSecPaddingPKCS7Key, NULL);
+    SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, NULL);
+    SecTransformSetAttribute(transform, kSecTransformInputAttributeName, ciphertextData, NULL);
+
+    CFDataRef roundtripData = SecTransformExecute(transform, &error);
+    is(error, NULL, "%s: checkKeyUse: SecTransformExecute (decrypt)", testName);
+
+    if(error) {
+        CFStringRef errorStr = CFErrorCopyDescription(error);
+        fail("%s: Decrypting data failed: %d %s", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(errorStr, kCFStringEncodingUTF8));
+        CFRelease(errorStr);
+    } else {
+        pass("%s: make test numbers match", testName);
+    }
+
+    CFReleaseSafe(transform);
+
+    eq_cf(plaintextData, roundtripData, "%s: checkKeyUse: roundtripped data is input data", testName);
+
+    CFReleaseSafe(plaintext);
+    CFReleaseSafe(plaintextData);
+    CFReleaseSafe(ciphertextData);
+    CFReleaseSafe(roundtripData);
+}
+
+
+
+#pragma clang diagnostic pop
+
+#else
+
+#endif /* TARGET_OS_MAC */
+
+
+#endif /* kc_key_helpers_h */