]> git.saurik.com Git - apple/security.git/blob - keychain/securityd/Regressions/secd-33-keychain-ctk.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / securityd / Regressions / secd-33-keychain-ctk.m
1 /*
2 * Copyright (c) 2015 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 #import <Foundation/Foundation.h>
25
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <Security/SecFramework.h>
28 #include <Security/SecBase.h>
29 #include <Security/SecItem.h>
30 #include <Security/SecItemPriv.h>
31 #include <Security/SecKey.h>
32 #include <Security/SecKeyPriv.h>
33 #include <Security/SecECKey.h>
34 #include <Security/SecAccessControl.h>
35 #include <Security/SecAccessControlPriv.h>
36 #include <Security/SecInternal.h>
37 #include <Security/SecCertificatePriv.h>
38 #include <utilities/SecFileLocations.h>
39 #include <utilities/SecCFWrappers.h>
40 #include <utilities/SecCFError.h>
41 #include <utilities/SecCFRelease.h>
42 #include <utilities/der_plist.h>
43 #include <Security/SecBase64.h>
44
45 #include <os/feature_private.h>
46
47 #include <libaks_acl_cf_keys.h>
48
49 #include <ctkclient/ctkclient_test.h>
50 #include <coreauthd_spi.h>
51
52 #include "secd_regressions.h"
53
54 #include "SecdTestKeychainUtilities.h"
55 #include "SecKeybagSupport.h"
56
57 const char *cert1 = "MIIFQzCCBCugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN8DrET5AAQ4dVIP+RD3XATFaBYpG9b2H0tV82gVGOv/t5cxOszAMxzsw7xlY/tMRrx5yz7IUUvueylHl98e7yMefP69vwqwSc4DWSELSqHOLMHd/uPLYLINIFqEW8Nq4Q02V2IxqBbiwtZeeSOqY3gQ2kiCd4cF8Itlr3UePJrlAgMBAAGjggKzMIICrzAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQg5YNVxRTOC13qs9cVUuvDIp6AH+jitdjhWJfai2bfP3QwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCGCGSAFlAwYIMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDETCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMDIGA1UdEQQrMCmgJwYIYIZIAWUDBgagGwQZ1Oc52nOc7TnOc52haFoIySreCmGE5znD4jAQBglghkgBZQMGCQEEAwEBADANBgkqhkiG9w0BAQsFAAOCAQEAVVGMeep+1wpVFdXFIXUTkxy9RjdOO3SmMGVomfVXofVOBfVzooaI+RV5UCURnoqoHYziBidxc9YKW6n9mX6p27KfrC1roHg6wu5xVEHJ93hju35g3WAXTnqNFiQpB+GU7UvJJEhkcTU2rChuYNS5SeFZ0pv1Gyzw7WjLfh9rdAPBfRg4gxpho9SMCUnI+p5KbEiptmimtPfsVq6htT3P+m2V4UXIT6sr7T6IpnPteMppsH43NKXNM6iPCkRCUPQ0d+lpfXAYGSFIzx2WesjSmrs/CHXfwmhnbrJNPCx9zlcCMmmfGcZGyufF+10wF9gv9qx+PUwi2xMKhwuKR1LoCg==";
58 const char *cert2 =
59 "MIIFCTCCA/GgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKij0LIQlW0VKahBGF4tu/xdwGWN+KTLLGyMQmuuG+NNG+vQMSsdXD1pd00YMBiGn3sC5b+G7lQLZ85mDQfO+eI8GDjG+Sh8W8Cghku20sxZnQ+kZOLOr//R2/ZXonVaxoBR/9tBPh0MIEIVzRS8JmltZVfhkbIR6Wiox3jVEAsPAgMBAAGjggJ5MIICdTAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQga85kaqoMEaV+E04P1gZ2OUlbCbvr623fC30WhBZn3bMwDgYDVR0PAQH/BAQDAgbAMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDDTCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMCIGA1UdEQQbMBmBF2NvbW1vbl9uYW1lQHBpdmRlbW8ub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQANg1tGsgO32fVXDyRPHFeqDa0QmQ4itHrh6BAK6n94QL8383wuPDFkPy1TfVYVdYm0Gne6hyH/Z13ycw1XXNddooT7+OiYK5F1TEhfQNiRhzTqblB/yc2lv6Ho0EsOrwPhaBRaO3EFUyjeNMxsvG8Dr9Y5u2B38ESB4OsLKHq0eD/WZjEAlyGx16Qi7YlLiHGfLMorgkg9Mbp73guNO1PItDTAnqHUUOlQ01ThNug0sR5ua1zlNFx6AIPoX4yAPrtlEMZtbsevsXlgDpO1zc26p5icBmQHYT7uzdTEEN4tmcxXg6Z/dGB63GCluf+Pc+ovRt/MMt2EbcIuwJ9C516H";
60 const char *cert3 =
61 "MIICETCCAbigAwIBAgIJANiM7uTufLiKMAkGByqGSM49BAEwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MxGjAYBgNVBAMTEUFwcGxlIFRlc3QgQ0EyIEVDMSAwHgYJKoZIhvcNAQkBFhF2a3V6ZWxhQGFwcGxlLmNvbTAeFw0xNjA1MTIxMTMyMzlaFw0yNjA1MTAxMTMyMzlaMGYxEDAOBgNVBAMTB3NldG9rZW4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQHKxfYgbqRHmThPnO9yQX5KrL/EPa6dZU52Wys5gC3/Mk0dNt9dLhpWblAVaeBzkos4juN3cxbnoB9MsC4bvoLoyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAJBgcqhkjOPQQBA0gAMEUCIQClcoYLhEA/xIGU94ZBcup26Pb7pXaWaaOM3+9z510TRwIgV/iprC051SuQzkqXA5weVliJOohFYjO+gUoH/6MJpDg=";
62
63 extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void));
64
65 static void test_item_add(void) {
66
67 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
68 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
69 __block NSUInteger objIDIdx = 0;
70
71 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
72 kSecClass, kSecClassGenericPassword,
73 kSecAttrTokenID, CFSTR("tokenid"),
74 kSecAttrService, CFSTR("ctktest-service"),
75 kSecValueData, valueData,
76 kSecReturnAttributes, kCFBooleanTrue,
77 NULL);
78 // Setup token hook.
79 __block int phase = 0;
80 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
81 phase++;
82 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
83
84 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
85 phase++;
86 is(objectID, NULL);
87 eq_cf(CFDictionaryGetValue(at, kSecClass), kSecClassGenericPassword);
88 eq_cf(CFDictionaryGetValue(at, kSecAttrService), CFDictionaryGetValue(attrs, kSecAttrService));
89 eq_cf(CFDictionaryGetValue(at, kSecAttrTokenID), CFSTR("tokenid"));
90 eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData);
91 CFDictionaryRemoveValue(at, kSecValueData);
92 ++objIDIdx;
93 return (__bridge_retained CFDataRef)[NSData dataWithBytes:&objIDIdx length:sizeof(objIDIdx)];
94 };
95
96 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
97 phase++;
98 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
99 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
100 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
101 CFDataRef acData = SecAccessControlCopyData(ac);
102 CFRelease(ac);
103 return acData;
104 };
105
106 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
107 phase++;
108 return CFRetain(valueData);
109 };
110 });
111
112 CFTypeRef result = NULL;
113 ok_status(SecItemAdd(attrs, &result));
114 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service"));
115 eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid"));
116 is(CFDictionaryGetValue(result, kSecValueData), NULL);
117 CFReleaseNull(result);
118
119 is(phase, 3);
120
121 phase = 0;
122 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
123 CFDictionarySetValue(attrs, kSecAttrService, CFSTR("ctktest-service1"));
124 ok_status(SecItemAdd(attrs, &result));
125 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service1"));
126 eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid"));
127 eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData);
128 CFReleaseNull(result);
129
130 is(phase, 4);
131
132 phase = 0;
133 CFDictionaryRemoveValue(attrs, kSecReturnAttributes);
134 CFDictionarySetValue(attrs, kSecAttrAccount, CFSTR("2nd"));
135 ok_status(SecItemAdd(attrs, &result));
136 eq_cf(result, valueData);
137 CFReleaseNull(result);
138 is(phase, 4);
139
140 CFRelease(attrs);
141 CFRelease(valueData);
142 }
143
144 static void test_item_query() {
145 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
146 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
147 CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1);
148
149 __block int phase = 0;
150 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
151 phase++;
152 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
153
154 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
155 phase++;
156 return CFRetain(valueData);
157 };
158 });
159
160 // Add non-token item with the same service, to test queries returning mixed results.
161 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
162 kSecClass, kSecClassGenericPassword,
163 kSecAttrService, CFSTR("ctktest-service"),
164 kSecValueData, valueData2,
165 NULL);
166 ok_status(SecItemAdd(attrs, NULL));
167 CFRelease(attrs);
168
169 // Query with service.
170 CFMutableDictionaryRef query;
171 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
172 kSecClass, kSecClassGenericPassword,
173 kSecAttrService, CFSTR("ctktest-service"),
174 kSecReturnAttributes, kCFBooleanTrue,
175 kSecReturnData, kCFBooleanTrue,
176 NULL);
177
178 phase = 0;
179 CFTypeRef result = NULL;
180 ok_status(SecItemCopyMatching(query, &result));
181 is(phase, 2);
182 is(CFGetTypeID(result), CFDictionaryGetTypeID());
183 eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData);
184 is(CFGetTypeID(CFDictionaryGetValue(result, kSecAttrAccessControl)), SecAccessControlGetTypeID());
185 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service"));
186 CFReleaseSafe(result);
187
188 phase = 0;
189 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
190 ok_status(SecItemCopyMatching(query, &result));
191 is(phase, 2);
192 is(CFGetTypeID(result), CFArrayGetTypeID());
193 is(CFArrayGetCount(result), 2);
194 CFReleaseSafe(result);
195
196 phase = 0;
197 CFDictionaryRemoveValue(query, kSecMatchLimit);
198 CFDictionaryRemoveValue(query, kSecReturnData);
199 ok_status(SecItemCopyMatching(query, &result));
200 is(phase, 0);
201 is(CFGetTypeID(result), CFDictionaryGetTypeID());
202 is(CFDictionaryGetValue(result, kSecValueData), NULL);
203 CFReleaseSafe(result);
204
205 phase = 0;
206 CFDictionaryRemoveValue(query, kSecReturnAttributes);
207 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
208 CFDictionarySetValue(query, kSecAttrTokenID, CFSTR("tokenid"));
209 ok_status(SecItemCopyMatching(query, &result));
210 is(phase, 2);
211 eq_cf(result, valueData);
212 CFReleaseSafe(result);
213
214 static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'};
215 NSData *persistentRefId = [NSData dataWithBytes:tk_persistent_ref_id length:sizeof(tk_persistent_ref_id)];
216 phase = 0;
217 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword,
218 (id)kSecAttrService : @"ctktest-service",
219 (id)kSecReturnPersistentRef : @YES }, &result));
220 is(phase, 0);
221 NSData *persistentRef = (__bridge NSData *)result;
222 is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
223 CFReleaseSafe(result);
224
225 phase = 0;
226 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword,
227 (id)kSecAttrService : @"ctktest-service",
228 (id)kSecReturnData : @YES,
229 (id)kSecReturnPersistentRef : @YES }, &result));
230 is(phase, 2);
231 persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
232 is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
233 CFReleaseSafe(result);
234
235 phase = 0;
236 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword,
237 (id)kSecAttrService : @"ctktest-service",
238 (id)kSecReturnAttributes : @YES,
239 (id)kSecReturnPersistentRef : @YES }, &result));
240 is(phase, 0);
241 persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
242 is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
243 CFReleaseSafe(result);
244
245 phase = 0;
246 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassGenericPassword,
247 (id)kSecAttrService : @"ctktest-service",
248 (id)kSecReturnData : @YES,
249 (id)kSecReturnAttributes : @YES,
250 (id)kSecReturnPersistentRef : @YES }, &result));
251 is(phase, 2);
252 persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
253 is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
254 CFReleaseSafe(result);
255
256 CFRelease(query);
257 CFRelease(valueData);
258 CFRelease(valueData2);
259 }
260
261 static void test_item_update() {
262 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
263 CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1);
264 CFTypeRef result = NULL;
265
266 CFMutableDictionaryRef query, attrs;
267
268 // Setup token hook.
269 __block int phase = 0;
270 __block bool store_value = false;
271 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
272 phase++;
273 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
274
275 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
276 phase++;
277 eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData2);
278 if (!store_value) {
279 CFDictionaryRemoveValue(at, kSecValueData);
280 }
281 return CFRetainSafe(objectID);
282 };
283
284 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
285 phase++;
286 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
287 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
288 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
289 CFDataRef acData = SecAccessControlCopyData(ac);
290 CFRelease(ac);
291 return acData;
292 };
293
294 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
295 phase++;
296 return CFRetain(valueData2);
297 };
298 });
299
300 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
301 kSecClass, kSecClassGenericPassword,
302 kSecAttrTokenID, CFSTR("tokenid"),
303 kSecAttrService, CFSTR("ctktest-service"),
304 NULL);
305
306 attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
307 kSecValueData, valueData2,
308 NULL);
309
310 ok_status(SecItemUpdate(query, attrs));
311 is(phase, 3);
312
313 phase = 0;
314 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
315 ok_status(SecItemCopyMatching(query, &result));
316 eq_cf(valueData2, result);
317 CFRelease(result);
318 is(phase, 2);
319
320 phase = 0;
321 store_value = true;
322 CFDictionaryRemoveValue(query, kSecReturnData);
323 ok_status(SecItemUpdate(query, attrs));
324 is(phase, 3);
325
326 phase = 0;
327 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
328 ok_status(SecItemCopyMatching(query, &result));
329 eq_cf(valueData2, result);
330 CFRelease(result);
331 is(phase, 0);
332
333 phase = 0;
334 CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1"));
335 CFDictionaryRemoveValue(query, kSecReturnData);
336 ok_status(SecItemUpdate(query, attrs));
337 is(phase, 5);
338
339 phase = 0;
340 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
341 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
342 ok_status(SecItemCopyMatching(query, &result));
343 is(phase, 0);
344 is(CFGetTypeID(result), CFArrayGetTypeID());
345 is(CFArrayGetCount(result), 2);
346 eq_cf(CFArrayGetValueAtIndex(result, 0), valueData2);
347 eq_cf(CFArrayGetValueAtIndex(result, 1), valueData2);
348
349 CFRelease(query);
350 CFRelease(attrs);
351 CFRelease(valueData2);
352 }
353
354 static void test_item_delete(void) {
355
356 CFMutableDictionaryRef query;
357 CFTypeRef result;
358
359 __block int phase = 0;
360 __block CFErrorRef deleteError = NULL;
361 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
362 phase++;
363 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
364
365 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
366 phase++;
367 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
368 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
369 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
370 CFDataRef acData = SecAccessControlCopyData(ac);
371 CFRelease(ac);
372 return acData;
373 };
374
375 blocks->deleteObject = ^bool(CFDataRef objectID, CFErrorRef *error) {
376 phase++;
377 if (deleteError != NULL) {
378 CFAssignRetained(*error, deleteError);
379 deleteError = NULL;
380 return false;
381 }
382 return true;
383 };
384 });
385
386 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
387 kSecClass, kSecClassGenericPassword,
388 kSecAttrTokenID, CFSTR("tokenid"),
389 kSecAttrService, CFSTR("ctktest-service"),
390 NULL);
391
392 phase = 0;
393 ok_status(SecItemDelete(query));
394 is(phase, 2);
395
396 phase = 0;
397 is_status(SecItemCopyMatching(query, &result), errSecItemNotFound);
398 is(phase, 0);
399
400 phase = 0;
401 CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1"));
402 ok_status(SecItemCopyMatching(query, &result));
403 is(phase, 0);
404
405 phase = 0;
406 #if LA_CONTEXT_IMPLEMENTED
407 LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; });
408 deleteError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL);
409 ok_status(SecItemDelete(query), "delete multiple token items");
410 is(phase, 6, "connect + delete-auth-fail + copyAccess + connect + delete + delete-2nd");
411 #else
412 ok_status(SecItemDelete(query), "delete multiple token items");
413 is(phase, 3, "connect + delete + delete");
414 #endif
415
416 phase = 0;
417 is_status(SecItemCopyMatching(query, &result), errSecItemNotFound);
418 is(phase, 0);
419
420 is_status(SecItemDelete(query), errSecItemNotFound);
421
422 CFRelease(query);
423 CFReleaseSafe(deleteError);
424 }
425
426 static void test_key_generate(int globalPersistence, int privatePersistence, int publicPersistence,
427 bool privateIsPersistent, bool publicIsPersistent) {
428 __block int phase = 0;
429 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
430 phase |= 0x01;
431
432 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
433 id privateKey;
434 CFTypeRef keyClass = CFDictionaryGetValue(at, kSecAttrKeyClass) ?: kSecAttrKeyClassPrivate;
435 eq_cf(keyClass, kSecAttrKeyClassPrivate, "only private keys can be created on token");
436 NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate };
437 if (objectID != NULL) {
438 phase |= 0x20;
439 privateKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)objectID, (CFDictionaryRef)params, NULL));
440 } else {
441 phase |= 0x02;
442 privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, error));
443 }
444 NSDictionary *privKeyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey));
445 CFDictionarySetValue(at, kSecClass, kSecClassKey);
446 CFDictionarySetValue(at, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
447 CFDictionarySetValue(at, kSecAttrKeySizeInBits, CFSTR("256"));
448 CFDictionarySetValue(at, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
449 return CFBridgingRetain(privKeyAttrs[(id)kSecValueData]);
450 };
451
452 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
453 phase |= 0x04;
454 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
455 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
456 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
457 CFDataRef acData = SecAccessControlCopyData(ac);
458 CFRelease(ac);
459 return acData;
460 };
461
462 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
463 phase |= 0x08;
464 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
465 CFDataRef publicData;
466 SecKeyCopyPublicBytes(privKey, &publicData);
467 CFRelease(privKey);
468 return publicData;
469 };
470
471 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
472 phase |= 0x10;
473 return kCFNull;
474 };
475 });
476
477 NSMutableDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
478 (id)kSecAttrKeySizeInBits: @"256",
479 (id)kSecAttrTokenID: @"tokenid",
480 }.mutableCopy;
481 if (globalPersistence >= 0) {
482 params[(id)kSecAttrIsPermanent] = globalPersistence ? @YES : @NO;
483 }
484 if (publicPersistence >= 0) {
485 params[(id)kSecPublicKeyAttrs] = @{ (id)kSecAttrIsPermanent: publicPersistence ? @YES : @NO };
486 }
487 if (privatePersistence >= 0) {
488 params[(id)kSecPrivateKeyAttrs] = @{ (id)kSecAttrIsPermanent: privatePersistence ? @YES : @NO };
489 }
490
491 NSError *error;
492 phase = 0;
493 id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error));
494 isnt(privateKey, nil, "failed to generate token key, error %@", error);
495 is(phase, privateIsPersistent ? 0x3f : 0x1f);
496 id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey));
497 isnt(publicKey, nil, "failed to get public key from private key");
498
499 NSDictionary *query = @{ (id)kSecValueRef: privateKey,
500 (id)kSecReturnAttributes: @YES,
501 (id)kSecReturnRef: @YES,
502 (id)kSecReturnData: @YES };
503 phase = 0;
504 NSDictionary *result;
505 if (privateIsPersistent) {
506 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent private key not found in kc");
507 is(phase, 0x19);
508 is(result[(id)kSecValueData], nil);
509 eq_cf((__bridge CFTypeRef)result[(id)kSecAttrTokenID], @"tokenid");
510 NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)result[(id)kSecValueRef]));
511 eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]);
512 keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey));
513 eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]);
514 } else {
515 is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral private key found in kc");
516 is(phase, 0x08);
517
518 // Balancing test count from the branch above
519 ok(true);
520 ok(true);
521 ok(true);
522 ok(true);
523 }
524
525 query = @{ (id)kSecValueRef: publicKey,
526 (id)kSecReturnAttributes: @YES,
527 (id)kSecReturnRef: @YES,
528 (id)kSecReturnData: @YES };
529 phase = 0;
530 result = nil;
531 if (publicIsPersistent) {
532 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), "persistent public key not found in kc");
533 NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey));
534 eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]);
535 } else {
536 is_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral public key found in kc");
537
538 // Balancing test count from the branch above
539 ok(true);
540 }
541
542 // Get OID from the private key and try to create duplicate of the key using its OID and attributes.
543 NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey));
544 NSData *oid = attrs[(id)kSecAttrTokenOID];
545 ok(oid != nil, "private key attributes need OID");
546 phase = 0;
547 id copyKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)[NSData data],
548 (CFDictionaryRef)@{ (id)kSecAttrTokenID: @"tokenid", (id)kSecAttrTokenOID: oid },
549 (void *)&error));
550 ok(copyKey != nil, "copied key is created");
551 is(phase, 0x21);
552 attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyKey));
553 is(phase, 0x29);
554 phase = 0;
555 eq_cf((__bridge CFTypeRef)attrs[(id)kSecClass], kSecClassKey);
556 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyClass], kSecAttrKeyClassPrivate);
557 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyType], kSecAttrKeyTypeECSECPrimeRandom);
558 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeySizeInBits], CFSTR("256"));
559 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], CFSTR("tokenid"));
560 id copyPublicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)copyKey));
561 ok(copyPublicKey != nil);
562 is(phase, 0x08);
563 NSDictionary *pubAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyPublicKey));
564 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)pubAttrs[(id)kSecAttrApplicationLabel]);
565 }
566
567 static void test_key_sign(void) {
568
569 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
570 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
571
572 __block int phase = 0;
573 __block CFErrorRef cryptoError = NULL;
574 __block SecKeyOperationType cryptoOperation = -1;
575 __block SecKeyAlgorithm cryptoAlgorithm = NULL;
576 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
577 phase++;
578
579 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
580 phase++;
581 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
582 CFDataRef publicData;
583 ok_status(SecKeyCopyPublicBytes(privKey, &publicData));
584 CFRelease(privKey);
585 return publicData;
586 };
587
588 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
589 phase++;
590 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
591 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
592 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
593 CFDataRef acData = SecAccessControlCopyData(ac);
594 CFRelease(ac);
595 return acData;
596 };
597
598 blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
599 SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1);
600 phase++;
601 cryptoOperation = operation;
602 cryptoAlgorithm = algorithm;
603 if (cryptoError != NULL) {
604 CFAssignRetained(*error, cryptoError);
605 cryptoError = NULL;
606 return NULL;
607 }
608 return CFRetainSafe(valueData);
609 };
610
611 blocks->copyObjectData = ^CFTypeRef(CFDataRef objectID, CFErrorRef *error) {
612 phase++;
613 return kCFNull;
614 };
615 });
616
617 NSDictionary *query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecReturnRef: @YES };
618
619 phase = 0;
620 SecKeyRef privateKey = NULL;
621 ok_status(SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey));
622 is(phase, 2);
623
624 phase = 0;
625 CFMutableDataRef sig = CFDataCreateMutable(NULL, 0);
626 CFDataSetLength(sig, 256);
627 size_t sigLen = CFDataGetLength(sig);
628 ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen));
629 is(phase, 1);
630 is(cryptoAlgorithm, kSecKeyAlgorithmECDSASignatureDigestX962);
631 is(cryptoOperation, kSecKeyOperationTypeSign);
632 CFDataSetLength(sig, sigLen);
633 is(CFDataGetLength(sig), CFDataGetLength(valueData));
634 eq_cf(valueData, sig);
635
636 #if LA_CONTEXT_IMPLEMENTED
637 phase = 0;
638 CFDataSetLength(sig, 256);
639 sigLen = CFDataGetLength(sig);
640 LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; });
641 cryptoError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationNeeded, NULL);
642 ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen));
643 is(phase, 4);
644 is(cryptoError, NULL);
645 CFDataSetLength(sig, sigLen);
646 is(CFDataGetLength(sig), CFDataGetLength(valueData));
647 eq_cf(valueData, sig);
648 #endif
649
650 NSError *error;
651 NSData *result;
652 result = CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionRaw,
653 valueData, (void *)&error));
654 eq_cf((__bridge CFDataRef)result, valueData);
655 is(cryptoAlgorithm, kSecKeyAlgorithmRSAEncryptionRaw);
656 is(cryptoOperation, kSecKeyOperationTypeDecrypt);
657
658 NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256 };
659 SecKeyRef otherPrivKey = NULL, otherPubKey = NULL;
660 ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)params, &otherPubKey, &otherPrivKey));
661
662 error = nil;
663 result = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privateKey, kSecKeyAlgorithmECDHKeyExchangeCofactor,
664 otherPubKey, (CFDictionaryRef)@{}, (void *)&error));
665 eq_cf((__bridge CFDataRef)result, valueData);
666 is(cryptoAlgorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor);
667 is(cryptoOperation, kSecKeyOperationTypeKeyExchange);
668
669 CFReleaseSafe(otherPrivKey);
670 CFReleaseSafe(otherPubKey);
671 CFReleaseSafe(cryptoError);
672 CFRelease(sig);
673 CFRelease(privateKey);
674 }
675
676 static void test_key_generate_with_params(void) {
677
678 const UInt8 data[] = "foo";
679 CFDataRef cred_ref = CFDataCreate(NULL, data, 4);
680 __block int phase = 0;
681 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
682 phase++;
683 eq_cf(CFDictionaryGetValue(attributes, kSecUseOperationPrompt), CFSTR("prompt"));
684 is(CFDictionaryGetValue(attributes, kSecUseAuthenticationUI), NULL);
685 eq_cf(CFDictionaryGetValue(attributes, kSecUseCredentialReference), cred_ref);
686
687 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
688 phase++;
689 SecCFCreateError(-4 /* kTKErrorCodeCanceledByUser */, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error);
690 return NULL;
691 };
692 });
693
694 CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL,
695 kSecAttrIsPermanent, kCFBooleanTrue,
696 NULL);
697
698 CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL,
699 kSecAttrKeyType, kSecAttrKeyTypeEC,
700 kSecAttrKeySizeInBits, CFSTR("256"),
701 kSecAttrTokenID, CFSTR("tokenid"),
702 kSecPrivateKeyAttrs, prk_params,
703 kSecUseOperationPrompt, CFSTR("prompt"),
704 kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow,
705 kSecUseCredentialReference, cred_ref,
706 NULL);
707 CFRelease(prk_params);
708
709 SecKeyRef publicKey = NULL, privateKey = NULL;
710 phase = 0;
711 is_status(SecKeyGeneratePair(params, &publicKey, &privateKey), errSecUserCanceled);
712 is(phase, 2);
713
714 CFReleaseSafe(publicKey);
715 CFReleaseSafe(privateKey);
716 CFRelease(params);
717 CFRelease(cred_ref);
718 }
719
720 static void test_error_codes(void) {
721
722 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
723 kSecClass, kSecClassGenericPassword,
724 kSecAttrTokenID, CFSTR("tokenid"),
725 NULL);
726 // Setup token hook.
727 __block OSStatus ctk_error = 0;
728 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
729 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
730 SecCFCreateError(ctk_error, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error);
731 return NULL;
732 };
733 });
734
735 ctk_error = kTKErrorCodeBadParameter;
736 is_status(SecItemAdd(attrs, NULL), errSecParam);
737
738 ctk_error = kTKErrorCodeNotImplemented;
739 is_status(SecItemAdd(attrs, NULL), errSecUnimplemented);
740
741 ctk_error = kTKErrorCodeCanceledByUser;
742 is_status(SecItemAdd(attrs, NULL), errSecUserCanceled);
743
744 CFRelease(attrs);
745 }
746
747 static CFDataRef copy_certificate_data(const char *base64Cert)
748 {
749 size_t size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), NULL, 0);
750 ok(size);
751 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, size);
752 CFDataSetLength(data, size);
753 size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), (char*)CFDataGetMutableBytePtr(data), CFDataGetLength(data));
754 ok(size);
755 CFDataSetLength(data, size);
756
757 return data;
758 }
759
760 static CFMutableDictionaryRef copy_certificate_attributes(const char *base64Cert)
761 {
762 CFDataRef data = copy_certificate_data(base64Cert);
763
764 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, data);
765 ok(cert);
766 CFDictionaryRef certAttributes = SecCertificateCopyAttributeDictionary(cert);
767 ok(certAttributes);
768 CFMutableDictionaryRef result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, certAttributes);
769 ok(result);
770
771 if (certAttributes)
772 CFRelease(certAttributes);
773 if (data)
774 CFRelease(data);
775 if (cert)
776 CFRelease(cert);
777
778 return result;
779 }
780
781 static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFDataRef oid, CFStringRef tokenID)
782 {
783 CFMutableDictionaryRef certAttributes = copy_certificate_attributes(base64cert);
784
785 CFDictionarySetValue(certAttributes, kSecAttrLabel, label);
786 CFDictionarySetValue(certAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate);
787 if (oid != NULL) {
788 CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid);
789 }
790 CFDictionaryRemoveValue(certAttributes, kSecValueData);
791
792 if (tokenID != NULL) {
793 SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
794 ok(acl);
795 CFTypeRef key[] = { kSecAttrTokenID };
796 CFTypeRef value[] = { tokenID };
797 CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
798 ok(SecAccessControlSetProtection(acl, protection, NULL));
799 CFRelease(protection);
800 ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
801 CFDataRef aclData = SecAccessControlCopyData(acl);
802 ok(aclData);
803 if (aclData) {
804 CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData);
805 CFRelease(aclData);
806 }
807
808 if (acl)
809 CFRelease(acl);
810 } else {
811 NSData *certData = CFBridgingRelease(copy_certificate_data(base64cert));
812 CFDictionarySetValue(certAttributes, kSecValueData, (__bridge CFDataRef)certData);
813 }
814
815 return certAttributes;
816 }
817
818 static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFDataRef oid, CFStringRef tokenID)
819 {
820 CFMutableDictionaryRef keyAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ;
821
822 CFDictionarySetValue(keyAttributes, kSecClass, kSecClassKey);
823 CFDictionarySetValue(keyAttributes, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
824 CFDictionarySetValue(keyAttributes, kSecAttrKeyType, kSecAttrKeyTypeRSA);
825 CFNumberRef keySize = CFNumberCreateWithCFIndex(kCFAllocatorDefault, 2048);
826 CFDictionarySetValue(keyAttributes, kSecAttrKeySizeInBits, keySize);
827 CFRelease(keySize);
828
829 CFDictionarySetValue(keyAttributes, kSecAttrCanDecrypt, kCFBooleanTrue);
830 CFDictionarySetValue(keyAttributes, kSecAttrCanSign, kCFBooleanTrue);
831 CFDictionarySetValue(keyAttributes, kSecAttrCanUnwrap, kCFBooleanTrue);
832 CFDictionarySetValue(keyAttributes, kSecAttrCanDerive, kCFBooleanFalse);
833 CFDictionarySetValue(keyAttributes, kSecAttrIsPrivate, kCFBooleanTrue);
834
835 CFDictionarySetValue(keyAttributes, kSecAttrLabel, label);
836 CFDictionarySetValue(keyAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate);
837 CFDictionarySetValue(keyAttributes, kSecAttrTokenOID, oid);
838 CFDictionarySetValue(keyAttributes, kSecAttrApplicationLabel, CFDictionaryGetValue(certAttributes, kSecAttrPublicKeyHash));
839
840 SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
841 ok(acl);
842 CFTypeRef key[] = { kSecAttrTokenID };
843 CFTypeRef value[] = { tokenID };
844 CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
845 ok(SecAccessControlSetProtection(acl, protection, NULL));
846 CFRelease(protection);
847 ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
848 CFDataRef aclData = SecAccessControlCopyData(acl);
849 ok(aclData);
850 if (aclData) {
851 CFDictionarySetValue(keyAttributes, kSecAttrAccessControl, aclData);
852 CFRelease(aclData);
853 }
854
855 if (acl)
856 CFRelease(acl);
857
858 return keyAttributes;
859 }
860
861 static void check_array_for_type_id(CFArrayRef array, CFTypeID typeID)
862 {
863 if (array && CFGetTypeID(array) == CFArrayGetTypeID()) {
864 for (CFIndex i = 0; i < CFArrayGetCount(array); ++i) {
865 ok(CFGetTypeID(CFArrayGetValueAtIndex(array, i)) == typeID);
866 }
867 }
868 }
869
870 static void test_propagate_token_items()
871 {
872 if (!os_feature_enabled(CryptoTokenKit, UseTokens)) {
873 // This test does not work if tokens cannot be used by keychain.
874 return;
875 }
876
877 NSData *cert1OID = [@"oid1" dataUsingEncoding:NSUTF8StringEncoding];
878 NSData *cert2OID = [@"oid2" dataUsingEncoding:NSUTF8StringEncoding];
879 NSData *key1OID = [@"oid3" dataUsingEncoding:NSUTF8StringEncoding];
880 NSData *key2OID = [@"oid4" dataUsingEncoding:NSUTF8StringEncoding];
881
882 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
883 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
884 if (CFEqual(oid, (__bridge CFDataRef)cert1OID)) {
885 return copy_certificate_data(cert1);
886 }
887 else if (CFEqual(oid, (__bridge CFDataRef)cert2OID)) {
888 return copy_certificate_data(cert2);
889 }
890 else if (CFEqual(oid, (__bridge CFDataRef)key1OID) || CFEqual(oid, (__bridge CFDataRef)key2OID)) {
891 return kCFNull;
892 }
893 else {
894 return NULL;
895 }
896 };
897 });
898
899 CFStringRef tokenID = CFSTR("com.apple.secdtest:propagate_test_token");
900
901 CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
902
903 CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), (__bridge CFDataRef)cert1OID, tokenID);
904 ok(certQuery);
905 CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), (__bridge CFDataRef)key1OID, tokenID);
906 ok(keyQuery);
907
908 CFArrayAppendValue(items, certQuery);
909 CFArrayAppendValue(items, keyQuery);
910 CFReleaseSafe(certQuery);
911 CFReleaseSafe(keyQuery);
912
913 certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), (__bridge CFDataRef)cert2OID, tokenID);
914 ok(certQuery);
915 keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), (__bridge CFDataRef)key2OID, tokenID);
916 ok(keyQuery);
917
918 CFArrayAppendValue(items, certQuery);
919 CFArrayAppendValue(items, keyQuery);
920 CFReleaseSafe(certQuery);
921 CFReleaseSafe(keyQuery);
922
923 OSStatus result;
924 ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL), "Failed to delete items.");
925
926 ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], items), "Failed to propagate items.");
927 CFRelease(items);
928
929 CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
930 CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
931 CFDictionarySetValue(query, kSecAttrAccessGroup, CFSTR("com.apple.token"));
932 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
933 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
934 CFTypeRef queryResult;
935 ok_status(SecItemCopyMatching(query, &queryResult));
936 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs");
937 check_array_for_type_id(queryResult, SecCertificateGetTypeID());
938 CFReleaseNull(queryResult);
939
940 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
941 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
942 ok_status(SecItemCopyMatching(query, &queryResult));
943 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs");
944 check_array_for_type_id(queryResult, CFDataGetTypeID());
945 CFReleaseNull(queryResult);
946
947 CFDictionarySetValue(query, kSecClass, kSecClassKey);
948 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
949 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
950 ok_status(SecItemCopyMatching(query, &queryResult));
951 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two keys");
952 check_array_for_type_id(queryResult, SecKeyGetTypeID());
953 CFReleaseNull(queryResult);
954
955 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
956 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
957 ok_status(SecItemCopyMatching(query, &queryResult));
958 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array");
959 CFReleaseNull(queryResult);
960
961 CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
962 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
963 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
964 ok_status(SecItemCopyMatching(query, &queryResult));
965 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two identities");
966 check_array_for_type_id(queryResult, SecIdentityGetTypeID());
967 CFReleaseNull(queryResult);
968
969 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
970 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
971 ok_status(SecItemCopyMatching(query, &queryResult));
972 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array");
973 CFReleaseNull(queryResult);
974
975 ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL), "Failed to delete items.");
976
977 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
978 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
979 is_status(SecItemCopyMatching(query, &queryResult), errSecItemNotFound);
980 CFReleaseNull(queryResult);
981 CFRelease(query);
982 }
983
984 static void test_identity_on_two_tokens() {
985 if (!os_feature_enabled(CryptoTokenKit, UseTokens)) {
986 // This test does not work if tokens cannot be used by keychains.
987 return;
988 }
989
990 @autoreleasepool {
991 NSString *tokenID1 = @"com.apple.secdtest:identity_test_token1";
992 NSString *tokenID2 = @"com.apple.secdtest:identity_test_token2";
993
994 NSError *error;
995 NSData *privKeyData = [[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters];
996 id privKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)privKeyData, (CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate}, (void *)&error));
997 id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)privKey));
998 NSData *pubKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash((__bridge SecKeyRef)publicKey));
999
1000 NSData *cert3OID = [@"oid1" dataUsingEncoding:NSUTF8StringEncoding];
1001 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
1002
1003 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
1004 if (CFEqual(oid, (__bridge CFDataRef)cert3OID))
1005 return copy_certificate_data(cert3);
1006 else
1007 return kCFNull;
1008 };
1009
1010 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
1011 if ([privKeyData isEqualToData:(__bridge NSData *)oid]) {
1012 return SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, error);
1013 }
1014 return NULL;
1015 };
1016
1017 });
1018
1019 id ac = CFBridgingRelease(SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL));
1020 id acData = CFBridgingRelease(SecAccessControlCopyData((__bridge SecAccessControlRef)ac));
1021 NSDictionary *keyQuery = @{ (id)kSecClass: (id)kSecClassKey,
1022 (id)kSecAttrTokenID: tokenID1,
1023 (id)kSecAttrKeyType : (id)kSecAttrKeyTypeECSECPrimeRandom,
1024 (id)kSecAttrKeySizeInBits : @"256",
1025 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
1026 (id)kSecAttrIsPrivate: @YES,
1027 (id)kSecAttrAccessControl: acData,
1028 (id)kSecAttrTokenOID : privKeyData,
1029 (id)kSecAttrApplicationLabel : pubKeyHash,
1030 };
1031 OSStatus result;
1032 ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)@[keyQuery]), "Failed to propagate key item.");
1033
1034 id privateKey;
1035 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)@{(id)kSecClass: (id)kSecClassKey, (id)kSecAttrTokenID: tokenID1, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecReturnRef: @YES}, (void *)&privateKey));
1036
1037 NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), (__bridge CFDataRef)cert3OID, (__bridge CFStringRef)tokenID2));
1038 ok(certQuery);
1039
1040 ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)@[certQuery]), "Failed to propagate cert item.");
1041
1042 CFTypeRef resultRef;
1043 NSDictionary *query = @{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken };
1044 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1045 CFReleaseNull(resultRef);
1046
1047 query = @{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken };
1048 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1049 CFReleaseNull(resultRef);
1050
1051 query = @{ (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken };
1052 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1053 CFReleaseNull(resultRef);
1054
1055 NSData *persRef, *persRef2;
1056 id newRef;
1057
1058 // Query persistent reference for key and verify that we can get key back using it.
1059 query = @{ (id)kSecValueRef: privateKey, (id)kSecReturnPersistentRef: @YES };
1060 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
1061 query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
1062 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
1063 eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
1064 query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
1065 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef));
1066 eq_cf((__bridge CFTypeRef)privateKey, (__bridge CFTypeRef)newRef);
1067
1068 // Query persistent reference for certificate and verify that we can get certificate back using it.
1069 id certRef;
1070 query = @{ (id)kSecClass: (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash: pubKeyHash, (id)kSecReturnRef: @YES };
1071 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&certRef));
1072
1073 persRef = nil;
1074 persRef2 = nil;
1075 newRef = nil;
1076 query = @{ (id)kSecValueRef: certRef, (id)kSecReturnPersistentRef: @YES };
1077 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
1078 query = @{ (id)kSecClass: (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
1079 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
1080 eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
1081 query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
1082 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef));
1083 eq_cf((__bridge CFTypeRef)certRef, (__bridge CFTypeRef)newRef);
1084
1085 // Query persistent reference for identity and verify that we can get identity back using it.
1086 id identityRef;
1087 NSDictionary *attrs;
1088 query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
1089 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
1090 identityRef = attrs[(id)kSecValueRef];
1091 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
1092
1093 persRef = nil;
1094 persRef2 = nil;
1095 attrs = nil;
1096 query = @{ (id)kSecValueRef: identityRef, (id)kSecReturnPersistentRef: @YES };
1097 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
1098 query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
1099 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
1100 eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
1101 query = @{ (id)kSecValuePersistentRef: persRef2, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
1102 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
1103 eq_cf((__bridge CFTypeRef)identityRef, (__bridge CFTypeRef)attrs[(id)kSecValueRef]);
1104 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
1105
1106 // Remove certificate from token and add it as regular keychain item (non-token) one. Following tests
1107 // repeat identity test for key-on-token, certificate-non-token hybrid identities.
1108 ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL));
1109 certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("reg_cert3"), NULL, NULL));
1110 ok_status(result = SecItemAdd((__bridge CFDictionaryRef)certQuery, NULL));
1111
1112 query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnRef: @YES };
1113 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&identityRef));
1114 isnt(identityRef, NULL);
1115
1116 persRef = nil;
1117 persRef2 = nil;
1118 attrs = nil;
1119 query = @{ (id)kSecValueRef: identityRef, (id)kSecReturnPersistentRef: @YES };
1120 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
1121 query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
1122 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
1123 eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
1124 query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
1125 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
1126 eq_cf((__bridge CFTypeRef)identityRef, (__bridge CFTypeRef)attrs[(id)kSecValueRef]);
1127 eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
1128
1129 // After removing token with key, getting identity from persistent reference must fail gracefully.
1130 ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL));
1131 query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
1132 is_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef), errSecItemNotFound);
1133
1134 // Getting persistent reference to non-token item with token-like (but malformed) data must not crash.
1135 NSData *data = CFBridgingRelease(CFPropertyListCreateDERData(kCFAllocatorDefault, (__bridge CFPropertyListRef)@[], NULL));
1136 query = @{ (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrLabel: @"probe", (id)kSecValueData: data};
1137 ok_status(result = SecItemAdd((__bridge CFDictionaryRef)query, NULL));
1138 NSDictionary *dict;
1139 query = @{ (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrLabel: @"probe", (id)kSecReturnPersistentRef: @YES, (id)kSecReturnData: @YES };
1140 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&dict));
1141 NSData *newData;
1142 query = @{ (id)kSecValuePersistentRef: dict[(id)kSecValuePersistentRef], (id)kSecReturnData: @YES };
1143 ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newData));
1144 eq_cf((__bridge CFTypeRef)data, (__bridge CFTypeRef)newData);
1145 }
1146 }
1147
1148 static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) {
1149 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
1150
1151 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
1152 return CFBridgingRetain([@"oid" dataUsingEncoding:NSUTF8StringEncoding]);
1153 };
1154
1155 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
1156 SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey);
1157 CFDataRef data = SecKeyCopyExternalRepresentation(publicKey, error);
1158 CFReleaseNull(publicKey);
1159 return data;
1160 };
1161
1162 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
1163 return kCFNull;
1164 };
1165
1166 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
1167 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
1168 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
1169 test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
1170 CFDataRef acData = SecAccessControlCopyData(ac);
1171 CFRelease(ac);
1172 return acData;
1173 };
1174
1175 blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
1176 CFTypeRef result = kCFNull;
1177 CFTypeRef algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1);
1178 switch (operation) {
1179 case kSecKeyOperationTypeKeyExchange: {
1180 if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandard) ||
1181 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
1182 NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes(privateKey));
1183 NSDictionary *params = @{
1184 (id)kSecAttrKeyType: attrs[(id)kSecAttrKeyType],
1185 (id)kSecAttrKeySizeInBits: attrs[(id)kSecAttrKeySizeInBits],
1186 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic,
1187 };
1188 SecKeyRef pubKey = SecKeyCreateWithData(in1, (CFDictionaryRef)params, error);
1189 if (pubKey == NULL) {
1190 return NULL;
1191 }
1192 result = SecKeyCopyKeyExchangeResult(privateKey, algorithm, pubKey, in2, error);
1193 CFReleaseSafe(pubKey);
1194 }
1195 break;
1196 }
1197 case kSecKeyOperationTypeDecrypt: {
1198 if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
1199 result = SecKeyCreateDecryptedData(privateKey, algorithm, in1, error);
1200 }
1201 break;
1202 }
1203 default:
1204 break;
1205 }
1206 return result;
1207 };
1208 });
1209
1210 NSDictionary *privateParams = CFBridgingRelease(SecKeyCopyAttributes(privateKey));
1211 NSDictionary *params = @{ (id)kSecAttrKeyType : privateParams[(id)kSecAttrKeyType],
1212 (id)kSecAttrKeySizeInBits : privateParams[(id)kSecAttrKeySizeInBits],
1213 (id)kSecAttrTokenID : @"tid-ies",
1214 (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @NO }
1215 };
1216 NSError *error;
1217 SecKeyRef tokenKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error);
1218 ok(tokenKey != NULL, "create token-based key (err %@)", error);
1219 SecKeyRef tokenPublicKey = SecKeyCopyPublicKey(tokenKey);
1220
1221 NSData *plaintext = [@"plaintext" dataUsingEncoding:NSUTF8StringEncoding];
1222
1223 error = nil;
1224 NSData *ciphertext = CFBridgingRelease(SecKeyCreateEncryptedData(tokenPublicKey, algorithm, (CFDataRef)plaintext, (void *)&error));
1225 ok(ciphertext, "failed to encrypt IES, err %@", error);
1226
1227 NSData *decrypted = CFBridgingRelease(SecKeyCreateDecryptedData(tokenKey, algorithm, (CFDataRef)ciphertext, (void *)&error));
1228 ok(decrypted, "failed to decrypt IES, err %@", error);
1229
1230 eq_cf((__bridge CFDataRef)plaintext, (__bridge CFDataRef)decrypted, "decrypted(%@) != plaintext(%@)", decrypted, plaintext);
1231
1232 CFReleaseNull(tokenKey);
1233 CFReleaseNull(tokenPublicKey);
1234 }
1235
1236 static void test_ecies() {
1237 NSError *error;
1238 SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error);
1239 ok(privateKey != NULL, "failed to generate CPU EC key: %@", error);
1240
1241 test_ies(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM);
1242
1243 CFReleaseNull(privateKey);
1244 }
1245
1246 static void test_rsawrap() {
1247 NSError *error;
1248 SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048}, (void *)&error);
1249 ok(privateKey != NULL, "failed to generate CPU RSA key: %@", error);
1250
1251 test_ies(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM);
1252
1253 CFReleaseNull(privateKey);
1254 }
1255
1256 static void tests(void) {
1257 /* custom keychain dir */
1258 secd_test_setup_temp_keychain("secd_33_keychain_ctk", NULL);
1259
1260 test_item_add();
1261 test_item_query();
1262 test_item_update();
1263 test_item_delete();
1264
1265 // params: int globalPersistence, int privatePersistence, int publicPersistence, bool privateIsPersistent, bool publicIsPersistent
1266 test_key_generate(-1, -1, -1, true, false);
1267 test_key_generate(0, -1, -1, false, false);
1268 test_key_generate(1, -1, -1, true, true);
1269 test_key_generate(-1, 0, 0, false, false);
1270 test_key_generate(-1, 1, 0, true, false);
1271 test_key_generate(-1, 0, 1, false, true);
1272 test_key_generate(-1, 1, 1, true, true);
1273 test_key_generate(0, 1, 1, true, true);
1274 test_key_generate(1, 1, 1, true, true);
1275
1276 test_key_sign();
1277 test_key_generate_with_params();
1278 test_error_codes();
1279 test_propagate_token_items();
1280 test_identity_on_two_tokens();
1281 test_rsawrap();
1282 test_ecies();
1283 }
1284
1285 int secd_33_keychain_ctk(int argc, char *const *argv) {
1286 if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
1287 plan_tests(539);
1288 } else {
1289 plan_tests(403);
1290 }
1291
1292 tests();
1293
1294 return 0;
1295 }