]> git.saurik.com Git - apple/security.git/blame - keychain/SecureObjectSync/SOSAccountBackup.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSAccountBackup.m
CommitLineData
5c19dc3a
A
1//
2// SOSAccountCircles.c
3// sec
4//
5
866f8763 6#include "SOSAccount.h"
5c19dc3a
A
7#include "SOSCloudKeychainClient.h"
8
9#include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
b54c578e
A
10
11#include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
12#include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
5c19dc3a 13#include <Security/SecureObjectSync/SOSViews.h>
b54c578e
A
14#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
15#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
5c19dc3a 16
b54c578e 17#include "keychain/SecureObjectSync/SOSInternal.h"
5c19dc3a 18
6b200bc3
A
19
20
5c19dc3a
A
21//
22// MARK: V0 Keybag keychain stuff
23//
24static 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
40static 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
e3d460c9 51bool SOSDeleteV0Keybag(CFErrorRef *error) {
5c19dc3a
A
52 CFDictionaryRef attributes = SOSCopyV0Attributes();
53
54 OSStatus result = SecItemDelete(attributes);
55
56 CFReleaseNull(attributes);
57
866f8763 58 return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %d"), (int)result);
5c19dc3a
A
59}
60
61static 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
77static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) {
78 if (CFEqualSafe(kSOSViewKeychainV0, viewName))
79 return false;
80
81 return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName);
82}
83
866f8763 84static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccount* account, CFStringRef viewName) {
5c19dc3a
A
85 CFMutableSetRef backupPeers = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
86
866f8763 87 SOSCircleRef circle = [account.trust getCircle:NULL];
5c19dc3a
A
88
89 require_quiet(circle, exit);
90
866f8763 91 SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
5c19dc3a
A
92 if (SOSPeerInfoIsViewBackupEnabled(peer, viewName))
93 CFSetAddValue(backupPeers, peer);
94 });
95
96exit:
97 return backupPeers;
98}
99
866f8763 100static void SOSAccountWithBackupPeersForView(SOSAccount* account, CFStringRef viewName, void (^action)(CFSetRef peers)) {
5c19dc3a
A
101 CFSetRef backupPeersForView = SOSAccountCopyBackupPeersForView(account, viewName);
102
103 action(backupPeersForView);
104
105 CFReleaseNull(backupPeersForView);
106}
107
6b200bc3 108
866f8763 109static bool SOSAccountWithBSKBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
5c19dc3a
A
110 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
111 __block SOSBackupSliceKeyBagRef bskb = NULL;
112 bool result = false;
866f8763 113 CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
5c19dc3a
A
114
115 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
6b200bc3
A
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 }
5c19dc3a 124 });
6b200bc3 125 CFReleaseNull(rkbg);
5c19dc3a
A
126
127 require_quiet(bskb, exit);
128
129 action(bskb, error);
130
131 result = true;
132
133exit:
134 CFReleaseNull(bskb);
135 return result;
136}
137
138CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) {
139 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName);
140}
141
b54c578e 142bool SOSAccountUpdateBackupRing(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
5c19dc3a
A
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) {
866f8763 148 return SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
5c19dc3a
A
149 }, modify);
150
151 CFReleaseNull(ringName);
152
153 return result;
154}
155
866f8763 156static bool SOSAccountSetKeybagForViewBackupRing(SOSAccount* account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) {
5c19dc3a
A
157 CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL);
158 bool result = false;
866f8763
A
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 }
5c19dc3a
A
165 CFSetAddValue(backupViewSet, viewName);
166
167 result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
168 SOSRingRef newRing = NULL;
866f8763 169 CFSetRef viewPeerSet = [account.trust copyPeerSetForView:viewName];
5c19dc3a
A
170 CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL);
171
172 SOSRingSetPeerIDs(existing, cleared);
173 SOSRingAddAll(existing, viewPeerSet);
174
866f8763 175 require_quiet(SOSRingSetBackupKeyBag(existing, account.fullPeerInfo, backupViewSet, keyBag, error), exit);
5c19dc3a
A
176
177 newRing = CFRetainSafe(existing);
178 exit:
179 CFReleaseNull(viewPeerSet);
180 CFReleaseNull(cleared);
181 return newRing;
182 });
866f8763 183
e0e0d90e 184 if (result && NULL != error && NULL != *error) {
5c19dc3a
A
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
866f8763 197bool SOSAccountNewBKSBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error)
5c19dc3a
A
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
866f8763 205bool SOSAccountIsBackupRingEmpty(SOSAccount* account, CFStringRef viewName) {
e0e0d90e 206 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
866f8763 207 SOSRingRef ring = [account.trust copyRing:backupRing err:NULL];
e0e0d90e
A
208 CFReleaseNull(backupRing);
209 int peercnt = 0;
210 if(ring) peercnt = SOSRingCountPeers(ring);
fa7225c8 211 CFReleaseNull(ring);
e0e0d90e
A
212 return peercnt == 0;
213}
214
866f8763 215bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname){
5c19dc3a
A
216 bool result = false;
217 CFErrorRef bsError = NULL;
218 CFDataRef backupSliceData = NULL;
fa7225c8 219 SOSRingRef ring = NULL;
5c19dc3a
A
220 SOSBackupSliceKeyBagRef backupSlice = NULL;
221
866f8763 222 require_quiet(SOSPeerInfoIsViewBackupEnabled(account.peerInfo, viewname), errOut);
5c19dc3a 223
5c19dc3a 224 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
866f8763 225 ring = [account.trust copyRing:ringName err:&bsError];
5c19dc3a
A
226 CFReleaseNull(ringName);
227
fa7225c8 228 require_quiet(ring, errOut);
5c19dc3a
A
229
230 //grab the backup slice from the ring
231 backupSliceData = SOSRingGetPayload(ring, &bsError);
fa7225c8 232 require_quiet(backupSliceData, errOut);
5c19dc3a
A
233
234 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
fa7225c8 235 require_quiet(backupSlice, errOut);
5c19dc3a
A
236
237 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
866f8763 238 SOSPeerInfoRef myPeer = account.peerInfo;
5c19dc3a
A
239
240 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
fa7225c8 241 require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut);
5c19dc3a
A
242
243 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
244 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
245 result = CFEqualSafe(myBK, myPeerInBSKBBK);
246 CFReleaseNull(myBK);
e0e0d90e 247 CFReleaseNull(myPeerInBSKBBK);
5c19dc3a 248
fa7225c8
A
249errOut:
250 CFReleaseNull(ring);
ecaf5866 251 CFReleaseNull(backupSlice);
fa7225c8 252
5c19dc3a
A
253 if (bsError) {
254 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
255 }
256 CFReleaseNull(bsError);
257 return result;
258}
259
866f8763 260bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccount* account, SOSPeerInfoRef testPeer, CFStringRef viewname){
5c19dc3a
A
261 bool result = false;
262 CFErrorRef bsError = NULL;
263 CFDataRef backupSliceData = NULL;
fa7225c8 264 SOSRingRef ring = NULL;
5c19dc3a
A
265 SOSBackupSliceKeyBagRef backupSlice = NULL;
266
fa7225c8 267 require_quiet(testPeer, errOut);
5c19dc3a
A
268
269 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
866f8763
A
270
271 ring = [account.trust copyRing:ringName err:&bsError];
5c19dc3a
A
272 CFReleaseNull(ringName);
273
fa7225c8 274 require_quiet(ring, errOut);
5c19dc3a
A
275
276 //grab the backup slice from the ring
277 backupSliceData = SOSRingGetPayload(ring, &bsError);
fa7225c8 278 require_quiet(backupSliceData, errOut);
5c19dc3a
A
279
280 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
fa7225c8 281 require_quiet(backupSlice, errOut);
5c19dc3a
A
282
283 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
284
285 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
fa7225c8 286 require_quiet(isSOSPeerInfo(peerInBSKB), errOut);
5c19dc3a
A
287
288 result = CFEqualSafe(testPeer, peerInBSKB);
289
fa7225c8
A
290errOut:
291 CFReleaseNull(ring);
ecaf5866 292 CFReleaseNull(backupSlice);
fa7225c8 293
5c19dc3a
A
294 if (bsError) {
295 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
296 }
297 CFReleaseNull(bsError);
298 return result;
299
300}
301
866f8763 302bool SOSAccountUpdateOurPeerInBackup(SOSAccount* account, SOSRingRef oldRing, CFErrorRef *error){
5c19dc3a
A
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
fa7225c8 315 result = SOSAccountNewBKSBForView(account, viewName, error);
5c19dc3a
A
316
317fail:
318 CFReleaseNull(viewName);
319 return result;
320}
321
866f8763
A
322void SOSAccountForEachBackupRingName(SOSAccount* account, void (^operation)(CFStringRef value)) {
323 SOSPeerInfoRef myPeer = account.peerInfo;
5c19dc3a 324 if (myPeer) {
fa7225c8 325 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
5c19dc3a 326
fa7225c8 327 CFSetForEach(allViews, ^(const void *value) {
5c19dc3a
A
328 CFStringRef viewName = asString(value, NULL);
329
330 if (viewName) {
331 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
332 operation(ringName);
333 CFReleaseNull(ringName);
334 }
335 });
fa7225c8 336 CFReleaseNull(allViews);
6b200bc3
A
337 // Only one "ring" now (other than backup rings) when there's more this will need to be modified.
338 operation(kSOSRecoveryRing);
5c19dc3a
A
339 }
340}
341
866f8763
A
342
343void 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
363void SOSAccountForEachBackupView(SOSAccount* account, void (^operation)(const void *value)) {
364 SOSPeerInfoRef myPeer = account.peerInfo;
5c19dc3a
A
365
366 if (myPeer) {
367 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
5c19dc3a 368 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
5c19dc3a 369 CFSetForEach(myBackupViews, operation);
5c19dc3a
A
370 CFReleaseNull(myBackupViews);
371 }
372}
373
6b200bc3 374
866f8763 375static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccount* account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error,
5c19dc3a
A
376 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
377 __block SOSBackupSliceKeyBagRef bskb = NULL;
378 bool result = false;
b54c578e 379
5c19dc3a
A
380 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
381 CFMutableSetRef newPeerList = CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(peers), peers);
382 CFArrayForEach(retiree, ^(const void *value) {
e0e0d90e
A
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 }
5c19dc3a
A
396 });
397 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, newPeerList, error);
398 CFReleaseNull(newPeerList);
399 });
b54c578e 400
5c19dc3a 401 require_quiet(bskb, exit);
b54c578e 402
5c19dc3a 403 action(bskb, error);
b54c578e 404
5c19dc3a 405 result = true;
b54c578e 406
5c19dc3a
A
407exit:
408 CFReleaseNull(bskb);
409 return result;
410}
411
fa7225c8 412
b54c578e
A
413SOSRingRef 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;
fa7225c8 421
b54c578e
A
422 SOSRingRef newRing = SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
423 CFReleaseNull(ringName);
424 CFMutableSetRef filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
425 CFMutableSetRef filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
fa7225c8 426
b54c578e
A
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}
fa7225c8 460
d64be36e 461void SOSAccountProcessBackupRings(SOSAccount* account) {
5c19dc3a 462 SOSAccountForEachBackupView(account, ^(const void *value) {
d64be36e 463 CFErrorRef localError = NULL;
5c19dc3a 464 CFStringRef viewName = (CFStringRef)value;
d64be36e 465 SOSAccountUpdateBackupRing(account, viewName, &localError, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
b54c578e
A
466 SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
467 return newRing;
5c19dc3a 468 });
d64be36e
A
469 if(localError) {
470 secnotice("ring", "Error during SOSAccountProcessBackupRings (%@)", localError);
471 CFReleaseNull(localError);
472 }
5c19dc3a 473 });
b54c578e 474}
5c19dc3a 475
b54c578e
A
476bool 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 });
866f8763 500
b54c578e
A
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
510errOut:
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
521bool 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 }
d64be36e
A
532 SOSAccountProcessBackupRings(account);
533 account.need_backup_peers_created_after_backup_key_set = true;
534 account.circle_rings_retirements_need_attention = true;
b54c578e
A
535 return true;
536
537}
538
539
540bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error)
541{
542 return SOSAccountSetBackupPublicKey(aTxn, NULL, error);
5c19dc3a
A
543}
544
866f8763 545bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
5c19dc3a
A
546 __block bool result = false;
547 SOSBackupSliceKeyBagRef backup_slice = NULL;
548
79b9da22
A
549 if(![account isInCircle:error]) {
550 return result;
551 }
5c19dc3a 552
e0e0d90e 553 if (setupV0Only) {
5c19dc3a
A
554 result = SOSSaveV0Keybag(aks_bag, error);
555 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
e0e0d90e
A
556 } else {
557 result = true;
5c19dc3a 558
e0e0d90e 559 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
5c19dc3a 560
e0e0d90e
A
561 SOSAccountForEachBackupView(account, ^(const void *value) {
562 CFStringRef viewname = (CFStringRef) value;
563 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
564 });
565 }
5c19dc3a 566
5c19dc3a
A
567exit:
568 CFReleaseNull(backup_slice);
569 return result;
570}
571
ecaf5866 572static CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){
5c19dc3a
A
573 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
574
575 CFSetForEach(peersInBackup, ^(const void *value) {
576 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
e0e0d90e
A
577 CFArrayForEach(peers, ^(const void *value) {
578 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
5c19dc3a 579 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
e0e0d90e 580 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
5c19dc3a
A
581 CFArrayAppendValue(removals, peer);
582 }
583 });
584
585 });
586
587 return removals;
5c19dc3a
A
588}
589
866f8763 590bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){
5c19dc3a
A
591 __block bool result = true;
592
866f8763 593 SOSFullPeerInfoRef fpi = account.fullPeerInfo;
5c19dc3a
A
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
e0e0d90e 603 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
5c19dc3a
A
604 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
605 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
606 return result;
607 });
ecaf5866
A
608 CFReleaseNull(removals);
609 CFReleaseNull(peersInBackup);
5c19dc3a
A
610 }
611 });
612
613 return result;
614
615}
616
866f8763 617SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){
e3d460c9
A
618 CFDataRef backupSliceData = NULL;
619 CFStringRef ringName = NULL;
620 SOSRingRef ring = NULL;
621 SOSBackupSliceKeyBagRef bskb = NULL;
622
e3d460c9 623 ringName = SOSBackupCopyRingNameForView(viewName);
866f8763 624 ring = [account.trust copyRing:ringName err:NULL];
e3d460c9
A
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
633exit:
fa7225c8 634 CFReleaseNull(ring);
e3d460c9
A
635 CFReleaseNull(ringName);
636
637 return bskb;
638}