]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTClique.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / ot / OTClique.m
1 /*
2 * Copyright (c) 2018 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 #if __OBJC2__
25
26 #import <TargetConditionals.h>
27 #import <Foundation/Foundation.h>
28
29 #import "keychain/ot/OTClique.h"
30 #import "keychain/ot/OTClique+Private.h"
31 #import "keychain/ot/OTConstants.h"
32 #import "keychain/ot/OTDefines.h"
33 #import "keychain/SigninMetrics/OctagonSignPosts.h"
34
35 #import <utilities/SecCFWrappers.h>
36 #import <utilities/debugging.h>
37
38 #import "keychain/SecureObjectSync/SOSCloudCircle.h"
39 #import "KeychainCircle/PairingChannel.h"
40 #import <Security/SecBase.h>
41
42 const NSString* kSecEntitlementPrivateOctagonEscrow = @"com.apple.private.octagon.escrow-content";
43
44 #if OCTAGON
45 #import <AuthKit/AuthKit.h>
46 #import <AuthKit/AuthKit_Private.h>
47 #import <SoftLinking/SoftLinking.h>
48 #import <CloudServices/SecureBackup.h>
49 #import <CloudServices/SecureBackupConstants.h>
50 #import "keychain/ot/OTControl.h"
51 #import "keychain/ckks/CKKSControl.h"
52 #import "keychain/ot/categories/OctagonEscrowRecoverer.h"
53
54 SOFT_LINK_FRAMEWORK(PrivateFrameworks, KeychainCircle);
55 SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CloudServices);
56
57 #pragma clang diagnostic push
58 #pragma clang diagnostic ignored "-Wstrict-prototypes"
59 SOFT_LINK_CLASS(KeychainCircle, KCPairingChannel);
60 SOFT_LINK_CLASS(KeychainCircle, OTPairingChannel);
61 SOFT_LINK_CLASS(CloudServices, SecureBackup);
62 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain);
63 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationAppleID, NSString*);
64 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationPassword, NSString*);
65 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupiCloudDataProtectionDeleteAllRecordsKey, NSString*);
66 SOFT_LINK_CONSTANT(CloudServices, kSecureBackupContainsiCDPDataKey, NSString*);
67
68 #pragma clang diagnostic pop
69 #endif
70
71 OTCliqueCDPContextType OTCliqueCDPContextTypeNone = @"cdpContextTypeNone";
72 OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn = @"cdpContextTypeSignIn";
73 OTCliqueCDPContextType OTCliqueCDPContextTypeRepair = @"cdpContextTypeRepair";
74 OTCliqueCDPContextType OTCliqueCDPContextTypeFinishPasscodeChange = @"cdpContextTypeFinishPasscodeChange";
75 OTCliqueCDPContextType OTCliqueCDPContextTypeRecoveryKeyGenerate = @"cdpContextTypeRecoveryKeyGenerate";
76 OTCliqueCDPContextType OTCliqueCDPContextTypeRecoveryKeyNew = @"cdpContextTypeRecoveryKeyNew";
77 OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode = @"cdpContextTypeUpdatePasscode";
78
79 NSString* OTCliqueStatusToString(CliqueStatus status)
80 {
81 switch(status) {
82 case CliqueStatusIn:
83 return @"CliqueStatusIn";
84 case CliqueStatusNotIn:
85 return @"CliqueStatusNotIn";
86 case CliqueStatusPending:
87 return @"CliqueStatusPending";
88 case CliqueStatusAbsent:
89 return @"CliqueStatusAbsent";
90 case CliqueStatusNoCloudKitAccount:
91 return @"CliqueStatusNoCloudKitAccount";
92 case CliqueStatusError:
93 return @"CliqueStatusError";
94 };
95 }
96 CliqueStatus OTCliqueStatusFromString(NSString* str)
97 {
98 if([str isEqualToString: @"CliqueStatusIn"]) {
99 return CliqueStatusIn;
100 } else if([str isEqualToString: @"CliqueStatusNotIn"]) {
101 return CliqueStatusNotIn;
102 } else if([str isEqualToString: @"CliqueStatusPending"]) {
103 return CliqueStatusPending;
104 } else if([str isEqualToString: @"CliqueStatusAbsent"]) {
105 return CliqueStatusAbsent;
106 } else if([str isEqualToString: @"CliqueStatusNoCloudKitAccount"]) {
107 return CliqueStatusNoCloudKitAccount;
108 } else if([str isEqualToString: @"CliqueStatusError"]) {
109 return CliqueStatusError;
110 }
111
112 return CliqueStatusError;
113 }
114
115 NSString* OTCDPStatusToString(OTCDPStatus status) {
116 switch(status) {
117 case OTCDPStatusUnknown:
118 return @"unknown";
119 case OTCDPStatusDisabled:
120 return @"disabled";
121 case OTCDPStatusEnabled:
122 return @"enabled";
123 }
124 }
125
126
127 @implementation OTConfigurationContext
128
129 - (OTControl* _Nullable)makeOTControl:(NSError**)error
130 {
131 #if OCTAGON
132 if (self.otControl) {
133 return self.otControl;
134 }
135 return [OTControl controlObject:true error:error];
136 #else
137 return nil;
138 #endif
139 }
140
141 - (CKKSControl* _Nullable)makeCKKSControl:(NSError**)error
142 {
143 #if OCTAGON
144 if(self.ckksControl) {
145 return self.ckksControl;
146 }
147 return [CKKSControl CKKSControlObject:true error:error];
148 #else
149 return nil;
150 #endif
151 }
152
153 - (instancetype)init
154 {
155 if((self = [super init])) {
156 _context = OTDefaultContext;
157 }
158 return self;
159 }
160 @end
161
162 @implementation OTBottleIDs
163 @end
164
165 @implementation OTOperationConfiguration
166
167 - (instancetype)init {
168 if ((self = [super init]) == nil) {
169 return nil;
170 }
171 _timeoutWaitForCKAccount = 10 * NSEC_PER_SEC;
172 _qualityOfService = NSQualityOfServiceDefault;
173 _discretionaryNetwork = NO;
174 _useCachedAccountStatus = NO;
175 return self;
176 }
177
178 + (BOOL)supportsSecureCoding {
179 return YES;
180 }
181
182 - (void)encodeWithCoder:(nonnull NSCoder *)coder {
183 [coder encodeObject:@(_timeoutWaitForCKAccount) forKey:@"timeoutWaitForCKAccount"];
184 [coder encodeObject:@(_qualityOfService) forKey:@"qualityOfService"];
185 [coder encodeObject:@(_discretionaryNetwork) forKey:@"discretionaryNetwork"];
186 [coder encodeObject:@(_useCachedAccountStatus) forKey:@"useCachedAccountStatus"];
187 }
188
189 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
190 _timeoutWaitForCKAccount = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"timeoutWaitForCKAccount"] unsignedLongLongValue];
191 _qualityOfService = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"qualityOfService"] integerValue];
192 _discretionaryNetwork = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"discretionaryNetwork"] boolValue];
193 _useCachedAccountStatus = [[coder decodeObjectOfClass:[NSNumber class] forKey:@"useCachedAccountStatus"] boolValue];
194 return self;
195 }
196
197 @end
198
199
200 @interface OTClique ()
201 @property (nonatomic, copy) NSString* cliqueMemberIdentifier;
202 @property (nonatomic, strong) OTConfigurationContext *ctx;
203 @property (nonatomic, strong) NSMutableDictionary *defaults;
204 @end
205
206 @implementation OTClique
207
208 + (BOOL)platformSupportsSOS
209 {
210 return (OctagonPlatformSupportsSOS() && OctagonIsSOSFeatureEnabled());
211 }
212
213 // defaults write com.apple.security.octagon enable -bool YES
214 -(BOOL)isOctagonPairingEnabled {
215 BOOL nsDefaults = self.defaults[OTDefaultsOctagonEnable] ? [self.defaults[OTDefaultsOctagonEnable] boolValue] : OctagonIsEnabled();
216 secnotice("octagon", "pairing is %@", nsDefaults ? @"on" : @"off");
217 return nsDefaults;
218 }
219
220 - (void)setPairingDefault:(BOOL)defaults
221 {
222 self.defaults[OTDefaultsOctagonEnable] = @(defaults);
223 }
224
225 - (void)removePairingDefault
226 {
227 [self.defaults removeObjectForKey:OTDefaultsOctagonEnable];
228 }
229
230 - (instancetype)initWithContextData:(OTConfigurationContext *)ctx
231 {
232 #if OCTAGON
233 if ((self = [super init])) {
234 _ctx = [[OTConfigurationContext alloc]init];
235 _ctx.context = ctx.context ?: OTDefaultContext;
236 _ctx.dsid = [ctx.dsid copy];
237 _ctx.altDSID = [ctx.altDSID copy];
238 _ctx.otControl = ctx.otControl;
239 _ctx.ckksControl = ctx.ckksControl;
240 _ctx.overrideEscrowCache = ctx.overrideEscrowCache;
241
242 self.defaults = [NSMutableDictionary dictionary];
243 }
244 return self;
245 #else
246 NSAssert(false, @"OTClique is not implemented on this platform");
247
248 // make the build analyzer happy
249 if ((self = [super init])) {
250 }
251 return self;
252 #endif // OCTAGON
253 }
254
255 - (NSString* _Nullable)cliqueMemberIdentifier
256 {
257 #if OCTAGON
258 __block NSString* retPeerID = nil;
259 __block bool subTaskSuccess = false;
260
261 OctagonSignpost fetchEgoPeerSignPost = OctagonSignpostBegin(OctagonSignpostNameFetchEgoPeer);
262 if(OctagonIsEnabled()) {
263 NSError* localError = nil;
264 OTControl* control = [self makeOTControl:&localError];
265 if(!control) {
266 secerror("octagon: Failed to create OTControl: %@", localError);
267 OctagonSignpostEnd(fetchEgoPeerSignPost, OctagonSignpostNameFetchEgoPeer, OctagonSignpostNumber1(OctagonSignpostNameFetchEgoPeer), (int)subTaskSuccess);
268 return nil;
269 }
270
271 [control fetchEgoPeerID:nil
272 context:self.ctx.context
273 reply:^(NSString* peerID, NSError* error) {
274 if(error) {
275 secerror("octagon: Failed to fetch octagon peer ID: %@", error);
276 }
277 retPeerID = peerID;
278 }];
279 secnotice("clique", "cliqueMemberIdentifier(octagon) received %@", retPeerID);
280 }
281
282 if([OTClique platformSupportsSOS]) {
283 CFErrorRef error = NULL;
284 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(&error);
285 retPeerID = (NSString*)CFBridgingRelease(CFRetainSafe(SOSPeerInfoGetPeerID(me)));
286 CFReleaseNull(me);
287 CFBridgingRelease(error);
288 }
289
290 secnotice("clique", "cliqueMemberIdentifier complete: %@", retPeerID);
291 subTaskSuccess = retPeerID ? true : false;
292 OctagonSignpostEnd(fetchEgoPeerSignPost, OctagonSignpostNameFetchEgoPeer, OctagonSignpostNumber1(OctagonSignpostNameFetchEgoPeer), (int)subTaskSuccess);
293 return retPeerID;
294 #else
295 return nil;
296 #endif
297 }
298
299 #if OCTAGON
300 - (OTControl* _Nullable)makeOTControl:(NSError**)error
301 {
302 return [self.ctx makeOTControl:error];
303 }
304
305 - (BOOL)establish:(NSError**)error
306 {
307 secnotice("clique-establish", "establish started");
308 OctagonSignpost establishSignPost = OctagonSignpostBegin(OctagonSignpostNameEstablish);
309 bool subTaskSuccess = false;
310 OTControl* control = [self makeOTControl:error];
311 if(!control) {
312 OctagonSignpostEnd(establishSignPost, OctagonSignpostNameEstablish, OctagonSignpostNumber1(OctagonSignpostNameEstablish), (int)subTaskSuccess);
313 return false;
314 }
315
316 __block BOOL success = NO;
317 __block NSError* localError = nil;
318
319 //only establish
320 [control establish:nil context:self.ctx.context altDSID:self.ctx.altDSID reply:^(NSError * _Nullable operationError) {
321 if(operationError) {
322 secnotice("clique-establish", "establish returned an error: %@", operationError);
323 }
324 success = operationError == nil;
325 localError = operationError;
326 }];
327
328 if(localError && error) {
329 *error = localError;
330 }
331 secnotice("clique-establish", "establish complete: %@", success ? @"YES" : @"NO");
332 subTaskSuccess = success ? true : false;
333 OctagonSignpostEnd(establishSignPost, OctagonSignpostNameEstablish, OctagonSignpostNumber1(OctagonSignpostNameEstablish), (int)subTaskSuccess);
334
335 return success;
336 }
337
338 - (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error
339 {
340 secnotice("clique-resetandestablish", "resetAndEstablish started");
341 bool subTaskSuccess = false;
342 OctagonSignpost resetAndEstablishSignPost = OctagonSignpostBegin(OctagonSignpostNameResetAndEstablish);
343
344 OTControl* control = [self makeOTControl:error];
345
346 if(!control) {
347 OctagonSignpostEnd(resetAndEstablishSignPost, OctagonSignpostNameResetAndEstablish, OctagonSignpostNumber1(OctagonSignpostNameResetAndEstablish), (int)subTaskSuccess);
348 return NO;
349 }
350
351 __block BOOL success = NO;
352 __block NSError* localError = nil;
353 [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID resetReason:resetReason reply:^(NSError * _Nullable operationError) {
354
355 if(operationError) {
356 secnotice("clique-resetandestablish", "resetAndEstablish returned an error: %@", operationError);
357 }
358 success = operationError == nil;
359 localError = operationError;
360 }];
361
362 if(localError && error) {
363 *error = localError;
364 }
365
366 secnotice("clique-resetandestablish", "establish complete: %@", success ? @"YES" : @"NO");
367 subTaskSuccess = success ? true : false;
368 OctagonSignpostEnd(resetAndEstablishSignPost, OctagonSignpostNameResetAndEstablish, OctagonSignpostNumber1(OctagonSignpostNameResetAndEstablish), (int)subTaskSuccess);
369
370 return success;
371 }
372 #endif // OCTAGON
373
374 + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error
375 {
376 return [OTClique newFriendsWithContextData:data resetReason:CuttlefishResetReasonUserInitiatedReset error:error];
377 }
378
379 + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error
380 {
381 #if OCTAGON
382 secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid);
383 bool result = false;
384 bool subTaskSuccess = false;
385 OctagonSignpost newFriendsSignpost = OctagonSignpostBegin(OctagonSignpostNameMakeNewFriends);
386
387 OTClique* clique = [[OTClique alloc] initWithContextData:data];
388
389 if(OctagonIsEnabled()) {
390 NSError* localError = nil;
391 [clique resetAndEstablish:resetReason error:&localError];
392
393 if(localError) {
394 secnotice("clique-newfriends", "account reset failed: %@", localError);
395 if(error) {
396 *error = localError;
397 }
398 OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
399 return nil;
400 } else {
401 secnotice("clique-newfriends", "Octagon account reset succeeded");
402 }
403 }
404
405 if([OTClique platformSupportsSOS]) {
406 CFErrorRef resetError = NULL;
407 result = SOSCCResetToOffering(&resetError);
408
409 if(!result || resetError){
410 secnotice("clique-newfriends", "newFriendsWithContextData: resetToOffering failed: %@", resetError);
411 if(error) {
412 *error = CFBridgingRelease(resetError);
413 } else {
414 CFBridgingRelease(resetError);
415 }
416 OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
417 return nil;
418 }
419 secnotice("clique-newfriends", "newFriendsWithContextData: reset the SOS circle");
420 } else {
421 secnotice("clique-newfriends", "newFriendsWithContextData: SOS disabled on this platform");
422 }
423 secnotice("clique-newfriends", "makeNewFriends complete");
424
425 subTaskSuccess = true;
426 OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
427
428 return clique;
429
430 #else // !OCTAGON
431 if (error)
432 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
433 return NULL;
434 #endif
435 }
436
437 + (BOOL)isCloudServicesAvailable
438 {
439 #if OCTAGON
440 if (isCloudServicesAvailable()) {
441 return YES;
442 }
443
444 static dispatch_once_t onceToken;
445 dispatch_once(&onceToken, ^{
446 secnotice("octagon", "CloudServices is unavailable on this platform");
447 });
448 return NO;
449 #else
450 return NO;
451 #endif
452 }
453
454 + (OTClique* _Nullable)performEscrowRecoveryWithContextData:(OTConfigurationContext*)data
455 escrowArguments:(NSDictionary*)sbdRecoveryArguments
456 error:(NSError**)error
457 {
458 #if OCTAGON
459 if ([OTClique isCloudServicesAvailable] == NO) {
460 if (error) {
461 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
462 }
463 return nil;
464 }
465
466 OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNamePerformEscrowRecovery);
467 bool subTaskSuccess = false;
468 NSError* localError = nil;
469
470 OTClique* clique = [[OTClique alloc] initWithContextData:data];
471
472 // Attempt the recovery from sbd
473 secnotice("clique-recovery", "attempting an escrow recovery for context:%@, altdsid:%@", data.context, data.altDSID);
474 id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
475 NSDictionary* recoveredInformation = nil;
476
477 OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformRecoveryFromSBD);
478 NSError* recoverError = [sb recoverWithInfo:sbdRecoveryArguments results:&recoveredInformation];
479 subTaskSuccess = (recoverError == nil) ? true : false;
480 OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNamePerformRecoveryFromSBD, OctagonSignpostNumber1(OctagonSignpostNamePerformRecoveryFromSBD), (int)subTaskSuccess);
481
482 if(recoverError) {
483 secnotice("clique-recovery", "sbd escrow recovery failed: %@", recoverError);
484 if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */
485 if([OTClique platformSupportsSOS]) {
486 secnotice("clique-recovery", "Can't restore legacy backup with no keybag. Resetting SOS to offering");
487 CFErrorRef blowItAwayError = NULL;
488 bool successfulReset = SOSCCResetToOffering(&blowItAwayError);
489 if(!successfulReset || blowItAwayError) {
490 secerror("clique-recovery: failed to reset to offering:%@", blowItAwayError);
491 } else {
492 secnotice("clique-recovery", "resetting SOS circle successful");
493 }
494 CFBridgingRelease(blowItAwayError);
495 } else {
496 secnotice("clique-recovery", "Legacy restore failed on a non-SOS platform");
497 }
498 } else {
499 if(error) {
500 *error = recoverError;
501 }
502 subTaskSuccess = false;
503 OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
504 return nil;
505 }
506 } else {
507 if(OctagonPlatformSupportsSOS()) { // Join if the legacy restore is complete now.
508 secnotice("clique-recovery", "attempting joinAfterRestore");
509 [clique joinAfterRestore:&localError];
510 secnotice("clique-recovery", "joinAfterRestore: %@", localError);
511 }
512 }
513
514 // look for OT Bottles
515 OTControl* control = [clique makeOTControl:&localError];
516 if (!control) {
517 secnotice("clique-recovery", "unable to create otcontrol: %@", localError);
518 if (error) {
519 *error = localError;
520 }
521 subTaskSuccess = false;
522 OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
523 return nil;
524 }
525
526 NSString *bottleID = recoveredInformation[@"bottleID"];
527 NSString *isValid = recoveredInformation[@"bottleValid"];
528 NSData *bottledPeerEntropy = recoveredInformation[@"EscrowServiceEscrowData"][@"BottledPeerEntropy"];
529 bool shouldResetOctagon = false;
530
531 if(bottledPeerEntropy && bottleID && [isValid isEqualToString:@"valid"]){
532 secnotice("clique-recovery", "recovering from bottle: %@", bottleID);
533 __block NSError* restoreBottleError = nil;
534
535 OctagonSignpost bottleRecoverySignPost = OctagonSignpostBegin(OctagonSignpostNamePerformOctagonJoin);
536 //restore bottle!
537 [control restore:OTCKContainerName
538 contextID:data.context
539 bottleSalt:data.altDSID
540 entropy:bottledPeerEntropy
541 bottleID:bottleID
542 reply:^(NSError * _Nullable restoreError) {
543 if(restoreError) {
544 secnotice("clique-recovery", "restore bottle errored: %@", restoreError);
545 } else {
546 secnotice("clique-recovery", "restoring bottle succeeded");
547 }
548 restoreBottleError = restoreError;
549 }];
550
551 subTaskSuccess = (restoreBottleError == nil) ? true : false;
552 OctagonSignpostEnd(bottleRecoverySignPost, OctagonSignpostNamePerformOctagonJoin, OctagonSignpostNumber1(OctagonSignpostNamePerformOctagonJoin), (int)subTaskSuccess);
553
554 if(restoreBottleError) {
555 if(error){
556 *error = restoreBottleError;
557 }
558 subTaskSuccess = false;
559 OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
560 return nil;
561 }
562 } else {
563 shouldResetOctagon = true;
564 }
565
566 if(shouldResetOctagon) {
567 secnotice("clique-recovery", "bottle %@ is not valid, resetting octagon", bottleID);
568 NSError* resetError = nil;
569
570 OctagonSignpost resetSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle);
571 [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError];
572 subTaskSuccess = (resetError == nil) ? true : false;
573 OctagonSignpostEnd(resetSignPost, OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle, OctagonSignpostNumber1(OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle), (int)subTaskSuccess);
574
575 if(resetError) {
576 secnotice("clique-recovery", "failed to reset octagon: %@", resetError);
577 if(error){
578 *error = resetError;
579 }
580 OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
581 return nil;
582 } else{
583 secnotice("clique-recovery", "reset octagon succeeded");
584 }
585 }
586
587 secnotice("clique-recovery", "recovery complete: %@", clique);
588
589 subTaskSuccess = clique ? true : false;
590 OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
591
592 return clique;
593 #else
594 if (error) {
595 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
596 }
597 return NULL;
598 #endif
599 }
600
601
602 - (KCPairingChannel *)setupPairingChannelAsInitiator:(KCPairingChannelContext *)ctx
603 {
604 #if OCTAGON
605 return [getKCPairingChannelClass() pairingChannelInitiator:ctx];
606 #else
607 return NULL;
608 #endif
609 }
610
611 - (KCPairingChannel * _Nullable)setupPairingChannelAsInitator:(KCPairingChannelContext *)ctx error:(NSError * __autoreleasing *)error
612 {
613 if (error) {
614 *error = nil;
615 }
616 return [self setupPairingChannelAsInitiator:ctx];
617 }
618
619 - (KCPairingChannel *)setupPairingChannelAsAcceptor:(KCPairingChannelContext *)ctx
620 {
621 #if OCTAGON
622 return [getKCPairingChannelClass() pairingChannelAcceptor:ctx];
623 #else
624 return NULL;
625 #endif
626 }
627
628 - (KCPairingChannel * _Nullable)setupPairingChannelAsAcceptor:(KCPairingChannelContext *)ctx error:(NSError * __autoreleasing *)error
629 {
630 if (error) {
631 *error = nil;
632 }
633
634 return [self setupPairingChannelAsAcceptor:ctx];
635 }
636
637
638 - (CliqueStatus)_fetchCliqueStatus:(OTOperationConfiguration *)configuration error:(NSError * __autoreleasing *)error
639 {
640 #if OCTAGON
641 __block CliqueStatus sosStatus = CliqueStatusError;
642 __block CliqueStatus octagonStatus = CliqueStatusError;
643 bool subTaskSuccess = false;
644
645 OctagonSignpost fetchCliqueStatusSignPost = OctagonSignpostBegin(OctagonSignpostNameFetchCliqueStatus);
646
647 // Octagon is supreme.
648
649 if(OctagonIsEnabled()) {
650 OTControl* control = [self makeOTControl:error];
651 if(!control) {
652 secnotice("clique-status", "cliqueStatus noOTControl");
653 OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess);
654
655 return CliqueStatusError;
656 }
657
658 __block NSError* localError = nil;
659 [control fetchCliqueStatus:nil context:self.ctx.context configuration:configuration reply:^(CliqueStatus cliqueStatus, NSError * _Nullable fetchError) {
660 if(fetchError){
661 octagonStatus = CliqueStatusError;
662 localError = fetchError;
663 secnotice("clique-status", "octagon clique status errored: %@", fetchError);
664 } else {
665 octagonStatus = cliqueStatus;
666 }
667 }];
668
669 if(OctagonAuthoritativeTrustIsEnabled() || !OctagonPlatformSupportsSOS()) {
670 secnotice("clique-status", "cliqueStatus(%{public}scached)(context:%@, altDSID:%@) returning %@ (error: %@)",
671 configuration.useCachedAccountStatus ? "" : "non-",
672 self.ctx.context, self.ctx.altDSID,
673 OTCliqueStatusToString(octagonStatus), localError);
674 if (localError && error) {
675 *error = localError;
676 subTaskSuccess = false;
677 } else {
678 subTaskSuccess = true;
679 }
680 OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess);
681 return octagonStatus;
682 }
683 }
684
685 if([OTClique platformSupportsSOS]) {
686 CFErrorRef circleStatusError = NULL;
687 sosStatus = kSOSCCError;
688 if(configuration.useCachedAccountStatus){
689 sosStatus = SOSCCThisDeviceIsInCircle(&circleStatusError);
690 } else {
691 sosStatus = SOSCCThisDeviceIsInCircleNonCached(&circleStatusError);
692 }
693 secnotice("clique-status", "sos clique status is %d (%@)", (int)sosStatus, circleStatusError);
694
695 if (error) {
696 *error = (NSError*)CFBridgingRelease(circleStatusError);
697 } else {
698 CFBridgingRelease(circleStatusError);
699 }
700 }
701 secnotice("clique-status", "cliqueStatus(%{public}scached)(context:%@, altDSID:%@) complete: %@",
702 configuration.useCachedAccountStatus ? "" : "non-",
703 self.ctx.context, self.ctx.altDSID,
704 OTCliqueStatusToString(octagonStatus));
705
706 subTaskSuccess = true;
707 OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess);
708
709 return octagonStatus;
710 #else // !OCTAGON
711 if(error){
712 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
713 }
714 return (CliqueStatus)kSOSCCError;
715 #endif
716 }
717
718 // Don't change rules for CoreCDP, and preserve legacy behavior for now
719 // preserve old behavior until CoreCDP can move to -fetchCliqueStatus:error:
720 #define LEGACY_WAITING_BEHAVIOR (TARGET_OS_OSX || TARGET_OS_IOS)
721
722 - (CliqueStatus)fetchCliqueStatus:(OTOperationConfiguration *)configuration error:(NSError * __autoreleasing * _Nonnull)error
723 {
724 return [self _fetchCliqueStatus:configuration error:error];
725 }
726
727 - (CliqueStatus)fetchCliqueStatus:(NSError * __autoreleasing *)error
728 {
729 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
730 #if LEGACY_WAITING_BEHAVIOR
731 configuration.timeoutWaitForCKAccount = 0;
732 #endif
733 return [self _fetchCliqueStatus:configuration error:error];
734 }
735
736 - (CliqueStatus)cachedCliqueStatus:(BOOL)usedCached error:(NSError * __autoreleasing *)error
737 {
738 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
739 #if LEGACY_WAITING_BEHAVIOR
740 configuration.timeoutWaitForCKAccount = 0;
741 #endif
742 if (usedCached) {
743 configuration.useCachedAccountStatus = YES;
744 }
745 return [self _fetchCliqueStatus:configuration error:error];
746 }
747
748
749 - (BOOL)removeFriendsInClique:(NSArray<NSString*>*)friendIdentifiers error:(NSError * __autoreleasing *)error
750 {
751 #if OCTAGON
752 secnotice("clique-removefriends", "removeFriendsInClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
753 OctagonSignpost removeFriendsSignPost = OctagonSignpostBegin(OctagonSignpostNameRemoveFriendsInClique);
754 bool subTaskSuccess = false;
755
756 // Annoying: we must sort friendIdentifiers into octagon/sos lists.
757 NSMutableArray<NSString*>* octagonIdentifiers = [NSMutableArray array];
758 NSMutableArray<NSString*>* sosIdentifiers = [NSMutableArray array];
759
760 for(NSString* friendIdentifier in friendIdentifiers) {
761 if([friendIdentifier hasPrefix:@"SHA256:"]) {
762 [octagonIdentifiers addObject: friendIdentifier];
763 } else {
764 [sosIdentifiers addObject: friendIdentifier];
765 }
766 }
767
768 // Ensure that we don't have any peers on the wrong platform
769 if(!OctagonIsEnabled() && octagonIdentifiers.count > 0) {
770 NSError *localError = [NSError errorWithDomain:NSOSStatusErrorDomain
771 code:errSecUnimplemented
772 userInfo:@{NSLocalizedDescriptionKey: @"Octagon is disabled; can't distrust any Octagon peers"}];
773 secnotice("clique-removefriends", "removeFriendsInClique failed:%@", localError);
774 if(error) {
775 *error = localError;
776 }
777 OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess);
778 return NO;
779 }
780
781 if(!OctagonPlatformSupportsSOS() && sosIdentifiers.count > 0) {
782 NSError *localError = [NSError errorWithDomain:NSOSStatusErrorDomain
783 code:errSecUnimplemented
784 userInfo:@{NSLocalizedDescriptionKey: @"SOS is not available on this platform; can't distrust any SOS peers"}];
785 secnotice("clique-removefriends", "removeFriendsInClique failed:%@", localError);
786 if(error) {
787 *error = localError;
788 }
789 OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess);
790 return NO;
791 }
792
793
794 __block NSError* localError = nil;
795 bool result = true;
796
797 if(OctagonIsEnabled() && octagonIdentifiers.count > 0) {
798 OTControl* control = [self makeOTControl:error];
799 if(!control) {
800 OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess);
801 return NO;
802 }
803
804 secnotice("clique-removefriends", "octagon: removing octagon friends: %@", octagonIdentifiers);
805 [control removeFriendsInClique:nil
806 context:self.ctx.context
807 peerIDs:octagonIdentifiers
808 reply:^(NSError* replyError) {
809 if(replyError) {
810 secnotice("clique-removefriends", "removeFriendsInClique failed: unable to remove friends: %@", replyError);
811 localError = replyError;
812 } else {
813 secnotice("clique-removefriends", "octagon: friends removed: %@", octagonIdentifiers);
814 }
815 }];
816 }
817
818 if([OTClique platformSupportsSOS] && sosIdentifiers.count >0) {
819 CFErrorRef removeFriendError = NULL;
820
821 secnotice("clique-removefriends", "removing sos friends: %@", sosIdentifiers);
822 result = SOSCCRemovePeersFromCircle((__bridge CFArrayRef)friendIdentifiers, &removeFriendError);
823
824 if(removeFriendError) {
825 secnotice("clique-removefriends", "removeFriendsInClique failed: unable to remove friends: %@", removeFriendError);
826 localError = CFBridgingRelease(removeFriendError);
827 }
828 }
829
830 if(error && localError) {
831 *error = localError;
832 }
833 secnotice("clique-removefriends", "removeFriendsInClique complete: %d", result);
834
835 subTaskSuccess = result;
836 OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess);
837
838 return result && localError == nil;
839 #else // !OCTAGON
840 return NO;
841 #endif
842 }
843
844 - (BOOL)leaveClique:(NSError * __autoreleasing *)error
845 {
846 #if OCTAGON
847 secnotice("clique-leaveClique", "leaveClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
848 CFErrorRef removeThisDeviceError = NULL;
849 bool result = false;
850 bool subTaskSuccess = false;
851
852 OctagonSignpost leaveCliqueSignPost = OctagonSignpostBegin(OctagonSignpostNameLeaveClique);
853
854 if(OctagonIsEnabled()) {
855 OTControl* control = [self makeOTControl:error];
856 if(!control) {
857 OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess);
858 return NO;
859 }
860
861 // We only want to issue a "leave" command if we're actively in a clique
862 __block NSError* localError = nil;
863 CliqueStatus currentStatus = [self fetchCliqueStatus:[[OTOperationConfiguration alloc] init]
864 error:&localError];
865
866 if(localError) {
867 secnotice("clique-leaveClique", "fetching current status errored: %@", localError);
868 if(error) {
869 *error = localError;
870 }
871 OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess);
872 return NO;
873 }
874
875 if(currentStatus == CliqueStatusNotIn) {
876 secnotice("clique-leaveClique", "current status is Not In; no need to leave");
877 subTaskSuccess = true;
878 OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess);
879 return YES;
880 }
881 [control leaveClique:nil context:self.ctx.context reply:^(NSError * _Nullable leaveError) {
882 if(leaveError) {
883 secnotice("clique-leaveClique", "leaveClique errored: %@", leaveError);
884 localError = leaveError;
885 } else {
886 secnotice("clique-leaveClique", "leaveClique success.");
887 }
888 }];
889
890 if(error) {
891 *error = localError;
892 }
893 result = !localError;
894 }
895
896 if([OTClique platformSupportsSOS]) {
897 result &= SOSCCRemoveThisDeviceFromCircle(&removeThisDeviceError);
898 if (error) {
899 *error = (NSError*)CFBridgingRelease(removeThisDeviceError);
900 } else {
901 CFBridgingRelease(removeThisDeviceError);
902 }
903 }
904 secnotice("clique-leaveClique", "leaveClique complete: %d", result);
905
906 subTaskSuccess = result;
907 OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess);
908
909 return result ? YES : NO;
910 #else // !OCTAGON
911 return NO;
912 #endif
913 }
914
915 - (NSDictionary<NSString*,NSString*>* _Nullable)peerDeviceNamesByPeerID:(NSError * __autoreleasing *)error
916 {
917 #if OCTAGON
918 secnotice("clique", "peerDeviceNamesByPeerID invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
919 OctagonSignpost peerNamesSignPost = OctagonSignpostBegin(OctagonSignpostNamePeerDeviceNamesByPeerID);
920 __block bool subTaskSuccess = false;
921 NSMutableDictionary<NSString*, NSString*>* retPeers = [NSMutableDictionary dictionary];
922
923 if(OctagonIsEnabled()) {
924 OTControl* control = [self makeOTControl:error];
925 if(!control) {
926 OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess);
927 return nil;
928 }
929
930 __block NSError* localError = nil;
931 __block NSDictionary<NSString*, NSString*>* localPeers = nil;
932
933 [control peerDeviceNamesByPeerID:nil context:OTDefaultContext reply:^(NSDictionary<NSString*,NSString*>* peers, NSError* controlError) {
934 if(controlError) {
935 secnotice("clique", "peerDeviceNamesByPeerID errored: %@", controlError);
936 } else {
937 secnotice("clique", "peerDeviceNamesByPeerID succeeded: %@", peers);
938 }
939 localError = controlError;
940 localPeers = peers;
941 }];
942
943 if(error && localError) {
944 *error = localError;
945 }
946 if(localError) {
947 OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess);
948 return nil;
949 }
950 [retPeers addEntriesFromDictionary:localPeers];
951 secnotice("clique", "Received %lu Octagon peers", (unsigned long)localPeers.count);
952 }
953
954 if([OTClique platformSupportsSOS]) {
955 CFErrorRef peerErrorRef = NULL;
956 NSMutableDictionary<NSString*,NSString*>* peerMapping = [NSMutableDictionary dictionary];
957 NSArray* arrayOfPeerRefs = CFBridgingRelease(SOSCCCopyPeerPeerInfo(&peerErrorRef));
958 if(arrayOfPeerRefs){
959 [arrayOfPeerRefs enumerateObjectsUsingBlock:^(id peerRef, NSUInteger idx, BOOL * stop) {
960 SOSPeerInfoRef peer = (__bridge SOSPeerInfoRef)peerRef;
961 if(peer){
962 [peerMapping setObject:(__bridge NSString*)SOSPeerInfoGetPeerName(peer) forKey:(__bridge NSString*)SOSPeerInfoGetPeerID(peer)];
963 }
964 }];
965 }
966 subTaskSuccess = (peerErrorRef == NULL || [retPeers count] == 0) ? true : false;
967
968 if (error) {
969 *error = (NSError*)CFBridgingRelease(peerErrorRef);
970 } else {
971 CFBridgingRelease(peerErrorRef);
972 }
973 [retPeers addEntriesFromDictionary:peerMapping];
974 secnotice("clique", "Received %lu SOS peers", (unsigned long)peerMapping.count);
975 }
976
977 OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess);
978 return retPeers;
979 #else // !OCTAGON
980 return NULL;
981 #endif
982 }
983
984 - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error
985 {
986 secnotice("clique-recovery", "joinAfterRestore for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
987 OctagonSignpost joinAfterRestoreSignPost = OctagonSignpostBegin(OctagonSignpostNameJoinAfterRestore);
988 bool subTaskSuccess = false;
989
990 if([OTClique platformSupportsSOS]) {
991 CFErrorRef restoreError = NULL;
992 bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError);
993 if (error) {
994 *error = (NSError*)CFBridgingRelease(restoreError);
995 } else {
996 CFBridgingRelease(restoreError);
997 }
998 secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided");
999
1000 subTaskSuccess = res;
1001 OctagonSignpostEnd(joinAfterRestoreSignPost, OctagonSignpostNameJoinAfterRestore, OctagonSignpostNumber1(OctagonSignpostNameJoinAfterRestore), (int)subTaskSuccess);
1002
1003 return res ? YES : NO;
1004 } else {
1005 secnotice("clique-recovery", "SOS disabled for this platform, returning NO");
1006 if(error){
1007 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1008 code:errSecUnimplemented
1009 userInfo:@{NSLocalizedDescriptionKey: @"join after restore unimplemented"}];
1010 }
1011 OctagonSignpostEnd(joinAfterRestoreSignPost, OctagonSignpostNameJoinAfterRestore, OctagonSignpostNumber1(OctagonSignpostNameJoinAfterRestore), (int)subTaskSuccess);
1012 return NO;
1013 }
1014 }
1015
1016 - (BOOL)safariPasswordSyncingEnabled:(NSError **)error
1017 {
1018 return [self fetchUserControllableViewsSyncingEnabled:error];
1019 }
1020
1021 - (BOOL)sosSafariPasswordSyncingEnabled:(NSError **)error
1022 {
1023 secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1024 OctagonSignpost safariSyncingEnabledSignPost = OctagonSignpostBegin(OctagonSignpostNameSafariPasswordSyncingEnabled);
1025 bool subTaskSuccess = false;
1026
1027 if([OTClique platformSupportsSOS]) {
1028 CFErrorRef viewErrorRef = NULL;
1029
1030 SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef);
1031 subTaskSuccess = (viewErrorRef == NULL) ? true : false;
1032
1033 BOOL viewMember = result == kSOSCCViewMember;
1034 if (error) {
1035 *error = (NSError*)CFBridgingRelease(viewErrorRef);
1036 } else {
1037 CFBridgingRelease(viewErrorRef);
1038 }
1039 OctagonSignpostEnd(safariSyncingEnabledSignPost, OctagonSignpostNameSafariPasswordSyncingEnabled, OctagonSignpostNumber1(OctagonSignpostNameSafariPasswordSyncingEnabled), (int)subTaskSuccess);
1040
1041 secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO");
1042 return viewMember;
1043 } else {
1044 secnotice("clique-safari", "SOS disabled for this platform, returning NO");
1045 if(error){
1046 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1047 code:errSecUnimplemented
1048 userInfo:@{NSLocalizedDescriptionKey: @"safari password syncing enabled unimplemented"}];
1049 }
1050 OctagonSignpostEnd(safariSyncingEnabledSignPost, OctagonSignpostNameSafariPasswordSyncingEnabled, OctagonSignpostNumber1(OctagonSignpostNameSafariPasswordSyncingEnabled), (int)subTaskSuccess);
1051 return NO;
1052 }
1053 }
1054
1055 - (BOOL)setUserControllableViewsSyncStatus:(BOOL)enabled
1056 error:(NSError* __autoreleasing *)error
1057 {
1058 if([OTClique platformSupportsSOS]) {
1059 // We either enable or disable this list of SOS views, taken from CDP.
1060 NSSet<NSString*>* sosViews = [NSSet setWithObjects:(__bridge id)kSOSViewWiFi,
1061 (__bridge id)kSOSViewAutofillPasswords,
1062 (__bridge id)kSOSViewSafariCreditCards,
1063 (__bridge id)kSOSViewOtherSyncable,
1064 nil];
1065
1066 BOOL sosResult = NO;
1067 if(enabled) {
1068 sosResult = [self sosViewSet:sosViews disabledViews:[NSSet set]];
1069 } else {
1070 sosResult = [self sosViewSet:[NSSet set] disabledViews:sosViews];
1071 }
1072
1073 if(sosResult == NO) {
1074 secnotice("clique-user-sync", "SOS view setting failed, but no error returned");
1075 if(error) {
1076 *error = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain
1077 code:kSOSErrorNotReady
1078 userInfo:@{
1079 NSLocalizedDescriptionKey: @"SOS reported failure, but no error given"
1080 }];
1081 }
1082
1083 return NO;
1084 }
1085 }
1086
1087 if(OctagonIsEnabled()) {
1088 return [self setOctagonUserControllableViewsSyncEnabled:enabled
1089 error:error];
1090 }
1091
1092 return YES;
1093 }
1094
1095 - (BOOL)setOctagonUserControllableViewsSyncEnabled:(BOOL)enabled
1096 error:(NSError* __autoreleasing *)error
1097 {
1098 #if OCTAGON
1099 OTControl* control = [self makeOTControl:error];
1100 if(!control) {
1101 return NO;
1102 }
1103
1104 __block NSError* localError = nil;
1105
1106 secnotice("clique-user-sync", "setting user-controllable-sync status to %@", enabled ? @"enabled" : @"paused");
1107
1108 [control setUserControllableViewsSyncStatus:self.ctx.containerName
1109 contextID:self.ctx.context
1110 enabled:enabled
1111 reply:^(BOOL nowSyncing, NSError* _Nullable fetchError) {
1112 if(fetchError) {
1113 secnotice("clique-user-sync", "setting user-controllable-sync status errored: %@", fetchError);
1114 localError = fetchError;
1115 } else {
1116 secnotice("clique-user-sync", "setting user-controllable-sync status succeeded, now : %@", nowSyncing ? @"enabled" : @"paused");
1117 }
1118 }];
1119
1120 if(error && localError) {
1121 *error = localError;
1122 }
1123
1124 return localError == nil;
1125 #else
1126 if(error) {
1127 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1128 code:errSecUnimplemented
1129 userInfo:@{NSLocalizedDescriptionKey: @"setOctagonUserControllableViewSync unimplemented on this platform"}];
1130 }
1131 return NO;
1132 #endif
1133 }
1134
1135 - (BOOL)fetchUserControllableViewsSyncingEnabled:(NSError* __autoreleasing *)error
1136 {
1137 if(!OctagonIsEnabled() && ![OTClique platformSupportsSOS]) {
1138 secnotice("clique-user-sync", "No syncing platforms enabled; views are not syncing");
1139 return NO;
1140 }
1141
1142 __block BOOL octagonSyncing = NO;
1143 #if OCTAGON
1144 if(OctagonIsEnabled()) {
1145 OTControl* control = [self makeOTControl:error];
1146 if(!control) {
1147 return NO;
1148 }
1149
1150 __block NSError* localError = nil;
1151 [control fetchUserControllableViewsSyncStatus:self.ctx.containerName
1152 contextID:self.ctx.context
1153 reply:^(BOOL nowSyncing, NSError* _Nullable fetchError) {
1154 if(fetchError) {
1155 secnotice("clique-user-sync", "fetching user-controllable-sync status errored: %@", fetchError);
1156 } else {
1157 secnotice("clique-user-sync", "fetched user-controllable-sync status as : %@", nowSyncing ? @"enabled" : @"paused");
1158 }
1159 octagonSyncing = nowSyncing;
1160 localError = fetchError;
1161 }];
1162
1163 if(localError) {
1164 if(error) {
1165 *error = localError;
1166 }
1167 return octagonSyncing;
1168 }
1169 }
1170 #endif
1171
1172 BOOL sosSafariEnabled = NO;
1173 if([OTClique platformSupportsSOS]) {
1174 NSError* localError = nil;
1175 sosSafariEnabled = [self sosSafariPasswordSyncingEnabled:&localError];
1176
1177 if(localError) {
1178 if(error) {
1179 *error = localError;
1180 }
1181 return sosSafariEnabled;
1182 }
1183 }
1184
1185 if(OctagonIsEnabled() && [OTClique platformSupportsSOS]) {
1186 // Return the OR of this value, so that the UI checkbox will be on if any syncing is occurring
1187 return octagonSyncing || sosSafariEnabled;
1188
1189 } else if(OctagonIsEnabled() && ![OTClique platformSupportsSOS]) {
1190 return octagonSyncing;
1191
1192 } else if(!OctagonIsEnabled()&& [OTClique platformSupportsSOS]) {
1193 return sosSafariEnabled;
1194
1195 } else {
1196 // Should be impossible, due to the check above. So:
1197 if(error) {
1198 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1199 code:errSecUnimplemented
1200 userInfo:@{NSLocalizedDescriptionKey: @"fetchUserControllableViewsSyncingEnabled has no meaning if all sync systems are not on this platform"}];
1201 }
1202 return NO;
1203 }
1204 }
1205
1206
1207 - (BOOL)isLastFriend:(NSError **)error
1208 {
1209 secnotice("clique-isLastFriend", "is last friend");
1210 return NO;
1211 }
1212
1213 - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error
1214 {
1215 secnotice("clique-legacy", "waitForInitialSync for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1216
1217 OctagonSignpost waitForInitialSyncSignPost = OctagonSignpostBegin(OctagonSignpostNameWaitForInitialSync);
1218 bool subTaskSuccess = false;
1219
1220 if([OTClique platformSupportsSOS]) {
1221 CFErrorRef initialSyncErrorRef = NULL;
1222 BOOL initialSyncResult = SOSCCWaitForInitialSync(&initialSyncErrorRef) ? YES : NO;
1223
1224 if (error) {
1225 *error = (NSError*)CFBridgingRelease(initialSyncErrorRef);
1226 } else {
1227 CFBridgingRelease(initialSyncErrorRef);
1228 }
1229 secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided");
1230
1231 subTaskSuccess = initialSyncResult ? true : false;
1232 OctagonSignpostEnd(waitForInitialSyncSignPost, OctagonSignpostNameWaitForInitialSync, OctagonSignpostNumber1(OctagonSignpostNameWaitForInitialSync), (int)subTaskSuccess);
1233
1234 return initialSyncResult;
1235 } else {
1236 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1237 if(error){
1238 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1239 code:errSecUnimplemented
1240 userInfo:@{NSLocalizedDescriptionKey: @"wait for initial sync unimplemented"}];
1241 }
1242 OctagonSignpostEnd(waitForInitialSyncSignPost, OctagonSignpostNameWaitForInitialSync, OctagonSignpostNumber1(OctagonSignpostNameWaitForInitialSync), (int)subTaskSuccess);
1243 return NO;
1244 }
1245 }
1246
1247 - (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error
1248 {
1249 secnotice("clique-legacy", "copyViewUnawarePeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1250
1251 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameCopyViewUnawarePeerInfo);
1252 bool subTaskSuccess = false;
1253
1254 if([OTClique platformSupportsSOS]) {
1255 CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL;
1256 CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(&copyViewUnawarePeerInfoErrorRef);
1257
1258 NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil);
1259 if (error) {
1260 *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef);
1261 } else {
1262 CFBridgingRelease(copyViewUnawarePeerInfoErrorRef);
1263 }
1264 subTaskSuccess = (peerList != nil) ? true : false;
1265 OctagonSignpostEnd(signPost, OctagonSignpostNameCopyViewUnawarePeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyViewUnawarePeerInfo), (int)subTaskSuccess);
1266
1267 return peerList;
1268 } else {
1269 secnotice("clique-legacy", "SOS disabled for this platform, returning NULL");
1270 if(error){
1271 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1272 code:errSecUnimplemented
1273 userInfo:@{NSLocalizedDescriptionKey: @"copy view unaware peer info unimplemented"}];
1274 }
1275 OctagonSignpostEnd(signPost, OctagonSignpostNameCopyViewUnawarePeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyViewUnawarePeerInfo), (int)subTaskSuccess);
1276 return nil;
1277 }
1278 }
1279
1280 - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
1281 {
1282 if(OctagonIsEnabled()) {
1283 bool enableUserViews = [enabledViews containsObject:(__bridge NSString*)kSOSViewAutofillPasswords];
1284 NSError* octagonError = nil;
1285 // This function should log its success or failure
1286 BOOL result = [self setOctagonUserControllableViewsSyncEnabled:enableUserViews error:&octagonError];
1287 if(!result) {
1288 return NO;
1289 }
1290 }
1291
1292 return [self sosViewSet:enabledViews disabledViews:disabledViews];
1293 }
1294
1295 - (BOOL)sosViewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
1296 {
1297 secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@ enable:%@, disable:%@",
1298 self.ctx.context, self.ctx.altDSID, enabledViews, disabledViews);
1299 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameViewSet);
1300 bool subTaskSuccess = false;
1301
1302 if([OTClique platformSupportsSOS]) {
1303 bool result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews);
1304
1305 BOOL viewSetResult = result ? YES : NO;
1306 subTaskSuccess = result;
1307 OctagonSignpostEnd(signPost, OctagonSignpostNameViewSet, OctagonSignpostNumber1(OctagonSignpostNameViewSet), (int)subTaskSuccess);
1308 return viewSetResult;
1309 } else {
1310 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1311 OctagonSignpostEnd(signPost, OctagonSignpostNameViewSet, OctagonSignpostNumber1(OctagonSignpostNameViewSet), (int)subTaskSuccess);
1312 return NO;
1313 }
1314 }
1315
1316 - (BOOL)setUserCredentialsAndDSID:(NSString*)userLabel
1317 password:(NSData*)userPassword
1318 error:(NSError *__autoreleasing*)error
1319 {
1320 secnotice("clique-legacy", "setUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1321 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameSetUserCredentialsAndDSID);
1322 bool subTaskSuccess = false;
1323
1324 if([OTClique platformSupportsSOS]) {
1325 CFErrorRef setCredentialsErrorRef = NULL;
1326 bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
1327 (__bridge CFDataRef)userPassword,
1328 (__bridge CFStringRef)self.ctx.dsid,
1329 &setCredentialsErrorRef);
1330
1331 BOOL setCredentialsResult = result ? YES : NO;
1332 secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef);
1333 if (error) {
1334 *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef);
1335 } else {
1336 CFBridgingRelease(setCredentialsErrorRef);
1337 }
1338 subTaskSuccess = result;
1339 OctagonSignpostEnd(signPost, OctagonSignpostNameSetUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameSetUserCredentialsAndDSID), (int)subTaskSuccess);
1340
1341 return setCredentialsResult;
1342 } else {
1343 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1344 if(error){
1345 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1346 code:errSecUnimplemented
1347 userInfo:@{NSLocalizedDescriptionKey: @"set user credentials unimplemented"}];
1348 }
1349 OctagonSignpostEnd(signPost, OctagonSignpostNameSetUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameSetUserCredentialsAndDSID), (int)subTaskSuccess);
1350 return NO;
1351 }
1352 }
1353
1354 - (BOOL)tryUserCredentialsAndDSID:(NSString*)userLabel
1355 password:(NSData*)userPassword
1356 error:(NSError *__autoreleasing*)error
1357 {
1358 secnotice("clique-legacy", "tryUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1359 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameTryUserCredentialsAndDSID);
1360 bool subTaskSuccess = false;
1361
1362 if([OTClique platformSupportsSOS]) {
1363 CFErrorRef tryCredentialsErrorRef = NULL;
1364 bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
1365 (__bridge CFDataRef)userPassword,
1366 (__bridge CFStringRef)self.ctx.dsid,
1367 &tryCredentialsErrorRef);
1368
1369 BOOL tryCredentialsResult = result ? YES : NO;
1370 secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef);
1371 if (error) {
1372 *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef);
1373 } else {
1374 CFBridgingRelease(tryCredentialsErrorRef);
1375 }
1376 subTaskSuccess = result;
1377 OctagonSignpostEnd(signPost, OctagonSignpostNameTryUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameTryUserCredentialsAndDSID), (int)subTaskSuccess);
1378 return tryCredentialsResult;
1379
1380 } else {
1381 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1382 if(error){
1383 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1384 code:errSecUnimplemented
1385 userInfo:@{NSLocalizedDescriptionKey: @"try user credentials unimplemented"}];
1386 }
1387 OctagonSignpostEnd(signPost, OctagonSignpostNameTryUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameTryUserCredentialsAndDSID), (int)subTaskSuccess);
1388 return NO;
1389 }
1390 }
1391
1392 - (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error
1393 {
1394 secnotice("clique-legacy", "copyPeerPeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1395 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameCopyPeerPeerInfo);
1396 bool subTaskSuccess = false;
1397
1398 if([OTClique platformSupportsSOS]) {
1399 CFErrorRef copyPeerErrorRef = NULL;
1400 CFArrayRef result = SOSCCCopyPeerPeerInfo(&copyPeerErrorRef);
1401
1402 NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil);
1403
1404 secnotice("clique-legacy", "copyPeerPeerInfo results: %@ (%@)", peerList, copyPeerErrorRef);
1405 if (error) {
1406 *error = (NSError*)CFBridgingRelease(copyPeerErrorRef);
1407 } else {
1408 CFBridgingRelease(copyPeerErrorRef);
1409 }
1410 subTaskSuccess = (peerList != nil) ? true : false;
1411 OctagonSignpostEnd(signPost, OctagonSignpostNameCopyPeerPeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyPeerPeerInfo), (int)subTaskSuccess);
1412 return peerList;
1413 } else {
1414 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1415 if(error){
1416 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1417 code:errSecUnimplemented
1418 userInfo:@{NSLocalizedDescriptionKey: @"copy peer peer info unimplemented"}];
1419 }
1420 OctagonSignpostEnd(signPost, OctagonSignpostNameCopyPeerPeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyPeerPeerInfo), (int)subTaskSuccess);
1421 return nil;
1422 }
1423 }
1424
1425 - (BOOL)peersHaveViewsEnabled:(NSArray<NSString*>*)viewNames error:(NSError *__autoreleasing*)error
1426 {
1427 secnotice("clique-legacy", "peersHaveViewsEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1428 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNamePeersHaveViewsEnabled);
1429 bool subTaskSuccess = false;
1430
1431 if([OTClique platformSupportsSOS]) {
1432 CFErrorRef viewsEnabledErrorRef = NULL;
1433 BOOL viewsEnabledResult = NO;
1434
1435 CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef);
1436 if(result){
1437 viewsEnabledResult = CFBooleanGetValue(result) ? YES : NO;
1438 }
1439 secnotice("clique-legacy", "peersHaveViewsEnabled results: %@ (%@)", viewsEnabledResult ? @"YES" : @"NO",
1440 viewsEnabledErrorRef);
1441 if (error) {
1442 *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef);
1443 } else {
1444 CFBridgingRelease(viewsEnabledErrorRef);
1445 }
1446 subTaskSuccess = viewsEnabledResult ? true : false;
1447 OctagonSignpostEnd(signPost, OctagonSignpostNamePeersHaveViewsEnabled, OctagonSignpostNumber1(OctagonSignpostNamePeersHaveViewsEnabled), (int)subTaskSuccess);
1448 return viewsEnabledResult;
1449 } else {
1450 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1451 if(error){
1452 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1453 code:errSecUnimplemented
1454 userInfo:@{NSLocalizedDescriptionKey: @"peers have views enabled unimplemented"}];
1455 }
1456 OctagonSignpostEnd(signPost, OctagonSignpostNamePeersHaveViewsEnabled, OctagonSignpostNumber1(OctagonSignpostNamePeersHaveViewsEnabled), (int)subTaskSuccess);
1457 return NO;
1458 }
1459 }
1460
1461 - (BOOL)requestToJoinCircle:(NSError *__autoreleasing*)error
1462 {
1463 bool result = false;
1464 bool subTaskSuccess = false;
1465 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameRequestToJoinCircle);
1466
1467 #if OCTAGON
1468 secnotice("clique-legacy", "requestToJoinCircle for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1469
1470 if(OctagonIsEnabled()) {
1471 // Sometimes, CoreCDP calls this to cause a circle creation to occur.
1472 // So, for Octagon, we might want to request a establish, but not a reset.
1473
1474 // Fetch the current trust status, so we know if we should fire off the establish.
1475 NSError* localError = nil;
1476 CliqueStatus status = [self fetchCliqueStatus: &localError];
1477
1478 if(localError) {
1479 secnotice("clique-legacy", "fetching clique status failed: %@", localError);
1480 if(error) {
1481 *error = localError;
1482 }
1483 OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess);
1484 return NO;
1485 }
1486
1487 if(status == CliqueStatusAbsent) {
1488 secnotice("clique-legacy", "clique status is %@; beginning an establish", OTCliqueStatusToString(status));
1489 [self establish:&localError];
1490
1491 if(localError) {
1492 if(error) {
1493 *error = localError;
1494 }
1495 OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess);
1496 return NO;
1497 } else {
1498 secnotice("clique-legacy", "establish succeeded");
1499 }
1500 } else {
1501 secnotice("clique-legacy", "clique status is %@; performing no Octagon actions", OTCliqueStatusToString(status));
1502 }
1503
1504 // If we didn't early-exit, and we aren't going to invoke SOS below, we succeeded.
1505 if(!OctagonPlatformSupportsSOS()) {
1506 secnotice("clique-legacy", "requestToJoinCircle platform does not support SOS");
1507 subTaskSuccess = true;
1508 OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess);
1509 return YES;
1510 }
1511 }
1512 #endif // OCTAGON
1513
1514 if([OTClique platformSupportsSOS]) {
1515 CFErrorRef joinErrorRef = NULL;
1516 result = SOSCCRequestToJoinCircle(&joinErrorRef);
1517 secnotice("clique-legacy", "sos requestToJoinCircle complete: %d %@", result, joinErrorRef);
1518 if (error) {
1519 *error = (NSError*)CFBridgingRelease(joinErrorRef);
1520 } else {
1521 CFBridgingRelease(joinErrorRef);
1522 }
1523 }
1524
1525 subTaskSuccess = result;
1526 OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess);
1527
1528 return result ? YES : NO;
1529 }
1530
1531 - (BOOL)accountUserKeyAvailable
1532 {
1533 secnotice("clique-legacy", "accountUserKeyAvailable for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1534 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameAccountUserKeyAvailable);
1535 bool subTaskSuccess = false;
1536
1537 if([OTClique platformSupportsSOS]) {
1538 BOOL canAuthenticate = SOSCCCanAuthenticate(NULL) ? YES : NO;
1539 if (canAuthenticate == NO) {
1540 secnotice("clique-legacy", "Security requires credentials...");
1541 }
1542 subTaskSuccess = canAuthenticate ? true : false;
1543 OctagonSignpostEnd(signPost, OctagonSignpostNameAccountUserKeyAvailable, OctagonSignpostNumber1(OctagonSignpostNameAccountUserKeyAvailable), (int)subTaskSuccess);
1544 return canAuthenticate;
1545 } else {
1546 secnotice("clique-legacy", "SOS disabled for this platform, returning NO");
1547 OctagonSignpostEnd(signPost, OctagonSignpostNameAccountUserKeyAvailable, OctagonSignpostNumber1(OctagonSignpostNameAccountUserKeyAvailable), (int)subTaskSuccess);
1548 return NO;
1549 }
1550 }
1551
1552 + (NSArray<NSData*>* _Nullable)fetchEscrowRecordsInternal:(OTConfigurationContext*)configurationContext
1553 error:(NSError**)error
1554 {
1555 #if OCTAGON
1556 secnotice("clique-fetchrecords", "fetching escrow records for context:%@, altdsid:%@", configurationContext.context, configurationContext.altDSID);
1557
1558 if(OctagonIsEnabled()) {
1559 __block NSError* localError = nil;
1560 __block NSArray<NSData*>* localRecords = nil;
1561
1562 OTControl *control = [configurationContext makeOTControl:&localError];
1563 if (!control) {
1564 secnotice("clique-fetchrecords", "unable to create otcontrol: %@", localError);
1565 if (error) {
1566 *error = localError;
1567 }
1568 return nil;
1569 }
1570 [control fetchEscrowRecords:OTCKContainerName
1571 contextID:configurationContext.context
1572 forceFetch:configurationContext.overrideEscrowCache
1573 reply:^(NSArray<NSData *> * _Nullable records,
1574 NSError * _Nullable fetchError) {
1575 if(fetchError) {
1576 secnotice("clique-fetchrecords", "fetchEscrowRecords errored: %@", fetchError);
1577 } else {
1578 secnotice("clique-fetchrecords", "fetchEscrowRecords succeeded: %@", records);
1579 }
1580 localError = fetchError;
1581 localRecords = records;
1582 }];
1583
1584 if(error && localError) {
1585 *error = localError;
1586 }
1587
1588 secnotice("clique-fetchrecords", "fetchEscrowRecords complete");
1589
1590 return localRecords;
1591 } else {
1592 // With octagon off, fail with 'unimplemented'
1593 if(error) {
1594 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1595 code:errSecUnimplemented
1596 userInfo:@{NSLocalizedDescriptionKey: @"fetching escrow records unimplemented"}];
1597 }
1598 return nil;
1599 }
1600 #else // !OCTAGON
1601 if (error) {
1602 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1603 }
1604 return NULL;
1605 #endif
1606 }
1607
1608 // MARK: SBD interfaces
1609 + (OTBottleIDs* _Nullable)findOptimalBottleIDsWithContextData:(OTConfigurationContext*)data
1610 error:(NSError**)error
1611 {
1612 #if OCTAGON
1613 secnotice("clique-findbottle", "finding optimal bottles for context:%@, altdsid:%@", data.context, data.altDSID);
1614 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameFindOptimalBottleIDsWithContextData);
1615 bool subTaskSuccess = false;
1616
1617 if(OctagonIsEnabled()) {
1618 __block NSError* localError = nil;
1619 __block NSArray<NSString*>* localViableBottleIDs = nil;
1620 __block NSArray<NSString*>* localPartiallyViableBottleIDs = nil;
1621
1622 OTControl *control = [data makeOTControl:&localError];
1623 if (!control) {
1624 secnotice("clique-findbottle", "unable to create otcontrol: %@", localError);
1625 if (error) {
1626 *error = localError;
1627 }
1628 OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess);
1629 return nil;
1630 }
1631 [control fetchAllViableBottles:OTCKContainerName
1632 context:data.context
1633 reply:^(NSArray<NSString *> * _Nullable sortedBottleIDs,
1634 NSArray<NSString*> * _Nullable sortedPartialBottleIDs,
1635 NSError * _Nullable fetchError) {
1636 if(fetchError) {
1637 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData errored: %@", fetchError);
1638 } else {
1639 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData succeeded: %@, %@", sortedBottleIDs, sortedPartialBottleIDs);
1640 }
1641 localError = fetchError;
1642 localViableBottleIDs = sortedBottleIDs;
1643 localPartiallyViableBottleIDs = sortedPartialBottleIDs;
1644 }];
1645
1646 if(error && localError) {
1647 *error = localError;
1648 }
1649 OTBottleIDs* bottleIDs = [[OTBottleIDs alloc] init];
1650 bottleIDs.preferredBottleIDs = localViableBottleIDs;
1651 bottleIDs.partialRecoveryBottleIDs = localPartiallyViableBottleIDs;
1652
1653 secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData complete");
1654
1655 subTaskSuccess = (localError == nil) ? true : false;
1656 OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess);
1657 return bottleIDs;
1658 } else {
1659 // With octagon off, fail with 'unimplemented'
1660 if(error) {
1661 *error = [NSError errorWithDomain:NSOSStatusErrorDomain
1662 code:errSecUnimplemented
1663 userInfo:@{NSLocalizedDescriptionKey: @"optimal bottle IDs unimplemented"}];
1664 }
1665 OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess);
1666 return nil;
1667 }
1668 #else // !OCTAGON
1669 if (error) {
1670 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1671 }
1672 return NULL;
1673 #endif
1674 }
1675
1676 + (OTClique* _Nullable)recoverWithContextData:(OTConfigurationContext*)data
1677 bottleID:(NSString*)bottleID
1678 escrowedEntropy:(NSData*)entropy
1679 error:(NSError**)error
1680 {
1681 #if OCTAGON
1682 secnotice("octagon", "replaced by performEscrowRecoveryWithContextData:escrowArguments:error: remove call");
1683 return nil;
1684 #else // !OCTAGON
1685 if (error) {
1686 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1687 }
1688 return NULL;
1689 #endif
1690 }
1691
1692 // used by sbd to fill in the escrow record
1693 // TODO: what extra entitlement do you need to call this?
1694 - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy,
1695 NSString* _Nullable bottleID,
1696 NSData* _Nullable signingPublicKey,
1697 NSError* _Nullable error))reply
1698 {
1699 #if OCTAGON
1700 secnotice("clique-fetchescrow", "fetching entropy for bottling for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
1701 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameFetchEscrowContents);
1702 __block bool subTaskSuccess = false;
1703 if(OctagonIsEnabled()) {
1704 NSError* controlError = nil;
1705 OTControl* control = [self makeOTControl:&controlError];
1706 if (!control) {
1707 OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess);
1708 reply(nil, nil, nil, controlError);
1709 return;
1710 }
1711 [control fetchEscrowContents:OTCKContainerName
1712 contextID:self.ctx.context
1713 reply:^(NSData * _Nullable entropy,
1714 NSString * _Nullable bottleID,
1715 NSData * _Nullable signingPublicKey,
1716 NSError * _Nullable error) {
1717 if(error){
1718 secnotice("clique-fetchescrow", "fetchEscrowContents errored: %@", error);
1719 } else{
1720 secnotice("clique-fetchescrow","fetchEscrowContents succeeded");
1721 }
1722 subTaskSuccess = (error == nil) ? true : false;
1723 OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess);
1724 reply (entropy, bottleID, signingPublicKey, error);
1725 }];
1726 } else {
1727 // With octagon off, fail with 'unimplemented'
1728 OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess);
1729 reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain
1730 code:errSecUnimplemented
1731 userInfo:@{NSLocalizedDescriptionKey: @"fetchEscrowRecordContents unimplemented"}]);
1732 }
1733 #else // !OCTAGON
1734 reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1735 #endif
1736 }
1737
1738 + (void)setNewRecoveryKeyWithData:(OTConfigurationContext *)ctx
1739 recoveryKey:(NSString*)recoveryKey reply:(nonnull void (^)(SecRecoveryKey *rk, NSError *error))reply
1740 {
1741 #if OCTAGON
1742 secnotice("octagon-setrecoverykey", "setNewRecoveryKeyWithData invoked for context: %@", ctx.context);
1743 //set the recovery key for SOS
1744 NSError* createRecoveryKeyError = nil;
1745 NSMutableDictionary *userInfo = [NSMutableDictionary new];
1746 NSError* retError = nil;
1747 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameSetNewRecoveryKeyWithData);
1748 __block bool subTaskSuccess = false;
1749
1750 SecRecoveryKey *rk = SecRKCreateRecoveryKeyWithError(recoveryKey, &createRecoveryKeyError);
1751 if (rk == nil) {
1752 secerror("octagon-setrecoverykey, SecRKCreateRecoveryKeyWithError() failed: %@", createRecoveryKeyError);
1753 userInfo[NSLocalizedDescriptionKey] = @"SecRKCreateRecoveryKeyWithError() failed";
1754 userInfo[NSUnderlyingErrorKey] = createRecoveryKeyError;
1755 if ([OTClique isCloudServicesAvailable] == NO) {
1756 retError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:userInfo];
1757 } else {
1758 retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
1759 }
1760 OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
1761 reply(nil, retError);
1762 return;
1763 }
1764 if([OTClique platformSupportsSOS]) {
1765 CFErrorRef registerError = nil;
1766 if (!SecRKRegisterBackupPublicKey(rk, &registerError)) {
1767 secerror("octagon-setrecoverykey, SecRKRegisterBackupPublicKey() failed: %@", registerError);
1768 NSError *underlyingError = CFBridgingRelease(registerError);
1769 userInfo[NSLocalizedDescriptionKey] = @"SecRKRegisterBackupPublicKey() failed";
1770 userInfo[NSUnderlyingErrorKey] = underlyingError;
1771 if ([OTClique isCloudServicesAvailable] == NO) {
1772 retError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:userInfo];
1773 } else {
1774 retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
1775 }
1776 OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
1777 reply(nil,retError);
1778 return;
1779 } else {
1780 secnotice("octagon-setrecoverykey", "successfully registered recovery key for SOS");
1781 }
1782 }
1783
1784 //set the recovery key for Octagon
1785 if(OctagonRecoveryKeyIsEnabled()) {
1786 NSError* controlError = nil;
1787 OTControl* control = [ctx makeOTControl:&controlError];
1788 if(!control) {
1789 secnotice("octagon-setrecoverykey", "failed to fetch OTControl object: %@", controlError);
1790 OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
1791 reply(nil, controlError);
1792 return;
1793 }
1794 [control createRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError * createError) {
1795 if(createError){
1796 secerror("octagon-setrecoverykey, failed to create octagon recovery key");
1797 OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
1798 reply(nil, createError);
1799 return;
1800 } else {
1801 secnotice("octagon-setrecoverykey", "successfully set octagon recovery key");
1802 subTaskSuccess = true;
1803 OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
1804 reply(rk, nil);
1805 return;
1806 }
1807 }];
1808 }
1809 #else // !OCTAGON
1810 reply(nil, [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1811 #endif
1812 }
1813
1814 + (void)recoverOctagonUsingData:(OTConfigurationContext *)ctx
1815 recoveryKey:(NSString*)recoveryKey
1816 reply:(void(^)(NSError* _Nullable error))reply
1817 {
1818 #if OCTAGON
1819 OctagonSignpost signpost = OctagonSignpostBegin(OctagonSignpostNameRecoverOctagonUsingData);
1820 __block bool subTaskSuccess = false;
1821
1822 if(OctagonRecoveryKeyIsEnabled()) {
1823 NSError* controlError = nil;
1824 OTControl* control = [ctx makeOTControl:&controlError];
1825
1826 secnotice("clique-recoverykey", "join using recovery key");
1827
1828 if(!control) {
1829 secnotice("clique-recoverykey", "failed to fetch OTControl object: %@", controlError);
1830 OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess);
1831 reply(controlError);
1832 return;
1833 }
1834 [control joinWithRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError *joinError) {
1835 if(joinError){
1836 secnotice("clique-recoverykey", "failed to join using recovery key: %@", joinError);
1837 OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess);
1838 reply(joinError);
1839 return;
1840 }
1841 secnotice("clique-recoverykey", "successfully joined using recovery key");
1842 subTaskSuccess = true;
1843 OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess);
1844 reply(nil);
1845 }];
1846 }
1847
1848 #else // !OCTAGON
1849 reply([NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1850 #endif
1851 }
1852
1853 - (void)performedCDPStateMachineRun:(OTCliqueCDPContextType)type
1854 success:(BOOL)success
1855 error:(NSError * _Nullable)error
1856 reply:(void(^)(NSError* _Nullable error))reply
1857 {
1858 #if OCTAGON
1859 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNamePerformedCDPStateMachineRun);
1860 NSError* controlError = nil;
1861 __block bool subTaskSuccess = false;
1862
1863 OTControl* control = [self makeOTControl:&controlError];
1864 if(!control) {
1865 secnotice("clique-cdp-sm", "octagon, failed to fetch OTControl object: %@", controlError);
1866 OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess);
1867 reply(controlError);
1868 return;
1869 }
1870
1871 [control postCDPFollowupResult:success type:type error:error containerName:OTCKContainerName contextName:OTDefaultContext reply:^(NSError *postError) {
1872 if(postError){
1873 secnotice("clique-cdp-sm", "failed to post %@ result: %@ ", type, postError);
1874 OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess);
1875 reply(postError);
1876 return;
1877 }
1878 if (success) {
1879 secnotice("clique-cdp-sm", "posted success: %@", type);
1880 } else {
1881 secnotice("clique-cdp-sm", "posted error: %@: %@", type, error);
1882 }
1883 subTaskSuccess = success ? true : false;
1884 OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess);
1885 reply(nil);
1886 }];
1887 #else // !OCTAGON
1888 reply([NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]);
1889 #endif
1890 }
1891
1892 - (BOOL)waitForOctagonUpgrade:(NSError** _Nullable)error
1893 {
1894 #if OCTAGON
1895 OTControl* control = nil;
1896 OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameWaitForOctagonUpgrade);
1897 __block bool subTaskSuccess = false;
1898
1899 if (!OctagonIsEnabled()) {
1900 secnotice("clique-waitforoctagonupgrade", "cannot upgrade, octagon is not enabled");
1901 if (error) {
1902 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"Octagon is not enabled"}];
1903 }
1904 OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess);
1905
1906 return NO;
1907 }
1908
1909 NSError *controlError = nil;
1910 control = [self makeOTControl:&controlError];
1911 if (!control) {
1912 secnotice("clique-waitforoctagonupgrade", "octagon, failed to fetch OTControl object: %@", controlError);
1913 if (error) {
1914 *error = controlError;
1915 }
1916 OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess);
1917 return NO;
1918 }
1919
1920 __block BOOL ret = NO;
1921 __block NSError* blockError = nil;
1922
1923 [control waitForOctagonUpgrade:OTCKContainerName context:OTDefaultContext reply:^(NSError *postError) {
1924 if(postError){
1925 secnotice("clique-waitforoctagonupgrade", "error from control: %@", postError);
1926 blockError = postError;
1927 ret = NO;
1928 } else {
1929 secnotice("clique-waitforoctagonupgrade", "successfully upgraded to octagon");
1930 ret = YES;
1931 }
1932 }];
1933
1934 if (blockError && error) {
1935 *error = blockError;
1936 }
1937 subTaskSuccess = ret ? true : false;
1938 OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess);
1939 return ret;
1940 #else // !OCTAGON
1941 if(error) {
1942 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1943 }
1944 return NO;
1945 #endif
1946 }
1947
1948 - (void)performedFailureCDPStateMachineRun:(OTCliqueCDPContextType)type
1949 error:(NSError * _Nullable)error
1950 reply:(void(^)(NSError* _Nullable error))reply
1951 {
1952 [self performedCDPStateMachineRun:type success:NO error:error reply:reply];
1953 }
1954
1955 - (void)performedSuccessfulCDPStateMachineRun:(OTCliqueCDPContextType)type
1956 reply:(void(^)(NSError* _Nullable error))reply
1957 {
1958 [self performedCDPStateMachineRun:type success:YES error:nil reply:reply];
1959 }
1960
1961 + (BOOL)setCDPEnabled:(OTConfigurationContext*)arguments
1962 error:(NSError* __autoreleasing*)error
1963 {
1964 #if OCTAGON
1965 NSError *controlError = nil;
1966 OTControl* control = [arguments makeOTControl:&controlError];
1967 if (!control) {
1968 secerror("octagon-setcdpenabled: failed to fetch OTControl object: %@", controlError);
1969 if (error) {
1970 *error = controlError;
1971 }
1972 return NO;
1973 }
1974
1975 __block NSError* reterror = nil;
1976
1977 [control setCDPEnabled:nil
1978 contextID:arguments.context
1979 reply:^(NSError * _Nullable resultError) {
1980 if(resultError) {
1981 secnotice("octagon-setcdpenabled", "failed to set CDP bit: %@", resultError);
1982 reterror = resultError;
1983 } else {
1984 secnotice("octagon-setcdpenabled", "successfully set CDP bit");
1985 }
1986 }];
1987
1988 if(reterror && error) {
1989 *error = reterror;
1990 }
1991
1992 return (reterror == nil);
1993 #else // !OCTAGON
1994 if(error) {
1995 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
1996 }
1997 return NO;
1998 #endif
1999 }
2000
2001 + (OTCDPStatus)getCDPStatus:(OTConfigurationContext*)arguments
2002 error:(NSError* __autoreleasing *)error
2003 {
2004 #if OCTAGON
2005 NSError *controlError = nil;
2006 OTControl* control = [arguments makeOTControl:&controlError];
2007 if (!control) {
2008 secerror("octagon-cdp-status: failed to fetch OTControl object: %@", controlError);
2009 if (error) {
2010 *error = controlError;
2011 }
2012 return OTCDPStatusUnknown;
2013 }
2014
2015 __block NSError* reterror = nil;
2016 __block OTCDPStatus retcdpstatus = OTCDPStatusUnknown;
2017
2018 [control getCDPStatus:nil
2019 contextID:arguments.context
2020 reply:^(OTCDPStatus status, NSError * _Nullable resultError) {
2021 if(resultError) {
2022 secnotice("octagon-cdp-status", "failed to fetch CDP status: %@", resultError);
2023 reterror = resultError;
2024
2025 } else {
2026 secnotice("octagon-cdp-status", "successfully fetched CDP status as %@", OTCDPStatusToString(status));
2027 retcdpstatus = status;
2028 }
2029 }];
2030
2031 if(reterror && error) {
2032 *error = reterror;
2033 }
2034
2035 return retcdpstatus;
2036 #else // !OCTAGON
2037 if(error) {
2038 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
2039 }
2040 return OTCDPStatusDisabled;
2041 #endif
2042 }
2043
2044 + (OTClique* _Nullable)resetProtectedData:(OTConfigurationContext*)data error:(NSError**)error
2045 {
2046 #if OCTAGON
2047 if ([OTClique isCloudServicesAvailable] == NO) {
2048 if (error) {
2049 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
2050 }
2051 return nil;
2052 }
2053 NSError *controlError = nil;
2054 OTControl *control = [data makeOTControl:&controlError];
2055 if (!control) {
2056 secerror("clique-reset-protected-data: unable to create otcontrol: %@", controlError);
2057 if (error) {
2058 *error = controlError;
2059 }
2060 return nil;
2061 }
2062
2063 __block NSError* localError = nil;
2064
2065 //delete all records
2066 id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
2067
2068 NSDictionary* deletionInformation = @{ getkSecureBackupAuthenticationAppleID() : data.authenticationAppleID,
2069 getkSecureBackupAuthenticationPassword() : data.passwordEquivalentToken,
2070 getkSecureBackupiCloudDataProtectionDeleteAllRecordsKey() : @YES,
2071 getkSecureBackupContainsiCDPDataKey() : @YES};
2072
2073 NSError* sbError = [sb disableWithInfo:deletionInformation];
2074 if(sbError) {
2075 secerror("clique-reset-protected-data: secure backup escrow record deletion failed: %@", sbError);
2076 if(error) {
2077 *error = sbError;
2078 }
2079 return nil;
2080 } else {
2081 secnotice("clique-reset-protected-data", "sbd disableWithInfo succeeded");
2082 }
2083
2084 //reset sos
2085 if(OctagonPlatformSupportsSOS()) {
2086 //reset SOS
2087 CFErrorRef sosError = NULL;
2088 bool resetSuccess = SOSCCResetToOffering(&sosError);
2089
2090 if(sosError || !resetSuccess) {
2091 secerror("clique-reset-protected-data: sos reset failed: %@", sosError);
2092 if(error) {
2093 *error = (NSError*)CFBridgingRelease(sosError);
2094 }
2095 return nil;
2096 } else {
2097 secnotice("clique-reset-protected-data", "sos reset succeeded");
2098 }
2099 } else {
2100 secnotice("clique-reset-protected-data", "platform does not support sos");
2101 }
2102
2103 //reset octagon
2104 OTClique* clique = [[OTClique alloc] initWithContextData:data];
2105 if(OctagonIsEnabled()) {
2106 [clique resetAndEstablish:CuttlefishResetReasonUserInitiatedReset error:&localError];
2107
2108 if(localError) {
2109 secerror("clique-reset-protected-data: account reset failed: %@", localError);
2110 if(error) {
2111 *error = localError;
2112 }
2113 return nil;
2114 } else {
2115 secnotice("clique-reset-protected-data", "Octagon account reset succeeded");
2116 }
2117 }
2118
2119 return clique;
2120 #else // !OCTAGON
2121 if(error) {
2122 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
2123 }
2124 return nil;
2125 #endif
2126
2127 }
2128
2129 @end
2130
2131 #endif /* OBJC2 */