]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSAccountBackup.m
Security-59306.11.20.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, CFErrorRef *error) {
462 SOSAccountForEachBackupView(account, ^(const void *value) {
463 CFStringRef viewName = (CFStringRef)value;
464 SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
465 SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
466 return newRing;
467 });
468 });
469 }
470
471 bool SOSAccountValidateBackupRingForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error) {
472 bool fixBackupRing = false;
473 CFStringRef ringName = NULL;
474 SOSRingRef ring = NULL;
475 CFDataRef recoveryKeyData = NULL;
476 SOSBackupSliceKeyBagRef currentBSKB = NULL;
477 CFMutableSetRef filteredPeerIDs = NULL;
478 CFMutableSetRef filteredPeerInfos = NULL;
479 CFSetRef ringPeerIDSet = NULL;
480
481 require_action_quiet(account && viewName, errOut, SecError(errSecParam, error, CFSTR("NULL account or viewName parameter")));
482 ringName = SOSBackupCopyRingNameForView(viewName);
483 require_action_quiet(ringName, errOut, CFSTR("No RingName for View"));
484 ring = SOSAccountCopyRingNamed(account, ringName, error);
485 require_quiet(ring, errOut);
486 recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
487 currentBSKB = SOSRingCopyBackupSliceKeyBag(ring, NULL);
488 filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
489 filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
490
491 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, viewName, ^(SOSPeerInfoRef peer) {
492 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
493 CFSetAddValue(filteredPeerInfos, peer);
494 });
495
496 ringPeerIDSet = SOSRingCopyPeerIDs(ring);
497 if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) {
498 fixBackupRing = true;
499 }
500
501 fixBackupRing &= !currentBSKB ||
502 !SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) ||
503 !SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData);
504
505 errOut:
506 CFReleaseNull(ringName);
507 CFReleaseNull(ring);
508 CFReleaseNull(ringPeerIDSet);
509 CFReleaseNull(recoveryKeyData);
510 CFReleaseNull(currentBSKB);
511 CFReleaseNull(filteredPeerIDs);
512 CFReleaseNull(filteredPeerInfos);
513 return fixBackupRing;
514 }
515
516 bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBackupKey, CFErrorRef *error)
517 {
518 SOSAccount* account = aTxn.account;
519 __block bool result = false;
520
521 account.backup_key = nil;
522 if(!SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
523 return SOSFullPeerInfoUpdateBackupKey(fpi, cfBackupKey, error);
524 })){
525 return result;
526 }
527 SOSAccountProcessBackupRings(account, NULL);
528 return true;
529
530 }
531
532
533 bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error)
534 {
535 return SOSAccountSetBackupPublicKey(aTxn, NULL, error);
536 }
537
538 bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
539 __block bool result = false;
540 SOSBackupSliceKeyBagRef backup_slice = NULL;
541
542 if(![account isInCircle:error]) {
543 return result;
544 }
545
546 if (setupV0Only) {
547 result = SOSSaveV0Keybag(aks_bag, error);
548 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
549 } else {
550 result = true;
551
552 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
553
554 SOSAccountForEachBackupView(account, ^(const void *value) {
555 CFStringRef viewname = (CFStringRef) value;
556 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
557 });
558 }
559
560 exit:
561 CFReleaseNull(backup_slice);
562 return result;
563 }
564
565 static CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){
566 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
567
568 CFSetForEach(peersInBackup, ^(const void *value) {
569 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
570 CFArrayForEach(peers, ^(const void *value) {
571 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
572 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
573 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
574 CFArrayAppendValue(removals, peer);
575 }
576 });
577
578 });
579
580 return removals;
581 }
582
583 bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){
584 __block bool result = true;
585
586 SOSFullPeerInfoRef fpi = account.fullPeerInfo;
587 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
588
589 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
590 CFSetForEach(permittedViews, ^(const void *value) {
591 CFStringRef viewName = (CFStringRef)value;
592 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
593 //grab current peers list
594 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
595 //get peer infos that have retired but are still in the backup peer list
596 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
597 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
598 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
599 return result;
600 });
601 CFReleaseNull(removals);
602 CFReleaseNull(peersInBackup);
603 }
604 });
605
606 return result;
607
608 }
609
610 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){
611 CFDataRef backupSliceData = NULL;
612 CFStringRef ringName = NULL;
613 SOSRingRef ring = NULL;
614 SOSBackupSliceKeyBagRef bskb = NULL;
615
616 ringName = SOSBackupCopyRingNameForView(viewName);
617 ring = [account.trust copyRing:ringName err:NULL];
618 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
619
620 //grab the backup slice from the ring
621 backupSliceData = SOSRingGetPayload(ring, error);
622 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
623
624 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
625
626 exit:
627 CFReleaseNull(ring);
628 CFReleaseNull(ringName);
629
630 return bskb;
631 }
632
633 bool SOSAccountIsLastBackupPeer(SOSAccount* account, CFErrorRef *error) {
634 __block bool retval = false;
635 SOSPeerInfoRef pi = account.peerInfo;
636
637 if(![account isInCircle:error]) {
638 return retval;
639 }
640
641 if(!SOSPeerInfoHasBackupKey(pi))
642 return retval;
643
644 SOSCircleRef circle = [account.trust getCircle:error];
645
646 if(SOSCircleCountValidSyncingPeers(circle, SOSAccountGetTrustedPublicCredential(account, error)) == 1){
647 retval = true;
648 return retval;
649 }
650 // We're in a circle with more than 1 ActiveValidPeers - are they in the backups?
651 SOSAccountForEachBackupView(account, ^(const void *value) {
652 CFStringRef viewname = (CFStringRef) value;
653 SOSBackupSliceKeyBagRef keybag = SOSAccountBackupSliceKeyBagForView(account, viewname, error);
654 require_quiet(keybag, inner_errOut);
655 retval |= ((SOSBSKBCountPeers(keybag) == 1) && (SOSBSKBPeerIsInKeyBag(keybag, pi)));
656 inner_errOut:
657 CFReleaseNull(keybag);
658 });
659
660 return retval;
661 }