]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c
Security-58286.251.4.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / secitem / si-33-keychain-backup.c
1 /*
2 * Copyright (c) 2010,2012-2014 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 #include <TargetConditionals.h>
26
27 #if TARGET_IPHONE_SIMULATOR
28 #define USE_KEYSTORE 0
29 #else /* No AppleKeyStore.kext on this OS. */
30 #define USE_KEYSTORE 1
31 #endif
32
33
34 #include <CoreFoundation/CoreFoundation.h>
35 #include <Security/SecBase.h>
36 #include <Security/SecItem.h>
37 #include <Security/SecInternal.h>
38 #include <Security/SecItemPriv.h>
39 #include <utilities/array_size.h>
40 #include <utilities/SecCFWrappers.h>
41
42 #if USE_KEYSTORE
43 #include <AssertMacros.h>
44 #include <libaks.h>
45 #endif
46
47 #include <stdlib.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
51 #include <sqlite3.h>
52
53 #include "../Security_regressions.h"
54
55 struct test_persistent_s {
56 CFTypeRef persist[2];
57 CFDictionaryRef query;
58 CFDictionaryRef query1;
59 CFDictionaryRef query2;
60 CFMutableDictionaryRef query3;
61 CFMutableDictionaryRef query4;
62 };
63
64 static void test_persistent(struct test_persistent_s *p)
65 {
66 int v_eighty = 80;
67 CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
68 const char *v_data = "test";
69 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
70 const void *keys[] = {
71 kSecClass,
72 kSecAttrServer,
73 kSecAttrAccount,
74 kSecAttrPort,
75 kSecAttrProtocol,
76 kSecAttrAuthenticationType,
77 kSecReturnPersistentRef,
78 kSecValueData
79 };
80 const void *values[] = {
81 kSecClassInternetPassword,
82 CFSTR("zuigt.nl"),
83 CFSTR("frtnbf"),
84 eighty,
85 CFSTR("http"),
86 CFSTR("dflt"),
87 kCFBooleanTrue,
88 pwdata
89 };
90 CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values,
91 array_size(keys), &kCFTypeDictionaryKeyCallBacks,
92 &kCFTypeDictionaryValueCallBacks);
93
94 p->persist[0] = NULL;
95 // NUKE anything we might have left around from a previous test run so we don't crash.
96 SecItemDelete(item);
97 ok_status(SecItemAdd(item, &p->persist[0]), "add internet password");
98 CFTypeRef results = NULL;
99 CFTypeRef results2 = NULL;
100 SKIP: {
101 skip("no persistent ref", 6, ok(p->persist[0], "got back persistent ref"));
102
103 /* Create a dict with all attrs except the data. */
104 keys[(array_size(keys)) - 2] = kSecReturnAttributes;
105 p->query = CFDictionaryCreate(NULL, keys, values,
106 (array_size(keys)) - 1, &kCFTypeDictionaryKeyCallBacks,
107 &kCFTypeDictionaryValueCallBacks);
108 ok_status(SecItemCopyMatching(p->query, &results), "find internet password by attr");
109
110 const void *keys_persist[] = {
111 kSecReturnAttributes,
112 kSecValuePersistentRef
113 };
114 const void *values_persist[] = {
115 kCFBooleanTrue,
116 p->persist[0]
117 };
118 p->query2 = CFDictionaryCreate(NULL, keys_persist, values_persist,
119 (array_size(keys_persist)), &kCFTypeDictionaryKeyCallBacks,
120 &kCFTypeDictionaryValueCallBacks);
121 ok_status(SecItemCopyMatching(p->query2, &results2), "find internet password by persistent ref");
122 ok(CFEqual(results, results2 ? results2 : CFSTR("")), "same item (attributes)");
123
124 CFReleaseNull(results);
125 CFReleaseNull(results2);
126
127 ok_status(SecItemDelete(p->query), "delete internet password");
128
129 ok_status(!SecItemCopyMatching(p->query, &results),
130 "don't find internet password by attributes");
131 ok(!results, "no results");
132 }
133
134 /* clean up left over from aborted run */
135 if (results) {
136 CFDictionaryRef cleanup = CFDictionaryCreate(NULL, (const void **)&kSecValuePersistentRef,
137 &results, 1, &kCFTypeDictionaryKeyCallBacks,
138 &kCFTypeDictionaryValueCallBacks);
139 SecItemDelete(cleanup);
140 CFRelease(results);
141 CFRelease(cleanup);
142 }
143
144 ok_status(!SecItemCopyMatching(p->query2, &results2),
145 "don't find internet password by persistent ref anymore");
146 ok(!results2, "no results");
147
148 CFReleaseNull(p->persist[0]);
149
150 /* Add a new item and get it's persitant ref. */
151 ok_status(SecItemAdd(item, &p->persist[0]), "add internet password");
152 p->persist[1] = NULL;
153 CFMutableDictionaryRef item2 = CFDictionaryCreateMutableCopy(NULL, 0, item);
154 CFDictionarySetValue(item2, kSecAttrAccount, CFSTR("johndoe-bu"));
155 // NUKE anything we might have left around from a previous test run so we don't crash.
156 SecItemDelete(item2);
157 ok_status(SecItemAdd(item2, &p->persist[1]), "add second internet password");
158 CFMutableDictionaryRef update = NULL;
159 CFStringRef server = NULL;
160 SKIP: {
161 skip("no persistent ref", 3, ok(p->persist[0], "got back persistent ref from first internet password"));
162
163 is(CFGetTypeID(p->persist[0]), CFDataGetTypeID(), "result is a CFData");
164 p->query3 = CFDictionaryCreateMutableForCFTypes(NULL);
165 CFDictionaryAddValue(p->query3, kSecValuePersistentRef, p->persist[0]);
166 update = CFDictionaryCreateMutableForCFTypes(NULL);
167 CFDictionaryAddValue(update, kSecAttrServer, CFSTR("zuigt.com"));
168 ok_status(SecItemUpdate(p->query3, update), "update via persitant ref");
169
170 /* Verify that the update really worked. */
171 CFDictionaryAddValue(p->query3, kSecReturnAttributes, kCFBooleanTrue);
172 ok_status(SecItemCopyMatching(p->query3, &results2), "find updated internet password by persistent ref");
173 server = CFDictionaryGetValue(results2, kSecAttrServer);
174 ok(CFEqual(server, CFSTR("zuigt.com")), "verify attribute was modified by update");
175 CFReleaseNull(results2);
176 CFDictionaryRemoveValue(p->query3, kSecReturnAttributes);
177 }
178
179 SKIP: {
180 skip("no persistent ref", 2, ok(p->persist[1], "got back persistent ref"));
181
182 /* Verify that item2 wasn't affected by the update. */
183 p->query4 = CFDictionaryCreateMutableForCFTypes(NULL);
184 CFDictionaryAddValue(p->query4, kSecValuePersistentRef, p->persist[1]);
185 CFDictionaryAddValue(p->query4, kSecReturnAttributes, kCFBooleanTrue);
186 ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref");
187 server = CFDictionaryGetValue(results2, kSecAttrServer);
188 ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update");
189 CFReleaseNull(results2);
190 }
191
192 /* Delete the item via persitant ref. */
193 ok_status(SecItemDelete(p->query3), "delete via persitant ref");
194 is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound,
195 "don't find deleted internet password by persistent ref");
196 CFReleaseNull(results2);
197 ok_status(SecItemCopyMatching(p->query4, &results2),
198 "find non deleted internet password by persistent ref");
199 CFReleaseNull(results2);
200
201 CFReleaseNull(update);
202 CFReleaseNull(item);
203 CFReleaseNull(item2);
204 CFReleaseNull(eighty);
205 CFReleaseNull(pwdata);
206 }
207
208 static void test_persistent2(struct test_persistent_s *p)
209 {
210 CFTypeRef results = NULL;
211 CFTypeRef results2 = NULL;
212
213 ok_status(!SecItemCopyMatching(p->query, &results),
214 "don't find internet password by attributes");
215 ok(!results, "no results");
216
217 ok_status(!SecItemCopyMatching(p->query2, &results2),
218 "don't find internet password by persistent ref anymore");
219 ok(!results2, "no results");
220
221 SKIP:{
222 ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref");
223 skip("non updated internet password by persistent ref NOT FOUND!", 2, results2);
224 ok(results2, "non updated internet password not found");
225 CFStringRef server = CFDictionaryGetValue(results2, kSecAttrServer);
226 ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update");
227 CFReleaseNull(results2);
228 }
229
230 is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound,
231 "don't find deleted internet password by persistent ref");
232 CFReleaseNull(results2);
233 ok_status(SecItemCopyMatching(p->query4, &results2),
234 "find non deleted internet password by persistent ref");
235 CFReleaseNull(results2);
236
237 ok_status(SecItemDelete(p->query4),"Deleted internet password by persistent ref");
238
239 CFRelease(p->query);
240 CFRelease(p->query2);
241 CFRelease(p->query3);
242 CFRelease(p->query4);
243 CFReleaseNull(p->persist[0]);
244 CFReleaseNull(p->persist[1]);
245 }
246
247 static CFMutableDictionaryRef test_create_lockdown_identity_query(void) {
248 CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
249 CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword);
250 CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("test-delete-me"));
251 CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("lockdown-identities"));
252 return query;
253 }
254
255 static CFMutableDictionaryRef test_create_managedconfiguration_query(void) {
256 CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
257 CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword);
258 CFDictionaryAddValue(query, kSecAttrService, CFSTR("com.apple.managedconfiguration"));
259 CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("Public"));
260 CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple"));
261 return query;
262 }
263
264 static void test_add_lockdown_identity_items(void) {
265 CFMutableDictionaryRef query = test_create_lockdown_identity_query();
266 const char *v_data = "lockdown identity data (which should be a cert + key)";
267 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
268 CFDictionaryAddValue(query, kSecValueData, pwdata);
269 ok_status(SecItemAdd(query, NULL), "test_add_lockdown_identity_items");
270 CFReleaseSafe(pwdata);
271 CFReleaseSafe(query);
272 }
273
274 static void test_remove_lockdown_identity_items(void) {
275 CFMutableDictionaryRef query = test_create_lockdown_identity_query();
276 ok_status(SecItemDelete(query), "test_remove_lockdown_identity_items");
277 CFReleaseSafe(query);
278 }
279
280 static void test_no_find_lockdown_identity_item(void) {
281 CFMutableDictionaryRef query = test_create_lockdown_identity_query();
282 is_status(SecItemCopyMatching(query, NULL), errSecItemNotFound,
283 "test_no_find_lockdown_identity_item");
284 CFReleaseSafe(query);
285 }
286
287 static CFMutableDictionaryRef test_create_sysbound_query(void) {
288 CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
289 CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword);
290 CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("sysbound"));
291 CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple"));
292 return query;
293 }
294
295 static void test_add_sysbound_item(void) {
296 CFMutableDictionaryRef query = test_create_sysbound_query();
297 int32_t val = kSecSecAttrSysBoundPreserveDuringRestore;
298 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &val);
299 CFDictionaryAddValue(query, kSecAttrSysBound, num);
300 CFReleaseNull(num);
301
302 const char *v_data = "sysbound identity data";
303 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
304 CFDictionaryAddValue(query, kSecValueData, pwdata);
305 ok_status(SecItemAdd(query, NULL), "test_add_sysbound_item");
306 CFReleaseSafe(pwdata);
307 CFReleaseSafe(query);
308 }
309
310 static void test_remove_sysbound_item(void) {
311 CFMutableDictionaryRef query = test_create_sysbound_query();
312 ok_status(SecItemDelete(query), "test_remove_sysbound_item");
313 CFReleaseSafe(query);
314 }
315
316 static void test_find_sysbound_item(OSStatus expectedCode) {
317 CFMutableDictionaryRef query = test_create_sysbound_query();
318 is_status(SecItemCopyMatching(query, NULL), expectedCode,
319 "test_find_sysbound_item");
320 CFReleaseSafe(query);
321 }
322
323 /*
324 * BT
325 */
326
327 static CFMutableDictionaryRef test_create_bt_query(bool sync) {
328 CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
329 CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword);
330 CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("com.apple.bluetooth"));
331 CFDictionaryAddValue(query, kSecAttrSynchronizable, sync ? kCFBooleanTrue : kCFBooleanFalse);
332 CFDictionarySetValue(query, kSecAttrAccount, sync ? CFSTR("sync") : CFSTR("non-sync"));
333 return query;
334 }
335
336 static void test_add_bt_items(const char *data) {
337 CFMutableDictionaryRef query = NULL;
338
339 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)data, strlen(data));
340
341 query = test_create_bt_query(false);
342 (void)SecItemDelete(query);
343 CFDictionarySetValue(query, kSecValueData, pwdata);
344 ok_status(SecItemAdd(query, NULL), "test_add_bt_item(nonsync)");
345 CFReleaseSafe(query);
346
347 query = test_create_bt_query(true);
348 (void)SecItemDelete(query);
349 CFDictionarySetValue(query, kSecValueData, pwdata);
350 ok_status(SecItemAdd(query, NULL), "test_add_bt_item(sync)");
351 CFReleaseSafe(query);
352
353 CFReleaseSafe(pwdata);
354 }
355
356 static void test_find_bt_item(OSStatus expectedCode, bool sync, const char *data) {
357 CFMutableDictionaryRef query = test_create_bt_query(sync);
358 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
359 CFDataRef pwdata = NULL;
360 is_status(SecItemCopyMatching(query, (CFTypeRef *)&pwdata), expectedCode,
361 "test_find_bt_item: %s", data);
362 CFIndex len = strlen(data);
363 is(len, CFDataGetLength(pwdata), "length wrong(%s)", data);
364 ok(memcmp(data, CFDataGetBytePtr(pwdata), len) == 0, "length wrong(%s)", data);
365 CFReleaseSafe(query);
366 }
367
368 /*
369 * MC
370 */
371
372 static void test_add_managedconfiguration_item(void) {
373 CFMutableDictionaryRef query = test_create_managedconfiguration_query();
374 const char *v_data = "public managedconfiguration password history data";
375 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
376 CFDictionaryAddValue(query, kSecValueData, pwdata);
377 ok_status(SecItemAdd(query, NULL), "test_add_managedconfiguration_item");
378 CFReleaseSafe(pwdata);
379 CFReleaseSafe(query);
380 }
381
382 static void test_find_managedconfiguration_item(void) {
383 CFMutableDictionaryRef query = test_create_managedconfiguration_query();
384 ok_status(SecItemCopyMatching(query, NULL), "test_find_managedconfiguration_item");
385 ok_status(SecItemDelete(query), "test_find_managedconfiguration_item (deleted)");
386 CFReleaseSafe(query);
387 }
388
389 #if USE_KEYSTORE
390 #define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0
391 static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password)
392 {
393 CFDataRef result = NULL;
394 void *bag = NULL;
395 int bagLen = 0;
396
397 keybag_handle_t handle = bad_keybag_handle;
398 require_noerr(aks_create_bag(DATA_ARG(password), bag_type, &handle), out);
399 require_noerr(aks_save_bag(handle, &bag, &bagLen), out);
400
401 result = CFDataCreate(kCFAllocatorDefault, bag, bagLen);
402 out:
403 return result;
404 }
405 #endif
406
407 /* Test low level keychain migration from device to device interface. */
408 static void tests(void)
409 {
410 {
411 CFMutableDictionaryRef lock_down_query = test_create_lockdown_identity_query();
412 (void)SecItemDelete(lock_down_query);
413 CFReleaseNull(lock_down_query);
414 }
415
416 int v_eighty = 80;
417 CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
418 const char *v_data = "test";
419 CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
420 CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
421 CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
422 CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net"));
423 CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith"));
424 CFDictionaryAddValue(query, kSecAttrPort, eighty);
425 CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP);
426 CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault);
427 CFDictionaryAddValue(query, kSecValueData, pwdata);
428 // NUKE anything we might have left around from a previous test run so we don't crash.
429 (void)SecItemDelete(query);
430
431 ok_status(SecItemAdd(query, NULL), "add internet password");
432 is_status(SecItemAdd(query, NULL), errSecDuplicateItem,
433 "add internet password again");
434
435 ok_status(SecItemCopyMatching(query, NULL), "Found the item we added");
436
437 struct test_persistent_s p = {};
438 test_persistent(&p);
439
440 CFDataRef backup = NULL, keybag = NULL, password = NULL;
441
442 test_add_lockdown_identity_items();
443 test_add_sysbound_item();
444 test_add_bt_items("kaka1");
445
446 #if USE_KEYSTORE
447 keybag = create_keybag(kAppleKeyStoreBackupBag, password);
448 #else
449 keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0);
450 #endif
451
452 ok(backup = _SecKeychainCopyBackup(keybag, password),
453 "_SecKeychainCopyBackup");
454
455 test_add_managedconfiguration_item();
456 test_remove_lockdown_identity_items();
457 test_remove_sysbound_item();
458
459 test_add_bt_items("kaka2");
460
461 ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
462 "_SecKeychainRestoreBackup");
463 CFReleaseSafe(backup);
464
465 test_no_find_lockdown_identity_item();
466 test_find_sysbound_item(errSecItemNotFound);
467 test_find_managedconfiguration_item();
468 /*
469 * Check that the kaka1 entry was "overwritten"
470 */
471 test_find_bt_item(errSecSuccess, true, "kaka2");
472 test_find_bt_item(errSecSuccess, false, "kaka1");
473
474 ok_status(SecItemCopyMatching(query, NULL),
475 "Found the item we added after restore");
476
477 test_persistent2(&p);
478
479 #if USE_KEYSTORE
480 CFReleaseNull(keybag);
481 keybag = create_keybag(kAppleKeyStoreOTABackupBag, password);
482 #endif
483
484 ok(backup = _SecKeychainCopyBackup(keybag, password),
485 "_SecKeychainCopyBackup");
486 ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
487 "_SecKeychainRestoreBackup");
488 ok_status(SecItemCopyMatching(query, NULL),
489 "Found the item we added after restore");
490 CFReleaseNull(backup);
491
492 // force tombstone to be added, since it's not the default behavior per rdar://14680869
493 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue);
494
495 ok_status(SecItemDelete(query), "Deleted item we added");
496
497 #if USE_KEYSTORE
498 CFReleaseNull(keybag);
499 keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password);
500 #endif
501
502 // add syncable item
503 CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue);
504 ok_status(SecItemAdd(query, NULL), "add internet password");
505
506 // and non-syncable item
507 test_add_managedconfiguration_item();
508
509 CFDictionaryRef syncableBackup = NULL;
510
511 CFErrorRef error = NULL;
512 CFDictionaryRef scratch = NULL;
513 SKIP: {
514 skip("skipping syncable backup tests", 7,
515 ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items"));
516
517 // TODO: add item, call SecServerCopyTruthInTheCloud again
518
519 // CFShow(syncableBackup);
520
521 // find and delete
522 skip("skipping syncable backup tests", 6,
523 ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy"));
524
525 skip("skipping syncable backup tests", 5,
526 ok_status(SecItemDelete(query), "delete item we backed up"));
527
528 // ensure we added a tombstone
529 CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue);
530 skip("skipping syncable backup tests", 4,
531 ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted"));
532 CFDictionaryRemoveValue(query, kSecAttrTombstone);
533
534 test_find_managedconfiguration_item(); // <- 2 tests here
535
536 // TODO: add a different new item - delete what's not in the syncableBackup?
537
538 // Do another backup after some changes
539 skip("skipping syncable backup tests", 1,
540 ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes"));
541
542 skip("skipping syncable backup tests", 0,
543 ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items"));
544 }
545 CFReleaseNull(scratch);
546 CFReleaseNull(error);
547
548 // non-syncable item should (still) be gone -> add should work
549 test_add_managedconfiguration_item();
550 test_find_managedconfiguration_item();
551
552 // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail
553 is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL),
554 "find restored item");
555 is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item");
556
557 CFReleaseSafe(syncableBackup);
558 CFReleaseSafe(keybag);
559 CFReleaseSafe(eighty);
560 CFReleaseSafe(pwdata);
561 CFReleaseSafe(query);
562 }
563
564 int si_33_keychain_backup(int argc, char *const *argv)
565 {
566 plan_tests(77);
567
568 tests();
569
570 return 0;
571 }