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