]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTDetermineCDPBitStatusOperation.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ot / OTDetermineCDPBitStatusOperation.m
1 /*
2 * Copyright (c) 2019 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 OCTAGON
25
26 #import "utilities/debugging.h"
27
28 #import "keychain/ot/ObjCImprovements.h"
29 #import "keychain/ot/OTDetermineCDPBitStatusOperation.h"
30 #import "keychain/ot/OTStates.h"
31
32 @interface OTDetermineCDPBitStatusOperation ()
33 @property OTOperationDependencies* deps;
34 @end
35
36 @implementation OTDetermineCDPBitStatusOperation
37 @synthesize intendedState = _intendedState;
38 @synthesize nextState = _nextState;
39
40 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
41 intendedState:(OctagonState*)intendedState
42 errorState:(OctagonState*)errorState
43 {
44 if((self = [super init])) {
45 _deps = dependencies;
46 _intendedState = intendedState;
47 _nextState = errorState;
48 }
49 return self;
50 }
51
52 - (void)groupStart
53 {
54 secnotice("octagon-cdp-status", "Checking CDP status");
55
56 NSError* localError = nil;
57 OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&localError];
58 if(localError && [self.deps.lockStateTracker isLockedError:localError]) {
59 secnotice("octagon-cdp-status", "Device is locked! restarting on unlock");
60 self.nextState = OctagonStateWaitForClassCUnlock;
61 return;
62 }
63
64 if(localError) {
65 secnotice("octagon-cdp-status", "Failed to load account metadata: %@", localError);
66 self.error = localError;
67 return;
68 }
69
70 secnotice("octagon-cdp-status", "CDP is %@", OTAccountMetadataClassC_CDPStateAsString(account.cdpState));
71
72 if(account.cdpState == OTAccountMetadataClassC_CDPState_ENABLED) {
73 self.nextState = self.intendedState;
74 } else {
75 // If the CDP status is unknown or disabled, double-check with TPH.
76 // If there are any peers, the CDP status really should be ENABLED.
77 __block OTAccountMetadataClassC_CDPState newState = OTAccountMetadataClassC_CDPState_UNKNOWN;
78
79 WEAKIFY(self);
80 [self.deps.cuttlefishXPCWrapper trustStatusWithContainer:self.deps.containerName
81 context:self.deps.contextID
82 reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus,
83 NSError *xpcError) {
84 STRONGIFY(self);
85 if(xpcError) {
86 secnotice("octagon-cdp-status", "Unable to talk with TPH; leaving CDP status as 'unknown': %@", xpcError);
87 return;
88 }
89
90 secnotice("octagon-cdp-status", "Octagon reports %d peers", (int)egoStatus.numberOfPeersInOctagon);
91 if(egoStatus.numberOfPeersInOctagon > 0) {
92 newState = OTAccountMetadataClassC_CDPState_ENABLED;
93 } else {
94 // As a last gasp, check in with SOS (if enabled). If there's a circle (in or out), CDP is on
95 if(self.deps.sosAdapter.sosEnabled) {
96 secnotice("octagon-cdp-status", "Requesting SOS status...");
97
98 NSError* circleError = nil;
99 SOSCCStatus circleStatus = [self.deps.sosAdapter circleStatus:&circleError];
100
101 if(circleError || circleStatus == kSOSCCError) {
102 secnotice("octagon-cdp-status", "Error fetching circle status. Leaving CDP status as 'unknown': %@", circleError);
103 } else if(circleStatus == kSOSCCCircleAbsent) {
104 secnotice("octagon-cdp-status", "SOS reports circle absent. Setting CDP to 'disabled'");
105 newState = OTAccountMetadataClassC_CDPState_DISABLED;
106 } else {
107 secnotice("octagon-cdp-status", "SOS reports some existing circle (%d). Setting CDP to 'enabled'", (int)circleStatus);
108 newState = OTAccountMetadataClassC_CDPState_ENABLED;
109 }
110 } else {
111 // No SOS? no CDP.
112 secnotice("octagon-cdp-status", "No SOS. CDP bit is off.");
113 newState = OTAccountMetadataClassC_CDPState_DISABLED;
114 }
115 }
116 }];
117
118 if(account.cdpState != newState) {
119 NSError* stateError = nil;
120 [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
121 if(metadata.cdpState == OTAccountMetadataClassC_CDPState_ENABLED) {
122 secnotice("octagon-cdp-status", "CDP bit is enabled on-disk, not modifying (would have been %@)", OTAccountMetadataClassC_CDPStateAsString(newState));
123
124 // Set this here to perform the right state choice later
125 newState = OTAccountMetadataClassC_CDPState_ENABLED;
126 return nil;
127 } else {
128 secnotice("octagon-cdp-status", "Writing CDP bit as %@", OTAccountMetadataClassC_CDPStateAsString(newState));
129 metadata.cdpState = newState;
130 return metadata;
131 }
132 } error:&stateError];
133
134 if(stateError) {
135 secnotice("octagon-cdp-status", "Failed to load account metadata: %@", stateError);
136 }
137 }
138
139 if(newState == OTAccountMetadataClassC_CDPState_ENABLED) {
140 self.nextState = self.intendedState;
141 } else {
142 self.nextState = OctagonStateWaitForCDP;
143 }
144 }
145 }
146
147 @end
148
149 #endif // OCTAGON