]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m
Security-57740.31.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 /*
25 * This is to fool os services to not provide the Keychain manager
26 * interface tht doens't work since we don't have unified headers
27 * between iOS and OS X. rdar://23405418/
28 */
29 #define __KEYCHAINCORE__ 1
30 #import <Foundation/Foundation.h>
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <Security/SecFramework.h>
34 #include <Security/SecBase.h>
35 #include <Security/SecItem.h>
36 #include <Security/SecItemPriv.h>
37 #include <Security/SecKey.h>
38 #include <Security/SecKeyPriv.h>
39 #include <Security/SecECKey.h>
40 #include <Security/SecAccessControl.h>
41 #include <Security/SecAccessControlPriv.h>
42 #include <Security/SecInternal.h>
43 #include <Security/SecCertificatePriv.h>
44 #include <utilities/SecFileLocations.h>
45 #include <utilities/SecCFWrappers.h>
46 #include <utilities/SecCFError.h>
47 #include <SecBase64.h>
48
49 #include <libaks_acl_cf_keys.h>
50
51 #include <ctkclient_test.h>
52 #include <coreauthd_spi.h>
53
54 #include "secd_regressions.h"
55
56 #include "SecdTestKeychainUtilities.h"
57 #include "SecKeybagSupport.h"
58
59 const char *cert1 = "MIIFQzCCBCugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN8DrET5AAQ4dVIP+RD3XATFaBYpG9b2H0tV82gVGOv/t5cxOszAMxzsw7xlY/tMRrx5yz7IUUvueylHl98e7yMefP69vwqwSc4DWSELSqHOLMHd/uPLYLINIFqEW8Nq4Q02V2IxqBbiwtZeeSOqY3gQ2kiCd4cF8Itlr3UePJrlAgMBAAGjggKzMIICrzAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQg5YNVxRTOC13qs9cVUuvDIp6AH+jitdjhWJfai2bfP3QwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCGCGSAFlAwYIMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDETCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMDIGA1UdEQQrMCmgJwYIYIZIAWUDBgagGwQZ1Oc52nOc7TnOc52haFoIySreCmGE5znD4jAQBglghkgBZQMGCQEEAwEBADANBgkqhkiG9w0BAQsFAAOCAQEAVVGMeep+1wpVFdXFIXUTkxy9RjdOO3SmMGVomfVXofVOBfVzooaI+RV5UCURnoqoHYziBidxc9YKW6n9mX6p27KfrC1roHg6wu5xVEHJ93hju35g3WAXTnqNFiQpB+GU7UvJJEhkcTU2rChuYNS5SeFZ0pv1Gyzw7WjLfh9rdAPBfRg4gxpho9SMCUnI+p5KbEiptmimtPfsVq6htT3P+m2V4UXIT6sr7T6IpnPteMppsH43NKXNM6iPCkRCUPQ0d+lpfXAYGSFIzx2WesjSmrs/CHXfwmhnbrJNPCx9zlcCMmmfGcZGyufF+10wF9gv9qx+PUwi2xMKhwuKR1LoCg==";
60 const char *cert2 =
61 "MIIFCTCCA/GgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJVUzENMAsGA1UEChMETklTVDEUMBIGA1UEAxMLUElWIFRlc3QgQ0EwHhcNMTUwOTE2MDAwMDAwWhcNMTYwOTE2MjM1OTU5WjBlMQswCQYDVQQGEwJVUzEbMBkGA1UEChMST2JlcnR1clRlY2hub2xvZ2llMRowGAYDVQQLExFJZGVudGl0eSBEaXZpc2lvbjEdMBsGA1UEAxMUSUQtT25lIFBJViBUZXN0IENhcmQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKij0LIQlW0VKahBGF4tu/xdwGWN+KTLLGyMQmuuG+NNG+vQMSsdXD1pd00YMBiGn3sC5b+G7lQLZ85mDQfO+eI8GDjG+Sh8W8Cghku20sxZnQ+kZOLOr//R2/ZXonVaxoBR/9tBPh0MIEIVzRS8JmltZVfhkbIR6Wiox3jVEAsPAgMBAAGjggJ5MIICdTAfBgNVHSMEGDAWgBTr2hnSCEKN9N4lh2nJu6sM05YwATApBgNVHQ4EIgQga85kaqoMEaV+E04P1gZ2OUlbCbvr623fC30WhBZn3bMwDgYDVR0PAQH/BAQDAgbAMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEDDTCBtAYDVR0fBIGsMIGpMIGmoIGjoIGghkRodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ1JMZGlyZWN0b3J5L2ZpY3RpdGlvdXNDUkwxLmNybIZYbGRhcDovL3NtaW1lMi5uaXN0Lmdvdi9jbj1Hb29kJTIwQ0Esbz1UZXN0JTIwQ2VydGlmaWNhdGVzLGM9VVM/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDCCASEGCCsGAQUFBwEBBIIBEzCCAQ8wPgYIKwYBBQUHMAGGMmh0dHA6Ly9maWN0aXRpb3VzLm5pc3QuZ292L2ZpY3RpdGlvdXNPQ1NQTG9jYXRpb24vMF4GCCsGAQUFBzAChlJodHRwOi8vZmljdGl0aW91cy5uaXN0Lmdvdi9maWN0aXRpb3VzQ2VydHNPbmx5Q01TZGlyZWN0b3J5L2NlcnRzSXNzdWVkVG9Hb29kQ0EucDdjMG0GCCsGAQUFBzAChmFsZGFwOi8vc21pbWUyLm5pc3QuZ292L2NuPUdvb2QlMjBDQSxvPVRlc3QlMjBDZXJ0aWZpY2F0ZXMsYz1VUz9jQUNlcnRpZmljYXRlLGNyb3NzQ2VydGlmaWNhdGVQYWlyMCIGA1UdEQQbMBmBF2NvbW1vbl9uYW1lQHBpdmRlbW8ub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQANg1tGsgO32fVXDyRPHFeqDa0QmQ4itHrh6BAK6n94QL8383wuPDFkPy1TfVYVdYm0Gne6hyH/Z13ycw1XXNddooT7+OiYK5F1TEhfQNiRhzTqblB/yc2lv6Ho0EsOrwPhaBRaO3EFUyjeNMxsvG8Dr9Y5u2B38ESB4OsLKHq0eD/WZjEAlyGx16Qi7YlLiHGfLMorgkg9Mbp73guNO1PItDTAnqHUUOlQ01ThNug0sR5ua1zlNFx6AIPoX4yAPrtlEMZtbsevsXlgDpO1zc26p5icBmQHYT7uzdTEEN4tmcxXg6Z/dGB63GCluf+Pc+ovRt/MMt2EbcIuwJ9C516H";
62 const char *cert3 =
63 "MIICETCCAbigAwIBAgIJANiM7uTufLiKMAkGByqGSM49BAEwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MxGjAYBgNVBAMTEUFwcGxlIFRlc3QgQ0EyIEVDMSAwHgYJKoZIhvcNAQkBFhF2a3V6ZWxhQGFwcGxlLmNvbTAeFw0xNjA1MTIxMTMyMzlaFw0yNjA1MTAxMTMyMzlaMGYxEDAOBgNVBAMTB3NldG9rZW4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJQ3VwZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMQ8wDQYDVQQLEwZDb3JlT1MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQHKxfYgbqRHmThPnO9yQX5KrL/EPa6dZU52Wys5gC3/Mk0dNt9dLhpWblAVaeBzkos4juN3cxbnoB9MsC4bvoLoyMwITAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAJBgcqhkjOPQQBA0gAMEUCIQClcoYLhEA/xIGU94ZBcup26Pb7pXaWaaOM3+9z510TRwIgV/iprC051SuQzkqXA5weVliJOohFYjO+gUoH/6MJpDg=";
64
65 extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock)(void));
66
67 static void test_item_add(void) {
68
69 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
70 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
71 static const UInt8 oid[] = { 0x05, 0x06, 0x07, 0x08 };
72 CFDataRef oidData = CFDataCreate(NULL, oid, sizeof(oid));
73
74 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
75 kSecClass, kSecClassGenericPassword,
76 kSecAttrTokenID, CFSTR("tokenid"),
77 kSecAttrService, CFSTR("ctktest-service"),
78 kSecValueData, valueData,
79 kSecReturnAttributes, kCFBooleanTrue,
80 NULL);
81 // Setup token hook.
82 __block int phase = 0;
83 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
84 phase++;
85 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
86
87 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
88 phase++;
89 is(objectID, NULL);
90 eq_cf(CFDictionaryGetValue(at, kSecClass), kSecClassGenericPassword);
91 eq_cf(CFDictionaryGetValue(at, kSecAttrService), CFDictionaryGetValue(attrs, kSecAttrService));
92 eq_cf(CFDictionaryGetValue(at, kSecAttrTokenID), CFSTR("tokenid"));
93 eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData);
94 CFDictionaryRemoveValue(at, kSecValueData);
95 return CFRetainSafe(oidData);
96 };
97
98 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
99 phase++;
100 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
101 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
102 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
103 CFDataRef acData = SecAccessControlCopyData(ac);
104 CFRelease(ac);
105 return acData;
106 };
107
108 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
109 phase++;
110 return CFRetain(valueData);
111 };
112 });
113
114 CFTypeRef result = NULL;
115 ok_status(SecItemAdd(attrs, &result));
116 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service"));
117 eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid"));
118 is(CFDictionaryGetValue(result, kSecValueData), NULL);
119 CFReleaseNull(result);
120
121 is(phase, 3);
122
123 phase = 0;
124 CFDictionarySetValue(attrs, kSecReturnData, kCFBooleanTrue);
125 CFDictionarySetValue(attrs, kSecAttrService, CFSTR("ctktest-service1"));
126 ok_status(SecItemAdd(attrs, &result));
127 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service1"));
128 eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid"));
129 eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData);
130 CFReleaseNull(result);
131
132 is(phase, 4);
133
134 phase = 0;
135 CFDictionaryRemoveValue(attrs, kSecReturnAttributes);
136 CFDictionarySetValue(attrs, kSecAttrAccount, CFSTR("2nd"));
137 ok_status(SecItemAdd(attrs, &result));
138 eq_cf(result, valueData);
139 CFReleaseNull(result);
140 is(phase, 4);
141
142 CFRelease(attrs);
143 CFRelease(valueData);
144 CFRelease(oidData);
145 }
146 static const int kItemAddTestCount = 31;
147
148 static void test_item_query() {
149 static const UInt8 oid[] = { 0x05, 0x06, 0x07, 0x08 };
150 CFDataRef oidData = CFDataCreate(NULL, oid, sizeof(oid));
151 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
152 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
153 CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1);
154
155 __block int phase = 0;
156 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
157 phase++;
158 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
159
160 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
161 phase++;
162 return CFRetain(valueData);
163 };
164 });
165
166 // Add non-token item with the same service, to test queries returning mixed results.
167 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
168 kSecClass, kSecClassGenericPassword,
169 kSecAttrService, CFSTR("ctktest-service"),
170 kSecValueData, valueData2,
171 NULL);
172 ok_status(SecItemAdd(attrs, NULL));
173 CFRelease(attrs);
174
175 // Query with service.
176 CFMutableDictionaryRef query;
177 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
178 kSecClass, kSecClassGenericPassword,
179 kSecAttrService, CFSTR("ctktest-service"),
180 kSecReturnAttributes, kCFBooleanTrue,
181 kSecReturnData, kCFBooleanTrue,
182 NULL);
183
184 phase = 0;
185 CFTypeRef result = NULL;
186 ok_status(SecItemCopyMatching(query, &result));
187 is(phase, 2);
188 is(CFGetTypeID(result), CFDictionaryGetTypeID());
189 eq_cf(CFDictionaryGetValue(result, kSecValueData), valueData);
190 is(CFGetTypeID(CFDictionaryGetValue(result, kSecAttrAccessControl)), SecAccessControlGetTypeID());
191 eq_cf(CFDictionaryGetValue(result, kSecAttrService), CFSTR("ctktest-service"));
192 CFReleaseSafe(result);
193
194 phase = 0;
195 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
196 ok_status(SecItemCopyMatching(query, &result));
197 is(phase, 2);
198 is(CFGetTypeID(result), CFArrayGetTypeID());
199 is(CFArrayGetCount(result), 2);
200 CFReleaseSafe(result);
201
202 phase = 0;
203 CFDictionaryRemoveValue(query, kSecMatchLimit);
204 CFDictionaryRemoveValue(query, kSecReturnData);
205 ok_status(SecItemCopyMatching(query, &result));
206 is(phase, 0);
207 is(CFGetTypeID(result), CFDictionaryGetTypeID());
208 is(CFDictionaryGetValue(result, kSecValueData), NULL);
209 CFReleaseSafe(result);
210
211 phase = 0;
212 CFDictionaryRemoveValue(query, kSecReturnAttributes);
213 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
214 CFDictionarySetValue(query, kSecAttrTokenID, CFSTR("tokenid"));
215 ok_status(SecItemCopyMatching(query, &result));
216 is(phase, 2);
217 eq_cf(result, valueData);
218 CFReleaseSafe(result);
219
220 CFRelease(query);
221 CFRelease(valueData);
222 CFRelease(valueData2);
223 CFRelease(oidData);
224 }
225 static const int kItemQueryTestCount = 21;
226
227 static void test_item_update() {
228 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
229 CFDataRef valueData2 = CFDataCreate(NULL, data, sizeof(data) - 1);
230 CFTypeRef result = NULL;
231
232 CFMutableDictionaryRef query, attrs;
233
234 // Setup token hook.
235 __block int phase = 0;
236 __block bool store_value = false;
237 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
238 phase++;
239 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
240
241 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
242 phase++;
243 eq_cf(CFDictionaryGetValue(at, kSecValueData), valueData2);
244 if (!store_value) {
245 CFDictionaryRemoveValue(at, kSecValueData);
246 }
247 return CFRetainSafe(objectID);
248 };
249
250 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
251 phase++;
252 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
253 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
254 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
255 CFDataRef acData = SecAccessControlCopyData(ac);
256 CFRelease(ac);
257 return acData;
258 };
259
260 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
261 phase++;
262 return CFRetain(valueData2);
263 };
264 });
265
266 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
267 kSecClass, kSecClassGenericPassword,
268 kSecAttrTokenID, CFSTR("tokenid"),
269 kSecAttrService, CFSTR("ctktest-service"),
270 NULL);
271
272 attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
273 kSecValueData, valueData2,
274 NULL);
275
276 ok_status(SecItemUpdate(query, attrs));
277 is(phase, 3);
278
279 phase = 0;
280 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
281 ok_status(SecItemCopyMatching(query, &result));
282 eq_cf(valueData2, result);
283 CFRelease(result);
284 is(phase, 2);
285
286 phase = 0;
287 store_value = true;
288 CFDictionaryRemoveValue(query, kSecReturnData);
289 ok_status(SecItemUpdate(query, attrs));
290 is(phase, 3);
291
292 phase = 0;
293 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
294 ok_status(SecItemCopyMatching(query, &result));
295 eq_cf(valueData2, result);
296 CFRelease(result);
297 is(phase, 0);
298
299 phase = 0;
300 CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1"));
301 CFDictionaryRemoveValue(query, kSecReturnData);
302 ok_status(SecItemUpdate(query, attrs));
303 is(phase, 5);
304
305 phase = 0;
306 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
307 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
308 ok_status(SecItemCopyMatching(query, &result));
309 is(phase, 0);
310 is(CFGetTypeID(result), CFArrayGetTypeID());
311 is(CFArrayGetCount(result), 2);
312 eq_cf(CFArrayGetValueAtIndex(result, 0), valueData2);
313 eq_cf(CFArrayGetValueAtIndex(result, 1), valueData2);
314
315 CFRelease(query);
316 CFRelease(attrs);
317 CFRelease(valueData2);
318 }
319 static const int kItemUpdateTestCount = 26;
320
321 static void test_item_delete(void) {
322
323 CFMutableDictionaryRef query;
324 CFTypeRef result;
325
326 __block int phase = 0;
327 __block CFErrorRef deleteError = NULL;
328 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
329 phase++;
330 eq_cf(CFDictionaryGetValue(attributes, kSecAttrTokenID), CFSTR("tokenid"));
331
332 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
333 phase++;
334 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
335 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
336 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
337 CFDataRef acData = SecAccessControlCopyData(ac);
338 CFRelease(ac);
339 return acData;
340 };
341
342 blocks->deleteObject = ^bool(CFDataRef objectID, CFErrorRef *error) {
343 phase++;
344 if (deleteError != NULL) {
345 CFAssignRetained(*error, deleteError);
346 deleteError = NULL;
347 return false;
348 }
349 return true;
350 };
351 });
352
353 query = CFDictionaryCreateMutableForCFTypesWith(NULL,
354 kSecClass, kSecClassGenericPassword,
355 kSecAttrTokenID, CFSTR("tokenid"),
356 kSecAttrService, CFSTR("ctktest-service"),
357 NULL);
358
359 phase = 0;
360 ok_status(SecItemDelete(query));
361 is(phase, 2);
362
363 phase = 0;
364 is_status(SecItemCopyMatching(query, &result), errSecItemNotFound);
365 is(phase, 0);
366
367 phase = 0;
368 CFDictionarySetValue(query, kSecAttrService, CFSTR("ctktest-service1"));
369 ok_status(SecItemCopyMatching(query, &result));
370 is(phase, 0);
371
372 phase = 0;
373 #if LA_CONTEXT_IMPLEMENTED
374 LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; });
375 deleteError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationFailed, NULL);
376 ok_status(SecItemDelete(query), "delete multiple token items");
377 is(phase, 6, "connect + delete-auth-fail + copyAccess + connect + delete + delete-2nd");
378 #else
379 ok_status(SecItemDelete(query), "delete multiple token items");
380 is(phase, 3, "connect + delete + delete");
381 #endif
382
383 phase = 0;
384 is_status(SecItemCopyMatching(query, &result), errSecItemNotFound);
385 is(phase, 0);
386
387 is_status(SecItemDelete(query), errSecItemNotFound);
388
389 CFRelease(query);
390 CFReleaseSafe(deleteError);
391 }
392 #if LA_CONTEXT_IMPLEMENTED
393 static const int kItemDeleteTestCount = 15;
394 #else
395 static const int kItemDeleteTestCount = 14;
396 #endif
397
398 static void test_key_generate(void) {
399
400 __block int phase = 0;
401 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
402 phase++;
403
404 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
405 phase++;
406 is(objectID, NULL);
407 CFDictionarySetValue(at, kSecClass, kSecClassKey);
408 SecKeyRef publicKey = NULL, privateKey = NULL;
409 CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL,
410 kSecAttrKeyType, kSecAttrKeyTypeEC,
411 kSecAttrKeySizeInBits, CFSTR("256"),
412 NULL);
413 ok_status(SecKeyGeneratePair(params, &publicKey, &privateKey));
414 CFDictionaryRef privKeyAttrs = SecKeyCopyAttributeDictionary(privateKey);
415 CFRelease(privateKey);
416 CFRelease(publicKey);
417 CFRelease(params);
418 CFDataRef oid = CFRetainSafe(CFDictionaryGetValue(privKeyAttrs, kSecValueData));
419 CFRelease(privKeyAttrs);
420 return oid;
421 };
422
423 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
424 phase++;
425 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
426 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
427 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
428 CFDataRef acData = SecAccessControlCopyData(ac);
429 CFRelease(ac);
430 return acData;
431 };
432
433 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
434 phase++;
435 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
436 CFDataRef publicData;
437 ok_status(SecKeyCopyPublicBytes(privKey, &publicData));
438 CFRelease(privKey);
439 return publicData;
440 };
441
442 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
443 phase++;
444 return kCFNull;
445 };
446 });
447
448 CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL,
449 kSecAttrIsPermanent, kCFBooleanTrue,
450 NULL);
451
452 CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL,
453 kSecAttrKeyType, kSecAttrKeyTypeEC,
454 kSecAttrKeySizeInBits, CFSTR("256"),
455 kSecAttrTokenID, CFSTR("tokenid"),
456 kSecPrivateKeyAttrs, prk_params,
457 NULL);
458 CFRelease(prk_params);
459
460 SecKeyRef publicKey = NULL, privateKey = NULL;
461 phase = 0;
462 ok_status(SecKeyGeneratePair(params, &publicKey, &privateKey));
463 is(phase, 6);
464
465 CFDictionaryRef query = CFDictionaryCreateForCFTypes(NULL,
466 kSecValueRef, privateKey,
467 kSecReturnAttributes, kCFBooleanTrue,
468 kSecReturnRef, kCFBooleanTrue,
469 kSecReturnData, kCFBooleanTrue,
470 NULL);
471 phase = 0;
472 CFDictionaryRef result = NULL, keyAttrs = NULL;
473 ok_status(SecItemCopyMatching(query, (CFTypeRef *)&result));
474 is(phase, 3);
475 is(CFDictionaryGetValue(result, kSecValueData), NULL);
476 eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid"));
477 keyAttrs = SecKeyCopyAttributeDictionary((SecKeyRef)CFDictionaryGetValue(result, kSecValueRef));
478 eq_cf(CFDictionaryGetValue(keyAttrs, kSecAttrApplicationLabel), CFDictionaryGetValue(result, kSecAttrApplicationLabel));
479 CFAssignRetained(keyAttrs, SecKeyCopyAttributeDictionary(publicKey));
480 eq_cf(CFDictionaryGetValue(keyAttrs, kSecAttrApplicationLabel), CFDictionaryGetValue(result, kSecAttrApplicationLabel));
481
482 CFRelease(result);
483 CFRelease(keyAttrs);
484 CFRelease(publicKey);
485 CFRelease(privateKey);
486
487 CFRelease(query);
488 CFRelease(params);
489 }
490 static const int kKeyGenerateTestCount = 14;
491
492 static void test_key_sign(void) {
493
494 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
495
496 static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 };
497 CFDataRef valueData = CFDataCreate(NULL, data, sizeof(data));
498
499 __block int phase = 0;
500 __block CFErrorRef cryptoError = NULL;
501 __block SecKeyOperationType cryptoOperation = -1;
502 __block SecKeyAlgorithm cryptoAlgorithm = NULL;
503 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
504 phase++;
505
506 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
507 phase++;
508 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
509 CFDataRef publicData;
510 ok_status(SecKeyCopyPublicBytes(privKey, &publicData));
511 CFRelease(privKey);
512 return publicData;
513 };
514
515 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
516 phase++;
517 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
518 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
519 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
520 CFDataRef acData = SecAccessControlCopyData(ac);
521 CFRelease(ac);
522 return acData;
523 };
524
525 blocks->copyObjectOperationAlgorithms = ^CFSetRef(CFDataRef oid, CFIndex operation, CFErrorRef *error) {
526 static NSSet *ops[] = {
527 [kSecKeyOperationTypeSign] = NULL,
528 [kSecKeyOperationTypeDecrypt] = NULL,
529 [kSecKeyOperationTypeKeyExchange] = NULL,
530 };
531
532 static dispatch_once_t onceToken;
533 dispatch_once(&onceToken, ^{
534 ops[kSecKeyOperationTypeSign] = [NSSet setWithArray:@[(id)kSecKeyAlgorithmECDSASignatureDigestX962]];
535 ops[kSecKeyOperationTypeDecrypt] = [NSSet setWithArray:@[(id)kSecKeyAlgorithmRSAEncryptionRaw]];
536 ops[kSecKeyOperationTypeKeyExchange] = [NSSet setWithArray:@[(id)kSecKeyAlgorithmECDHKeyExchangeCofactor]];
537 });
538
539 return CFBridgingRetain(ops[operation]);
540 };
541
542 blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
543 SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(algorithms, CFArrayGetCount(algorithms) - 1);
544 phase++;
545 cryptoOperation = operation;
546 cryptoAlgorithm = algorithm;
547 if (cryptoError != NULL) {
548 CFAssignRetained(*error, cryptoError);
549 cryptoError = NULL;
550 return NULL;
551 }
552 return CFRetainSafe(valueData);
553 };
554
555 blocks->copyObjectData = ^CFTypeRef(CFDataRef objectID, CFErrorRef *error) {
556 phase++;
557 return kCFNull;
558 };
559 });
560
561 NSDictionary *query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecReturnRef: @YES };
562
563 phase = 0;
564 SecKeyRef privateKey = NULL;
565 ok_status(SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&privateKey));
566 is(phase, 2);
567
568 phase = 0;
569 CFMutableDataRef sig = CFDataCreateMutable(NULL, 0);
570 CFDataSetLength(sig, 256);
571 size_t sigLen = CFDataGetLength(sig);
572 ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen));
573 is(phase, 1);
574 is(cryptoAlgorithm, kSecKeyAlgorithmECDSASignatureDigestX962);
575 is(cryptoOperation, kSecKeyOperationTypeSign);
576 CFDataSetLength(sig, sigLen);
577 is(CFDataGetLength(sig), CFDataGetLength(valueData));
578 eq_cf(valueData, sig);
579
580 #if LA_CONTEXT_IMPLEMENTED
581 phase = 0;
582 CFDataSetLength(sig, 256);
583 sigLen = CFDataGetLength(sig);
584 LASetErrorCodeBlock(^{ return (CFErrorRef)NULL; });
585 cryptoError = CFErrorCreate(NULL, CFSTR(kTKErrorDomain), kTKErrorCodeAuthenticationFailed, NULL);
586 ok_status(SecKeyRawSign(privateKey, kSecPaddingPKCS1, data, sizeof(data), CFDataGetMutableBytePtr(sig), &sigLen));
587 is(phase, 4);
588 is(cryptoError, NULL);
589 CFDataSetLength(sig, sigLen);
590 is(CFDataGetLength(sig), CFDataGetLength(valueData));
591 eq_cf(valueData, sig);
592 #endif
593
594 NSError *error;
595 NSData *result;
596 result = CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionRaw,
597 valueData, (void *)&error));
598 eq_cf((__bridge CFDataRef)result, valueData);
599 is(cryptoAlgorithm, kSecKeyAlgorithmRSAEncryptionRaw);
600 is(cryptoOperation, kSecKeyOperationTypeDecrypt);
601
602 NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256 };
603 SecKeyRef otherPrivKey = NULL, otherPubKey = NULL;
604 ok_status(SecKeyGeneratePair((CFDictionaryRef)params, &otherPubKey, &otherPrivKey));
605
606 error = nil;
607 result = CFBridgingRelease(SecKeyCopyKeyExchangeResult(privateKey, kSecKeyAlgorithmECDHKeyExchangeCofactor,
608 otherPubKey, (CFDictionaryRef)@{}, (void *)&error));
609 eq_cf((__bridge CFDataRef)result, valueData);
610 is(cryptoAlgorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor);
611 is(cryptoOperation, kSecKeyOperationTypeKeyExchange);
612
613 CFReleaseSafe(otherPrivKey);
614 CFReleaseSafe(otherPubKey);
615 CFReleaseSafe(cryptoError);
616 CFRelease(sig);
617 CFRelease(privateKey);
618 #endif
619 }
620 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
621 #if LA_CONTEXT_IMPLEMENTED
622 static const int kKeySignTestCount = 20;
623 #else
624 static const int kKeySignTestCount = 15;
625 #endif
626 #else
627 static const int kKeySignTestCount = 0;
628 #endif
629
630 static void test_key_generate_with_params(void) {
631
632 const UInt8 data[] = "foo";
633 CFDataRef cred_ref = CFDataCreate(NULL, data, 4);
634 __block int phase = 0;
635 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
636 phase++;
637 eq_cf(CFDictionaryGetValue(attributes, kSecUseOperationPrompt), CFSTR("prompt"));
638 is(CFDictionaryGetValue(attributes, kSecUseAuthenticationUI), NULL);
639 eq_cf(CFDictionaryGetValue(attributes, kSecUseCredentialReference), cred_ref);
640
641 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
642 phase++;
643 SecCFCreateError(-4 /* kTKErrorCodeCanceledByUser */, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error);
644 return NULL;
645 };
646 });
647
648 CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL,
649 kSecAttrIsPermanent, kCFBooleanTrue,
650 NULL);
651
652 CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL,
653 kSecAttrKeyType, kSecAttrKeyTypeEC,
654 kSecAttrKeySizeInBits, CFSTR("256"),
655 kSecAttrTokenID, CFSTR("tokenid"),
656 kSecPrivateKeyAttrs, prk_params,
657 kSecUseOperationPrompt, CFSTR("prompt"),
658 kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow,
659 kSecUseCredentialReference, cred_ref,
660 NULL);
661 CFRelease(prk_params);
662
663 SecKeyRef publicKey = NULL, privateKey = NULL;
664 phase = 0;
665 diag("This will produce an internal assert - on purpose");
666 is_status(SecKeyGeneratePair(params, &publicKey, &privateKey), errSecUserCanceled);
667 is(phase, 2);
668
669 CFReleaseSafe(publicKey);
670 CFReleaseSafe(privateKey);
671 CFRelease(params);
672 CFRelease(cred_ref);
673 }
674 static const int kKeyGenerateWithParamsTestCount = 5;
675
676 static void test_error_codes(void) {
677
678 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableForCFTypesWith(NULL,
679 kSecClass, kSecClassGenericPassword,
680 kSecAttrTokenID, CFSTR("tokenid"),
681 NULL);
682 // Setup token hook.
683 __block OSStatus ctk_error = 0;
684 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
685 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
686 SecCFCreateError(ctk_error, CFSTR(kTKErrorDomain), CFSTR(""), NULL, error);
687 return NULL;
688 };
689 });
690
691 ctk_error = kTKErrorCodeBadParameter;
692 is_status(SecItemAdd(attrs, NULL), errSecParam);
693
694 ctk_error = -1 /* kTKErrorCodeNotImplemented */;
695 is_status(SecItemAdd(attrs, NULL), errSecUnimplemented);
696
697 ctk_error = -4 /* kTKErrorCodeCanceledByUser */;
698 is_status(SecItemAdd(attrs, NULL), errSecUserCanceled);
699
700 CFRelease(attrs);
701 }
702 static const int kErrorCodesCount = 3;
703
704 static CFDataRef copy_certificate_data(const char *base64Cert)
705 {
706 size_t size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), NULL, 0);
707 ok(size);
708 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, size);
709 CFDataSetLength(data, size);
710 size = SecBase64Decode(base64Cert, strnlen(base64Cert, 2048), (char*)CFDataGetMutableBytePtr(data), CFDataGetLength(data));
711 ok(size);
712 CFDataSetLength(data, size);
713
714 return data;
715 }
716
717 static CFMutableDictionaryRef copy_certificate_attributes(const char *base64Cert)
718 {
719 CFDataRef data = copy_certificate_data(base64Cert);
720
721 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, data);
722 ok(cert);
723 CFDictionaryRef certAttributes = SecCertificateCopyAttributeDictionary(cert);
724 ok(certAttributes);
725 CFMutableDictionaryRef result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, certAttributes);
726 ok(result);
727
728 if (certAttributes)
729 CFRelease(certAttributes);
730 if (data)
731 CFRelease(data);
732 if (cert)
733 CFRelease(cert);
734
735 return result;
736 }
737
738 static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFStringRef oid, CFStringRef tokenID)
739 {
740 CFMutableDictionaryRef certAttributes = copy_certificate_attributes(base64cert);
741
742 CFDictionarySetValue(certAttributes, kSecAttrLabel, label);
743 CFDictionarySetValue(certAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate);
744 CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid);
745 CFDictionaryRemoveValue(certAttributes, kSecValueData);
746
747 SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
748 ok(acl);
749 CFTypeRef key[] = { kSecAttrTokenID };
750 CFTypeRef value[] = { tokenID };
751 CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
752 ok(SecAccessControlSetProtection(acl, protection, NULL));
753 CFRelease(protection);
754 ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
755 CFDataRef aclData = SecAccessControlCopyData(acl);
756 ok(aclData);
757 if (aclData) {
758 CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData);
759 CFRelease(aclData);
760 }
761
762 if (acl)
763 CFRelease(acl);
764
765 return certAttributes;
766 }
767
768 static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFStringRef oid, CFStringRef tokenID)
769 {
770 CFMutableDictionaryRef keyAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ;
771
772 CFDictionarySetValue(keyAttributes, kSecClass, kSecClassKey);
773 CFDictionarySetValue(keyAttributes, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
774 CFDictionarySetValue(keyAttributes, kSecAttrKeyType, kSecAttrKeyTypeRSA);
775 CFNumberRef keySize = CFNumberCreateWithCFIndex(kCFAllocatorDefault, 2048);
776 CFDictionarySetValue(keyAttributes, kSecAttrKeySizeInBits, keySize);
777 CFRelease(keySize);
778
779 CFDictionarySetValue(keyAttributes, kSecAttrCanDecrypt, kCFBooleanTrue);
780 CFDictionarySetValue(keyAttributes, kSecAttrCanSign, kCFBooleanTrue);
781 CFDictionarySetValue(keyAttributes, kSecAttrCanUnwrap, kCFBooleanTrue);
782 CFDictionarySetValue(keyAttributes, kSecAttrCanDerive, kCFBooleanFalse);
783 CFDictionarySetValue(keyAttributes, kSecAttrIsPrivate, kCFBooleanTrue);
784
785 CFDictionarySetValue(keyAttributes, kSecAttrLabel, label);
786 CFDictionarySetValue(keyAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate);
787 CFDictionarySetValue(keyAttributes, kSecAttrTokenOID, oid);
788 CFDictionarySetValue(keyAttributes, kSecAttrApplicationLabel, CFDictionaryGetValue(certAttributes, kSecAttrPublicKeyHash));
789
790 SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
791 ok(acl);
792 CFTypeRef key[] = { kSecAttrTokenID };
793 CFTypeRef value[] = { tokenID };
794 CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
795 ok(SecAccessControlSetProtection(acl, protection, NULL));
796 CFRelease(protection);
797 ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
798 CFDataRef aclData = SecAccessControlCopyData(acl);
799 ok(aclData);
800 if (aclData) {
801 CFDictionarySetValue(keyAttributes, kSecAttrAccessControl, aclData);
802 CFRelease(aclData);
803 }
804
805 if (acl)
806 CFRelease(acl);
807
808 return keyAttributes;
809 }
810
811 static void check_array_for_type_id(CFArrayRef array, CFTypeID typeID)
812 {
813 if (array && CFGetTypeID(array) == CFArrayGetTypeID()) {
814 for (CFIndex i = 0; i < CFArrayGetCount(array); ++i) {
815 ok(CFGetTypeID(CFArrayGetValueAtIndex(array, i)) == typeID);
816 }
817 }
818 }
819
820 static void test_propagate_token_items()
821 {
822 CFStringRef cert1OID = CFSTR("oid1");
823 CFStringRef cert2OID = CFSTR("oid2");
824 CFStringRef key1OID = CFSTR("oid3");
825 CFStringRef key2OID = CFSTR("oid4");
826
827 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
828 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
829 if (CFEqual(oid, cert1OID)) {
830 return copy_certificate_data(cert1);
831 }
832 else if (CFEqual(oid, cert2OID)) {
833 return copy_certificate_data(cert2);
834 }
835 else if (CFEqual(oid, key1OID) || CFEqual(oid, key2OID)) {
836 return kCFNull;
837 }
838 else {
839 return NULL;
840 }
841 };
842 });
843
844 CFStringRef tokenID = CFSTR("com.apple.secdtest:propagate_test_token");
845
846 CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
847
848 CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), cert1OID, tokenID);
849 ok(certQuery);
850 CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), key1OID, tokenID);
851 ok(keyQuery);
852
853 CFArrayAppendValue(items, certQuery);
854 CFArrayAppendValue(items, keyQuery);
855 CFReleaseSafe(certQuery);
856 CFReleaseSafe(keyQuery);
857
858 certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), cert2OID, tokenID);
859 ok(certQuery);
860 keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), key2OID, tokenID);
861 ok(keyQuery);
862
863 CFArrayAppendValue(items, certQuery);
864 CFArrayAppendValue(items, keyQuery);
865 CFReleaseSafe(certQuery);
866 CFReleaseSafe(keyQuery);
867
868 OSStatus result;
869 ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items.");
870
871 ok_status(result = SecItemUpdateTokenItems(tokenID, items), "Failed to propagate items.");
872 CFRelease(items);
873
874 CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
875 CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
876 CFDictionarySetValue(query, kSecAttrAccessGroup, CFSTR("com.apple.token"));
877 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
878 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
879 CFTypeRef queryResult;
880 ok_status(SecItemCopyMatching(query, &queryResult));
881 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs");
882 check_array_for_type_id(queryResult, SecCertificateGetTypeID());
883 CFReleaseNull(queryResult);
884
885 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
886 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
887 ok_status(SecItemCopyMatching(query, &queryResult));
888 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two certs");
889 check_array_for_type_id(queryResult, CFDataGetTypeID());
890 CFReleaseNull(queryResult);
891
892 CFDictionarySetValue(query, kSecClass, kSecClassKey);
893 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
894 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
895 ok_status(SecItemCopyMatching(query, &queryResult));
896 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two keys");
897 check_array_for_type_id(queryResult, SecKeyGetTypeID());
898 CFReleaseNull(queryResult);
899
900 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
901 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
902 ok_status(SecItemCopyMatching(query, &queryResult));
903 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array");
904 CFReleaseNull(queryResult);
905
906 CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
907 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
908 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
909 ok_status(SecItemCopyMatching(query, &queryResult));
910 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 2, "Expect array with two identities");
911 check_array_for_type_id(queryResult, SecIdentityGetTypeID());
912 CFReleaseNull(queryResult);
913
914 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanFalse);
915 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
916 ok_status(SecItemCopyMatching(query, &queryResult));
917 ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array");
918 CFReleaseNull(queryResult);
919
920 ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items.");
921
922 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
923 CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
924 is_status(SecItemCopyMatching(query, &queryResult), errSecItemNotFound);
925 CFReleaseNull(queryResult);
926 CFRelease(query);
927 }
928 static const int kPropagateCount = 66;
929
930 static void test_identity_on_two_tokens() {
931 CFStringRef cert3OID = CFSTR("oid1");
932 TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
933
934 blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) {
935 is(objectID, NULL);
936 return (__bridge_retained CFDataRef)[[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters];
937 };
938
939 blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) {
940 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
941 ok(privKey);
942 CFDataRef publicData;
943 ok_status(SecKeyCopyPublicBytes(privKey, &publicData));
944 CFReleaseSafe(privKey);
945 return publicData;
946 };
947
948 blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
949 if (CFEqual(oid, cert3OID))
950 return copy_certificate_data(cert3);
951 else
952 return kCFNull;
953 };
954
955 blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
956 SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL);
957 SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL);
958 SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL);
959 CFDataRef acData = SecAccessControlCopyData(ac);
960 CFRelease(ac);
961 return acData;
962 };
963
964 blocks->copyOperationResult = ^CFTypeRef(CFDataRef objectID, CFIndex operation, CFArrayRef algorithms, CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
965 ok(operation == 0);
966 SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes);
967 ok(privKey);
968 CFDataRef signature = SecKeyCreateSignature(privKey, kSecKeyAlgorithmECDSASignatureDigestX962, in1, error);
969 ok(signature);
970 CFReleaseSafe(privKey);
971 return signature;
972 };
973
974 });
975
976 @autoreleasepool {
977 NSString *tokenID1 = @"com.apple.secdtest:identity_test_token1";
978 NSString *tokenID2 = @"com.apple.secdtest:identity_test_token2";
979
980 NSDictionary *params = @{ (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC,
981 (id)kSecAttrKeySizeInBits : @"256",
982 (id)kSecAttrTokenID : tokenID1,
983 (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @YES/*, (id)kSecAttrIsPrivate : @YES*/ }
984 };
985
986 SecKeyRef publicKey = NULL, privateKey = NULL;
987 ok_status(SecKeyGeneratePair((CFDictionaryRef)params, &publicKey, &privateKey));
988
989 NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), cert3OID, (__bridge CFStringRef)tokenID2));
990 ok(certQuery);
991
992 OSStatus result;
993 ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[certQuery]), "Failed to propagate items.");
994
995 NSData *pubKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash(publicKey));
996
997 CFTypeRef resultRef;
998 NSDictionary *query = @{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES };
999 ok_status(result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1000 CFReleaseSafe(resultRef);
1001
1002 query = @{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES };
1003 ok_status(result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1004 CFReleaseSafe(resultRef);
1005
1006 query = @{ (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES };
1007 ok_status(result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&resultRef));
1008 CFReleaseSafe(resultRef);
1009 }
1010 }
1011 static const int kIdentityonTwoTokensCount = 20;
1012
1013
1014 static void tests(void) {
1015 /* custom keychain dir */
1016 secd_test_setup_temp_keychain("secd_33_keychain_ctk", NULL);
1017
1018 test_item_add();
1019 test_item_query();
1020 test_item_update();
1021 test_item_delete();
1022 test_key_generate();
1023 test_key_sign();
1024 test_key_generate_with_params();
1025 test_error_codes();
1026 test_propagate_token_items();
1027 test_identity_on_two_tokens();
1028 }
1029
1030 int secd_33_keychain_ctk(int argc, char *const *argv) {
1031 plan_tests(kItemAddTestCount +
1032 kItemQueryTestCount +
1033 kItemUpdateTestCount +
1034 kItemDeleteTestCount +
1035 kKeyGenerateTestCount +
1036 kKeySignTestCount +
1037 kKeyGenerateWithParamsTestCount +
1038 kErrorCodesCount +
1039 kPropagateCount +
1040 kIdentityonTwoTokensCount +
1041 kSecdTestSetupTestCount);
1042 tests();
1043
1044 return 0;
1045 }