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