]> git.saurik.com Git - apple/security.git/blob - keychain/securityd/SOSCloudCircleServer.m
Security-59306.80.4.tar.gz
[apple/security.git] / keychain / securityd / SOSCloudCircleServer.m
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <AssertMacros.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <CoreFoundation/CFPriv.h>
28
29 #import "keychain/SecureObjectSync/SOSAccountTransaction.h"
30
31 #include "keychain/securityd/SOSCloudCircleServer.h"
32 #include <Security/SecureObjectSync/SOSCloudCircle.h>
33 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
34
35 #include "keychain/SecureObjectSync/SOSCircle.h"
36 #include "keychain/SecureObjectSync/SOSAccount.h"
37 #include "keychain/SecureObjectSync/SOSAccountPriv.h"
38 #include "keychain/SecureObjectSync/SOSAccountGhost.h"
39
40 #include "keychain/SecureObjectSync/SOSTransport.h"
41 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
42 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
43 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
44 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
45 #include "keychain/SecureObjectSync/SOSInternal.h"
46 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
47 #include "keychain/SecureObjectSync/SOSMessage.h"
48 #include "keychain/SecureObjectSync/SOSBackupInformation.h"
49 #include "keychain/SecureObjectSync/SOSDataSource.h"
50 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
51 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
52 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
53 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
54 #import "keychain/SecureObjectSync/SOSAuthKitHelpers.h"
55 #import "keychain/ot/OTManager.h"
56 #import "keychain/SigninMetrics/OctagonSignPosts.h"
57 #import "NSError+UsefulConstructors.h"
58
59 #include <utilities/SecADWrapper.h>
60 #include <utilities/SecCFWrappers.h>
61 #include <utilities/SecCFRelease.h>
62
63 #include <utilities/SecCFError.h>
64 #include <utilities/debugging.h>
65 #include <utilities/SecCoreCrypto.h>
66 #include <utilities/SecTrace.h>
67
68 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
69
70 #include <corecrypto/ccrng.h>
71 #include <corecrypto/ccrng_pbkdf2_prng.h>
72 #include <corecrypto/ccec.h>
73 #include <corecrypto/ccdigest.h>
74 #include <corecrypto/ccsha2.h>
75 #include <CommonCrypto/CommonRandomSPI.h>
76 #include <Security/SecKeyPriv.h>
77 #include <Security/SecFramework.h>
78
79 #include <utilities/SecFileLocations.h>
80 #include <utilities/SecAKSWrappers.h>
81 #include "keychain/securityd/SecItemServer.h"
82 #include <Security/SecItemPriv.h>
83
84 #include <TargetConditionals.h>
85
86 #include <utilities/iCloudKeychainTrace.h>
87 #include <Security/SecAccessControlPriv.h>
88 #include "keychain/securityd/SecDbKeychainItem.h"
89
90 #include <os/activity.h>
91 #include <xpc/private.h>
92
93 #include <os/state_private.h>
94
95 #if TARGET_OS_IPHONE
96 #include <MobileGestalt.h>
97 #else
98 #include <AppleSystemInfo/AppleSystemInfo.h>
99 #endif
100
101 #define SOSCKCSCOPE "sync"
102 #define RUN_AS_ROOT_ERROR 550
103
104 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
105 #import <SystemConfiguration/SystemConfiguration.h>
106
107 #include <notify.h>
108
109 static int64_t getTimeDifference(time_t start);
110 CFStringRef const SOSAggdSyncCompletionKey = CFSTR("com.apple.security.sos.synccompletion");
111 CFStringRef const SOSAggdSyncTimeoutKey = CFSTR("com.apple.security.sos.timeout");
112
113 typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(void);
114
115 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL;
116
117
118
119 //
120 // Forward declared
121 //
122
123 static void do_with_account(void (^action)(SOSAccountTransaction* txn));
124
125 //
126 // Constants
127 //
128
129 CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data");
130
131 CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count");
132
133 CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date");
134
135 static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData)
136 {
137 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
138 kSecClass, kSecClassGenericPassword,
139 kSecAttrService, service,
140 kSecAttrAccessGroup, kSOSInternalAccessGroup,
141 kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse,
142 NULL);
143 }
144
145 CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
146 {
147 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);
148
149 CFDataRef result = NULL;
150
151 OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);
152
153 CFReleaseNull(query);
154
155 if (copyResult != noErr) {
156 SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
157 CFReleaseNull(result);
158 return NULL;
159 }
160
161 if (!isData(result)) {
162 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
163 CFReleaseNull(result);
164 return NULL;
165 }
166
167 return result;
168 }
169
170 static CFDataRef SOSKeychainCopySavedAccountData()
171 {
172 CFErrorRef error = NULL;
173 CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error);
174 if (!accountData) {
175 secnotice("account", "Failed to load account: %@", error);
176 secerror("Failed to load account: %@", error);
177 }
178 CFReleaseNull(error);
179
180 return accountData;
181 }
182
183 bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error)
184 {
185 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false);
186
187 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
188 kSecValueData, data,
189 kSecAttrAccessible, accessibility,
190 NULL);
191 OSStatus saveStatus = SecItemUpdate(query, update);
192
193 if (errSecItemNotFound == saveStatus) {
194 CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
195 CFDictionaryForEach(update, ^(const void *key, const void *value) {
196 CFDictionaryAddValue(add, key, value);
197 });
198 saveStatus = SecItemAdd(add, NULL);
199 CFReleaseNull(add);
200 }
201
202 CFReleaseNull(query);
203 CFReleaseNull(update);
204
205 return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service);
206 }
207
208 static void SOSKeychainAccountEnsureSaved(CFDataRef accountAsData)
209 {
210 static CFDataRef sLastSavedAccountData = NULL;
211
212 CFErrorRef saveError = NULL;
213 require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
214
215 if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, accountAsData, &saveError)) {
216 secerror("Can't save account: %@", saveError);
217 goto exit;
218 }
219
220 CFAssignRetained(sLastSavedAccountData, CFRetainSafe(accountAsData));
221
222 exit:
223 CFReleaseNull(saveError);
224 }
225
226 static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
227 {
228 secdebug("account", "Created account");
229
230 CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
231 SOSAccount* account = NULL;
232
233 SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride()
234 : SecItemDataSourceFactoryGetDefault();
235
236 require_quiet(factory, done);
237
238 if (savedAccount) {
239 NSError* inflationError = NULL;
240
241 account = [SOSAccount accountFromData:(__bridge NSData*) savedAccount
242 factory:factory
243 error:&inflationError];
244
245 if (account){
246 [account.trust updateGestalt:account newGestalt:our_gestalt];
247 } else {
248 secerror("Got error inflating account: %@", inflationError);
249 }
250
251 }
252 CFReleaseNull(savedAccount);
253
254 if (!account) {
255 account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
256
257 if (!account)
258 secerror("Got NULL creating account");
259 }
260
261 [account startStateMachine];
262
263 done:
264 CFReleaseNull(savedAccount);
265 return account;
266 }
267
268 //
269 // Mark: Gestalt Handling
270 //
271
272 CFStringRef SOSGestaltVersion = NULL;
273 CFStringRef SOSGestaltModel = NULL;
274 CFStringRef SOSGestaltDeviceName = NULL;
275
276 void
277 SOSCCSetGestalt_Server(CFStringRef deviceName,
278 CFStringRef version,
279 CFStringRef model,
280 CFStringRef serial)
281 {
282 SOSGestaltDeviceName = CFRetainSafe(deviceName);
283 SOSGestaltVersion = CFRetainSafe(version);
284 SOSGestaltModel = CFRetainSafe(model);
285 SOSGestaltSerial = CFRetainSafe(serial);
286 }
287
288 CFStringRef SOSCCCopyOSVersion(void)
289 {
290 static dispatch_once_t once;
291 dispatch_once(&once, ^{
292 if (SOSGestaltVersion == NULL) {
293 CFDictionaryRef versions = _CFCopySystemVersionDictionary();
294 if (versions) {
295 CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey);
296 if (isString(versionValue))
297 SOSGestaltVersion = CFRetainSafe((CFStringRef) versionValue);
298 }
299
300 CFReleaseNull(versions);
301 if (SOSGestaltVersion == NULL) {
302 SOSGestaltVersion = CFSTR("Unknown model");
303 }
304 }
305 });
306 return CFRetainSafe(SOSGestaltVersion);
307 }
308
309
310 static CFStringRef CopyModelName(void)
311 {
312 static dispatch_once_t once;
313 dispatch_once(&once, ^{
314 if (SOSGestaltModel == NULL) {
315 #if TARGET_OS_IPHONE
316 SOSGestaltModel = MGCopyAnswer(kMGQDeviceName, NULL);
317 #else
318 SOSGestaltModel = ASI_CopyComputerModelName(FALSE);
319 #endif
320 if (SOSGestaltModel == NULL)
321 SOSGestaltModel = CFSTR("Unknown model");
322 }
323 });
324 return CFStringCreateCopy(kCFAllocatorDefault, SOSGestaltModel);
325 }
326
327 static CFStringRef CopyComputerName(SCDynamicStoreRef store)
328 {
329 if (SOSGestaltDeviceName == NULL) {
330 CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL);
331 if (deviceName == NULL) {
332 deviceName = CFSTR("Unknown name");
333 }
334 return deviceName;
335 }
336 return SOSGestaltDeviceName;
337 }
338
339 static bool _EngineMessageProtocolV2Enabled(void)
340 {
341 #if DEBUG
342 //sudo rhr
343 static dispatch_once_t onceToken;
344 static bool v2_enabled = false;
345 dispatch_once(&onceToken, ^{
346 CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
347
348 if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) {
349 v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref);
350 secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled");
351 }
352 CFReleaseSafe(v2Pref);
353 });
354
355 return v2_enabled;
356 #else
357 return false;
358 #endif
359 }
360
361
362 static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context)
363 {
364 CFStringRef modelName = CopyModelName();
365 CFStringRef computerName = CopyComputerName(store);
366 CFStringRef osVersion = SOSCCCopyOSVersion();
367
368 SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0;
369 CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version);
370
371 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
372 kPIUserDefinedDeviceNameKey, computerName,
373 kPIDeviceModelNameKey, modelName,
374 kPIMessageProtocolVersionKey, protocolVersion,
375 kPIOSVersionKey, osVersion,
376 NULL);
377 CFReleaseSafe(osVersion);
378 CFReleaseSafe(modelName);
379 CFReleaseSafe(computerName);
380 CFReleaseSafe(protocolVersion);
381
382 return gestalt;
383 }
384
385 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context)
386 {
387 do_with_account(^(SOSAccountTransaction* txn) {
388 if(txn.account){
389 CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context);
390 if ([txn.account.trust updateGestalt:txn.account newGestalt:gestalt]) {
391 secnotice("circleOps", "Changed our peer's gestalt information. This is not a circle change.");
392 }
393 CFReleaseSafe(gestalt);
394 }
395 });
396 }
397
398
399 static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info)
400 {
401 SCDynamicStoreContext context = { .info = info };
402 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context);
403 CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL);
404 CFArrayRef keys = NULL;
405 CFDictionaryRef gestalt = NULL;
406
407 if (store == NULL || computerKey == NULL) {
408 goto done;
409 }
410 keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks);
411 if (keys == NULL) {
412 goto done;
413 }
414 gestalt = CreateDeviceGestaltDictionary(store, keys, info);
415 SCDynamicStoreSetNotificationKeys(store, keys, NULL);
416 SCDynamicStoreSetDispatchQueue(store, queue);
417
418 done:
419 if (store) CFRelease(store);
420 if (computerKey) CFRelease(computerKey);
421 if (keys) CFRelease(keys);
422 return gestalt;
423 }
424
425 os_state_block_t accountStateBlock = ^os_state_data_t(os_state_hints_t hints) {
426 os_state_data_t retval = NULL;
427 CFDataRef savedAccount = NULL;
428 if(hints->osh_api != OS_STATE_API_REQUEST) return NULL;
429
430 /* Get account DER */
431 savedAccount = SOSKeychainCopySavedAccountData();
432 require_quiet(savedAccount, errOut);
433
434 /* make a os_state_data_t object to return. */
435 size_t statelen = CFDataGetLength(savedAccount);
436 retval = (os_state_data_t)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen));
437 require_quiet(retval, errOut);
438
439 retval->osd_type = OS_STATE_DATA_PROTOCOL_BUFFER;
440 memcpy(retval->osd_data, CFDataGetBytePtr(savedAccount), statelen);
441 retval->osd_size = statelen;
442 strlcpy(retval->osd_title, "CloudCircle Account Object", sizeof(retval->osd_title));
443
444 errOut:
445 CFReleaseNull(savedAccount);
446 return retval;
447 };
448
449 #define FOR_EXISTING_ACCOUNT 1
450 #define CREATE_ACCOUNT_IF_NONE 0
451
452 static SOSAccount* GetSharedAccount(bool onlyIfItExists) {
453 static SOSAccount* sSharedAccount = NULL;
454 static dispatch_once_t onceToken;
455
456 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
457 if(geteuid() == 0){
458 secerror("Cannot inflate account object as root");
459 return NULL;
460 }
461 #endif
462
463 if(onlyIfItExists) {
464 return sSharedAccount;
465 }
466
467 dispatch_once(&onceToken, ^{
468 secdebug("account", "Account Creation start");
469
470 CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
471
472 if (!gestalt) {
473 #if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR
474 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
475 #else
476 secerror("Didn't get machine gestalt! This is going to be ugly.");
477 #endif
478 }
479
480 sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
481
482 SOSAccountAddChangeBlock(sSharedAccount, ^(SOSAccount *account, SOSCircleRef circle,
483 CFSetRef peer_additions, CFSetRef peer_removals,
484 CFSetRef applicant_additions, CFSetRef applicant_removals) {
485 CFErrorRef pi_error = NULL;
486 SOSPeerInfoRef me = account.peerInfo;
487 if(!me) {
488 secinfo("circleOps", "Change block called with no peerInfo");
489 return;
490 }
491
492 if(!SOSCircleHasPeer(circle, me, NULL)) {
493 secinfo("circleOps", "Change block called while not in circle");
494 return;
495 }
496
497 // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
498 if (CFSetGetCount(peer_additions) != 0) {
499 secnotice("updates", "Requesting Ensure Peer Registration.");
500 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
501 } else {
502 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
503 }
504
505 if (CFSetContainsValue(peer_additions, me)) {
506 // TODO: Potentially remove from here and move this to the engine
507 // TODO: We also need to do this when our views change.
508 CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault);
509 CFSetRemoveValue(peers, me);
510 if (!CFSetIsEmpty(peers)) {
511 SOSCCRequestSyncWithPeers(peers);
512 }
513 CFReleaseNull(peers);
514 }
515
516 CFReleaseNull(pi_error);
517
518 if (CFSetGetCount(peer_additions) != 0 ||
519 CFSetGetCount(peer_removals) != 0 ||
520 CFSetGetCount(applicant_additions) != 0 ||
521 CFSetGetCount(applicant_removals) != 0) {
522
523 if(CFSetGetCount(peer_removals) != 0)
524 {
525 CFErrorRef localError = NULL;
526 CFMutableArrayRef removed = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
527 CFSetForEach(peer_removals, ^(const void *value) {
528 CFArrayAppendValue(removed, value);
529 });
530 SOSAccountRemoveBackupPeers(account, removed, &localError);
531 if(localError)
532 secerror("Had trouble removing: %@, error: %@", removed, localError);
533 CFReleaseNull(localError);
534 CFReleaseNull(removed);
535 }
536 secnotice("circleOps", "peer counts changed, posting kSOSCCCircleChangedNotification");
537 account.notifyCircleChangeOnExit = true;
538 }
539 });
540
541 SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) {
542 CFRetainSafe(changes);
543 __block CFMutableArrayRef handledKeys = NULL;
544 do_with_account(^(SOSAccountTransaction* txn) {
545 CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false);
546 secdebug(SOSCKCSCOPE, "Received: %@", changeDescription);
547 CFReleaseSafe(changeDescription);
548
549 CFErrorRef error = NULL;
550 handledKeys = SOSTransportDispatchMessages(txn, changes, &error);
551 if (!handledKeys || error) {
552 secerror("Error handling updates: %@", error);
553 }
554 CFReleaseNull(error);
555 });
556 CFReleaseSafe(changes);
557 return handledKeys;
558 });
559 CFReleaseSafe(gestalt);
560
561 sSharedAccount.saveBlock = ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) {
562 if (flattenedAccount) {
563 SOSKeychainAccountEnsureSaved(flattenedAccount);
564 } else {
565 secerror("Failed to transform account into data, error: %@", flattenFailError);
566 }
567 };
568 // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
569 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
570
571 // provide state handler to sysdiagnose and logging
572 os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock);
573
574 [sSharedAccount ghostBustSchedule];
575
576 });
577
578 return sSharedAccount;
579 }
580
581 CFTypeRef GetSharedAccountRef(void)
582 {
583 return (__bridge CFTypeRef)GetSharedAccount(FOR_EXISTING_ACCOUNT);
584 }
585
586 static void do_with_account(void (^action)(SOSAccountTransaction* txn)) {
587 @autoreleasepool {
588 SOSAccount* account = GetSharedAccount(CREATE_ACCOUNT_IF_NONE);
589
590 if(account){
591 [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
592 action(txn);
593 }];
594 }
595 }
596 }
597
598 static bool isValidUser(CFErrorRef* error) {
599 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
600 if(geteuid() == 0){
601 secerror("Cannot inflate account object as root");
602 SOSErrorCreate(kSOSErrorUnsupported, error, NULL, CFSTR("Cannot inflate account object as root"));
603 return false;
604 }
605 #endif
606
607 return true;
608 }
609
610 static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
611 {
612 #if TARGET_OS_SIMULATOR
613 action();
614 return true;
615 #else
616 bool beenUnlocked = false;
617 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
618
619 require_action_quiet(beenUnlocked, fail,
620 SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
621 CFSTR("Keybag never unlocked, ask after first unlock")));
622
623 action();
624
625 return true;
626
627 fail:
628 return false;
629 #endif
630 }
631
632 static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error))
633 {
634 __block bool action_result = false;
635
636 return isValidUser(error) && do_if_after_first_unlock(error, ^{
637 do_with_account(^(SOSAccountTransaction* txn) {
638 action_result = action(txn, error);
639 });
640
641 }) && action_result;
642 }
643
644 static bool isAssertionLockAcquireError(CFErrorRef error) {
645 return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain));
646 }
647
648 static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error))
649 {
650 bool result = false;
651
652 CFErrorRef statusError = NULL;
653
654 __block bool action_result = false;
655 __block bool attempted_action = false;
656 __block CFErrorRef localError = NULL;
657
658
659 if(!isValidUser(error)){
660 if (error && !*error && localError) {
661 CFTransferRetained(*error, localError);
662 }
663 CFReleaseNull(localError);
664 CFReleaseNull(statusError);
665
666 return result;
667 }
668
669 result = SecAKSDoWithUserBagLockAssertion(&localError, ^{
670 // SOSAccountGhostBustingOptions need to be retrieved from RAMP while not holding the account queue
671 // yet we only want to request RAMP info if it's "time" to ghostbust.
672
673 #if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX)
674 __block bool ghostbustnow = false;
675 __block SOSAccountGhostBustingOptions gbOptions = 0;
676
677 // Avoid mutual deadlock for just checking date.
678 // Check to see if we're InCircle using the client API - will read cached value if available; otherwise it'll do the round trip and lock appropriately
679 SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(NULL);
680 if(circleStatus == kSOSCCInCircle) {
681 // Only need the account object to check settings
682 SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT);
683 if(tmpAccount.settings) {
684 ghostbustnow = [tmpAccount ghostBustCheckDate];
685 }
686
687 // Get ramp settings from the Cloud
688 if(ghostbustnow) {
689 gbOptions = [SOSAccount ghostBustGetRampSettings];
690 }
691 }
692 #endif
693
694 do_with_account(^(SOSAccountTransaction* txn) {
695 SOSAccount *account = txn.account;
696 if ([account isInCircle:(NULL)] && [SOSAuthKitHelpers accountIsHSA2]) {
697 if(![SOSAuthKitHelpers peerinfoHasMID: account]) {
698 // This is the first good opportunity to update our FullPeerInfo and
699 // push the resulting circle.
700 [SOSAuthKitHelpers updateMIDInPeerInfo: account];
701 }
702 }
703 #if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX)
704 if(ghostbustnow) {
705 [account ghostBustPeriodic:gbOptions complete:^(bool ghostBusted, NSError *error) {
706 secnotice("ghostbust", "GhostBusting: %@", ghostBusted ? CFSTR("true"): CFSTR("false"));
707 }];
708 }
709 #endif
710 attempted_action = true;
711 action_result = action(txn, error);
712 });
713 });
714
715
716
717 // For <rdar://problem/24355048> 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked
718 // If we fail with an error attempting to get an assertion while someone else has one and the system is unlocked, it must be trying to lock.
719 // we assume our caller will hold the lock assertion for us to finsh our job.
720 // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again.
721
722 if(result || !isAssertionLockAcquireError(localError)){
723 if (error && !*error && localError) {
724 CFTransferRetained(*error, localError);
725 }
726 CFReleaseNull(localError);
727 CFReleaseNull(statusError);
728
729 return (result && action_result);
730 }
731 if(attempted_action){
732 if (error && !*error && localError) {
733 CFTransferRetained(*error, localError);
734 }
735 CFReleaseNull(localError);
736 CFReleaseNull(statusError);
737
738 return (result && action_result);
739 }
740
741 bool isUnlocked = false;
742 (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError);
743 if(!isUnlocked){
744 secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError);
745 if (error && !*error && localError) {
746 CFTransferRetained(*error, localError);
747 }
748 CFReleaseNull(localError);
749 CFReleaseNull(statusError);
750
751 return result && action_result;
752 }
753
754 CFReleaseNull(localError);
755
756 secnotice("while-unlocked-hack", "Trying action while unlocked without assertion");
757
758 result = true;
759 do_with_account(^(SOSAccountTransaction* txn) {
760 action_result = action(txn, &localError);
761 });
762
763 secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError);
764
765 if (error && !*error && localError) {
766 CFTransferRetained(*error, localError);
767 }
768 CFReleaseNull(localError);
769 CFReleaseNull(statusError);
770
771 return result && action_result;
772 }
773
774
775
776 CFTypeRef SOSKeychainAccountGetSharedAccount()
777 {
778 __block SOSAccount* result = NULL;
779 result = GetSharedAccount(FOR_EXISTING_ACCOUNT);
780
781 if(!result) {
782 secnotice("secAccount", "Failed request for account object");
783 }
784 return (__bridge CFTypeRef)result;
785 }
786
787 //
788 // Mark: Credential processing
789 //
790
791
792 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
793 __block SOSViewResultCode status = kSOSCCGeneralViewError;
794
795 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
796 bool retval = false;
797
798 switch(action) {
799 case kSOSCCViewQuery:
800 status = [txn.account.trust viewStatus:txn.account name:viewname err:error];
801 retval = true;
802 break;
803 case kSOSCCViewEnable:
804 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
805 retval = true;
806 break;
807
808 case kSOSCCViewDisable:
809 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
810 retval = true;
811 break;
812 default:
813 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
814 retval = false;
815 break;
816 }
817 return retval;
818 });
819 return status;
820 }
821
822 bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) {
823 __block bool status = false;
824 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCViewSet);
825
826 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
827 status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent];
828 return true;
829 });
830 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCViewSet, OctagonSignpostNumber1(SOSSignpostNameSOSCCViewSet), (int)status);
831 return status;
832 }
833
834
835 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
836 return SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, NULL);
837 }
838
839
840 void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){
841 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncTheLastDataToKVS);
842 __block CFErrorRef localError = NULL;
843
844 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
845
846 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
847
848 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
849 if (sync_error) {
850 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
851 localError = sync_error;
852 } else {
853 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
854 }
855
856 dispatch_semaphore_signal(wait_for);
857 });
858
859 if(waitForeverForSynchronization)
860 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
861 else
862 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC));
863
864 wait_for = nil;
865 bool subTaskSuccess = (localError == NULL) ? true : false;
866 OctagonSignpostEnd(signPost, SOSSignpostNameSyncTheLastDataToKVS, OctagonSignpostNumber1(SOSSignpostNameSyncTheLastDataToKVS), (int)subTaskSuccess);
867 }
868
869 #define kWAIT2MINID "EFRESH"
870
871 static bool SyncKVSAndWait(CFErrorRef *error) {
872 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncKVSAndWait);
873
874 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
875
876 __block bool success = false;
877
878 secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
879
880 os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
881 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
882 secnotice("fresh", "EFP returned, callback error: %@", sync_error);
883
884 success = (sync_error == NULL);
885 if (error) {
886 CFRetainAssign(*error, sync_error);
887 }
888
889 dispatch_semaphore_signal(wait_for);
890 });
891
892
893 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
894 secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL);
895 });
896 OctagonSignpostEnd(signPost, SOSSignpostNameSyncKVSAndWait, OctagonSignpostNumber1(SOSSignpostNameSyncKVSAndWait), (int)success);
897
898 return success;
899 }
900
901 static bool Flush(CFErrorRef *error) {
902 __block bool success = false;
903 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameFlush);
904
905 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
906 secnotice("flush", "Starting");
907
908 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
909 success = (sync_error == NULL);
910 if (error) {
911 CFRetainAssign(*error, sync_error);
912 }
913
914 dispatch_semaphore_signal(wait_for);
915 });
916
917 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
918
919 secnotice("flush", "Returned %s", success? "Success": "Failure");
920
921 OctagonSignpostEnd(signPost, SOSSignpostNameFlush, OctagonSignpostNumber1(SOSSignpostNameFlush), (int)success);
922
923 return success;
924 }
925
926 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
927 secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label);
928 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCTryUserCredentials);
929
930 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
931 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
932 SOSAccountAssertDSID(txn.account, dsid);
933 }
934 return true;
935 });
936
937 require_quiet(result, done);
938
939 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
940 require_quiet(Flush(error), done); // And processed it already...before asserting
941
942 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
943 return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
944 });
945
946 require_quiet(result, done);
947 require_quiet(Flush(error), done);
948
949 done:
950 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCTryUserCredentials, OctagonSignpostNumber1(SOSSignpostNameSOSCCTryUserCredentials), (int)result);
951
952 return result;
953 }
954
955 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
956 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
957
958 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID);
959
960 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
961 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
962 SOSAccountAssertDSID(txn.account, dsid);
963 }
964 return true;
965 });
966
967 require_quiet(result, done);
968
969 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
970 require_quiet(Flush(error), done); // And processed it already...before asserting
971
972 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
973 return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
974 });
975
976 require_quiet(result, done);
977 require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
978
979 result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
980 return SOSAccountGenerationSignatureUpdate(txn.account, error);
981 });
982
983 secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@",
984 dsid, user_label, result, error ? *error : NULL);
985 done:
986 OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result);
987 return result;
988 }
989
990 static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) {
991 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
992 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID);
993
994 NSError* localError = nil;
995 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
996
997 SFSignInAnalytics *syncAndWaitEvent = nil;
998 SFSignInAnalytics *flushEvent = nil;
999 SFSignInAnalytics *secondFlushEvent = nil;
1000 SFSignInAnalytics *generationSignatureUpdateEvent = nil;
1001
1002 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1003 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
1004 SOSAccountAssertDSID(txn.account, dsid);
1005 }
1006 return true;
1007 });
1008
1009 require_quiet(result, done);
1010 syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"];
1011 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
1012 [syncAndWaitEvent stopWithAttributes:nil];
1013
1014 flushEvent = [parent newSubTaskForEvent:@"flushEvent"];
1015 require_quiet(Flush(error), done); // And processed it already...before asserting
1016 [flushEvent stopWithAttributes:nil];
1017
1018 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
1019 return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
1020 });
1021
1022 require_quiet(result, done);
1023 secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"];
1024 require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
1025 [secondFlushEvent stopWithAttributes:nil];
1026
1027 generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"];
1028 result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1029 return SOSAccountGenerationSignatureUpdate(txn.account, error);
1030 });
1031 [generationSignatureUpdateEvent stopWithAttributes:nil];
1032
1033
1034 done:
1035 if(syncAndWaitEvent){
1036 [syncAndWaitEvent stopWithAttributes:nil];
1037 }
1038 if(flushEvent){
1039 [flushEvent stopWithAttributes:nil];
1040 }
1041 if(secondFlushEvent){
1042 [secondFlushEvent stopWithAttributes:nil];
1043 }
1044 if(generationSignatureUpdateEvent){
1045 [generationSignatureUpdateEvent stopWithAttributes:nil];
1046 }
1047 secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@",
1048 dsid, user_label, result, error ? *error : NULL);
1049
1050 OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result);
1051
1052 return result;
1053 }
1054
1055 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
1056 {
1057 // TODO: Return error if DSID is NULL to insist our callers provide one?
1058 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
1059 }
1060
1061 bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error)
1062 {
1063 return SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error);
1064 }
1065 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
1066 {
1067 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
1068 }
1069
1070 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
1071 {
1072 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCanAuthenticate);
1073
1074 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1075 // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet.
1076 // <rdar://problem/32732066>
1077 SOSAccountRestartPrivateCredentialTimer(txn.account);
1078 return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL;
1079 });
1080
1081 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
1082 CFIndex code = CFErrorGetCode(*error);
1083 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
1084 CFReleaseNull(*error);
1085 }
1086 }
1087
1088 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCanAuthenticate, OctagonSignpostNumber1(SOSSignpostNameSOSCCCanAuthenticate), (int)result);
1089
1090 return result;
1091 }
1092
1093 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
1094 {
1095 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1096 SOSAccountPurgePrivateCredential(txn.account);
1097 return true;
1098 });
1099 }
1100
1101 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
1102 {
1103 __block SOSCCStatus status;
1104
1105 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1106 status = [txn.account getCircleStatus:block_error];
1107
1108 return true;
1109 }) ? status : kSOSCCError;
1110 }
1111
1112 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
1113 {
1114 __block bool result = true;
1115 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle);
1116
1117 bool joined = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1118 result = SOSAccountJoinCircles(txn, block_error);
1119 return result;
1120 });
1121
1122 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)joined);
1123 return joined;
1124 }
1125
1126 bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1127 {
1128 __block bool result = true;
1129 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle);
1130
1131 bool requested = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1132 result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error);
1133 return result;
1134 });
1135 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)requested);
1136 return requested;
1137 }
1138
1139 bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error)
1140 {
1141 __block bool result = true;
1142 __block CFErrorRef localError = NULL;
1143
1144 bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1145 result = SOSAccountHasPublicKey(txn.account, &localError);
1146 return result;
1147 });
1148
1149 if(error != NULL && localError != NULL)
1150 *error = localError;
1151
1152 return hasPublicKey;
1153 }
1154
1155 bool SOSCCAccountIsNew_Server(CFErrorRef *error)
1156 {
1157 __block bool result = true;
1158 __block CFErrorRef localError = NULL;
1159
1160 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1161 result = SOSAccountIsNew(txn.account, &localError);
1162 return result;
1163 });
1164
1165 if(error != NULL && localError != NULL)
1166 *error = localError;
1167
1168 return result;
1169 }
1170 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
1171 {
1172 __block bool result = true;
1173 bool returned = false;
1174 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore);
1175 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1176 SOSAccountEnsurePeerRegistration(txn.account, block_error);
1177 result = SOSAccountJoinCirclesAfterRestore(txn, block_error);
1178 return result;
1179 });
1180 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result);
1181 return returned;
1182
1183 }
1184
1185 bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1186 {
1187 __block bool result = true;
1188 bool returned = false;
1189 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore);
1190 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1191 NSError* localError = nil;
1192 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1193
1194 SFSignInAnalytics *ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"];
1195 SOSAccountEnsurePeerRegistration(txn.account, block_error);
1196 if(block_error && *block_error){
1197 NSError* blockError = (__bridge NSError*)*block_error;
1198 if(blockError){
1199 [ensurePeerRegistrationEvent logRecoverableError:blockError];
1200 secerror("ensure peer registration error: %@", blockError);
1201 }
1202 }
1203 [ensurePeerRegistrationEvent stopWithAttributes:nil];
1204 result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error);
1205 return result;
1206 });
1207 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result);
1208 return returned;
1209
1210 }
1211
1212 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
1213 {
1214 bool returned = false;
1215 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1216 return SyncKVSAndWait(block_error);
1217 });
1218 if (returned) {
1219 returned = Flush(error);
1220 }
1221 return returned;
1222 }
1223
1224 bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){
1225 __block bool result = true;
1226 bool returned = false;
1227 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1228 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1229 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1230
1231 if(fpi && ring) {
1232 result = SOSRingApply(ring, txn.account.accountKey, fpi , error);
1233 }
1234 CFReleaseNull(ring);
1235 return result;
1236 });
1237 return returned;
1238 }
1239
1240 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){
1241 __block bool result = true;
1242 bool returned = false;
1243 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1244 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1245 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1246 if(fpi && ring) {
1247 result = SOSRingWithdraw(ring, txn.account.accountKey, fpi , error);
1248 }
1249 CFReleaseNull(ring);
1250 return result;
1251 });
1252 return returned;
1253 }
1254
1255 bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){
1256 __block bool result = true;
1257 bool returned = false;
1258 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1259 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1260 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1261 if(fpi && ring) {
1262 result = SOSRingResetToOffering(ring, NULL, fpi, error);
1263 }
1264 CFReleaseNull(ring);
1265 return result;
1266 });
1267 return returned;
1268 }
1269
1270 CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){
1271 __block CFMutableDictionaryRef result = NULL;
1272 __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
1273
1274 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1275 SOSAccountForEachRing(txn.account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) {
1276 CFStringAppendFormat(description, NULL, CFSTR("%@\n"), ring);
1277 return NULL;
1278 });
1279 if(result)
1280 return true;
1281 return false;
1282 });
1283
1284 return description;
1285 }
1286
1287 SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){
1288 __block bool result = true;
1289 SOSRingStatus returned;
1290 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1291 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1292 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
1293
1294 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1295 if(myPeer && ring) {
1296 result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer));
1297 }
1298 CFReleaseNull(ring);
1299
1300 return result;
1301 });
1302 return returned;
1303 }
1304
1305 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1306 {
1307 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1308 SOSAccountSetToNew(txn.account);
1309 return true;
1310 });
1311 }
1312
1313 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1314 {
1315 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToOffering);
1316
1317 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1318 bool result = false;
1319
1320 SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error);
1321 if (!user_key) {
1322 return result;
1323 }
1324 result = [txn.account.trust resetToOffering:txn key:user_key err:block_error];
1325 return result;
1326 });
1327 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToOffering, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToOffering), (int)resetResult);
1328 return resetResult;
1329 }
1330
1331 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1332 {
1333 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty);
1334
1335 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1336 bool result = false;
1337
1338 if (!SOSAccountHasPublicKey(txn.account, error)) {
1339 return result;
1340 }
1341 result = [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error];
1342 return result;
1343 });
1344 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult);
1345 return resetResult;
1346 }
1347
1348 bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1349 {
1350 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty);
1351
1352 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1353 bool result = false;
1354
1355 if (!SOSAccountHasPublicKey(txn.account, error)) {
1356 return result;
1357 }
1358 result = [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error];
1359 return result;
1360 });
1361 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult);
1362 return resetResult;
1363 }
1364
1365 bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1366 {
1367 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
1368
1369 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1370 bool result = [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error];
1371 return result;
1372 });
1373 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult);
1374
1375 return removeResult;
1376 }
1377
1378 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1379 {
1380 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
1381
1382 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1383 bool result = [txn.account.trust leaveCircle:txn.account err:block_error];
1384 return result;
1385 });
1386 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult);
1387 return removeResult;
1388 }
1389
1390 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1391 {
1392 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
1393
1394 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1395 bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, block_error);
1396 return result;
1397 });
1398 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
1399 return removeResult;
1400 }
1401
1402 bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error)
1403 {
1404 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
1405
1406 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1407 bool result = SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error);
1408 return result;
1409 });
1410 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
1411 return removeResult;
1412 }
1413
1414 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1415 {
1416 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCLoggedOutOfAccount);
1417
1418 bool loggedOutResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1419 secnotice("circleOps", "Signed out of account!");
1420
1421
1422 bool waitForeverForSynchronization = true;
1423
1424 bool result = [txn.account.trust leaveCircle:txn.account err:block_error];
1425
1426 [txn restart]; // Make sure this gets finished before we set to new.
1427
1428 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1429
1430 SOSAccountSetToNew(txn.account);
1431
1432
1433 return result;
1434 });
1435 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCLoggedOutOfAccount, OctagonSignpostNumber1(SOSSignpostNameSOSCCLoggedOutOfAccount), (int)loggedOutResult);
1436 return loggedOutResult;
1437 }
1438
1439 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1440 {
1441 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1442 bool waitForeverForSynchronization = false;
1443
1444 bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error);
1445
1446 [txn restart]; // Make sure this gets finished before we set to new.
1447
1448 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1449
1450 return result;
1451 });
1452
1453 }
1454
1455 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1456 {
1457 __block CFArrayRef result = NULL;
1458
1459 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplicantPeerInfo);
1460
1461 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1462 result = SOSAccountCopyApplicants(txn.account, block_error);
1463 return result != NULL;
1464 });
1465
1466 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplicantPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplicantPeerInfo), (int)(result != NULL));
1467
1468 return result;
1469 }
1470
1471 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1472 {
1473 __block CFArrayRef result = NULL;
1474
1475 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1476 result = SOSAccountCopyGeneration(txn.account, block_error);
1477 return result != NULL;
1478 });
1479
1480 return result;
1481 }
1482
1483 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1484 {
1485 __block CFArrayRef result = NULL;
1486 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyValidPeerPeerInfo);
1487
1488 @autoreleasepool {
1489
1490 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1491 @autoreleasepool {
1492 result = SOSAccountCopyValidPeers(txn.account, block_error);
1493 }
1494 return result != NULL;
1495 });
1496 }
1497 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyValidPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyValidPeerPeerInfo), (int)(result != NULL));
1498
1499 return result;
1500 }
1501
1502 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1503 {
1504 __block bool result = NULL;
1505 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCValidateUserPublic);
1506
1507 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1508 result = SOSValidateUserPublic(txn.account, block_error);
1509 return result;
1510 });
1511 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCValidateUserPublic, OctagonSignpostNumber1(SOSSignpostNameSOSCCValidateUserPublic), (int)result);
1512
1513 return result;
1514 }
1515
1516 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1517 {
1518 __block CFArrayRef result = NULL;
1519
1520 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1521 result = SOSAccountCopyNotValidPeers(txn.account, block_error);
1522 return result != NULL;
1523 });
1524
1525 return result;
1526 }
1527
1528 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1529 {
1530 __block CFArrayRef result = NULL;
1531
1532 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1533 result = SOSAccountCopyRetired(txn.account, block_error);
1534 return result != NULL;
1535 });
1536
1537 return result;
1538 }
1539
1540 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1541 {
1542 __block CFArrayRef result = NULL;
1543 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo);
1544
1545 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1546 result = SOSAccountCopyViewUnaware(txn.account, block_error);
1547 return result != NULL;
1548 });
1549 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyViewUnawarePeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo), (int)(result != NULL));
1550
1551 return result;
1552 }
1553
1554 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1555 {
1556 CFArrayRef result = NULL;
1557 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1558 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1559 if (ds) {
1560 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1561 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1562 SOSDataSourceRelease(ds, error);
1563 }
1564
1565 return result;
1566 }
1567
1568 static int64_t getTimeDifference(time_t start)
1569 {
1570 time_t stop;
1571 int64_t duration;
1572
1573 stop = time(NULL);
1574
1575 duration = stop - start;
1576
1577 return SecBucket1Significant(duration);
1578 }
1579
1580 static uint64_t initialSyncTimeoutFromDefaultsWrite(void)
1581 {
1582 uint64_t timeout = 10;
1583
1584 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
1585 CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
1586
1587 if (isNumber(initialSyncTimeout)) {
1588 CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout);
1589 }
1590 CFReleaseNull(initialSyncTimeout);
1591 return timeout;
1592 }
1593
1594 bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) {
1595 __block dispatch_semaphore_t inSyncSema = NULL;
1596 __block bool result = false;
1597 __block bool synced = false;
1598 bool timed_out = false;
1599 __block CFStringRef inSyncCallID = NULL;
1600 __block time_t start;
1601 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1602 SFSignInAnalytics* syncingEvent = nil;
1603 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync);
1604
1605 NSError* localError = nil;
1606 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1607
1608 secnotice("initial sync", "Wait for initial sync start!");
1609
1610 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1611 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1612 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1613
1614 if (!alreadyInSync) {
1615 start = time(NULL);
1616 inSyncSema = dispatch_semaphore_create(0);
1617
1618 SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"];
1619 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1620 synced = true;
1621
1622 if(inSyncSema){
1623 dispatch_semaphore_signal(inSyncSema);
1624 NSDictionary* attributes = @{@"finishedSyncing" : @YES};
1625 [syncingEvent stopWithAttributes:attributes];
1626 }
1627 return true;
1628 });
1629 NSDictionary* attributes = @{};
1630 [callWhenInSyncEvent stopWithAttributes:attributes];
1631 }
1632 else{
1633 synced = true;
1634 }
1635 return true;
1636 });
1637
1638 require_quiet(result, fail);
1639
1640
1641 if(inSyncSema){
1642 syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"];
1643 if(shouldUseInitialSyncV0){
1644 secnotice("piggy","setting initial sync timeout to 5 minutes");
1645 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1646 }
1647 else{
1648 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1649 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1650 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1651 }
1652 }
1653 if (timed_out && shouldUseInitialSyncV0) {
1654 do_with_account(^(SOSAccountTransaction* txn) {
1655 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1656 if(inSyncSema){
1657 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1658 }
1659 }
1660 });
1661 NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}];
1662 [syncingEvent logUnrecoverableError:error];
1663 NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES};
1664 [syncingEvent stopWithAttributes:attributes];
1665 }
1666
1667 require_quiet(result, fail);
1668
1669 if(result)
1670 {
1671 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1672 }
1673 else if(!result)
1674 {
1675 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1676 }
1677
1678 secnotice("initial sync", "Finished!: %d", result);
1679
1680 fail:
1681 CFReleaseNull(inSyncCallID);
1682 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result);
1683
1684 return result;
1685 }
1686
1687 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1688
1689 __block dispatch_semaphore_t inSyncSema = NULL;
1690 __block bool result = false;
1691 __block bool synced = false;
1692 bool timed_out = false;
1693 __block CFStringRef inSyncCallID = NULL;
1694 __block time_t start;
1695 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1696 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync);
1697
1698 secnotice("initial sync", "Wait for initial sync start!");
1699
1700 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1701 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1702 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1703
1704 if (!alreadyInSync) {
1705 start = time(NULL);
1706 inSyncSema = dispatch_semaphore_create(0);
1707
1708 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1709 synced = true;
1710
1711 if(inSyncSema){
1712 dispatch_semaphore_signal(inSyncSema);
1713
1714 }
1715 return true;
1716 });
1717 }
1718 else{
1719 synced = true;
1720 }
1721 return true;
1722 });
1723
1724 require_quiet(result, fail);
1725
1726 if(inSyncSema){
1727 if(shouldUseInitialSyncV0){
1728 secnotice("piggy","setting initial sync timeout to 5 minutes");
1729 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1730 }
1731 else{
1732 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1733 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1734 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1735 }
1736 }
1737 if (timed_out && shouldUseInitialSyncV0) {
1738 do_with_account(^(SOSAccountTransaction* txn) {
1739 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1740 if(inSyncSema){
1741 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1742 }
1743 }
1744 });
1745 }
1746
1747 require_quiet(result, fail);
1748
1749 if(result)
1750 {
1751 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1752 }
1753 else if(!result)
1754 {
1755 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1756 }
1757
1758 secnotice("initial sync", "Finished!: %d", result);
1759
1760 fail:
1761 CFReleaseNull(inSyncCallID);
1762 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result);
1763
1764 return result;
1765 }
1766
1767
1768 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccount* account, CFErrorRef *error) {
1769 __block CFArrayRef result = NULL;
1770
1771 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1772 if (valueFetched == kCFBooleanTrue) {
1773 SOSPeerInfoRef myPI = account.peerInfo;
1774 if (myPI) {
1775 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1776 result = CFSetCopyValues(enabled);
1777 });
1778 }
1779 } else if (isSet(valueFetched)) {
1780 result = CFSetCopyValues((CFSetRef)valueFetched);
1781 }
1782
1783 if (result == NULL) {
1784 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1785 }
1786
1787 return result;
1788 }
1789
1790 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1791
1792 __block CFArrayRef views = NULL;
1793
1794 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1795 views = SOSAccountCopyYetToSyncViews(txn.account, error);
1796
1797 return true;
1798 });
1799
1800 return views;
1801 }
1802
1803 bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error) {
1804 CFErrorRef localerror = NULL;
1805 SOSBackupSliceKeyBagRef bskb = SOSBackupSliceKeyBagForView(viewName, &localerror);
1806
1807 if(bskbEncoded && bskb) {
1808 *bskbEncoded = SOSBSKBCopyEncoded(bskb, &localerror);
1809 }
1810
1811 if(output) {
1812 *output = SOSWrapToBackupSliceKeyBag(bskb, input, &localerror);
1813 }
1814
1815 if(error) {
1816 *error = localerror;
1817 }
1818 return localerror == NULL;
1819 }
1820
1821 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){
1822 __block SOSBackupSliceKeyBagRef bskb = NULL;
1823 (void) do_with_account(^ (SOSAccountTransaction* txn) {
1824 bskb = SOSAccountBackupSliceKeyBagForView(txn.account, viewName, error);
1825 });
1826 return bskb;
1827 }
1828
1829 CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error) {
1830 CFDataRef encrypted = NULL;
1831 bskb_keybag_handle_t bskb_handle = 0;
1832
1833 require_quiet(bskb, exit);
1834
1835 bskb_handle = SOSBSKBLoadLocked(bskb, error);
1836 require_quiet(bskb_handle, exit);
1837
1838 SecAccessControlRef access = NULL;
1839 require_quiet(access = SecAccessControlCreate(kCFAllocatorDefault, error), exit);
1840 require_quiet(SecAccessControlSetProtection(access, kSecAttrAccessibleWhenUnlocked, error), exit);
1841
1842 // ks_encrypt_data takes a dictionary as its plaintext.
1843 CFMutableDictionaryRef plaintext = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1844 CFDictionarySetValue(plaintext, CFSTR("data"), input);
1845
1846 require_quiet(ks_encrypt_data_legacy(bskb_handle, access, NULL, plaintext, NULL, &encrypted, false, error), exit);
1847
1848 exit:
1849 CFReleaseNull(bskb);
1850 if(bskb_handle != 0) {
1851 ks_close_keybag(bskb_handle, error);
1852 }
1853 if(error && *error) {
1854 secnotice("backup", "Failed to wrap to a BKSB: %@", *error);
1855 }
1856 return encrypted;
1857
1858 }
1859
1860 CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){
1861
1862 __block CFDictionaryRef result = NULL;
1863
1864 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1865 CFErrorRef localError = NULL;
1866 SOSCCStatus status = [txn.account getCircleStatus:&localError];
1867
1868 CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error);
1869 CFDictionaryRef escrowRecords = NULL;
1870 CFDictionaryRef record = NULL;
1871 switch(status) {
1872 case kSOSCCInCircle:
1873 //get the escrow record in the peer info!
1874 escrowRecords = SOSPeerInfoCopyEscrowRecord(txn.account.peerInfo);
1875 if(escrowRecords){
1876 record = CFDictionaryGetValue(escrowRecords, dsid);
1877 if(record)
1878 result = CFRetainSafe(record);
1879 }
1880 CFReleaseNull(escrowRecords);
1881 break;
1882 case kSOSCCRequestPending:
1883 //set the escrow record in the peer info/application?
1884 break;
1885 case kSOSCCNotInCircle:
1886 case kSOSCCCircleAbsent:
1887 //set the escrow record in the account expansion!
1888 escrowRecords = SOSAccountGetValue(txn.account, kSOSEscrowRecord, error);
1889 if(escrowRecords){
1890 record = CFDictionaryGetValue(escrowRecords, dsid);
1891 if(record)
1892 result = CFRetainSafe(record);
1893 }
1894 break;
1895 default:
1896 secdebug("account", "no circle status!");
1897 break;
1898 }
1899 return true;
1900 });
1901
1902 return result;
1903 }
1904
1905 CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error) {
1906 __block CFDictionaryRef result = NULL;
1907
1908 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1909 result = SOSBackupInformation(txn, error);
1910 return true;
1911 });
1912 return result;
1913 }
1914
1915 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){
1916
1917 if (escrow_label == NULL) {
1918 return false;
1919 }
1920
1921 __block bool result = true;
1922 __block CFErrorRef block_error = NULL;
1923
1924 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1925 SOSCCStatus status = [txn.account getCircleStatus:&block_error];
1926
1927 CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error);
1928
1929 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
1930 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
1931
1932 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
1933 CFStringAppend(timeDescription, decription);
1934 });
1935 CFStringAppend(timeDescription, CFSTR("]"));
1936
1937 CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries);
1938
1939 CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1940 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts);
1941 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription);
1942
1943 CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1944 CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries);
1945
1946 switch(status) {
1947 case kSOSCCInCircle:
1948 //set the escrow record in the peer info!
1949 if(!SOSFullPeerInfoAddEscrowRecord(txn.account.fullPeerInfo, dsid, escrowRecord, error)){
1950 secdebug("accout", "Could not set escrow record in the full peer info");
1951 result = false;
1952 }
1953 break;
1954 case kSOSCCRequestPending:
1955 //set the escrow record in the peer info/application?
1956 break;
1957 case kSOSCCNotInCircle:
1958 case kSOSCCCircleAbsent:
1959 //set the escrow record in the account expansion!
1960
1961 if(!SOSAccountAddEscrowRecords(txn.account, dsid, escrowRecord, error)) {
1962 secdebug("account", "Could not set escrow record in expansion data");
1963 result = false;
1964 }
1965 break;
1966 default:
1967 secdebug("account", "no circle status!");
1968 break;
1969 }
1970 CFReleaseNull(attempts);
1971 CFReleaseNull(timeDescription);
1972 CFReleaseNull(escrowTimeAndTries);
1973 CFReleaseNull(escrowRecord);
1974
1975 return true;
1976 });
1977
1978 return result;
1979 }
1980
1981 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1982 {
1983 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants);
1984
1985 bool acceptResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1986 bool result = SOSAccountAcceptApplicants(txn.account, applicants, block_error);
1987 return result;
1988 });
1989 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)acceptResult);
1990 return acceptResult;
1991 }
1992
1993 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1994 {
1995 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants);
1996
1997 bool rejectResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1998 bool result = SOSAccountRejectApplicants(txn.account, applicants, block_error);
1999 return result;
2000 });
2001 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)rejectResult);
2002 return rejectResult;
2003 }
2004
2005 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
2006 {
2007 __block CFArrayRef result = NULL;
2008
2009 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2010 result = SOSAccountCopyPeers(txn.account, block_error);
2011 return result != NULL;
2012 });
2013
2014 return result;
2015 }
2016
2017 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
2018 {
2019 __block CFArrayRef result = NULL;
2020 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo);
2021
2022 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2023 result = SOSAccountCopyConcurringPeers(txn.account, block_error);
2024 return result != NULL;
2025 });
2026 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo), (int)(result != NULL));
2027
2028 return result;
2029 }
2030
2031 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
2032 {
2033 __block SOSPeerInfoRef result = NULL;
2034 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyMyPeerInfo);
2035
2036 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2037 // Create a copy to be DERed/sent back to client
2038 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
2039 return result != NULL;
2040 });
2041 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyMyPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyMyPeerInfo), (int)(result != NULL));
2042
2043 return result;
2044 }
2045
2046 CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error)
2047 {
2048 __block CFDataRef accountState = NULL;
2049
2050 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2051 // Copy account state from the keychain
2052 accountState = SOSAccountCopyAccountStateFromKeychain(block_error);
2053 return accountState != NULL;
2054 });
2055
2056 return accountState;
2057 }
2058
2059 bool SOSCCDeleteAccountState_Server(CFErrorRef* error)
2060 {
2061 __block bool result = NULL;
2062
2063 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2064 // Delete account state from the keychain
2065 result = SOSAccountDeleteAccountStateFromKeychain(block_error);
2066 return result;
2067 });
2068
2069 return result;
2070 }
2071
2072 CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error)
2073 {
2074 __block CFDataRef engineState = NULL;
2075
2076 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2077 // Copy engine state from the keychain
2078 engineState = SOSAccountCopyEngineStateFromKeychain(block_error);
2079 return engineState != NULL;
2080 });
2081
2082 return engineState;
2083 }
2084
2085 bool SOSCCDeleteEngineState_Server(CFErrorRef* error)
2086 {
2087 __block bool result = NULL;
2088
2089 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2090 // Delete engine state from the keychain
2091 result = SOSAccountDeleteEngineStateFromKeychain(block_error);
2092 return result;
2093 });
2094
2095 return result;
2096 }
2097
2098
2099
2100 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
2101 __block SOSPeerInfoRef result = NULL;
2102 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSetNewPublicBackupKey);
2103
2104 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock");
2105 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2106 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquired account lock");
2107 if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){
2108 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set in account");
2109 [txn restart]; // Finish the transaction to update any changes to the peer info.
2110
2111 // Create a copy to be DERed/sent back to client
2112 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
2113 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set and pushed");
2114 }
2115 else
2116 {
2117 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
2118 }
2119 return result != NULL;
2120 });
2121
2122 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSetNewPublicBackupKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCSetNewPublicBackupKey), (int)(result != NULL));
2123 return result;
2124 }
2125
2126 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
2127 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterSingleRecoverySecret);
2128
2129 bool registerResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2130 bool result = SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error);
2131 return result;
2132 });
2133 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterSingleRecoverySecret, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterSingleRecoverySecret), (int)registerResult);
2134 return registerResult;
2135 }
2136
2137 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
2138 {
2139 __block CFStringRef result = NULL;
2140
2141 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2142 result = SOSAccountCopyIncompatibilityInfo(txn.account, block_error);
2143 return result != NULL;
2144 });
2145
2146 return result;
2147 }
2148
2149 bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error) {
2150 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2151 return SOSAccountIsLastBackupPeer(txn.account, block_error);
2152 });
2153 return result;
2154 }
2155
2156 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
2157 {
2158 __block enum DepartureReason result = kSOSDepartureReasonError;
2159
2160 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2161 result = SOSAccountGetLastDepartureReason(txn.account, block_error);
2162 return result != kSOSDepartureReasonError;
2163 });
2164
2165 return result;
2166 }
2167
2168 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
2169 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2170 SOSAccountSetLastDepartureReason(txn.account, reason);
2171 return true;
2172 });
2173 }
2174
2175 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
2176 {
2177 secnotice("updates", "Request for registering peers");
2178 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessEnsurePeerRegistration);
2179
2180 bool processResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2181 bool result = SOSAccountEnsurePeerRegistration(txn.account, error);
2182 return result;
2183 });
2184 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessEnsurePeerRegistration), (int)processResult);
2185 return processResult;
2186 }
2187
2188 CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) {
2189 __block CFSetRef result = NULL;
2190 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithPeers);
2191
2192 if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2193 result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error);
2194 return result != NULL;
2195 })) {
2196 // Be sure we don't return a result if we got an error
2197 CFReleaseNull(result);
2198 }
2199 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithPeers), (int)(result != NULL));
2200
2201 return result;
2202 }
2203
2204 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
2205 {
2206 /*
2207 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
2208 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
2209 */
2210 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
2211 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithAllPeers);
2212
2213 CFErrorRef action_error = NULL;
2214
2215 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2216 return SOSAccountRequestSyncWithAllPeers(txn, block_error);
2217 })) {
2218 if (action_error) {
2219 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
2220 secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know");
2221 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
2222 CFReleaseNull(action_error);
2223 } else {
2224 secerror("Unexpected error: %@", action_error);
2225 }
2226 }
2227
2228 SecErrorPropagate(action_error, error);
2229 }
2230
2231 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithAllPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithAllPeers), (int)result);
2232
2233 return result;
2234 }
2235
2236 //
2237 // Sync requesting
2238 //
2239
2240 void SOSCCRequestSyncWithPeer(CFStringRef peerID) {
2241 CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL);
2242
2243 SOSCCRequestSyncWithPeersList(peers);
2244
2245 CFReleaseNull(peers);
2246 }
2247
2248 void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) {
2249 CFMutableArrayRef peerIDArray = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
2250
2251 CFSetForEach(peerIDs, ^(const void *value) {
2252 if (isString(value)) {
2253 CFArrayAppendValue(peerIDArray, value);
2254 } else if (isSOSPeerInfo(value)) {
2255 SOSPeerInfoRef peer = asSOSPeerInfo(value);
2256 CFArrayAppendValue(peerIDArray, SOSPeerInfoGetPeerID(peer));
2257 } else {
2258 secerror("Bad element, skipping: %@", value);
2259 }
2260 });
2261
2262 SOSCCRequestSyncWithPeersList(peerIDArray);
2263
2264 CFReleaseNull(peerIDArray);
2265 }
2266
2267 void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) {
2268 os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2269 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithPeersList);
2270
2271 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
2272
2273 CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) {
2274 secnotice("syncwith", "Request Sync With: %@", description);
2275 });
2276
2277 SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty,
2278 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2279 CFReleaseNull(empty);
2280 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithPeersList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithPeersList), (int)true);
2281 });
2282 }
2283
2284 void SOSCCRequestSyncWithBackupPeerList(CFArrayRef /* CFStringRef */ backupPeerIDs) {
2285 os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeerList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2286 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList);
2287
2288 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
2289
2290 CFStringArrayPerformWithDescription(backupPeerIDs, ^(CFStringRef description) {
2291 secnotice("syncwith", "Request backup sync With: %@", description);
2292 });
2293
2294 SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerIDs,
2295 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2296
2297 CFReleaseNull(empty);
2298 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithBackupPeerList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList), (int)true);
2299
2300 });
2301 }
2302
2303 bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) {
2304 return false;
2305 }
2306
2307 void SOSCCEnsurePeerRegistration(void)
2308 {
2309 os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2310 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCEnsurePeerRegistration);
2311 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2312 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCEnsurePeerRegistration), (int)true);
2313
2314 });
2315 }
2316
2317 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
2318 {
2319 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCHandleUpdateMessage);
2320
2321 CFArrayRef result = NULL;
2322 SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set
2323
2324 result = account ? SOSCloudKeychainHandleUpdateMessage(updates) : CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
2325
2326 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCHandleUpdateMessage, OctagonSignpostNumber1(SOSSignpostNameSOSCCHandleUpdateMessage), (int)(result != NULL));
2327
2328 return result;
2329 }
2330
2331 SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) {
2332 __block SOSPeerInfoRef application = NULL;
2333 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplication);
2334
2335 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2336 application = SOSAccountCopyApplication(txn.account, error);
2337 return application != NULL;
2338 });
2339 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplication, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplication), (int)(application != NULL));
2340
2341 return application;
2342 }
2343
2344 bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) {
2345 bool result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2346 return SOSAccountCleanupAllKVSKeys(txn.account, error);
2347 });
2348 if(result && error && *error) {
2349 CFReleaseNull(*error);
2350 }
2351 return result;
2352 }
2353
2354 bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error)
2355 {
2356 __block bool result = false;
2357 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2358 return SOSAccountPopulateKVSWithBadKeys(txn.account, error);
2359 });
2360 return result;
2361 }
2362 CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) {
2363 __block CFDataRef pbblob = NULL;
2364 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyCircleJoiningBlob);
2365
2366 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2367 pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error);
2368 return pbblob != NULL;
2369 });
2370 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyCircleJoiningBlob), (int)(pbblob != NULL));
2371
2372 return pbblob;
2373 }
2374
2375 CFDataRef SOSCCCopyInitialSyncData_Server(SOSInitialSyncFlags flags, CFErrorRef *error) {
2376 __block CFDataRef pbblob = NULL;
2377 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyInitialSyncData);
2378
2379 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2380 pbblob = SOSAccountCopyInitialSyncData(txn.account, flags, error);
2381 return pbblob != NULL;
2382 });
2383 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyInitialSyncData, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyInitialSyncData), (int)(pbblob != NULL));
2384
2385 return pbblob;
2386 }
2387
2388 bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) {
2389 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob);
2390
2391 bool joinResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2392 bool result = SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error);
2393 return result;
2394 });
2395
2396 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCJoinWithCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob), (int)joinResult);
2397 return joinResult;
2398 }
2399
2400 CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) {
2401 __block CFBooleanRef result = NULL;
2402 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2403 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCPeersHaveViewsEnabled);
2404 result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error);
2405 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCPeersHaveViewsEnabled, OctagonSignpostNumber1(SOSSignpostNameSOSCCPeersHaveViewsEnabled), (int)(result != NULL));
2406 return result != NULL;
2407 });
2408
2409 return result;
2410 }
2411
2412 bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){
2413 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterRecoveryPublicKey);
2414
2415 bool registerResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2416 bool result = false;
2417 if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) {
2418 result = SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error);
2419 }
2420 else {
2421 result = SOSAccountClearRecoveryPublicKey(txn, recovery_key, error);
2422 }
2423 return result;
2424 });
2425 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterRecoveryPublicKey), (int)registerResult);
2426 return registerResult;
2427 }
2428
2429 CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){
2430
2431 __block CFDataRef result = NULL;
2432 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyRecoveryPublicKey);
2433 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2434 result = SOSAccountCopyRecoveryPublicKey(txn, error);
2435 return result != NULL;
2436 });
2437 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyRecoveryPublicKey), (int)(result != NULL));
2438 return result;
2439 }
2440
2441 bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2442 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCMessageFromPeerIsPending);
2443
2444 bool pendingResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2445 bool result = SOSAccountMessageFromPeerIsPending(txn, peer, error);
2446 return result;
2447 });
2448 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCMessageFromPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCMessageFromPeerIsPending), (int)pendingResult);
2449 return pendingResult;
2450 }
2451
2452 bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2453 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSendToPeerIsPending);
2454
2455 bool sendResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2456 bool result = SOSAccountSendToPeerIsPending(txn, peer, error);
2457 return result;
2458 });
2459 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSendToPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCSendToPeerIsPending), (int)sendResult);
2460 return sendResult;
2461 }
2462
2463 void SOSCCResetOTRNegotiation_Server(CFStringRef peerid)
2464 {
2465 CFErrorRef localError = NULL;
2466 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2467 SOSAccountResetOTRNegotiationCoder(txn.account, peerid);
2468 return true;
2469 });
2470 if(localError)
2471 {
2472 secerror("error resetting otr negotation: %@", localError);
2473 }
2474 }
2475
2476 void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup)
2477 {
2478 CFErrorRef localError = NULL;
2479 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2480 SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup);
2481 return true;
2482 });
2483 if(localError)
2484 {
2485 secerror("error sending next message: %@", localError);
2486 }
2487 }
2488
2489 void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivSigningKey, CFErrorRef error))
2490 {
2491 CFErrorRef error = NULL;
2492 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2493 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2494 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err);
2495 CFErrorRef errorArg = err ? *err : NULL;
2496 action(signingKey, errorArg);
2497 CFReleaseNull(signingKey);
2498 return true;
2499 });
2500 CFReleaseNull(error);
2501 }
2502
2503 void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error))
2504 {
2505 CFErrorRef error = NULL;
2506 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2507 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2508 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, err);
2509 CFErrorRef errorArg = err ? *err : NULL;
2510 action(signingKey, errorArg);
2511 CFReleaseNull(signingKey);
2512 return true;
2513 });
2514 CFReleaseNull(error);
2515 }
2516
2517 void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error))
2518 {
2519 CFErrorRef error = NULL;
2520 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2521 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2522 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, err);
2523 CFErrorRef errorArg = err ? *err : NULL;
2524 action(signingKey, errorArg);
2525 CFReleaseNull(signingKey);
2526 return true;
2527 });
2528 CFReleaseNull(error);
2529 }
2530
2531 void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error))
2532 {
2533 CFErrorRef error = NULL;
2534 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2535 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2536 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, err);
2537 CFErrorRef errorArg = err ? *err : NULL;
2538 action(signingKey, errorArg);
2539 CFReleaseNull(signingKey);
2540 return true;
2541 });
2542 CFReleaseNull(error);
2543 }
2544
2545 void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error))
2546 {
2547 CFErrorRef localError = NULL;
2548 do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2549 SecKeyRef encryptionKey = NULL;
2550 SecKeyRef signingKey = NULL;
2551 CFErrorRef errorArg = err ? *err : NULL;
2552
2553 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2554 require_action_quiet(fpi, fail, secerror("device does not have a peer"); SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, &errorArg));
2555
2556 signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, &errorArg);
2557 require_action_quiet(signingKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys signing key error: %@", errorArg));
2558 CFReleaseNull(errorArg);
2559
2560 encryptionKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, &errorArg);
2561 require_action_quiet(encryptionKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys encryption key error: %@", errorArg));
2562
2563 action(encryptionKey, signingKey, errorArg);
2564 CFReleaseNull(signingKey);
2565 CFReleaseNull(encryptionKey);
2566 CFReleaseNull(errorArg);
2567 return true;
2568 fail:
2569 action(NULL, NULL, errorArg);
2570 CFReleaseNull(errorArg);
2571 CFReleaseNull(signingKey);
2572 CFReleaseNull(encryptionKey);
2573 return true;
2574 });
2575 CFReleaseNull(localError);
2576 }
2577
2578 static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, int keySize, SecKeyRef octagonPublicKey, NSError** error) {
2579 NSError* localerror = nil;
2580
2581 CFDataRef publicKeyHash = SecKeyCopyPublicKeyHash(octagonPublicKey);
2582
2583 NSMutableDictionary* query = [@{
2584 (id)kSecClass : (id)kSecClassKey,
2585 (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC,
2586 (id)kSecAttrKeyClass : (id)kSecAttrKeyClassPrivate,
2587 (id)kSecAttrAccessGroup : (id)kSOSInternalAccessGroup,
2588 (id)kSecAttrLabel : keyLabel,
2589 (id)kSecAttrApplicationLabel : (__bridge NSData*)(publicKeyHash),
2590 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
2591 (id)kSecUseDataProtectionKeychain : @YES,
2592 (id)kSecValueData : keyDataToSave,
2593 } mutableCopy];
2594
2595 CFTypeRef result = NULL;
2596 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &result);
2597
2598 if(status == errSecSuccess) {
2599 CFReleaseNull(publicKeyHash);
2600 return true;
2601 }
2602 if(status == errSecDuplicateItem) {
2603 // Add every primary key attribute to this find dictionary
2604 NSMutableDictionary* findQuery = [[NSMutableDictionary alloc] init];
2605 findQuery[(id)kSecClass] = query[(id)kSecClass];
2606 findQuery[(id)kSecAttrKeyType] = query[(id)kSecAttrKeyTypeEC];
2607 findQuery[(id)kSecAttrKeyClass] = query[(id)kSecAttrKeyClassPrivate];
2608 findQuery[(id)kSecAttrAccessGroup] = query[(id)kSecAttrAccessGroup];
2609 findQuery[(id)kSecAttrLabel] = query[(id)kSecAttrLabel];
2610 findQuery[(id)kSecAttrApplicationLabel] = query[(id)kSecAttrApplicationLabel];
2611 findQuery[(id)kSecUseDataProtectionKeychain] = query[(id)kSecUseDataProtectionKeychain];
2612
2613 NSMutableDictionary* updateQuery = [query mutableCopy];
2614 updateQuery[(id)kSecClass] = nil;
2615
2616 status = SecItemUpdate((__bridge CFDictionaryRef)findQuery, (__bridge CFDictionaryRef)updateQuery);
2617
2618 if(status) {
2619 localerror = [NSError
2620 errorWithDomain:NSOSStatusErrorDomain
2621 code:status
2622 description:[NSString stringWithFormat:@"SecItemUpdate: %d", (int)status]];
2623 }
2624 } else {
2625 localerror = [NSError
2626 errorWithDomain:NSOSStatusErrorDomain
2627 code:status
2628 description:[NSString stringWithFormat:@"SecItemAdd: %d", (int)status]];
2629 }
2630 if(localerror && error) {
2631 *error = localerror;
2632 }
2633
2634 CFReleaseNull(publicKeyHash);
2635
2636 return (status == errSecSuccess);
2637 }
2638
2639 static NSString* createKeyLabel(NSDictionary *gestalt, NSString* circleName, NSString* prefix)
2640 {
2641 NSString *keyName = [NSString stringWithFormat:@"ID for %@-%@",SOSPeerGestaltGetName((__bridge CFDictionaryRef)(gestalt)), circleName];
2642
2643 NSString* octagonSigningKeyName = [prefix stringByAppendingString: keyName];
2644
2645 return octagonSigningKeyName;
2646 }
2647
2648 static NSError* saveKeysToKeychain(SOSAccount* account, NSData* octagonSigningFullKey, NSData* octagonEncryptionFullKey, SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef)
2649 {
2650 NSError* saveToKeychainError = nil;
2651
2652 NSString* circleName = (__bridge NSString*)(SOSCircleGetName(account.trust.trustedCircle));
2653 NSString* signingPrefix = @"Octagon Peer Signing ";
2654 NSString* encryptionPrefix = @"Octagon Peer Encryption ";
2655 NSString* octagonSigningKeyName = createKeyLabel(account.gestalt, circleName, signingPrefix);
2656 NSString* octagonEncryptionKeyName = createKeyLabel(account.gestalt, circleName, encryptionPrefix);
2657
2658 /* behavior mimics GeneratePermanentFullECKey_internal */
2659 saveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError);
2660 if(saveToKeychainError) {
2661 secerror("octagon: could not save signing key: %@", saveToKeychainError);
2662 return saveToKeychainError;
2663 }
2664 saveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError);
2665 if(saveToKeychainError) {
2666 secerror("octagon: could not save encryption key: %@", saveToKeychainError);
2667 return saveToKeychainError;
2668 }
2669
2670 return nil;
2671 }
2672
2673 void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey,
2674 CFDataRef signingPublicKey, CFDataRef encryptionPublicKey,
2675 SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef,
2676 void (^action)(CFErrorRef error))
2677 {
2678 CFErrorRef localError = NULL;
2679 do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2680 CFErrorRef updateOctagonKeysError = NULL;
2681 bool updatedPeerInfo = SOSAccountUpdatePeerInfoAndPush(txn.account, CFSTR("Updating Octagon Keys in SOS"), &updateOctagonKeysError, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) {
2682
2683 //save octagon key set to the keychain
2684 NSError* saveError = nil;
2685 saveError = saveKeysToKeychain(txn.account, (__bridge NSData*)octagonSigningFullKey, (__bridge NSData*)octagonEncryptionFullKey,
2686 octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef);
2687
2688 if(saveError) {
2689 secerror("octagon: failed to save Octagon keys to the keychain: %@", saveError);
2690 action((__bridge CFErrorRef)saveError);
2691 return false;
2692 }
2693
2694 //now update the peer info to contain octagon keys
2695 if(pi){
2696 CFErrorRef setError = NULL;
2697 SOSPeerInfoSetOctagonKeysInDescription(pi, octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef, &setError);
2698 if(setError) {
2699 secerror("octagon: Failed to set Octagon Keys in peerInfo: %@", setError);
2700 action(setError);
2701 return false;
2702 }
2703 } else {
2704 secnotice("octagon", "No peer info to update?");
2705 NSError *noPIError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorPeerNotFound userInfo:@{NSLocalizedDescriptionKey : @"Device has no full peer info"}];
2706 action((__bridge CFErrorRef)noPIError);
2707 return false;
2708 }
2709
2710 secnotice("octagon", "Success! Upated Octagon keys in SOS!");
2711
2712 action(nil);
2713 return true;
2714 });
2715 return updatedPeerInfo;
2716 });
2717 CFReleaseNull(localError);
2718 }
2719
2720 void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error))
2721 {
2722 CFErrorRef cfAccountError = NULL;
2723 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2724 CFSetRef sosPeerSet = [txn.account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) {
2725 return true;
2726 }];
2727
2728 CFErrorRef errorArg = cferror ? *cferror : NULL;
2729 action(sosPeerSet, errorArg);
2730 CFReleaseNull(sosPeerSet);
2731 return true;
2732 });
2733 CFReleaseNull(cfAccountError);
2734 }
2735
2736 void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error))
2737 {
2738 CFErrorRef cfAccountError = NULL;
2739 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2740 SOSAccount* account = txn.account;
2741 NSString* peerID = nil;
2742 CFErrorRef localError = nil;
2743
2744 if([account getCircleStatus:nil] == kSOSCCInCircle){
2745 peerID = [txn.account peerID];
2746 }
2747 else{
2748 SOSErrorCreate(kSOSErrorNoCircle, &localError, NULL, CFSTR("Not in circle"));
2749 }
2750 action((__bridge CFStringRef)peerID, localError);
2751 CFReleaseNull(localError);
2752 return true;
2753 });
2754 CFReleaseNull(cfAccountError);
2755 }
2756
2757 void
2758 SOSCCAccountTriggerSyncWithBackupPeer_server(CFStringRef peer)
2759 {
2760 #if OCTAGON
2761 secnotice("syncwith", "SOSCCAccountTriggerSyncWithBackupPeer_server: %@", peer);
2762 if (peer == NULL) {
2763 return;
2764 }
2765 SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef();
2766 [account triggerBackupForPeers:@[(__bridge NSString *)peer]];
2767 #endif
2768 }
2769