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