]> git.saurik.com Git - apple/security.git/blobdiff - secacltests/sec_acl_stress.c
Security-57336.1.9.tar.gz
[apple/security.git] / secacltests / sec_acl_stress.c
diff --git a/secacltests/sec_acl_stress.c b/secacltests/sec_acl_stress.c
new file mode 100644 (file)
index 0000000..7f14d3d
--- /dev/null
@@ -0,0 +1,344 @@
+//
+//  sec_acl_stress.c
+//  Security
+//
+//  Created by Vratislav Kužela on 20/05/15.
+//
+//
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
+#include <Security/SecBase.h>
+#include <utilities/array_size.h>
+#include <utilities/SecCFWrappers.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <Security/SecAccessControl.h>
+#include <Security/SecAccessControlPriv.h>
+#include <libaks_acl_cf_keys.h>
+
+#include "testlist.h"
+
+#if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
+#define USE_KEYSTORE  1
+#elif TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+#define USE_KEYSTORE  1
+#else /* no keystore on this platform */
+#define USE_KEYSTORE  0
+#endif
+
+#if USE_KEYSTORE
+#include <coreauthd_spi.h>
+#endif
+
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+#include <MobileKeyBag/MobileKeyBag.h>
+#endif
+
+enum ItemAttrType {
+    kBoolItemAttr,
+    kNumberItemAttr,
+    kStringItemAttr,
+    kDataItemAttr,
+    kBlobItemAttr,
+    kDateItemAttr,
+    kAccessabilityItemAttr,
+    kAccessGroupItemAttr,
+};
+
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+CFStringRef temporaryPasscode = CFSTR("1111");
+static bool changePasscode(CFStringRef oldPasscode, CFStringRef newPasscode)
+{
+    CFDataRef oldPasscodeData = NULL;
+    CFDataRef newPasscodeData= NULL;
+    if (oldPasscode) {
+        oldPasscodeData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, oldPasscode, kCFStringEncodingUTF8, 0x00);
+    }
+
+    if (newPasscode) {
+        newPasscodeData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, newPasscode, kCFStringEncodingUTF8, 0x00);
+    }
+
+    int status = MKBKeyBagChangeSystemSecret(oldPasscodeData, newPasscodeData, NULL);
+
+    CFReleaseSafe(oldPasscodeData);
+    CFReleaseSafe(newPasscodeData);
+    return status == kMobileKeyBagSuccess;
+}
+#endif
+
+#if !TARGET_IPHONE_SIMULATOR
+static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) {
+    va_list ap;
+    va_start(ap, each);
+    CFStringRef attr;
+    while((attr = va_arg(ap, CFStringRef)) != NULL) {
+        enum ItemAttrType atype = va_arg(ap, enum ItemAttrType);
+        each(attr, atype);
+    }
+    va_end(ap);
+}
+
+static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) {
+    CFStringRef iclass = CFDictionaryGetValue(item, kSecClass);
+    if (!iclass) {
+        return;
+    } else if (CFEqual(iclass, kSecClassGenericPassword)) {
+        WithEachString(each,
+                       kSecAttrAccessible,          kAccessabilityItemAttr,
+                       kSecAttrAccessGroup,         kAccessGroupItemAttr,
+                       kSecAttrAccount,             kStringItemAttr,
+                       kSecAttrService,             kStringItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       NULL);
+    } else if (CFEqual(iclass, kSecClassInternetPassword)) {
+        WithEachString(each,
+                       kSecAttrAccessible,          kAccessabilityItemAttr,
+                       kSecAttrAccessGroup,         kAccessGroupItemAttr,
+                       kSecAttrAccount,             kStringItemAttr,
+                       kSecAttrSecurityDomain,      kStringItemAttr,
+                       kSecAttrServer,              kStringItemAttr,
+                       kSecAttrProtocol,            kNumberItemAttr,
+                       kSecAttrAuthenticationType,  kNumberItemAttr,
+                       kSecAttrPort,                kNumberItemAttr,
+                       kSecAttrPath,                kStringItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       NULL);
+    } else if (CFEqual(iclass, kSecClassCertificate)) {
+        WithEachString(each,
+                       kSecAttrAccessible,          kAccessabilityItemAttr,
+                       kSecAttrAccessGroup,         kAccessGroupItemAttr,
+                       kSecAttrCertificateType,     kNumberItemAttr,
+                       kSecAttrIssuer,              kDataItemAttr,
+                       kSecAttrSerialNumber,        kDataItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       NULL);
+    } else if (CFEqual(iclass, kSecClassKey)) {
+        WithEachString(each,
+                       kSecAttrAccessible,          kAccessabilityItemAttr,
+                       kSecAttrAccessGroup,         kAccessGroupItemAttr,
+                       kSecAttrKeyClass,            kStringItemAttr, // kNumberItemAttr on replies
+                       kSecAttrApplicationLabel,    kDataItemAttr,
+                       kSecAttrApplicationTag,      kDataItemAttr,
+                       kSecAttrKeyType,             kNumberItemAttr,
+                       kSecAttrKeySizeInBits,       kNumberItemAttr,
+                       kSecAttrEffectiveKeySize,    kNumberItemAttr,
+                       kSecAttrStartDate,           kDateItemAttr,
+                       kSecAttrEndDate,             kDateItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       NULL);
+    } else if (CFEqual(iclass, kSecClassIdentity)) {
+        WithEachString(each,
+                       kSecAttrAccessible,          kAccessabilityItemAttr,
+                       kSecAttrAccessGroup,         kAccessGroupItemAttr,
+                       kSecAttrCertificateType,     kNumberItemAttr,
+                       kSecAttrIssuer,              kDataItemAttr,
+                       kSecAttrSerialNumber,        kDataItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       kSecAttrKeyClass,            kStringItemAttr, // kNumberItemAttr on replies
+                       kSecAttrApplicationLabel,    kDataItemAttr,
+                       kSecAttrApplicationTag,      kDataItemAttr,
+                       kSecAttrKeyType,             kNumberItemAttr,
+                       kSecAttrKeySizeInBits,       kNumberItemAttr,
+                       kSecAttrEffectiveKeySize,    kNumberItemAttr,
+                       kSecAttrStartDate,           kDateItemAttr,
+                       kSecAttrEndDate,             kDateItemAttr,
+                       kSecAttrSynchronizable,      kBoolItemAttr,
+                       NULL);
+    }
+}
+
+static CFMutableDictionaryRef ItemCreate(int num) {
+    CFStringRef iclass = NULL;
+    switch (num % 4) {
+        case 0:
+            iclass = kSecClassInternetPassword;
+            break;
+        case 1:
+            iclass = kSecClassGenericPassword;
+            break;
+        case 2:
+            iclass = kSecClassKey;
+            break;
+        case 3:
+            iclass = kSecClassCertificate;
+            break;
+    }
+    return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, iclass, NULL);
+}
+
+static void tests(bool isPasscodeSet)
+{
+    for (int num = 0 ; num < 8; ++num) {
+        __block CFTypeRef protection = NULL;
+        CFMutableDictionaryRef item = ItemCreate(num);
+        ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) {
+            CFTypeRef value = NULL;
+            switch (atype) {
+                case kBoolItemAttr:
+                    value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse);
+                    CFRetain(value);
+                    break;
+                case kNumberItemAttr:
+                    value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
+                    break;
+                case kStringItemAttr:
+                case kBlobItemAttr:
+                    value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num);
+                    break;
+                case kDataItemAttr:
+                {
+                    char buf[10];
+                    int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num);
+                    value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len);
+                    break;
+                }
+                case kDateItemAttr:
+                    value = NULL; // Don't mess with dates on create.
+                    break;
+                case kAccessabilityItemAttr:
+                {
+                    CFStringRef accessabilites[] = {
+                        kSecAttrAccessibleWhenUnlocked,
+                        kSecAttrAccessibleAfterFirstUnlock,
+                        kSecAttrAccessibleAlways,
+                        kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
+                        kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
+                        kSecAttrAccessibleAlwaysThisDeviceOnly,
+                    };
+                    protection = accessabilites[num % array_size(accessabilites)];
+                    break;
+                }
+                case kAccessGroupItemAttr:
+                {
+                    CFStringRef accessGroups[] = {
+                        NULL,
+                        CFSTR("com.apple.security.sos"),          // Secd internally uses this
+                    };
+                    value = accessGroups[num % array_size(accessGroups)];
+                    break;
+                }
+            }
+            if (value)
+                CFDictionarySetValue(item, attr, value);
+            CFReleaseSafe(value);
+        });
+
+        SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL);
+        ok(aclRef, "Create SecAccessControlRef");
+        ok(SecAccessControlSetProtection(aclRef, protection, NULL), "Set protection");
+        ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL), "Set operation decrypt to true");
+        ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL), "Set operation delete to true");
+        ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL), "Set operation encrypt to true");
+
+        SecAccessControlRef invalidAclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL);
+        ok(invalidAclRef, "Create invalid SecAccessControlRef");
+        ok(SecAccessControlSetProtection(invalidAclRef, protection, NULL), "Set protection");
+        CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("invalidPolicy"), NULL);
+        ok(constraint, "Create invalid constraint");
+        ok(SecAccessControlAddConstraintForOperation(invalidAclRef, kAKSKeyOpDecrypt, constraint, NULL), "Add invalid constraint");
+        CFReleaseSafe(constraint);
+
+        CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse);
+        CFDictionarySetValue(item, kSecAttrAccessControl, invalidAclRef);
+        is_status(SecItemAdd(item, NULL), errSecParam, "do not add local with invalid acl");
+        is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after add failed");
+
+        CFDictionarySetValue(item, kSecAttrAccessControl, aclRef);
+        ok_status(SecItemAdd(item, NULL), "add local ");
+        ok_status(SecItemCopyMatching(item, NULL), "find local");
+        ok_status(SecItemDelete(item), "delete local");
+        is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local");
+
+        CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue);
+        is_status(SecItemAdd(item, NULL), errSecParam, "add sync");
+        is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find sync");
+        CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse);
+
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+        SecAccessControlRef privateKeyUsageAclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, kSecAccessControlPrivateKeyUsage, NULL);
+        ok(privateKeyUsageAclRef, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
+        CFDictionarySetValue(item, kSecAttrAccessControl, privateKeyUsageAclRef);
+        is_status(SecItemAdd(item, NULL), errSecAuthFailed, "add local - kSecAccessControlPrivateKeyUsage without constraint");
+        CFReleaseNull(privateKeyUsageAclRef);
+
+        if(isPasscodeSet) {
+            privateKeyUsageAclRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, kSecAccessControlDevicePasscode | kSecAccessControlPrivateKeyUsage, NULL);
+            ok(privateKeyUsageAclRef, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
+            CFDictionarySetValue(item, kSecAttrAccessControl, privateKeyUsageAclRef);
+            is_status(SecItemAdd(item, NULL), errSecAuthFailed, "add local - kSecAccessControlPrivateKeyUsage with constraint");
+            CFReleaseSafe(privateKeyUsageAclRef);
+            SecAccessControlRef aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, kSecAccessControlUserPresence, NULL);
+            ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction");
+
+            CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef);
+            ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
+            CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);
+            is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local  - acl with authentication UI");
+            CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip);
+            is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "find local  - acl with authentication UI");
+            CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow);
+            ok_status(SecItemDelete(item), "delete local  - acl with authentication UI");
+            is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local  - acl with authentication UI");
+
+            CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);
+            ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
+            is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local  - acl with authentication UI");
+            ok_status(SecItemDelete(item), "delete local  - acl with authentication UI");
+            is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local  - acl with authentication UI");
+            CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow);
+            CFReleaseSafe(aclWithUIRef);
+
+            aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL);
+            ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction");
+
+            CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef);
+            ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
+            changePasscode(temporaryPasscode, NULL);
+            ok_status(SecItemDelete(item), "delete local - AKPU");
+            changePasscode(NULL, temporaryPasscode);
+            CFReleaseSafe(aclWithUIRef);
+        }
+#endif
+
+        CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip);
+        is_status(SecItemAdd(item, NULL), errSecParam, "add local - invalid kSecUseAuthenticationUISkip");
+        is_status(SecItemDelete(item), errSecParam, "delete local - invalid kSecUseAuthenticationUISkip");
+
+        CFRelease(item);
+        CFReleaseSafe(aclRef);
+        CFReleaseSafe(invalidAclRef);
+    }
+}
+#endif
+
+int sec_acl_stress(int argc, char *const *argv)
+{
+#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+    bool removeTemporaryPasscode = false;
+    bool isPasscodeSet = false;
+    if (MKBGetDeviceLockState(NULL) == kMobileKeyBagDisabled) {
+        removeTemporaryPasscode = changePasscode(NULL, temporaryPasscode);
+        isPasscodeSet = MKBGetDeviceLockState(NULL) != kMobileKeyBagDisabled;
+    }
+
+    plan_tests(isPasscodeSet?288:168);
+    tests(isPasscodeSet);
+
+    if (removeTemporaryPasscode) {
+        changePasscode(temporaryPasscode, NULL);
+    }
+#elif TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR
+    plan_tests(152);
+    tests(false);
+#else
+    plan_tests(1);
+    ok(true);
+#endif
+
+
+    return 0;
+}