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