1/* 2 * Copyright (c) 2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include <Security/SecItem.h> 26#include <Security/SecAccessControl.h> 27#include <Security/SecAccessControlPriv.h> 28#include <Security/SecInternal.h> 29#include <utilities/SecCFWrappers.h> 30#include <utilities/array_size.h> 31#include <libaks_acl_cf_keys.h> 32 33#include "Security_regressions.h" 34 35static CFTypeRef kSecAccessControlKeyProtection = CFSTR("prot"); 36 37// TODO: Use real name of this policy from SCred/AppleCredentialManager 38CFTypeRef kSecAccessControlPolicyUserPresent = CFSTR("DeviceOwnerAuthenticated"); 39 40static void tests(void) 41{ 42 CFAllocatorRef allocator = kCFAllocatorDefault; 43 CFTypeRef protection = kSecAttrAccessibleAlways; 44 SecAccessControlCreateFlags flags = kSecAccessControlUserPresence; 45 CFErrorRef error = NULL; 46 47 // Simple API tests: 48 49 // 1: ACL with protection only 50 SecAccessControlRef acl = SecAccessControlCreateWithFlags(allocator, protection, 0, &error); 51 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error); 52 CFReleaseNull(error); 53 CFReleaseNull(acl); 54 55 // 2: ACL with flags only (not allowed) 56 acl = SecAccessControlCreateWithFlags(allocator, NULL, flags, &error); 57 ok(acl == NULL, "SecAccessControlCreateWithFlags"); 58 CFReleaseNull(error); 59 CFReleaseNull(acl); 60 61 // 3: ACL with protection and flags 62 acl = SecAccessControlCreateWithFlags(allocator, protection, flags, &error); 63 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error); 64 CFReleaseNull(error); 65 66 // Extended API tests: 67 68 // 4: Check created ACL 69 CFTypeRef aclProtection = SecAccessControlGetProtection(acl); 70 is(aclProtection, protection, "SecAccessControlGetProtection"); 71 72 SecAccessConstraintRef aclConstraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt); 73 // 5: Check created ACL 74 ok(aclConstraint != NULL && isDictionary(aclConstraint), "SecAccessControlGetConstraint"); 75 // 6: Check created ACL 76 eq_string(CFDictionaryGetValue(aclConstraint, kAKSKeyAclConstraintPolicy), kSecAccessControlPolicyUserPresent, "SecAccessControlGetConstraint"); 77 78 CFReleaseNull(acl); 79 80 // Simple SPI tests: 81 82 // 7: Empty ACL 83 acl = SecAccessControlCreate(allocator, &error); 84 ok(acl != NULL, "SecAccessControlCreate: %@", error); 85 CFReleaseNull(error); 86 87 // 8: ACL protection 88 bool result = SecAccessControlSetProtection(acl, protection, &error); 89 ok(result, "SecAccessControlSetProtection: %@", error); 90 CFReleaseNull(error); 91 92 aclProtection = SecAccessControlGetProtection(acl); 93 // 9: ACL protection 94 is(aclProtection, protection, "SecAccessControlGetProtection"); 95 96 // 10: Policy constraint 97 SecAccessConstraintRef policy = SecAccessConstraintCreatePolicy(kSecAccessControlPolicyUserPresent, &error); 98 ok(policy != NULL, "SecAccessConstraintCreatePolicy: %@", error); 99 // 11: Policy constraint 100 ok(isDictionary(policy), "SecAccessConstraintCreatePolicy"); 101 // 12: Policy constraint 102 is(CFDictionaryGetValue(policy, kAKSKeyAclConstraintPolicy), kSecAccessControlPolicyUserPresent, "SecAccessConstraintCreatePolicy"); 103 CFReleaseNull(error); 104 CFReleaseNull(policy); 105 106 // 13: Passcode constraint 107 SecAccessConstraintRef passcode = SecAccessConstraintCreatePasscode(true); 108 ok(passcode != NULL && isDictionary(passcode), "SecAccessConstraintCreatePasscode"); 109 // 14: Passcode constraint 110 is(CFDictionaryGetValue(passcode, kAKSKeyAclConstraintUserPasscode), kCFBooleanTrue, "SecAccessConstraintCreatePasscode"); 111// CFReleaseNull(passcode); passcode will be used in later tests 112 113 // 15: TouchID constraint 114 CFUUIDRef uuid = CFUUIDCreate(allocator); 115 CFStringRef uuidString = CFUUIDCreateString(allocator, uuid); 116 CFDataRef uuidData = CFStringCreateExternalRepresentation(allocator, uuidString, kCFStringEncodingUTF8, 0); 117 SecAccessConstraintRef touchID = SecAccessConstraintCreateTouchID(uuidData, &error); 118 ok(touchID != NULL, "SecAccessConstraintCreateTouchID: %@", error); 119 // 16: TouchID constraint 120 ok(isDictionary(touchID), "SecAccessConstraintCreateTouchID"); 121 // 17: TouchID constraint 122 is(CFDictionaryGetValue(touchID, kAKSKeyAclConstraintBio), uuidData, "SecAccessConstraintCreateTouchID"); 123 CFReleaseNull(error); 124 CFReleaseNull(touchID); 125 CFReleaseNull(uuidData); 126 CFReleaseNull(uuidString); 127 CFReleaseNull(uuid); 128 129 touchID = SecAccessConstraintCreateTouchID(NULL, &error); 130 // 18: TouchID constraint 131 ok(touchID != NULL, "SecAccessConstraintCreateTouchID: %@", error); 132 // 19: TouchID constraint 133 ok(isDictionary(touchID), "SecAccessConstraintCreateTouchID"); 134 // 20: TouchID constraint 135 is(CFDictionaryGetValue(touchID, kAKSKeyAclConstraintBio), kCFBooleanTrue, "SecAccessConstraintCreateTouchID"); 136 CFReleaseNull(error); 137 // CFReleaseNull(touchID); touchID will be used in later tests 138 139 // 21: KofN constraint 140 CFTypeRef constraints_array[] = { passcode, touchID }; 141 CFArrayRef constraintsArray = CFArrayCreate(allocator, constraints_array, array_size(constraints_array), &kCFTypeArrayCallBacks); 142 SecAccessConstraintRef kofn = SecAccessConstraintCreateKofN(1, constraintsArray, &error); 143 ok(kofn != NULL, "SecAccessConstraintCreateKofN: %@", error); 144 // 22: KofN constraint 145 ok(isDictionary(kofn), "SecAccessConstraintCreateKofN"); 146 CFTypeRef kofnConstraint = CFDictionaryGetValue(kofn, kAKSKeyAclConstraintKofN); 147 // 23: KofN constraint 148 ok(kofnConstraint != NULL && isDictionary(kofnConstraint), "SecAccessConstraintCreateKofN"); 149 CFNumberRef required = CFNumberCreateWithCFIndex(allocator, 1); 150 // 24: KofN constraint 151 is(CFDictionaryGetValue(kofnConstraint, kAKSKeyAclParamKofN), required, "SecAccessConstraintCreateKofN"); 152 // 25: KofN constraint 153 is(CFDictionaryGetValue(kofnConstraint, kAKSKeyAclConstraintBio), kCFBooleanTrue, "SecAccessConstraintCreateKofN"); 154 // 26: KofN constraint 155 is(CFDictionaryGetValue(kofnConstraint, kAKSKeyAclConstraintUserPasscode), kCFBooleanTrue, "SecAccessConstraintCreateKofN"); 156 CFReleaseNull(error); 157 CFReleaseNull(kofn); 158 CFReleaseNull(required); 159 CFReleaseNull(constraintsArray); 160 CFReleaseNull(passcode); 161 162 // 27: Set constraint option 163 CFTypeRef accesss_groups_array[] = { CFSTR("wheel"), CFSTR("staff") }; 164 CFArrayRef accessGroupsArray = CFArrayCreate(allocator, accesss_groups_array, array_size(accesss_groups_array), &kCFTypeArrayCallBacks); 165 result = SecAccessConstraintSetOption(touchID, kAKSKeyAclConstraintAccessGroups, accessGroupsArray, &error); 166 ok(result, "SecAccessConstraintSetOption: %@", error); 167 // 28: Set constraint option 168 is(CFDictionaryGetValue(touchID, kAKSKeyAclConstraintAccessGroups), accessGroupsArray, "SecAccessConstraintSetOption"); 169 CFReleaseNull(error); 170 // CFReleaseNull(accessGroupsArray); accessGroupsArray will be used in later tests 171 172 // 29: Add ACL constraint for operation 173 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDecrypt, touchID, &error); 174 ok(result, "SecAccessControlAddConstraintForOperation: %@", error); 175 CFReleaseNull(error); 176 177 // 30: Get ACL operation constraint 178 SecAccessConstraintRef constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt); 179 is(constraint, touchID, "SecAccessControlGetConstraint"); 180 CFReleaseNull(touchID); 181 182 // 31: Add ACL constraint for operation (kCFBooleanTrue) 183 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDecrypt, kCFBooleanTrue, &error); 184 ok(result, "SecAccessControlAddConstraintForOperation: %@", error); 185 CFReleaseNull(error); 186 187 // 32: Get ACL operation constraint (kCFBooleanTrue) 188 constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt); 189 is(constraint, kCFBooleanTrue, "SecAccessControlGetConstraint"); 190 191 // 33: ACL access groups 192 SecAccessControlSetAccessGroups(acl, accessGroupsArray); 193 CFArrayRef aclAccessGroups = SecAccessControlGetAccessGroups(acl, kAKSKeyOpDecrypt); 194 is(aclAccessGroups, accessGroupsArray, "SecAccessControlGetAccessGroups"); 195 196 // 34: Get ACL constraints 197 CFDictionaryRef constraints = SecAccessControlGetConstraints(acl); 198 ok(constraints != NULL && isDictionary(constraints), "SecAccessControlGetConstraints"); 199 // 35: Get ACL constraints 200 is(CFDictionaryGetValue(constraints, kAKSKeyOpDecrypt), kCFBooleanTrue, "SecAccessControlGetConstraints"); 201 // 36: Get ACL constraints 202 is(CFDictionaryGetValue(constraints, kAKSKeyAccessGroups), accessGroupsArray, "SecAccessControlGetConstraints"); 203 CFReleaseNull(accessGroupsArray); 204 205 // 37: Remove ACL operation constraint 206 SecAccessControlRemoveConstraintForOperation(acl, kAKSKeyOpDecrypt); 207SKIP: { 208 // All constraints are removed so any operation should be allowed. 209 constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt); 210 skip("ACL access groups are considered as a constraint which blocks ACL operations", 1, constraint == kCFBooleanTrue); 211 is(constraint, kCFBooleanTrue, "SecAccessControlRemoveConstraintForOperation"); 212 } 213 214 // 38: ACL export and import 215 CFDataRef aclData = SecAccessControlCopyData(acl); 216 ok(aclData != NULL, "SecAccessControlCopyData"); 217 218 SecAccessControlRef aclCopy = SecAccessControlCreateFromData(allocator, aclData, &error); 219 // 39: ACL export and import 220 ok(aclCopy != NULL, "SecAccessControlCopyData: %@", error); 221 // 40: ACL export and import 222 ok(CFEqual(aclCopy, acl), "SecAccessControlCopyData"); 223 CFReleaseNull(error); 224 CFReleaseNull(aclCopy); 225 CFReleaseNull(aclData); 226 227 // Extended SPI tests: 228 229 // 41: kAKSKeyDefaultOpAcl 230 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, &error); 231 ok(result, "SecAccessControlAddConstraintForOperation: %@", error); 232 constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt); 233 // 42: kAKSKeyDefaultOpAcl 234 is(constraint, kCFBooleanTrue, "SecAccessControlRemoveConstraintForOperation"); 235 CFReleaseNull(error); 236 237 CFReleaseNull(acl); 238} 239 240int si_77_SecAccessControl(int argc, char *const *argv) 241{ 242 plan_tests(42); 243 244 tests(); 245 246 return 0; 247} 248