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