]> git.saurik.com Git - apple/security.git/blob - keychain/otctl/otctl.m
Security-59306.101.1.tar.gz
[apple/security.git] / keychain / otctl / otctl.m
1 //
2 // Security
3 //
4
5 #import <TargetConditionals.h>
6 #import <Foundation/Foundation.h>
7 #import <Security/SecInternalReleasePriv.h>
8 #import <Security/Security.h>
9 #import <err.h>
10
11 #import "keychain/otctl/OTControlCLI.h"
12 #import "keychain/otctl/EscrowRequestCLI.h"
13 #import "keychain/escrowrequest/Framework/SecEscrowRequest.h"
14 #include "lib/SecArgParse.h"
15 #include "utilities/debugging.h"
16
17 #if TARGET_OS_WATCH
18 #import "keychain/otpaird/OTPairingClient.h"
19 #endif /* TARGET_OS_WATCH */
20
21 static int start = false;
22 static int signIn = false;
23 static int signOut = false;
24 static int resetoctagon = false;
25 static int resetProtectedData = false;
26
27 static int fetchAllBottles = false;
28 static int recover = false;
29 static int depart = false;
30
31 static int status = false;
32
33 static int er_trigger = false;
34 static int er_status = false;
35 static int er_reset = false;
36 static int er_store = false;
37 static int ckks_policy_flag = false;
38
39 static int ttr_flag = false;
40
41 static int health = false;
42
43 #if TARGET_OS_WATCH
44 static int pairme = false;
45 #endif /* TARGET_OS_WATCH */
46
47 static char* bottleIDArg = NULL;
48 static char* contextNameArg = NULL;
49 static char* secretArg = NULL;
50 static char* skipRateLimitingCheckArg = NULL;
51 static int json = false;
52
53 static char* altDSIDArg = NULL;
54 static char* containerStr = NULL;
55 static char* radarNumber = NULL;
56 static char* appleIDArg = NULL;
57 static char* dsidArg = NULL;
58
59 static void internalOnly(void)
60 {
61 if(!SecIsInternalRelease()) {
62 secnotice("octagon", "Tool not available on non internal builds");
63 errx(1, "Tool not available on non internal builds");
64 }
65 }
66
67 int main(int argc, char** argv)
68 {
69 static struct argument options[] = {
70 {.shortname = 's', .longname = "secret", .argument = &secretArg, .description = "escrow secret"},
71 {.shortname = 'e', .longname = "bottleID", .argument = &bottleIDArg, .description = "bottle record id"},
72 {.shortname = 'r', .longname = "skipRateLimiting", .argument = &skipRateLimitingCheckArg, .description = " enter values YES or NO, option defaults to NO, This gives you the opportunity to skip the rate limiting check when performing the cuttlefish health check"},
73 {.shortname = 'j', .longname = "json", .flag = &json, .flagval = true, .description = "Output in JSON"},
74
75 {.longname = "altDSID", .argument = &altDSIDArg, .description = "altDSID (for sign-in/out)"},
76 {.longname = "entropy", .argument = &secretArg, .description = "escrowed entropy in JSON"},
77
78 {.longname = "appleID", .argument = &appleIDArg, .description = "AppleID"},
79 {.longname = "dsid", .argument = &dsidArg, .description = "DSID"},
80
81 {.longname = "container", .argument = &containerStr, .description = "CloudKit container name"},
82 {.longname = "radar", .argument = &radarNumber, .description = "Radar number"},
83
84 {.command = "start", .flag = &start, .flagval = true, .description = "Start Octagon state machine"},
85 {.command = "sign-in", .flag = &signIn, .flagval = true, .description = "Inform Cuttlefish container of sign in"},
86 {.command = "sign-out", .flag = &signOut, .flagval = true, .description = "Inform Cuttlefish container of sign out"},
87 {.command = "status", .flag = &status, .flagval = true, .description = "Report Octagon status"},
88
89 {.command = "resetoctagon", .flag = &resetoctagon, .flagval = true, .description = "Reset and establish new Octagon trust"},
90 {.command = "resetProtectedData", .flag = &resetProtectedData, .flagval = true, .description = "Reset ProtectedData"},
91
92 {.command = "allBottles", .flag = &fetchAllBottles, .flagval = true, .description = "Fetch all viable bottles"},
93 {.command = "recover", .flag = &recover, .flagval = true, .description = "Recover using this bottle"},
94 {.command = "depart", .flag = &depart, .flagval = true, .description = "Depart from Octagon Trust"},
95
96 {.command = "er-trigger", .flag = &er_trigger, .flagval = true, .description = "Trigger an Escrow Request request"},
97 {.command = "er-status", .flag = &er_status, .flagval = true, .description = "Report status on any pending Escrow Request requests"},
98 {.command = "er-reset", .flag = &er_reset, .flagval = true, .description = "Delete all Escrow Request requests"},
99 {.command = "er-store", .flag = &er_store, .flagval = true, .description = "Store any pending Escrow Request prerecords"},
100
101 {.command = "health", .flag = &health, .flagval = true, .description = "Check Octagon Health status"},
102 {.command = "ckks-policy", .flag = &ckks_policy_flag, .flagval = true, .description = "Trigger a refetch of the CKKS policy"},
103
104 {.command = "taptoradar", .flag = &ttr_flag, .flagval = true, .description = "Trigger a TapToRadar"},
105
106
107 #if TARGET_OS_WATCH
108 {.command = "pairme", .flag = &pairme, .flagval = true, .description = "Perform pairing (watchOS only)"},
109 #endif /* TARGET_OS_WATCH */
110 {}};
111
112 static struct arguments args = {
113 .programname = "otctl",
114 .description = "Control and report on Octagon Trust",
115 .arguments = options,
116 };
117
118 if(!options_parse(argc, argv, &args)) {
119 printf("\n");
120 print_usage(&args);
121 return -1;
122 }
123
124 @autoreleasepool {
125 NSError* error = nil;
126
127 // Use a synchronous control object
128 OTControl* rpc = [OTControl controlObject:true error:&error];
129 if(error || !rpc) {
130 errx(1, "no OTControl failed: %s", [[error description] UTF8String]);
131 }
132
133 NSString* context = contextNameArg ? [NSString stringWithCString:contextNameArg encoding:NSUTF8StringEncoding] : OTDefaultContext;
134 NSString* container = containerStr ? [NSString stringWithCString:containerStr encoding:NSUTF8StringEncoding] : nil;
135 NSString* altDSID = altDSIDArg ? [NSString stringWithCString:altDSIDArg encoding:NSUTF8StringEncoding] : nil;
136 NSString* dsid = dsidArg ? [NSString stringWithCString:dsidArg encoding:NSUTF8StringEncoding] : nil;
137 NSString* appleID = appleIDArg ? [NSString stringWithCString:appleIDArg encoding:NSUTF8StringEncoding] : nil;
138
139 NSString* skipRateLimitingCheck = skipRateLimitingCheckArg ? [NSString stringWithCString:skipRateLimitingCheckArg encoding:NSUTF8StringEncoding] : @"NO";
140
141 OTControlCLI* ctl = [[OTControlCLI alloc] initWithOTControl:rpc];
142
143 NSError* escrowRequestError = nil;
144 EscrowRequestCLI* escrowctl = [[EscrowRequestCLI alloc] initWithEscrowRequest:[SecEscrowRequest request:&escrowRequestError]];
145 if(escrowRequestError) {
146 errx(1, "SecEscrowRequest failed: %s", [[escrowRequestError description] UTF8String]);
147 }
148 if(resetoctagon) {
149 long ret = [ctl resetOctagon:container context:context altDSID:altDSID];
150 return (int)ret;
151 }
152 if(resetProtectedData) {
153 internalOnly();
154 long ret = [ctl resetProtectedData:container context:context altDSID:altDSID appleID:appleID dsid:dsid];
155 return (int)ret;
156 }
157 if(fetchAllBottles) {
158 return (int)[ctl fetchAllBottles:altDSID containerName:container context:context control:rpc];
159 }
160 if(recover) {
161 NSString* entropyJSON = secretArg ? [NSString stringWithCString:secretArg encoding:NSUTF8StringEncoding] : nil;
162 NSString* bottleID = bottleIDArg ? [NSString stringWithCString:bottleIDArg encoding:NSUTF8StringEncoding] : nil;
163
164 if(!entropyJSON || !bottleID) {
165 print_usage(&args);
166 return -1;
167 }
168
169 NSData* entropy = [[NSData alloc] initWithBase64EncodedString:entropyJSON options:0];
170 if(!entropy) {
171 print_usage(&args);
172 return -1;
173 }
174
175 return (int)[ctl recoverUsingBottleID:bottleID
176 entropy:entropy
177 altDSID:altDSID
178 containerName:container
179 context:context
180 control:rpc];
181 }
182 if(depart) {
183 return (int)[ctl depart:container context:context];
184 }
185 if(start) {
186 internalOnly();
187 return (int)[ctl startOctagonStateMachine:container context:context];
188 }
189 if(signIn) {
190 internalOnly();
191 return (int)[ctl signIn:altDSID container:container context:context];
192 }
193 if(signOut) {
194 internalOnly();
195 return (int)[ctl signOut:container context:context];
196 }
197
198 if(status) {
199 return (int)[ctl status:container context:context json:json];
200 }
201
202 if(health) {
203 BOOL skip = NO;
204 if([skipRateLimitingCheck isEqualToString:@"YES"]) {
205 skip = YES;
206 } else {
207 skip = NO;
208 }
209 return (int)[ctl healthCheck:container context:context skipRateLimitingCheck:skip];
210 }
211 if(ckks_policy_flag) {
212 return (int)[ctl refetchCKKSPolicy:container context:context];
213 }
214 if (ttr_flag) {
215 if (radarNumber == NULL) {
216 radarNumber = "1";
217 }
218 return (int)[ctl tapToRadar:@"action" description:@"description" radar:[NSString stringWithUTF8String:radarNumber]];
219 }
220
221 if(er_trigger) {
222 internalOnly();
223 return (int)[escrowctl trigger];
224 }
225 if(er_status) {
226 return (int)[escrowctl status];
227 }
228 if(er_reset) {
229 return (int)[escrowctl reset];
230 }
231 if(er_store) {
232 return (int)[escrowctl storePrerecordsInEscrow];
233 }
234
235
236 #if TARGET_OS_WATCH
237 if (pairme) {
238 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
239 OTPairingInitiateWithCompletion(NULL, ^(bool success, NSError *pairingError) {
240 if (success) {
241 printf("successfully paired with companion\n");
242 } else {
243 printf("failed to pair with companion: %s\n", pairingError.description.UTF8String);
244 }
245 dispatch_semaphore_signal(sema);
246 });
247 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
248 return 0;
249 }
250 #endif /* TARGET_OS_WATCH */
251
252 print_usage(&args);
253 return -1;
254 }
255 return 0;
256 }