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