2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #import <TargetConditionals.h>
27 #import <Foundation/Foundation.h>
29 #import "keychain/ot/OTClique.h"
30 #import "keychain/ot/OTConstants.h"
31 #import "keychain/ot/OTDefines.h"
33 #import <utilities/SecCFWrappers.h>
34 #import <utilities/debugging.h>
36 #import "keychain/SecureObjectSync/SOSCloudCircle.h"
37 #import "KeychainCircle/PairingChannel.h"
38 #import <Security/SecBase.h>
40 const NSString* kSecEntitlementPrivateOctagonEscrow = @"com.apple.private.octagon.escrow-content";
43 #import <AuthKit/AuthKit.h>
44 #import <AuthKit/AuthKit_Private.h>
45 #import <SoftLinking/SoftLinking.h>
46 #import <CloudServices/SecureBackup.h>
47 #import <CloudServices/SecureBackupConstants.h>
48 #import "keychain/ot/OTControl.h"
49 #import "keychain/ot/categories/OctagonEscrowRecoverer.h"
51 SOFT_LINK_FRAMEWORK(PrivateFrameworks, KeychainCircle);
52 SOFT_LINK_FRAMEWORK(PrivateFrameworks, CloudServices);
54 #pragma clang diagnostic push
55 #pragma clang diagnostic ignored "-Wstrict-prototypes"
56 SOFT_LINK_CLASS(KeychainCircle, KCPairingChannel);
57 SOFT_LINK_CLASS(KeychainCircle, OTPairingChannel);
58 SOFT_LINK_CLASS(CloudServices, SecureBackup);
59 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain);
61 #pragma clang diagnostic pop
64 OTCliqueCDPContextType OTCliqueCDPContextTypeNone = @"cdpContextTypeNone";
65 OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn = @"cdpContextTypeSignIn";
66 OTCliqueCDPContextType OTCliqueCDPContextTypeRepair = @"cdpContextTypeRepair";
67 OTCliqueCDPContextType OTCliqueCDPContextTypeFinishPasscodeChange = @"cdpContextTypeFinishPasscodeChange";
68 OTCliqueCDPContextType OTCliqueCDPContextTypeRecoveryKeyGenerate = @"cdpContextTypeRecoveryKeyGenerate";
69 OTCliqueCDPContextType OTCliqueCDPContextTypeRecoveryKeyNew = @"cdpContextTypeRecoveryKeyNew";
70 OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode = @"cdpContextTypeUpdatePasscode";
72 NSString* OTCliqueStatusToString(CliqueStatus status)
76 return @"CliqueStatusIn";
77 case CliqueStatusNotIn:
78 return @"CliqueStatusNotIn";
79 case CliqueStatusPending:
80 return @"CliqueStatusPending";
81 case CliqueStatusAbsent:
82 return @"CliqueStatusAbsent";
83 case CliqueStatusNoCloudKitAccount:
84 return @"CliqueStatusNoCloudKitAccount";
85 case CliqueStatusError:
86 return @"CliqueStatusError";
89 CliqueStatus OTCliqueStatusFromString(NSString* str)
91 if([str isEqualToString: @"CliqueStatusIn"]) {
92 return CliqueStatusIn;
93 } else if([str isEqualToString: @"CliqueStatusNotIn"]) {
94 return CliqueStatusNotIn;
95 } else if([str isEqualToString: @"CliqueStatusPending"]) {
96 return CliqueStatusPending;
97 } else if([str isEqualToString: @"CliqueStatusAbsent"]) {
98 return CliqueStatusAbsent;
99 } else if([str isEqualToString: @"CliqueStatusNoCloudKitAccount"]) {
100 return CliqueStatusNoCloudKitAccount;
101 } else if([str isEqualToString: @"CliqueStatusError"]) {
102 return CliqueStatusError;
105 return CliqueStatusError;
109 @implementation OTConfigurationContext
110 - (OTControl* _Nullable)makeOTControl:(NSError**)error
113 if (self.otControl) {
114 return self.otControl;
116 return [OTControl controlObject:true error:error];
123 @implementation OTBottleIDs
126 @implementation OTOperationConfiguration
128 - (instancetype)init {
129 if ((self = [super init]) == nil) {
132 _timeoutWaitForCKAccount = 10 * NSEC_PER_SEC;
133 _qualityOfService = NSQualityOfServiceDefault;
134 _discretionaryNetwork = NO;
135 _useCachedAccountStatus = NO;
139 + (BOOL)supportsSecureCoding {
143 - (void)encodeWithCoder:(nonnull NSCoder *)coder {
144 [coder encodeObject:@(_timeoutWaitForCKAccount) forKey:@"timeoutWaitForCKAccount"];
145 [coder encodeObject:@(_qualityOfService) forKey:@"qualityOfService"];
146 [coder encodeObject:@(_discretionaryNetwork) forKey:@"discretionaryNetwork"];
147 [coder encodeObject:@(_useCachedAccountStatus) forKey:@"useCachedAccountStatus"];
150 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
151 _timeoutWaitForCKAccount = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"timeoutWaitForCKAccount"] unsignedLongLongValue];
152 _qualityOfService = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"qualityOfService"] integerValue];
153 _discretionaryNetwork = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"discretionaryNetwork"] boolValue];
154 _useCachedAccountStatus = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"useCachedAccountStatus"] boolValue];
161 @interface OTClique ()
162 @property (nonatomic, copy) NSString* cliqueMemberIdentifier;
163 @property (nonatomic, strong) OTConfigurationContext *ctx;
164 @property (nonatomic, strong) NSMutableDictionary *defaults;
167 @implementation OTClique
169 + (BOOL)platformSupportsSOS
171 return (OctagonPlatformSupportsSOS() && OctagonIsSOSFeatureEnabled());
174 // defaults write com.apple.security.octagon enable -bool YES
175 -(BOOL)isOctagonPairingEnabled {
176 BOOL nsDefaults = self.defaults[OTDefaultsOctagonEnable] ? [self.defaults[OTDefaultsOctagonEnable] boolValue] : OctagonIsEnabled();
177 secnotice("octagon", "pairing is %@", nsDefaults ? @"on" : @"off");
181 - (void)setPairingDefault:(BOOL)defaults
183 self.defaults[OTDefaultsOctagonEnable] = @(defaults);
186 - (void)removePairingDefault
188 [self.defaults removeObjectForKey:OTDefaultsOctagonEnable];
191 - (instancetype)initWithContextData:(OTConfigurationContext *)ctx error:(NSError * __autoreleasing *)error
196 _ctx = [[OTConfigurationContext alloc]init];
197 _ctx.context = ctx.context ?: OTDefaultContext;
198 _ctx.dsid = [ctx.dsid copy];
199 _ctx.altDSID = [ctx.altDSID copy];
200 _ctx.analytics = ctx.analytics;
201 _ctx.otControl = ctx.otControl;
203 self.defaults = [NSMutableDictionary dictionary];
207 NSAssert(false, @"OTClique is not implemented on this platform");
212 - (NSString* _Nullable)cliqueMemberIdentifier
215 __block NSString* retPeerID = nil;
217 if(OctagonIsEnabled()) {
218 NSError* localError = nil;
219 OTControl* control = [self makeOTControl:&localError];
221 secerror("octagon: Failed to create OTControl: %@", localError);
225 [control fetchEgoPeerID:nil
226 context:self.ctx.context
227 reply:^(NSString* peerID, NSError* error) {
229 secerror("octagon: Failed to fetch octagon peer ID: %@", error);
233 secnotice("clique", "cliqueMemberIdentifier(octagon) received %@", retPeerID);
236 if([OTClique platformSupportsSOS]) {
237 CFErrorRef error = NULL;
238 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(&error);
239 retPeerID = (NSString*)CFBridgingRelease(CFRetainSafe(SOSPeerInfoGetPeerID(me)));
243 secnotice("clique", "cliqueMemberIdentifier complete: %@", retPeerID);
251 - (OTControl* _Nullable)makeOTControl:(NSError**)error
253 return [self.ctx makeOTControl:error];
256 - (BOOL)establish:(NSError**)error
258 secnotice("clique-establish", "establish started");
260 OTControl* control = [self makeOTControl:error];
265 __block BOOL success = NO;
266 __block NSError* localError = nil;
268 [control establish:nil context:self.ctx.context altDSID:self.ctx.altDSID reply:^(NSError * _Nullable operationError) {
271 secnotice("clique-establish", "reenact establish returned an error: %@", operationError);
273 success = !!operationError;
274 localError = operationError;
277 if(localError && error) {
280 secnotice("clique-establish", "establish complete: %@", success ? @"YES" : @"NO");
285 - (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error
287 secnotice("clique-resetandestablish", "resetAndEstablish started");
289 OTControl* control = [self makeOTControl:error];
295 __block BOOL success = NO;
296 __block NSError* localError = nil;
297 [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID resetReason:resetReason reply:^(NSError * _Nullable operationError) {
300 secnotice("clique-resetandestablish", "resetAndEstablish returned an error: %@", operationError);
302 success = !!operationError;
303 localError = operationError;
306 if(localError && error) {
310 secnotice("clique-resetandestablish", "establish complete: %@", success ? @"YES" : @"NO");
316 + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error
318 return [OTClique newFriendsWithContextData:data resetReason:CuttlefishResetReasonUserInitiatedReset error:error];
321 + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error
324 secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid);
327 OTClique* clique = [[OTClique alloc] initWithContextData:data error:error];
329 if(OctagonIsEnabled()) {
330 NSError* localError = nil;
331 [clique resetAndEstablish:resetReason error:&localError];
334 secnotice("clique-newfriends", "account reset failed: %@", localError);
340 secnotice("clique-newfriends", "Octagon account reset succeeded");
344 if([OTClique platformSupportsSOS]) {
345 CFErrorRef resetError = NULL;
346 NSData* analyticsData = nil;
348 NSError* encodingError = nil;
349 analyticsData = [NSKeyedArchiver archivedDataWithRootObject:data.analytics requiringSecureCoding:YES error:&encodingError];
352 secnotice("clique-newfriends", "newFriendsWithContextData: unable to serialize analytics: %@", encodingError);
357 result = SOSCCResetToEmptyWithAnalytics((__bridge CFDataRef)analyticsData, &resetError);
359 result = SOSCCResetToEmpty(&resetError);
362 if(!result || resetError){
363 secnotice("clique-newfriends", "newFriendsWithContextData: resetToOffering failed: %@", resetError);
365 *error = CFBridgingRelease(resetError);
369 secnotice("clique-newfriends", "newFriendsWithContextData: reset the SOS circle");
371 secnotice("clique-newfriends", "newFriendsWithContextData: SOS disabled on this platform");
373 secnotice("clique-newfriends", "makeNewFriends complete");
379 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
384 + (OTClique* _Nullable)performEscrowRecoveryWithContextData:(OTConfigurationContext*)data
385 escrowArguments:(NSDictionary*)sbdRecoveryArguments
386 error:(NSError**)error
389 secnotice("clique-recovery", "attempting an escrow recovery for context:%@, altdsid:%@", data.context, data.altDSID);
391 id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
393 NSDictionary* recoveredInformation = nil;
394 NSError* recoverError = [sb recoverWithInfo:sbdRecoveryArguments results:&recoveredInformation];
397 secnotice("clique-recovery", "sbd escrow recovery failed: %@", recoverError);
398 if([OTClique platformSupportsSOS]) {
399 if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */
400 secnotice("clique-recovery", "Can't restore legacy backup with no keybag. Resetting SOS to offering");
401 CFErrorRef blowItAwayError = NULL;
402 bool successfulReset = SOSCCResetToOffering(&blowItAwayError);
403 if(!successfulReset || blowItAwayError) {
404 secerror("clique-recovery: failed to reset to offering:%@", blowItAwayError);
406 secnotice("clique-recovery", "resetting SOS circle successful");
410 *error = recoverError;
416 *error = recoverError;
422 NSError* localError = nil;
423 OTClique* clique = [[OTClique alloc] initWithContextData:data
426 if(!clique || localError) {
427 secnotice("clique-recovery", "unable to create otclique: %@", localError);
434 OTControl* control = [clique makeOTControl:&localError];
436 secnotice("clique-recovery", "unable to create otcontrol: %@", localError);
443 NSString *bottleID = recoveredInformation[@"bottleID"];
444 NSString *isValid = recoveredInformation[@"bottleValid"];
445 NSData *bottledPeerEntropy = recoveredInformation[@"EscrowServiceEscrowData"][@"BottledPeerEntropy"];
446 bool shouldResetOctagon = false;
448 if(bottledPeerEntropy && bottleID && [isValid isEqualToString:@"valid"]){
449 secnotice("clique-recovery", "recovering from bottle: %@", bottleID);
450 __block NSError* restoreBottleError = nil;
453 [control restore:OTCKContainerName
454 contextID:data.context
455 bottleSalt:data.altDSID
456 entropy:bottledPeerEntropy
458 reply:^(NSError * _Nullable restoreError) {
460 secnotice("clique-recovery", "restore bottle errored: %@", restoreError);
462 secnotice("clique-recovery", "restoring bottle succeeded");
464 restoreBottleError = restoreError;
467 if(restoreBottleError) {
469 *error = restoreBottleError;
474 shouldResetOctagon = true;
477 if(OctagonPlatformSupportsSOS()) {
478 secnotice("clique-recovery", "attempting joinAfterRestore");
479 [clique joinAfterRestore:&localError];
480 secnotice("clique-recovery", "joinAfterRestore: %@", localError);
483 if(shouldResetOctagon) {
484 secnotice("clique-recovery", "bottle %@ is not valid, resetting octagon", bottleID);
485 NSError* resetError = nil;
486 [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError];
488 secnotice("clique-recovery", "failed to reset octagon: %@", resetError);
490 secnotice("clique-recovery", "reset octagon succeeded");
494 secnotice("clique-recovery", "recovery complete: %@", clique);
499 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
506 - (KCPairingChannel *)setupPairingChannelAsInitiator:(KCPairingChannelContext *)ctx
509 return [getKCPairingChannelClass() pairingChannelInitiator:ctx];
515 - (KCPairingChannel * _Nullable)setupPairingChannelAsInitator:(KCPairingChannelContext *)ctx error:(NSError * __autoreleasing *)error
520 return [self setupPairingChannelAsInitiator:ctx];
523 - (KCPairingChannel *)setupPairingChannelAsAcceptor:(KCPairingChannelContext *)ctx
526 return [getKCPairingChannelClass() pairingChannelAcceptor:ctx];
532 - (KCPairingChannel * _Nullable)setupPairingChannelAsAcceptor:(KCPairingChannelContext *)ctx error:(NSError * __autoreleasing *)error
538 return [self setupPairingChannelAsAcceptor:ctx];
542 - (CliqueStatus)_fetchCliqueStatus:(OTOperationConfiguration *)configuration error:(NSError * __autoreleasing *)error
545 __block CliqueStatus sosStatus = CliqueStatusError;
546 __block CliqueStatus octagonStatus = CliqueStatusError;
548 // Octagon is supreme.
550 if(OctagonIsEnabled()) {
551 OTControl* control = [self makeOTControl:error];
553 secnotice("clique-status", "cliqueStatus noOTControl");
554 return CliqueStatusError;
557 __block NSError* localError = nil;
558 [control fetchCliqueStatus:nil context:self.ctx.context configuration:configuration reply:^(CliqueStatus cliqueStatus, NSError * _Nullable fetchError) {
560 octagonStatus = CliqueStatusError;
561 localError = fetchError;
562 secnotice("clique-status", "octagon clique status errored: %@", fetchError);
564 octagonStatus = cliqueStatus;
568 if(OctagonAuthoritativeTrustIsEnabled() || !OctagonPlatformSupportsSOS()) {
569 secnotice("clique-status", "cliqueStatus(%{public}scached)(context:%@, altDSID:%@) returning %@ (error: %@)",
570 configuration.useCachedAccountStatus ? "" : "non-",
571 self.ctx.context, self.ctx.altDSID,
572 OTCliqueStatusToString(octagonStatus), localError);
573 if (localError && error) {
576 return octagonStatus;
580 if([OTClique platformSupportsSOS]) {
581 CFErrorRef circleStatusError = NULL;
582 sosStatus = kSOSCCError;
583 if(configuration.useCachedAccountStatus){
584 sosStatus = SOSCCThisDeviceIsInCircle(&circleStatusError);
586 sosStatus = SOSCCThisDeviceIsInCircleNonCached(&circleStatusError);
588 secnotice("clique-status", "sos clique status is %d (%@)", (int)sosStatus, circleStatusError);
591 *error = (NSError*)CFBridgingRelease(circleStatusError);
593 CFBridgingRelease(circleStatusError);
596 secnotice("clique-status", "cliqueStatus(%{public}scached)(context:%@, altDSID:%@) complete: %@",
597 configuration.useCachedAccountStatus ? "" : "non-",
598 self.ctx.context, self.ctx.altDSID,
599 OTCliqueStatusToString(octagonStatus));
600 return octagonStatus;
603 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
605 return (CliqueStatus)kSOSCCError;
609 // Don't change rules for CoreCDP, and preserve legacy behavior for now
610 // preserve old behavior until CoreCDP can move to -fetchCliqueStatus:error:
611 #define LEGACY_WAITING_BEHAVIOR (TARGET_OS_OSX || TARGET_OS_IOS)
613 - (CliqueStatus)fetchCliqueStatus:(OTOperationConfiguration *)configuration error:(NSError * __autoreleasing * _Nonnull)error
615 return [self _fetchCliqueStatus:configuration error:error];
618 - (CliqueStatus)fetchCliqueStatus:(NSError * __autoreleasing *)error
620 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
621 #if LEGACY_WAITING_BEHAVIOR
622 configuration.timeoutWaitForCKAccount = 0;
624 return [self _fetchCliqueStatus:configuration error:error];
627 - (CliqueStatus)cachedCliqueStatus:(BOOL)usedCached error:(NSError * __autoreleasing *)error
629 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
630 #if LEGACY_WAITING_BEHAVIOR
631 configuration.timeoutWaitForCKAccount = 0;
634 configuration.useCachedAccountStatus = YES;
636 return [self _fetchCliqueStatus:configuration error:error];
640 - (BOOL)removeFriendsInClique:(NSArray<NSString*>*)friendIdentifiers error:(NSError * __autoreleasing *)error
643 secnotice("clique-removefriends", "removeFriendsInClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
645 // Annoying: we must sort friendIdentifiers into octagon/sos lists.
646 NSMutableArray<NSString*>* octagonIdentifiers = [NSMutableArray array];
647 NSMutableArray<NSString*>* sosIdentifiers = [NSMutableArray array];
649 for(NSString* friendIdentifier in friendIdentifiers) {
650 if([friendIdentifier hasPrefix:@"SHA256:"]) {
651 [octagonIdentifiers addObject: friendIdentifier];
653 [sosIdentifiers addObject: friendIdentifier];
657 // Ensure that we don't have any peers on the wrong platform
658 if(!OctagonIsEnabled() && octagonIdentifiers.count > 0) {
659 NSError *localError = [NSError errorWithDomain:NSOSStatusErrorDomain
660 code:errSecUnimplemented
661 userInfo:@{NSLocalizedDescriptionKey: @"Octagon is disabled; can't distrust any Octagon peers"}];
662 secnotice("clique-removefriends", "removeFriendsInClique failed:%@", localError);
669 if(!OctagonPlatformSupportsSOS() && sosIdentifiers.count > 0) {
670 NSError *localError = [NSError errorWithDomain:NSOSStatusErrorDomain
671 code:errSecUnimplemented
672 userInfo:@{NSLocalizedDescriptionKey: @"SOS is not available on this platform; can't distrust any SOS peers"}];
673 secnotice("clique-removefriends", "removeFriendsInClique failed:%@", localError);
681 __block NSError* localError = nil;
684 if(OctagonIsEnabled() && octagonIdentifiers.count > 0) {
685 OTControl* control = [self makeOTControl:error];
690 secnotice("clique-removefriends", "octagon: removing octagon friends: %@", octagonIdentifiers);
692 [control removeFriendsInClique:nil
693 context:self.ctx.context
694 peerIDs:octagonIdentifiers
695 reply:^(NSError* replyError) {
697 secnotice("clique-removefriends", "removeFriendsInClique failed: unable to remove friends: %@", replyError);
698 localError = replyError;
700 secnotice("clique-removefriends", "octagon: friends removed: %@", octagonIdentifiers);
705 if([OTClique platformSupportsSOS] && sosIdentifiers.count >0) {
706 CFErrorRef removeFriendError = NULL;
707 NSData* analyticsData = nil;
709 secnotice("clique-removefriends", "removing sos friends: %@", sosIdentifiers);
711 if(self.ctx.analytics){
712 NSError* encodingError = nil;
713 analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
717 result = SOSCCRemovePeersFromCircleWithAnalytics((__bridge CFArrayRef)friendIdentifiers, (__bridge CFDataRef)analyticsData, &removeFriendError);
719 result = SOSCCRemovePeersFromCircle((__bridge CFArrayRef)friendIdentifiers, &removeFriendError);
722 if(removeFriendError) {
723 secnotice("clique-removefriends", "removeFriendsInClique failed: unable to remove friends: %@", removeFriendError);
724 localError = CFBridgingRelease(removeFriendError);
728 if(error && localError) {
731 secnotice("clique-removefriends", "removeFriendsInClique complete: %d", result);
733 return result && localError == nil;
739 - (BOOL)leaveClique:(NSError * __autoreleasing *)error
742 secnotice("clique-leaveClique", "leaveClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
743 CFErrorRef removeThisDeviceError = NULL;
746 if(OctagonIsEnabled()) {
747 OTControl* control = [self makeOTControl:error];
752 __block NSError* localError = nil;
753 [control leaveClique:nil context:self.ctx.context reply:^(NSError * _Nullable leaveError) {
755 secnotice("clique-leaveClique", "leaveClique errored: %@", leaveError);
756 localError = leaveError;
758 secnotice("clique-leaveClique", "leaveClique success.");
765 result = !localError;
768 if([OTClique platformSupportsSOS]) {
769 NSData* analyticsData = nil;
771 if(self.ctx.analytics) {
772 NSError* encodingError = nil;
773 analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
775 secnotice("clique-leaveClique", "leaveClique unable to archive analytics object: %@", encodingError);
780 result &= SOSCCRemoveThisDeviceFromCircleWithAnalytics((__bridge CFDataRef)analyticsData, &removeThisDeviceError);
782 result &= SOSCCRemoveThisDeviceFromCircle(&removeThisDeviceError);
786 *error = (NSError*)CFBridgingRelease(removeThisDeviceError);
788 CFBridgingRelease(removeThisDeviceError);
791 secnotice("clique-leaveClique", "leaveClique complete: %d", result);
793 return result ? YES : NO;
799 - (NSDictionary<NSString*,NSString*>* _Nullable)peerDeviceNamesByPeerID:(NSError * __autoreleasing *)error
802 secnotice("clique", "peerDeviceNamesByPeerID invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
804 NSMutableDictionary<NSString*, NSString*>* retPeers = [NSMutableDictionary dictionary];
806 if(OctagonIsEnabled()) {
807 OTControl* control = [self makeOTControl:error];
812 __block NSError* localError = nil;
813 __block NSDictionary<NSString*, NSString*>* localPeers = nil;
815 [control peerDeviceNamesByPeerID:nil context:OTDefaultContext reply:^(NSDictionary<NSString*,NSString*>* peers, NSError* controlError) {
817 secnotice("clique", "peerDeviceNamesByPeerID errored: %@", controlError);
819 secnotice("clique", "peerDeviceNamesByPeerID succeeded: %@", peers);
821 localError = controlError;
825 if(error && localError) {
831 [retPeers addEntriesFromDictionary:localPeers];
832 secnotice("clique", "Received %lu Octagon peers", (unsigned long)localPeers.count);
835 if([OTClique platformSupportsSOS]) {
836 CFErrorRef peerErrorRef = NULL;
837 NSMutableDictionary<NSString*,NSString*>* peerMapping = [NSMutableDictionary dictionary];
838 NSArray* arrayOfPeerRefs = CFBridgingRelease(SOSCCCopyPeerPeerInfo(&peerErrorRef));
840 [arrayOfPeerRefs enumerateObjectsUsingBlock:^(id peerRef, NSUInteger idx, BOOL * stop) {
841 SOSPeerInfoRef peer = (__bridge SOSPeerInfoRef)peerRef;
843 [peerMapping setObject:(__bridge NSString*)SOSPeerInfoGetPeerName(peer) forKey:(__bridge NSString*)SOSPeerInfoGetPeerID(peer)];
848 *error = (NSError*)CFBridgingRelease(peerErrorRef);
850 CFBridgingRelease(peerErrorRef);
853 [retPeers addEntriesFromDictionary:peerMapping];
854 secnotice("clique", "Received %lu SOS peers", (unsigned long)peerMapping.count);
863 - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error
865 secnotice("clique-recovery", "joinAfterRestore for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
866 if([OTClique platformSupportsSOS]) {
867 CFErrorRef restoreError = NULL;
869 bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError);
871 *error = (NSError*)CFBridgingRelease(restoreError);
873 CFBridgingRelease(restoreError);
875 secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided");
878 secnotice("clique-recovery", "SOS disabled for this platform, returning NO");
880 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
881 code:errSecUnimplemented
882 userInfo:@{NSLocalizedDescriptionKey: @"join after restore unimplemented"}];
888 - (BOOL)safariPasswordSyncingEnabled:(NSError **)error
890 secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
892 if([OTClique platformSupportsSOS]) {
893 CFErrorRef viewErrorRef = NULL;
895 SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef);
897 BOOL viewMember = result == kSOSCCViewMember;
899 *error = (NSError*)CFBridgingRelease(viewErrorRef);
901 CFBridgingRelease(viewErrorRef);
904 secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO");
908 secnotice("clique-safari", "SOS disabled for this platform, returning NO");
910 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
911 code:errSecUnimplemented
912 userInfo:@{NSLocalizedDescriptionKey: @"safari password syncing enabled unimplemented"}];
918 - (BOOL)isLastFriend:(NSError **)error
920 secnotice("clique-isLastFriend", "is last friend");
924 - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error
926 secnotice("clique-legacy", "waitForInitialSync for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
927 if([OTClique platformSupportsSOS]) {
928 CFErrorRef initialSyncErrorRef = NULL;
930 if(self.ctx.analytics){
931 NSError* encodingError = nil;
932 NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
933 if(!encodingError && analyticsData){
934 result = SOSCCWaitForInitialSyncWithAnalytics((__bridge CFDataRef)analyticsData, &initialSyncErrorRef);
936 result = SOSCCWaitForInitialSync(&initialSyncErrorRef);
939 result = SOSCCWaitForInitialSync(&initialSyncErrorRef);
942 BOOL initialSyncResult = (result == true);
944 *error = (NSError*)CFBridgingRelease(initialSyncErrorRef);
946 CFBridgingRelease(initialSyncErrorRef);
948 secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided");
949 return initialSyncResult;
951 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
953 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
954 code:errSecUnimplemented
955 userInfo:@{NSLocalizedDescriptionKey: @"wait for initial sync unimplemented"}];
961 - (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error
963 secnotice("clique-legacy", "copyViewUnawarePeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
965 if([OTClique platformSupportsSOS]) {
966 CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL;
967 CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef);
969 NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil);
971 *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef);
973 CFBridgingRelease(copyViewUnawarePeerInfoErrorRef);
977 secnotice("clique-legacy", "SOS disabled for this platform, returning NULL");
979 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
980 code:errSecUnimplemented
981 userInfo:@{NSLocalizedDescriptionKey: @"copy view unaware peer info unimplemented"}];
987 - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
989 secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
990 if([OTClique platformSupportsSOS]) {
992 if(self.ctx.analytics){
993 NSError* encodingError = nil;
994 NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
995 if(!encodingError && analyticsData){
996 result = SOSCCViewSetWithAnalytics((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews, (__bridge CFDataRef)analyticsData);
998 result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews);
1001 result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews);
1004 BOOL viewSetResult = (result == true);
1005 return viewSetResult;
1007 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1012 - (BOOL)setUserCredentialsAndDSID:(NSString*)userLabel
1013 password:(NSData*)userPassword
1014 error:(NSError *__autoreleasing*)error
1016 secnotice("clique-legacy", "setUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1017 if([OTClique platformSupportsSOS]) {
1018 CFErrorRef setCredentialsErrorRef = NULL;
1019 bool result = false;
1020 if(self.ctx.analytics){
1021 NSError* encodingError = nil;
1022 NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
1023 if(!encodingError && analyticsData){
1024 result = SOSCCSetUserCredentialsAndDSIDWithAnalytics((__bridge CFStringRef)userLabel,
1025 (__bridge CFDataRef)userPassword,
1026 (__bridge CFStringRef)self.ctx.dsid,
1027 (__bridge CFDataRef)analyticsData,
1028 &setCredentialsErrorRef);
1030 result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
1031 (__bridge CFDataRef)userPassword,
1032 (__bridge CFStringRef)self.ctx.dsid,
1033 &setCredentialsErrorRef);
1036 result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
1037 (__bridge CFDataRef)userPassword,
1038 (__bridge CFStringRef)self.ctx.dsid,
1039 &setCredentialsErrorRef);
1042 BOOL setCredentialsResult = (result == true);
1044 *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef);
1046 CFBridgingRelease(setCredentialsErrorRef);
1048 secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef);
1049 return setCredentialsResult;
1051 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1053 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1054 code:errSecUnimplemented
1055 userInfo:@{NSLocalizedDescriptionKey: @"set user credentials unimplemented"}];
1061 - (BOOL)tryUserCredentialsAndDSID:(NSString*)userLabel
1062 password:(NSData*)userPassword
1063 error:(NSError *__autoreleasing*)error
1065 secnotice("clique-legacy", "tryUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1067 if([OTClique platformSupportsSOS]) {
1068 CFErrorRef tryCredentialsErrorRef = NULL;
1069 bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
1070 (__bridge CFDataRef)userPassword,
1071 (__bridge CFStringRef)self.ctx.dsid,
1072 &tryCredentialsErrorRef);
1074 BOOL tryCredentialsResult = (result == true);
1076 *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef);
1078 CFBridgingRelease(tryCredentialsErrorRef);
1080 secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef);
1081 return tryCredentialsResult;
1083 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1085 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1086 code:errSecUnimplemented
1087 userInfo:@{NSLocalizedDescriptionKey: @"try user credentials unimplemented"}];
1093 - (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error
1095 secnotice("clique-legacy", "copyPeerPeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1097 if([OTClique platformSupportsSOS]) {
1098 CFErrorRef copyPeerErrorRef = NULL;
1099 CFArrayRef result = SOSCCCopyPeerPeerInfo(©PeerErrorRef);
1101 NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil);
1104 *error = (NSError*)CFBridgingRelease(copyPeerErrorRef);
1106 CFBridgingRelease(copyPeerErrorRef);
1108 secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList);
1112 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1114 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1115 code:errSecUnimplemented
1116 userInfo:@{NSLocalizedDescriptionKey: @"copy peer peer info unimplemented"}];
1122 - (BOOL)peersHaveViewsEnabled:(NSArray<NSString*>*)viewNames error:(NSError *__autoreleasing*)error
1124 secnotice("clique-legacy", "peersHaveViewsEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1126 if([OTClique platformSupportsSOS]) {
1127 CFErrorRef viewsEnabledErrorRef = NULL;
1128 BOOL viewsEnabledResult = NO;
1130 CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef);
1132 viewsEnabledResult = CFBooleanGetValue(result);
1135 *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef);
1137 CFBridgingRelease(viewsEnabledErrorRef);
1139 secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO");
1141 return viewsEnabledResult;
1143 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1145 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1146 code:errSecUnimplemented
1147 userInfo:@{NSLocalizedDescriptionKey: @"peers have views enabled unimplemented"}];
1153 - (BOOL)requestToJoinCircle:(NSError *__autoreleasing*)error
1155 bool result = false;
1156 CFErrorRef joinErrorRef = NULL;
1159 secnotice("clique-legacy", "requestToJoinCircle for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1161 if(OctagonIsEnabled()) {
1162 NSError* localError = nil;
1163 [self resetAndEstablish:CuttlefishResetReasonLegacyJoinCircle error:&localError];
1166 secnotice("clique-legacy", "account reset failed: %@", localError);
1168 *error = localError;
1172 secnotice("clique-legacy", "account reset succeeded");
1175 // If we didn't early-exit, and we aren't going to invoke SOS below, we succeeded.
1176 if(!OctagonPlatformSupportsSOS()) {
1177 secnotice("clique-legacy", "sos requestToJoinCircle results: %d %@", result, joinErrorRef);
1183 if([OTClique platformSupportsSOS]) {
1184 NSData* analyticsData = nil;
1185 if(self.ctx.analytics){
1186 NSError* encodingError = nil;
1187 analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
1191 result = SOSCCRequestToJoinCircleWithAnalytics((__bridge CFDataRef)analyticsData, &joinErrorRef);
1193 result = SOSCCRequestToJoinCircle(&joinErrorRef);
1196 secnotice("clique-legacy", "sos requestToJoinCircle complete: %d %@", result, joinErrorRef);
1200 *error = (NSError*)CFBridgingRelease(joinErrorRef);
1202 CFBridgingRelease(joinErrorRef);
1204 return result ? YES : NO;
1207 - (BOOL)accountUserKeyAvailable
1209 secnotice("clique-legacy", "accountUserKeyAvailable for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1211 if([OTClique platformSupportsSOS]) {
1212 BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL);
1213 if (canAuthenticate == NO) {
1214 secnotice("clique-legacy", "Security requires credentials...");
1216 return canAuthenticate;
1218 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1223 // MARK: SBD interfaces
1224 + (OTBottleIDs* _Nullable)findOptimalBottleIDsWithContextData:(OTConfigurationContext*)data
1225 error:(NSError**)error
1228 secnotice("clique-findbottle", "finding optimal bottles for context:%@, altdsid:%@", data.context, data.altDSID);
1230 if(OctagonIsEnabled()) {
1231 __block NSError* localError = nil;
1232 __block NSArray<NSString*>* localViableBottleIDs = nil;
1233 __block NSArray<NSString*>* localPartiallyViableBottleIDs = nil;
1235 OTControl *control = [data makeOTControl:&localError];
1237 secnotice("clique-findbottle", "unable to create otcontrol: %@", localError);
1239 *error = localError;
1243 [control fetchAllViableBottles:OTCKContainerName
1244 context:data.context
1245 reply:^(NSArray<NSString *> * _Nullable sortedBottleIDs,
1246 NSArray<NSString*> * _Nullable sortedPartialBottleIDs,
1247 NSError * _Nullable fetchError) {
1249 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData errored: %@", fetchError);
1251 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData succeeded: %@, %@", sortedBottleIDs, sortedPartialBottleIDs);
1253 localError = fetchError;
1254 localViableBottleIDs = sortedBottleIDs;
1255 localPartiallyViableBottleIDs = sortedPartialBottleIDs;
1258 if(error && localError) {
1259 *error = localError;
1261 OTBottleIDs* bottleIDs = [[OTBottleIDs alloc] init];
1262 bottleIDs.preferredBottleIDs = localViableBottleIDs;
1263 bottleIDs.partialRecoveryBottleIDs = localPartiallyViableBottleIDs;
1265 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData complete");
1269 // With octagon off, fail with 'unimplemented'
1271 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1272 code:errSecUnimplemented
1273 userInfo:@{NSLocalizedDescriptionKey: @"optimal bottle IDs unimplemented"}];
1279 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1285 + (OTClique* _Nullable)recoverWithContextData:(OTConfigurationContext*)data
1286 bottleID:(NSString*)bottleID
1287 escrowedEntropy:(NSData*)entropy
1288 error:(NSError**)error
1291 secnotice("octagon", "replaced by performEscrowRecoveryWithContextData:escrowArguments:error: remove call");
1295 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1301 // used by sbd to fill in the escrow record
1302 // TODO: what extra entitlement do you need to call this?
1303 - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy,
1304 NSString* _Nullable bottleID,
1305 NSData* _Nullable signingPublicKey,
1306 NSError* _Nullable error))reply
1309 secnotice("clique-fetchescrow", "fetching entropy for bottling for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1311 if(OctagonIsEnabled()) {
1312 NSError* controlError = nil;
1313 OTControl* control = [self makeOTControl:&controlError];
1315 reply(nil, nil, nil, controlError);
1318 [control fetchEscrowContents:OTCKContainerName
1319 contextID:self.ctx.context
1320 reply:^(NSData * _Nullable entropy,
1321 NSString * _Nullable bottleID,
1322 NSData * _Nullable signingPublicKey,
1323 NSError * _Nullable error) {
1325 secnotice("clique-fetchescrow", "fetchEscrowContents errored: %@", error);
1327 secnotice("clique-fetchescrow","fetchEscrowContents succeeded");
1329 reply (entropy, bottleID, signingPublicKey, error);
1334 // With octagon off, fail with 'unimplemented'
1335 reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain
1336 code:errSecUnimplemented
1337 userInfo:@{NSLocalizedDescriptionKey: @"fetchEscrowRecordContents unimplemented"}]);
1340 reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1344 + (void)setNewRecoveryKeyWithData:(OTConfigurationContext *)ctx
1345 recoveryKey:(NSString*)recoveryKey reply:(nonnull void (^)(SecRecoveryKey *rk, NSError *error))reply
1348 secnotice("octagon-setrecoverykey", "setNewRecoveryKeyWithData invoked for context: %@", ctx.context);
1349 //set the recovery key for SOS
1350 NSError* createRecoveryKeyError = nil;
1351 NSMutableDictionary *userInfo = [NSMutableDictionary new];
1352 NSError* retError = nil;
1354 SecRecoveryKey *rk = SecRKCreateRecoveryKeyWithError(recoveryKey, &createRecoveryKeyError);
1356 secerror("octagon-setrecoverykey, SecRKCreateRecoveryKeyWithError() failed: %@", createRecoveryKeyError);
1357 userInfo[NSLocalizedDescriptionKey] = @"SecRKCreateRecoveryKeyWithError() failed";
1358 userInfo[NSUnderlyingErrorKey] = createRecoveryKeyError;
1359 retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
1360 reply(nil, retError);
1363 if([OTClique platformSupportsSOS]) {
1364 CFErrorRef registerError = nil;
1365 if (!SecRKRegisterBackupPublicKey(rk, ®isterError)) {
1366 secerror("octagon-setrecoverykey, SecRKRegisterBackupPublicKey() failed: %@", registerError);
1367 NSError *underlyingError = CFBridgingRelease(registerError);
1368 userInfo[NSLocalizedDescriptionKey] = @"SecRKRegisterBackupPublicKey() failed";
1369 userInfo[NSUnderlyingErrorKey] = underlyingError;
1370 retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
1371 reply(nil,retError);
1374 secnotice("octagon-setrecoverykey", "successfully registered recovery key for SOS");
1378 //set the recovery key for Octagon
1379 if(OctagonRecoveryKeyIsEnabled()) {
1380 NSError* controlError = nil;
1381 OTControl* control = [ctx makeOTControl:&controlError];
1383 secnotice("octagon-setrecoverykey", "failed to fetch OTControl object: %@", controlError);
1384 reply(nil, controlError);
1387 [control createRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError * createError) {
1389 secerror("octagon-setrecoverykey, failed to create octagon recovery key");
1390 reply(nil, createError);
1393 secnotice("octagon-setrecoverykey", "successfully set octagon recovery key");
1400 reply(nil, [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1404 + (void)recoverOctagonUsingData:(OTConfigurationContext *)ctx
1405 recoveryKey:(NSString*)recoveryKey
1406 reply:(void(^)(NSError* _Nullable error))reply
1409 if(OctagonRecoveryKeyIsEnabled()) {
1410 NSError* controlError = nil;
1411 OTControl* control = [ctx makeOTControl:&controlError];
1413 secnotice("clique-recoverykey", "join using recovery key");
1416 secnotice("clique-recoverykey", "failed to fetch OTControl object: %@", controlError);
1417 reply(controlError);
1420 [control joinWithRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError *joinError) {
1422 secnotice("clique-recoverykey", "failed to join using recovery key: %@", joinError);
1426 secnotice("clique-recoverykey", "successfully joined using recovery key");
1432 reply([NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1436 - (void)performedCDPStateMachineRun:(OTCliqueCDPContextType)type
1437 success:(BOOL)success
1438 error:(NSError * _Nullable)error
1439 reply:(void(^)(NSError* _Nullable error))reply
1442 NSError* controlError = nil;
1443 OTControl* control = [self makeOTControl:&controlError];
1445 secnotice("clique-cdp-sm", "octagon, failed to fetch OTControl object: %@", controlError);
1446 reply(controlError);
1450 [control postCDPFollowupResult:success type:type error:error containerName:OTCKContainerName contextName:OTDefaultContext reply:^(NSError *postError) {
1452 secnotice("clique-cdp-sm", "failed to post %@ result: %@ ", type, postError);
1457 secnotice("clique-cdp-sm", "posted success: %@", type);
1459 secnotice("clique-cdp-sm", "posted error: %@: %@", type, error);
1464 reply([NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1468 - (BOOL)waitForOctagonUpgrade:(NSError** _Nullable)error
1471 OTControl* control = nil;
1473 if (!OctagonIsEnabled()) {
1474 secnotice("clique-waitforoctagonupgrade", "cannot upgrade, octagon is not enabled");
1476 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"Octagon is not enabled"}];
1481 NSError *controlError = nil;
1482 control = [self makeOTControl:&controlError];
1484 secnotice("clique-waitforoctagonupgrade", "octagon, failed to fetch OTControl object: %@", controlError);
1486 *error = controlError;
1491 __block BOOL ret = NO;
1492 __block NSError* blockError = nil;
1494 [control waitForOctagonUpgrade:OTCKContainerName context:OTDefaultContext reply:^(NSError *postError) {
1496 secnotice("clique-waitforoctagonupgrade", "error from control: %@", postError);
1497 blockError = postError;
1500 secnotice("clique-waitforoctagonupgrade", "successfully upgraded to octagon");
1505 if (blockError && error) {
1506 *error = blockError;
1512 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1518 - (void)performedFailureCDPStateMachineRun:(OTCliqueCDPContextType)type
1519 error:(NSError * _Nullable)error
1520 reply:(void(^)(NSError* _Nullable error))reply
1522 [self performedCDPStateMachineRun:type success:NO error:error reply:reply];
1525 - (void)performedSuccessfulCDPStateMachineRun:(OTCliqueCDPContextType)type
1526 reply:(void(^)(NSError* _Nullable error))reply
1528 [self performedCDPStateMachineRun:type success:YES error:nil reply:reply];