]>
Commit | Line | Data |
---|---|---|
866f8763 A |
1 | // |
2 | // SOSAccountUpdate.c | |
3 | // sec | |
4 | // | |
5 | ||
6 | #include "SOSAccountPriv.h" | |
7 | #include "SOSAccountLog.h" | |
8 | ||
b54c578e A |
9 | #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h" |
10 | #include "keychain/SecureObjectSync/SOSTransport.h" | |
866f8763 | 11 | #include <Security/SecureObjectSync/SOSViews.h> |
b54c578e A |
12 | #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" |
13 | #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" | |
14 | #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" | |
15 | #include "keychain/SecureObjectSync/SOSPeerInfoDER.h" | |
866f8763 | 16 | #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h> |
b54c578e | 17 | #import "keychain/SecureObjectSync/SOSAccountGhost.h" |
866f8763 | 18 | |
b54c578e A |
19 | #import "keychain/SecureObjectSync/SOSAccountTrust.h" |
20 | #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" | |
21 | #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" | |
866f8763 A |
22 | |
23 | static void DifferenceAndCall(CFSetRef old_members, CFSetRef new_members, void (^updatedCircle)(CFSetRef additions, CFSetRef removals)) | |
24 | { | |
25 | CFMutableSetRef additions = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, new_members); | |
26 | CFMutableSetRef removals = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, old_members); | |
27 | ||
28 | ||
29 | CFSetForEach(old_members, ^(const void * value) { | |
30 | CFSetRemoveValue(additions, value); | |
31 | }); | |
32 | ||
33 | CFSetForEach(new_members, ^(const void * value) { | |
34 | CFSetRemoveValue(removals, value); | |
35 | }); | |
36 | ||
37 | updatedCircle(additions, removals); | |
38 | ||
39 | CFReleaseSafe(additions); | |
40 | CFReleaseSafe(removals); | |
41 | } | |
42 | static CFMutableSetRef SOSAccountCopyIntersectedViews(CFSetRef peerViews, CFSetRef myViews) { | |
43 | __block CFMutableSetRef views = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); | |
44 | if (peerViews && myViews) CFSetForEach(peerViews, ^(const void *view) { | |
45 | if (CFSetContainsValue(myViews, view)) { | |
46 | CFSetAddValue(views, view); | |
47 | } | |
48 | }); | |
49 | return views; | |
50 | } | |
51 | ||
52 | static inline bool isSyncing(SOSPeerInfoRef peer, SecKeyRef upub) { | |
53 | if(!SOSPeerInfoApplicationVerify(peer, upub, NULL)) return false; | |
54 | if(SOSPeerInfoIsRetirementTicket(peer)) return false; | |
55 | return true; | |
56 | } | |
57 | ||
58 | static bool isBackupSOSRing(SOSRingRef ring) | |
59 | { | |
60 | return isSOSRing(ring) && (kSOSRingBackup == SOSRingGetType(ring)); | |
61 | } | |
62 | ||
63 | static void SOSAccountAppendPeerMetasForViewBackups(SOSAccount* account, CFSetRef views, CFMutableArrayRef appendTo) | |
64 | { | |
65 | CFMutableDictionaryRef ringToViewTable = NULL; | |
66 | ||
67 | if([account getCircleStatus:NULL] != kSOSCCInCircle) | |
68 | return; | |
69 | ||
70 | if(!(SOSAccountHasCompletedInitialSync(account))){ | |
71 | secnotice("backup", "Haven't finished initial backup syncing, not registering backup metas with engine"); | |
72 | return; | |
73 | } | |
74 | if(!SOSPeerInfoV2DictionaryHasData(account.peerInfo, sBackupKeyKey)){ | |
75 | secnotice("backup", "No key to backup to, we don't enable individual view backups"); | |
76 | return; | |
77 | } | |
78 | ringToViewTable = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); | |
79 | ||
80 | CFSetForEach(views, ^(const void *value) { | |
81 | CFStringRef viewName = value; | |
82 | if (isString(viewName) && !CFEqualSafe(viewName, kSOSViewKeychainV0)) { | |
83 | CFStringRef ringName = SOSBackupCopyRingNameForView(viewName); | |
84 | viewName = ringName; | |
85 | SOSRingRef ring = [account.trust copyRing:ringName err:NULL]; | |
86 | if (ring && isBackupSOSRing(ring)) { | |
87 | CFTypeRef currentValue = (CFTypeRef) CFDictionaryGetValue(ringToViewTable, ring); | |
88 | ||
89 | if (isSet(currentValue)) { | |
90 | CFSetAddValue((CFMutableSetRef)currentValue, viewName); | |
91 | } else { | |
92 | CFMutableSetRef viewNameSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); | |
93 | CFSetAddValue(viewNameSet, viewName); | |
94 | ||
95 | CFDictionarySetValue(ringToViewTable, ring, viewNameSet); | |
96 | CFReleaseNull(viewNameSet); | |
97 | } | |
98 | } else { | |
99 | secwarning("View '%@' not being backed up – ring %@:%@ not backup ring.", viewName, ringName, ring); | |
100 | } | |
101 | CFReleaseNull(ringName); | |
102 | CFReleaseNull(ring); | |
103 | } | |
104 | }); | |
105 | ||
106 | CFDictionaryForEach(ringToViewTable, ^(const void *key, const void *value) { | |
107 | SOSRingRef ring = (SOSRingRef) key; | |
108 | CFSetRef viewNames = asSet(value, NULL); | |
109 | if (isSOSRing(ring) && viewNames) { | |
110 | if (SOSAccountIntersectsWithOutstanding(account, viewNames)) { | |
111 | CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { | |
112 | secnotice("engine-notify", "Not ready, no peer meta: R: %@ Vs: %@", SOSRingGetName(ring), ringViews); | |
113 | }); | |
114 | } else { | |
115 | bool meta_added = false; | |
116 | CFErrorRef create_error = NULL; | |
117 | SOSBackupSliceKeyBagRef key_bag = NULL; | |
118 | SOSPeerMetaRef newMeta = NULL; | |
119 | ||
120 | CFDataRef ring_payload = SOSRingGetPayload(ring, NULL); | |
121 | require_quiet(isData(ring_payload), skip); | |
122 | ||
123 | key_bag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, ring_payload, &create_error); | |
124 | require_quiet(key_bag, skip); | |
125 | ||
126 | newMeta = SOSPeerMetaCreateWithComponents(SOSRingGetName(ring), viewNames, ring_payload); | |
127 | require_quiet(SecAllocationError(newMeta, &create_error, CFSTR("Didn't make peer meta for: %@"), ring), skip); | |
128 | CFArrayAppendValue(appendTo, newMeta); | |
129 | ||
130 | CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { | |
131 | secnotice("engine-notify", "Backup peer meta: R: %@ Vs: %@ VD: %@", SOSRingGetName(ring), ringViews, ring_payload); | |
132 | }); | |
133 | ||
134 | meta_added = true; | |
135 | ||
136 | skip: | |
137 | if (!meta_added) { | |
138 | CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { | |
139 | secerror("Failed to register backup meta from %@ for views %@. Error (%@)", ring, ringViews, create_error); | |
140 | }); | |
141 | } | |
142 | CFReleaseNull(newMeta); | |
143 | CFReleaseNull(key_bag); | |
144 | CFReleaseNull(create_error); | |
145 | } | |
146 | } | |
147 | }); | |
148 | ||
149 | CFReleaseNull(ringToViewTable); | |
150 | } | |
151 | ||
152 | bool SOSAccountSyncingV0(SOSAccount* account) { | |
153 | __block bool syncingV0 = false; | |
154 | SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { | |
155 | if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) { | |
156 | syncingV0 = true; | |
157 | } | |
158 | }); | |
159 | ||
160 | return syncingV0; | |
161 | } | |
162 | ||
163 | void SOSAccountNotifyEngines(SOSAccount* account) | |
164 | { | |
d64be36e A |
165 | dispatch_assert_queue(account.queue); |
166 | ||
866f8763 A |
167 | SOSAccountTrustClassic *trust = account.trust; |
168 | SOSFullPeerInfoRef identity = trust.fullPeerInfo; | |
169 | SOSCircleRef circle = trust.trustedCircle; | |
170 | ||
171 | SOSPeerInfoRef myPi = SOSFullPeerInfoGetPeerInfo(identity); | |
172 | CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi); | |
173 | CFMutableArrayRef syncing_peer_metas = NULL; | |
174 | CFMutableArrayRef zombie_peer_metas = NULL; | |
175 | CFErrorRef localError = NULL; | |
176 | SOSPeerMetaRef myMeta = NULL; | |
177 | ||
178 | if (myPi_id && isSyncing(myPi, account.accountKey) && SOSCircleHasPeer(circle, myPi, NULL)) { | |
179 | CFMutableSetRef myViews = SOSPeerInfoCopyEnabledViews(myPi); | |
180 | ||
181 | // We add V0 views to everyone if we see a V0 peer, or a peer with the view explicity enabled | |
182 | // V2 peers shouldn't be explicity enabling the uber V0 view, though the seeds did. | |
183 | __block bool addV0Views = SOSAccountSyncingV0(account); | |
d64be36e A |
184 | |
185 | bool selfSupportCKKSForAll = SOSPeerInfoSupportsCKKSForAll(myPi); | |
186 | secnotice("engine-notify", "Self peer(%@) %@ CKKS For All", myPi_id, selfSupportCKKSForAll ? @"supports" : @"doesn't support"); | |
187 | ||
866f8763 A |
188 | syncing_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); |
189 | zombie_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); | |
190 | SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { | |
191 | CFMutableArrayRef arrayToAddTo = isSyncing(peer, account.accountKey) ? syncing_peer_metas : zombie_peer_metas; | |
192 | ||
193 | // Compute views each peer is in that we are also in ourselves | |
194 | CFMutableSetRef peerEnabledViews = SOSPeerInfoCopyEnabledViews(peer); | |
195 | CFMutableSetRef views = SOSAccountCopyIntersectedViews(peerEnabledViews, myViews); | |
196 | CFReleaseNull(peerEnabledViews); | |
197 | ||
198 | if(addV0Views) { | |
199 | CFSetAddValue(views, kSOSViewKeychainV0); | |
200 | } | |
d64be36e A |
201 | |
202 | // If this peer supports CKKS4All, let's sync zero views to it. | |
203 | if(selfSupportCKKSForAll && SOSPeerInfoSupportsCKKSForAll(peer)) { | |
204 | secnotice("engine-notify", "Peer %@ supports CKKS For All; ignoring in SOS syncing", SOSPeerInfoGetPeerID(peer)); | |
205 | CFSetRemoveAllValues(views); | |
206 | } | |
866f8763 A |
207 | |
208 | CFStringSetPerformWithDescription(views, ^(CFStringRef viewsDescription) { | |
209 | secnotice("engine-notify", "Meta: %@: %@", SOSPeerInfoGetPeerID(peer), viewsDescription); | |
210 | }); | |
211 | ||
212 | SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(SOSPeerInfoGetPeerID(peer), views, NULL); | |
213 | CFReleaseNull(views); | |
214 | ||
215 | CFArrayAppendValue(arrayToAddTo, peerMeta); | |
216 | CFReleaseNull(peerMeta); | |
217 | }); | |
218 | ||
219 | // We don't make a backup peer meta for the magic V0 peer | |
220 | // Set up all the rest before we munge the set | |
221 | SOSAccountAppendPeerMetasForViewBackups(account, myViews, syncing_peer_metas); | |
222 | ||
223 | // If we saw someone else needing V0, we sync V0, too! | |
224 | if (addV0Views) { | |
225 | CFSetAddValue(myViews, kSOSViewKeychainV0); | |
226 | } | |
227 | ||
228 | CFStringSetPerformWithDescription(myViews, ^(CFStringRef viewsDescription) { | |
229 | secnotice("engine-notify", "My Meta: %@: %@", myPi_id, viewsDescription); | |
230 | }); | |
231 | myMeta = SOSPeerMetaCreateWithComponents(myPi_id, myViews, NULL); | |
232 | CFReleaseSafe(myViews); | |
233 | } | |
234 | ||
235 | SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account.factory, SOSCircleGetName(circle), NULL); | |
236 | if (engine) { | |
237 | SOSEngineCircleChanged(engine, myMeta, syncing_peer_metas, zombie_peer_metas); | |
238 | } | |
239 | ||
240 | CFReleaseNull(myMeta); | |
241 | CFReleaseSafe(localError); | |
242 | ||
243 | CFReleaseNull(syncing_peer_metas); | |
244 | CFReleaseNull(zombie_peer_metas); | |
245 | } | |
246 | ||
247 | ||
248 | // Upcoming call to View Changes Here | |
249 | void SOSAccountNotifyOfChange(SOSAccount* account, SOSCircleRef oldCircle, SOSCircleRef newCircle) | |
250 | { | |
251 | account.circle_rings_retirements_need_attention = true; | |
252 | ||
253 | CFMutableSetRef old_members = SOSCircleCopyPeers(oldCircle, kCFAllocatorDefault); | |
254 | CFMutableSetRef new_members = SOSCircleCopyPeers(newCircle, kCFAllocatorDefault); | |
255 | ||
256 | CFMutableSetRef old_applicants = SOSCircleCopyApplicants(oldCircle, kCFAllocatorDefault); | |
257 | CFMutableSetRef new_applicants = SOSCircleCopyApplicants(newCircle, kCFAllocatorDefault); | |
258 | ||
259 | SOSPeerInfoRef me = account.peerInfo; | |
260 | if(me && CFSetContainsValue(new_members, me)) | |
261 | SOSAccountSetValue(account, kSOSEscrowRecord, kCFNull, NULL); //removing the escrow records from the account object | |
262 | ||
263 | DifferenceAndCall(old_members, new_members, ^(CFSetRef added_members, CFSetRef removed_members) { | |
264 | DifferenceAndCall(old_applicants, new_applicants, ^(CFSetRef added_applicants, CFSetRef removed_applicants) { | |
265 | CFArrayForEach((__bridge CFArrayRef)(account.change_blocks), ^(const void * notificationBlock) { | |
266 | secnotice("updates", "calling change block"); | |
79b9da22 | 267 | ((__bridge SOSAccountCircleMembershipChangeBlock) notificationBlock)(account, newCircle, added_members, removed_members, added_applicants, removed_applicants); |
866f8763 A |
268 | }); |
269 | }); | |
270 | }); | |
271 | ||
272 | CFReleaseNull(old_applicants); | |
273 | CFReleaseNull(new_applicants); | |
274 | ||
275 | CFReleaseNull(old_members); | |
276 | CFReleaseNull(new_members); | |
277 | } | |
278 | ||
279 | CF_RETURNS_RETAINED | |
280 | CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccount* account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error) { | |
281 | SOSAccountTrustClassic* trust = account.trust; | |
282 | CFStringRef circle_name = SOSCircleGetName(trust.trustedCircle); | |
283 | CFMutableArrayRef handledRetirementIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); | |
284 | // We only handle one circle, look it up: | |
285 | ||
286 | if(!trust.trustedCircle) // We don't fail, we intentionally handle nothing. | |
287 | return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); | |
288 | ||
ecaf5866 | 289 | CFDictionaryRef retirement_dictionary = asDictionary(CFDictionaryGetValue(circle_retirement_messages, circle_name), NULL); |
866f8763 A |
290 | if(!retirement_dictionary) |
291 | return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); | |
292 | ||
293 | CFDictionaryForEach(retirement_dictionary, ^(const void *key, const void *value) { | |
294 | if(isData(value)) { | |
295 | SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value); | |
296 | if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) { | |
297 | [trust.retirees addObject: (__bridge id _Nonnull)(pi)]; | |
298 | ||
299 | account.circle_rings_retirements_need_attention = true; // Have to handle retirements. | |
300 | ||
301 | CFArrayAppendValue(handledRetirementIDs, key); | |
302 | } | |
303 | CFReleaseNull(pi); | |
304 | } | |
305 | }); | |
306 | ||
307 | // If we are in the retiree list, we somehow got resurrected | |
308 | // clearly we took care of proper departure before so leave | |
309 | // and delcare that we withdrew this time. | |
310 | SOSPeerInfoRef me = account.peerInfo; | |
311 | ||
312 | if (me && [trust.retirees containsObject:(__bridge id _Nonnull)(me)]) { | |
313 | SOSAccountPurgeIdentity(account); | |
314 | trust.departureCode = kSOSDiscoveredRetirement; | |
315 | } | |
316 | ||
317 | CFDictionaryRef result = (CFArrayGetCount(handledRetirementIDs) == 0) ? CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL) | |
318 | : CFDictionaryCreateForCFTypes(kCFAllocatorDefault, circle_name, handledRetirementIDs, NULL); | |
319 | ||
320 | CFReleaseNull(handledRetirementIDs); | |
321 | return result; | |
322 | } | |
323 | ||
324 | static SOSCircleRef SOSAccountCreateCircleFrom(CFStringRef circleName, CFTypeRef value, CFErrorRef *error) { | |
325 | if (value && !isData(value) && !isNull(value)) { | |
ecaf5866 | 326 | secnotice("circleOps", "Value provided not appropriate for a circle"); |
866f8763 A |
327 | CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(value)); |
328 | SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, | |
329 | CFSTR("Expected data or NULL got %@"), description); | |
330 | CFReleaseSafe(description); | |
331 | return NULL; | |
332 | } | |
333 | ||
334 | SOSCircleRef circle = NULL; | |
335 | if (!value || isNull(value)) { | |
ecaf5866 | 336 | secnotice("circleOps", "No circle found in data: %@", value); |
866f8763 A |
337 | circle = NULL; |
338 | } else { | |
339 | circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, error); | |
340 | if (circle) { | |
341 | CFStringRef name = SOSCircleGetName(circle); | |
342 | if (!CFEqualSafe(name, circleName)) { | |
ecaf5866 | 343 | secnotice("circleOps", "Expected circle named %@, got %@", circleName, name); |
866f8763 A |
344 | SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, |
345 | CFSTR("Expected circle named %@, got %@"), circleName, name); | |
346 | CFReleaseNull(circle); | |
347 | } | |
348 | } else { | |
ecaf5866 | 349 | secnotice("circleOps", "SOSCircleCreateFromData returned NULL."); |
866f8763 A |
350 | } |
351 | } | |
352 | return circle; | |
353 | } | |
354 | ||
355 | bool SOSAccountHandleCircleMessage(SOSAccount* account, | |
356 | CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error) { | |
357 | bool success = false; | |
358 | CFErrorRef localError = NULL; | |
d64be36e A |
359 | |
360 | if(account && account.accountIsChanging) { | |
361 | secnotice("circleOps", "SOSAccountHandleCircleMessage called before signing in to new account"); | |
362 | return true; // we want to drop circle notifications when account is changing | |
363 | } | |
364 | ||
866f8763 A |
365 | SOSCircleRef circle = SOSAccountCreateCircleFrom(circleName, encodedCircleMessage, &localError); |
366 | if (circle) { | |
367 | success = [account.trust updateCircleFromRemote:account.circle_transport newCircle:circle err:&localError]; | |
368 | CFReleaseSafe(circle); | |
369 | } else { | |
370 | secerror("NULL circle found, ignoring ..."); | |
371 | success = true; // don't pend this NULL thing. | |
372 | } | |
373 | ||
374 | if (!success) { | |
375 | if (isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)) { | |
376 | secerror("Incompatible circle found, abandoning membership: %@", circleName); | |
377 | } | |
378 | ||
379 | if (error) { | |
380 | *error = localError; | |
381 | localError = NULL; | |
382 | } | |
383 | ||
384 | } | |
385 | ||
386 | CFReleaseNull(localError); | |
387 | ||
388 | return success; | |
389 | } | |
390 | ||
391 | bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef parameters, CFErrorRef *error){ | |
d64be36e A |
392 | if(account && account.accountIsChanging) { |
393 | secnotice("circleOps", "SOSAccountHandleParametersChange called before signing in to new account"); | |
394 | return true; // we want to drop parm notifications when account is changing | |
395 | } | |
866f8763 A |
396 | |
397 | SecKeyRef newKey = NULL; | |
d64be36e | 398 | CFDataRef pbkdfParams = NULL; |
866f8763 A |
399 | bool success = false; |
400 | ||
d64be36e A |
401 | if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &pbkdfParams, error)) { |
402 | debugDumpUserParameters(CFSTR("SOSAccountHandleParametersChange got new user key parameters:"), pbkdfParams); | |
403 | CFStringRef keyid = SOSCopyIDOfKeyWithLength(newKey, 8, NULL); | |
404 | secnotice("circleOps", "SOSAccountHandleParametersChange got new public key: %@", keyid); | |
405 | CFReleaseNull(keyid); | |
866f8763 A |
406 | |
407 | if (CFEqualSafe(account.accountKey, newKey)) { | |
ecaf5866 | 408 | secnotice("circleOps", "Got same public key sent our way. Ignoring."); |
866f8763 A |
409 | success = true; |
410 | } else if (CFEqualSafe(account.previousAccountKey, newKey)) { | |
ecaf5866 | 411 | secnotice("circleOps", "Got previous public key repeated. Ignoring."); |
866f8763 A |
412 | success = true; |
413 | } else { | |
414 | SOSAccountSetUnTrustedUserPublicKey(account, newKey); | |
ecaf5866 | 415 | CFReleaseNull(newKey); |
d64be36e | 416 | SOSAccountSetParameters(account, pbkdfParams); |
866f8763 A |
417 | |
418 | if(SOSAccountRetryUserCredentials(account)) { | |
ecaf5866 | 419 | secnotice("circleOps", "Successfully used cached password with new parameters"); |
866f8763 A |
420 | SOSAccountGenerationSignatureUpdate(account, error); |
421 | } else { | |
ecaf5866 | 422 | secnotice("circleOps", "Got new parameters for public key - could not find or use cached password"); |
866f8763 A |
423 | SOSAccountPurgePrivateCredential(account); |
424 | } | |
ecaf5866 | 425 | secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountHandleParametersChange"); |
866f8763 A |
426 | account.circle_rings_retirements_need_attention = true; |
427 | account.key_interests_need_updating = true; | |
428 | ||
429 | success = true; | |
430 | } | |
431 | } | |
432 | ||
433 | CFReleaseNull(newKey); | |
d64be36e | 434 | CFReleaseNull(pbkdfParams); |
866f8763 A |
435 | |
436 | return success; | |
437 | } | |
438 |