]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSAccountBackup.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSAccountBackup.m
1 //
2 // SOSAccountCircles.c
3 // sec
4 //
5
6 #include "SOSAccount.h"
7 #include "SOSCloudKeychainClient.h"
8
9 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
10
11 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
12 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
13 #include <Security/SecureObjectSync/SOSViews.h>
14 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
15 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
16
17 #include "keychain/SecureObjectSync/SOSInternal.h"
18
19
20
21 //
22 // MARK: V0 Keybag keychain stuff
23 //
24 static bool SecItemUpdateOrAdd(CFDictionaryRef query, CFDictionaryRef update, CFErrorRef *error)
25 {
26 OSStatus saveStatus = SecItemUpdate(query, update);
27
28 if (errSecItemNotFound == saveStatus) {
29 CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
30 CFDictionaryForEach(update, ^(const void *key, const void *value) {
31 CFDictionaryAddValue(add, key, value);
32 });
33 saveStatus = SecItemAdd(add, NULL);
34 CFReleaseNull(add);
35 }
36
37 return SecError(saveStatus, error, CFSTR("Error saving %@"), query);
38 }
39
40 static CFDictionaryRef SOSCopyV0Attributes() {
41 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
42 kSecClass, kSecClassGenericPassword,
43 kSecAttrAccessGroup, CFSTR("com.apple.sbd"),
44 kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
45 kSecAttrAccount, CFSTR("SecureBackupPublicKeybag"),
46 kSecAttrService, CFSTR("SecureBackupService"),
47 kSecAttrSynchronizable, kCFBooleanTrue,
48 NULL);
49 }
50
51 bool SOSDeleteV0Keybag(CFErrorRef *error) {
52 CFDictionaryRef attributes = SOSCopyV0Attributes();
53
54 OSStatus result = SecItemDelete(attributes);
55
56 CFReleaseNull(attributes);
57
58 return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %d"), (int)result);
59 }
60
61 static bool SOSSaveV0Keybag(CFDataRef v0Keybag, CFErrorRef *error) {
62 CFDictionaryRef attributes = SOSCopyV0Attributes();
63
64 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
65 kSecValueData, v0Keybag,
66 NULL);
67
68
69 bool result = SecItemUpdateOrAdd(attributes, update, error);
70 CFReleaseNull(attributes);
71 CFReleaseNull(update);
72
73 return result;
74 }
75
76
77 static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) {
78 if (CFEqualSafe(kSOSViewKeychainV0, viewName))
79 return false;
80
81 return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName);
82 }
83
84 static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccount* account, CFStringRef viewName) {
85 CFMutableSetRef backupPeers = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
86
87 SOSCircleRef circle = [account.trust getCircle:NULL];
88
89 require_quiet(circle, exit);
90
91 SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
92 if (SOSPeerInfoIsViewBackupEnabled(peer, viewName))
93 CFSetAddValue(backupPeers, peer);
94 });
95
96 exit:
97 return backupPeers;
98 }
99
100 static void SOSAccountWithBackupPeersForView(SOSAccount* account, CFStringRef viewName, void (^action)(CFSetRef peers)) {
101 CFSetRef backupPeersForView = SOSAccountCopyBackupPeersForView(account, viewName);
102
103 action(backupPeersForView);
104
105 CFReleaseNull(backupPeersForView);
106 }
107
108
109 static bool SOSAccountWithBSKBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
110 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
111 __block SOSBackupSliceKeyBagRef bskb = NULL;
112 bool result = false;
113 CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
114
115 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
116 if(! rkbg) {
117 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, peers, error);
118 } else {
119 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
120 CFDictionaryAddValue(additionalKeys, bskbRkbgPrefix, rkbg);
121 bskb = SOSBackupSliceKeyBagCreateWithAdditionalKeys(kCFAllocatorDefault, peers, additionalKeys, error);
122 CFReleaseNull(additionalKeys);
123 }
124 });
125 CFReleaseNull(rkbg);
126
127 require_quiet(bskb, exit);
128
129 action(bskb, error);
130
131 result = true;
132
133 exit:
134 CFReleaseNull(bskb);
135 return result;
136 }
137
138 CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) {
139 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName);
140 }
141
142 bool SOSAccountUpdateBackupRing(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
143 SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) {
144
145 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
146
147 bool result = SOSAccountUpdateNamedRing(account, ringName, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) {
148 return SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
149 }, modify);
150
151 CFReleaseNull(ringName);
152
153 return result;
154 }
155
156 static bool SOSAccountSetKeybagForViewBackupRing(SOSAccount* account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) {
157 CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL);
158 bool result = false;
159
160 if(!SecAllocationError(backupViewSet, error, CFSTR("No backup view set created"))){
161 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
162
163 return result;
164 }
165 CFSetAddValue(backupViewSet, viewName);
166
167 result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
168 SOSRingRef newRing = NULL;
169 CFSetRef viewPeerSet = [account.trust copyPeerSetForView:viewName];
170 CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL);
171
172 SOSRingSetPeerIDs(existing, cleared);
173 SOSRingAddAll(existing, viewPeerSet);
174
175 require_quiet(SOSRingSetBackupKeyBag(existing, account.fullPeerInfo, backupViewSet, keyBag, error), exit);
176
177 newRing = CFRetainSafe(existing);
178 exit:
179 CFReleaseNull(viewPeerSet);
180 CFReleaseNull(cleared);
181 return newRing;
182 });
183
184 if (result && NULL != error && NULL != *error) {
185 secerror("Got Success and Error (dropping error): %@", *error);
186 CFReleaseNull(*error);
187 }
188
189 if (!result) {
190 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
191 }
192
193 CFReleaseNull(backupViewSet);
194 return result;
195 }
196
197 bool SOSAccountNewBKSBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error)
198 {
199 return SOSAccountWithBSKBForView(account, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
200 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
201 return result;
202 });
203 }
204
205 bool SOSAccountIsBackupRingEmpty(SOSAccount* account, CFStringRef viewName) {
206 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
207 SOSRingRef ring = [account.trust copyRing:backupRing err:NULL];
208 CFReleaseNull(backupRing);
209 int peercnt = 0;
210 if(ring) peercnt = SOSRingCountPeers(ring);
211 CFReleaseNull(ring);
212 return peercnt == 0;
213 }
214
215 bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname){
216 bool result = false;
217 CFErrorRef bsError = NULL;
218 CFDataRef backupSliceData = NULL;
219 SOSRingRef ring = NULL;
220 SOSBackupSliceKeyBagRef backupSlice = NULL;
221
222 require_quiet(SOSPeerInfoIsViewBackupEnabled(account.peerInfo, viewname), errOut);
223
224 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
225 ring = [account.trust copyRing:ringName err:&bsError];
226 CFReleaseNull(ringName);
227
228 require_quiet(ring, errOut);
229
230 //grab the backup slice from the ring
231 backupSliceData = SOSRingGetPayload(ring, &bsError);
232 require_quiet(backupSliceData, errOut);
233
234 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
235 require_quiet(backupSlice, errOut);
236
237 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
238 SOSPeerInfoRef myPeer = account.peerInfo;
239
240 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
241 require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut);
242
243 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
244 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
245 result = CFEqualSafe(myBK, myPeerInBSKBBK);
246 CFReleaseNull(myBK);
247 CFReleaseNull(myPeerInBSKBBK);
248
249 errOut:
250 CFReleaseNull(ring);
251 CFReleaseNull(backupSlice);
252
253 if (bsError) {
254 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
255 }
256 CFReleaseNull(bsError);
257 return result;
258 }
259
260 bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccount* account, SOSPeerInfoRef testPeer, CFStringRef viewname){
261 bool result = false;
262 CFErrorRef bsError = NULL;
263 CFDataRef backupSliceData = NULL;
264 SOSRingRef ring = NULL;
265 SOSBackupSliceKeyBagRef backupSlice = NULL;
266
267 require_quiet(testPeer, errOut);
268
269 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
270
271 ring = [account.trust copyRing:ringName err:&bsError];
272 CFReleaseNull(ringName);
273
274 require_quiet(ring, errOut);
275
276 //grab the backup slice from the ring
277 backupSliceData = SOSRingGetPayload(ring, &bsError);
278 require_quiet(backupSliceData, errOut);
279
280 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
281 require_quiet(backupSlice, errOut);
282
283 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
284
285 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
286 require_quiet(isSOSPeerInfo(peerInBSKB), errOut);
287
288 result = CFEqualSafe(testPeer, peerInBSKB);
289
290 errOut:
291 CFReleaseNull(ring);
292 CFReleaseNull(backupSlice);
293
294 if (bsError) {
295 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
296 }
297 CFReleaseNull(bsError);
298 return result;
299
300 }
301
302 bool SOSAccountUpdateOurPeerInBackup(SOSAccount* account, SOSRingRef oldRing, CFErrorRef *error){
303 bool result = false;
304 CFSetRef viewNames = SOSBackupRingGetViews(oldRing, error);
305 __block CFStringRef viewName = NULL;
306 require_quiet(viewNames, fail);
307 require_quiet(SecRequirementError(1 == CFSetGetCount(viewNames), error, CFSTR("Only support single view backup rings")), fail);
308
309 CFSetForEach(viewNames, ^(const void *value) {
310 if (isString(value)) {
311 viewName = CFRetainSafe((CFStringRef) value);
312 }
313 });
314
315 result = SOSAccountNewBKSBForView(account, viewName, error);
316
317 fail:
318 CFReleaseNull(viewName);
319 return result;
320 }
321
322 void SOSAccountForEachBackupRingName(SOSAccount* account, void (^operation)(CFStringRef value)) {
323 SOSPeerInfoRef myPeer = account.peerInfo;
324 if (myPeer) {
325 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
326
327 CFSetForEach(allViews, ^(const void *value) {
328 CFStringRef viewName = asString(value, NULL);
329
330 if (viewName) {
331 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
332 operation(ringName);
333 CFReleaseNull(ringName);
334 }
335 });
336 CFReleaseNull(allViews);
337 // Only one "ring" now (other than backup rings) when there's more this will need to be modified.
338 operation(kSOSRecoveryRing);
339 }
340 }
341
342
343 void SOSAccountForEachRingName(SOSAccount* account, void (^operation)(CFStringRef value)) {
344 SOSPeerInfoRef myPeer = account.peerInfo;
345 if (myPeer) {
346 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
347
348 CFSetForEach(allViews, ^(const void *value) {
349 CFStringRef viewName = asString(value, NULL);
350
351 if (viewName) {
352 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
353 operation(ringName);
354 CFReleaseNull(ringName);
355 }
356 });
357 CFReleaseNull(allViews);
358 // Only one "ring" now (other than backup rings) when there's more this will need to be modified.
359 operation(kSOSRecoveryRing);
360 }
361 }
362
363 void SOSAccountForEachBackupView(SOSAccount* account, void (^operation)(const void *value)) {
364 SOSPeerInfoRef myPeer = account.peerInfo;
365
366 if (myPeer) {
367 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
368 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
369 CFSetForEach(myBackupViews, operation);
370 CFReleaseNull(myBackupViews);
371 }
372 }
373
374
375 static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccount* account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error,
376 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
377 __block SOSBackupSliceKeyBagRef bskb = NULL;
378 bool result = false;
379
380 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
381 CFMutableSetRef newPeerList = CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(peers), peers);
382 CFArrayForEach(retiree, ^(const void *value) {
383 if (!isSOSPeerInfo(value)) {
384 secerror("Peer list contains a non-peerInfo element");
385 } else {
386 SOSPeerInfoRef retiringPeer = (SOSPeerInfoRef)value;
387 CFStringRef retiringPeerID = SOSPeerInfoGetPeerID(retiringPeer);
388
389 CFSetForEach(newPeerList, ^(const void *peerFromAccount) {
390 CFStringRef peerFromAccountID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)peerFromAccount);
391 if (peerFromAccountID && retiringPeerID && CFStringCompare(peerFromAccountID, retiringPeerID, 0) == 0){
392 CFSetRemoveValue(newPeerList, peerFromAccount);
393 }
394 });
395 }
396 });
397 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, newPeerList, error);
398 CFReleaseNull(newPeerList);
399 });
400
401 require_quiet(bskb, exit);
402
403 action(bskb, error);
404
405 result = true;
406
407 exit:
408 CFReleaseNull(bskb);
409 return result;
410 }
411
412
413 SOSRingRef SOSAccountCreateBackupRingForView(SOSAccount* account, CFStringRef ringBackupViewName, CFErrorRef *error) {
414 if(!account) return NULL;
415 if(!ringBackupViewName) return NULL;
416 SOSPeerInfoRef myPeerInfo = account.trust.peerInfo;
417 if(!myPeerInfo || !SOSPeerInfoHasBackupKey(myPeerInfo)) return NULL;
418 if(!SOSPeerInfoIsEnabledView(myPeerInfo, ringBackupViewName)) return NULL;
419 CFStringRef ringName = SOSBackupCopyRingNameForView(ringBackupViewName);
420 if(!ringName) return NULL;
421
422 SOSRingRef newRing = SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
423 CFReleaseNull(ringName);
424 CFMutableSetRef filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
425 CFMutableSetRef filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
426
427 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, ringBackupViewName, ^(SOSPeerInfoRef peer) {
428 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
429 CFSetAddValue(filteredPeerInfos, peer);
430 });
431
432 CFMutableSetRef viewSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
433 CFSetAddValue(viewSet, ringBackupViewName);
434
435 SOSBackupSliceKeyBagRef bskb = NULL;
436 CFDataRef recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
437 if(recoveryKeyData) {
438 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
439 CFDictionaryAddValue(additionalKeys, bskbRkbgPrefix, recoveryKeyData);
440 bskb = SOSBackupSliceKeyBagCreateWithAdditionalKeys(kCFAllocatorDefault, filteredPeerInfos, additionalKeys, error);
441 CFReleaseNull(additionalKeys);
442 } else {
443 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, filteredPeerInfos, error);
444 }
445 if(bskb) {
446 SOSRingSetPeerIDs(newRing, filteredPeerIDs);
447 SOSRingSetBackupKeyBag(newRing, account.fullPeerInfo, viewSet, bskb, error);
448 SOSBackupRingSetViews(newRing, account.fullPeerInfo, viewSet, error);
449 } else {
450 CFReleaseNull(newRing);
451 }
452
453 CFReleaseNull(viewSet);
454 CFReleaseNull(filteredPeerIDs);
455 CFReleaseNull(filteredPeerInfos);
456 CFReleaseNull(bskb);
457 CFReleaseNull(recoveryKeyData);
458 return newRing;
459 }
460
461 void SOSAccountProcessBackupRings(SOSAccount* account) {
462 SOSAccountForEachBackupView(account, ^(const void *value) {
463 CFErrorRef localError = NULL;
464 CFStringRef viewName = (CFStringRef)value;
465 SOSAccountUpdateBackupRing(account, viewName, &localError, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
466 SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
467 return newRing;
468 });
469 if(localError) {
470 secnotice("ring", "Error during SOSAccountProcessBackupRings (%@)", localError);
471 CFReleaseNull(localError);
472 }
473 });
474 }
475
476 bool SOSAccountValidateBackupRingForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error) {
477 bool fixBackupRing = false;
478 CFStringRef ringName = NULL;
479 SOSRingRef ring = NULL;
480 CFDataRef recoveryKeyData = NULL;
481 SOSBackupSliceKeyBagRef currentBSKB = NULL;
482 CFMutableSetRef filteredPeerIDs = NULL;
483 CFMutableSetRef filteredPeerInfos = NULL;
484 CFSetRef ringPeerIDSet = NULL;
485
486 require_action_quiet(account && viewName, errOut, SecError(errSecParam, error, CFSTR("NULL account or viewName parameter")));
487 ringName = SOSBackupCopyRingNameForView(viewName);
488 require_action_quiet(ringName, errOut, CFSTR("No RingName for View"));
489 ring = SOSAccountCopyRingNamed(account, ringName, error);
490 require_quiet(ring, errOut);
491 recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
492 currentBSKB = SOSRingCopyBackupSliceKeyBag(ring, NULL);
493 filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
494 filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
495
496 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, viewName, ^(SOSPeerInfoRef peer) {
497 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
498 CFSetAddValue(filteredPeerInfos, peer);
499 });
500
501 ringPeerIDSet = SOSRingCopyPeerIDs(ring);
502 if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) {
503 fixBackupRing = true;
504 }
505
506 fixBackupRing &= !currentBSKB ||
507 !SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) ||
508 !SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData);
509
510 errOut:
511 CFReleaseNull(ringName);
512 CFReleaseNull(ring);
513 CFReleaseNull(ringPeerIDSet);
514 CFReleaseNull(recoveryKeyData);
515 CFReleaseNull(currentBSKB);
516 CFReleaseNull(filteredPeerIDs);
517 CFReleaseNull(filteredPeerInfos);
518 return fixBackupRing;
519 }
520
521 bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBackupKey, CFErrorRef *error)
522 {
523 SOSAccount* account = aTxn.account;
524 __block bool result = false;
525
526 account.backup_key = nil;
527 if(!SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
528 return SOSFullPeerInfoUpdateBackupKey(fpi, cfBackupKey, error);
529 })){
530 return result;
531 }
532 SOSAccountProcessBackupRings(account);
533 account.need_backup_peers_created_after_backup_key_set = true;
534 account.circle_rings_retirements_need_attention = true;
535 return true;
536
537 }
538
539
540 bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error)
541 {
542 return SOSAccountSetBackupPublicKey(aTxn, NULL, error);
543 }
544
545 bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
546 __block bool result = false;
547 SOSBackupSliceKeyBagRef backup_slice = NULL;
548
549 if(![account isInCircle:error]) {
550 return result;
551 }
552
553 if (setupV0Only) {
554 result = SOSSaveV0Keybag(aks_bag, error);
555 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
556 } else {
557 result = true;
558
559 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
560
561 SOSAccountForEachBackupView(account, ^(const void *value) {
562 CFStringRef viewname = (CFStringRef) value;
563 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
564 });
565 }
566
567 exit:
568 CFReleaseNull(backup_slice);
569 return result;
570 }
571
572 static CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){
573 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
574
575 CFSetForEach(peersInBackup, ^(const void *value) {
576 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
577 CFArrayForEach(peers, ^(const void *value) {
578 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
579 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
580 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
581 CFArrayAppendValue(removals, peer);
582 }
583 });
584
585 });
586
587 return removals;
588 }
589
590 bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){
591 __block bool result = true;
592
593 SOSFullPeerInfoRef fpi = account.fullPeerInfo;
594 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
595
596 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
597 CFSetForEach(permittedViews, ^(const void *value) {
598 CFStringRef viewName = (CFStringRef)value;
599 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
600 //grab current peers list
601 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
602 //get peer infos that have retired but are still in the backup peer list
603 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
604 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
605 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
606 return result;
607 });
608 CFReleaseNull(removals);
609 CFReleaseNull(peersInBackup);
610 }
611 });
612
613 return result;
614
615 }
616
617 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){
618 CFDataRef backupSliceData = NULL;
619 CFStringRef ringName = NULL;
620 SOSRingRef ring = NULL;
621 SOSBackupSliceKeyBagRef bskb = NULL;
622
623 ringName = SOSBackupCopyRingNameForView(viewName);
624 ring = [account.trust copyRing:ringName err:NULL];
625 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
626
627 //grab the backup slice from the ring
628 backupSliceData = SOSRingGetPayload(ring, error);
629 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
630
631 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
632
633 exit:
634 CFReleaseNull(ring);
635 CFReleaseNull(ringName);
636
637 return bskb;
638 }