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