]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTControl.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / ot / OTControl.m
1 /*
2 * Copyright (c) 2017 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 <Foundation/NSXPCConnection_Private.h>
27 #import <xpc/xpc.h>
28
29 #import <Security/SecItemPriv.h>
30 #import <Security/SecXPCHelper.h>
31
32 #import "keychain/ot/OTClique.h"
33 #import "keychain/ot/OTControl.h"
34 #import "keychain/ot/OTDefines.h"
35 #import "keychain/ot/OTControlProtocol.h"
36 #import "keychain/ot/OctagonControlServer.h"
37
38 #include <security_utilities/debugging.h>
39
40 #if OCTAGON
41 #import <SecurityFoundation/SFKey.h>
42 #endif
43
44 @interface OTControl ()
45 @property NSXPCConnection *connection;
46 @property bool sync;
47 @end
48
49 @implementation OTControl
50
51 - (instancetype)initWithConnection:(NSXPCConnection*)connection sync:(bool)sync {
52 if(self = [super init]) {
53 _connection = connection;
54 _sync = sync;
55 }
56 return self;
57 }
58
59 - (void)dealloc {
60 [self.connection invalidate];
61 }
62
63 - (NSXPCConnection<OTControlProtocol>*)getConnection:(void (^)(NSError *error))handler
64 {
65 if(self.sync) {
66 return [self.connection synchronousRemoteObjectProxyWithErrorHandler: handler];
67 } else {
68 return [self.connection remoteObjectProxyWithErrorHandler: handler];
69 }
70 }
71
72 - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID
73 reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error))reply
74 {
75 [[self getConnection: ^(NSError* error) {
76 reply(nil, nil, error);
77 }] restore:contextID dsid:dsid secret:secret escrowRecordID:escrowRecordID reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError *error) {
78 reply(signingKeyData, encryptionKeyData, error);
79 }];
80 }
81
82 -(void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply
83 {
84 [[self getConnection: ^(NSError* error) {
85 reply(NO, error);
86 }] reset:^(BOOL result, NSError * _Nullable error) {
87 reply(result, error);
88 }];
89 }
90
91 - (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply
92 {
93 [self octagonSigningPublicKey:reply];
94 }
95
96 - (void)octagonSigningPublicKey:(nonnull void (^)(NSData * _Nullable, NSError * _Nullable))reply {
97 [[self getConnection: ^(NSError* error) {
98 reply(nil, error);
99 }] octagonSigningPublicKey:^(NSData *signingKey, NSError * _Nullable error) {
100 reply(signingKey, error);
101 }];
102
103 }
104
105 - (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply
106 {
107 [self octagonEncryptionPublicKey:reply];
108 }
109
110 - (void)octagonEncryptionPublicKey:(nonnull void (^)(NSData * _Nullable, NSError * _Nullable))reply
111 {
112 [[self getConnection: ^(NSError* error) {
113 reply(nil, error);
114 }] octagonEncryptionPublicKey:^(NSData *encryptionKey, NSError * _Nullable error) {
115 reply(encryptionKey, error);
116 }];
117 }
118
119 - (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply
120 {
121 [self listOfEligibleBottledPeerRecords:reply];
122 }
123
124 - (void)listOfEligibleBottledPeerRecords:(nonnull void (^)(NSArray * _Nullable, NSError * _Nullable))reply
125 {
126 [[self getConnection: ^(NSError* error) {
127 reply(nil, error);
128 }] listOfEligibleBottledPeerRecords:^(NSArray *list, NSError * _Nullable error) {
129 reply(list, error);
130 }];
131
132 }
133
134 - (void)signIn:(NSString*)altDSID container:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
135 {
136 [[self getConnection: ^(NSError* error) {
137 reply(error);
138 }] signIn:altDSID container:container context:contextID reply:^(NSError * _Nullable error) {
139 reply(error);
140 }];
141 }
142
143 - (void)signOut:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
144 {
145 [[self getConnection: ^(NSError* error) {
146 reply(error);
147 }] signOut:container context:contextID reply:^(NSError * _Nullable error) {
148 reply(error);
149 }];
150 }
151
152 - (void)notifyIDMSTrustLevelChangeForContainer:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
153 {
154 [[self getConnection: ^(NSError* error) {
155 reply(error);
156 }] notifyIDMSTrustLevelChangeForContainer:container context:contextID reply:^(NSError * _Nullable error) {
157 reply(error);
158 }];
159 }
160
161 - (void)handleIdentityChangeForSigningKey:(SFECKeyPair* _Nonnull)peerSigningKey
162 ForEncryptionKey:(SFECKeyPair* _Nonnull)encryptionKey
163 ForPeerID:(NSString*)peerID
164 reply:(void (^)(BOOL result,
165 NSError* _Nullable error))reply
166 {
167 #if OCTAGON
168 [[self getConnection: ^(NSError* error) {
169 reply(NO, error);
170 }] handleIdentityChangeForSigningKey:peerSigningKey ForEncryptionKey:encryptionKey ForPeerID:peerID reply:^(BOOL result, NSError* _Nullable error) {
171 reply(result, error);
172 }];
173 #else
174 reply(NO, NULL);
175 #endif
176 }
177
178 - (void)rpcEpochWithConfiguration:(OTJoiningConfiguration*)config
179 reply:(void (^)(uint64_t epoch,
180 NSError * _Nullable error))reply
181 {
182 #if OCTAGON
183 [[self getConnection: ^(NSError* error) {
184 reply(0, error);
185 }] rpcEpochWithConfiguration:config reply:^(uint64_t epoch,
186 NSError * _Nullable error) {
187 reply(epoch, error);
188 }];
189 #else
190 reply(0, NULL);
191 #endif
192 }
193
194 - (void)rpcPrepareIdentityAsApplicantWithConfiguration:(OTJoiningConfiguration*)config
195 reply:(void (^)(NSString * _Nullable peerID,
196 NSData * _Nullable permanentInfo,
197 NSData * _Nullable permanentInfoSig,
198 NSData * _Nullable stableInfo,
199 NSData * _Nullable stableInfoSig,
200 NSError * _Nullable error))reply
201 {
202 #if OCTAGON
203 [[self getConnection: ^(NSError* error) {
204 reply(nil, nil, nil, nil, nil, error);
205 }] rpcPrepareIdentityAsApplicantWithConfiguration:config reply:^(NSString* pID, NSData* pI, NSData* piSig, NSData* si, NSData* siSig, NSError* e) {
206 reply(pID, pI, piSig, si, siSig, e);
207 }];
208 #else
209 reply(NULL, NULL, NULL, NULL, NULL, NULL);
210 #endif
211 }
212
213 - (void)rpcVoucherWithConfiguration:(OTJoiningConfiguration*)config
214 peerID:(NSString*)peerID
215 permanentInfo:(NSData *)permanentInfo
216 permanentInfoSig:(NSData *)permanentInfoSig
217 stableInfo:(NSData *)stableInfo
218 stableInfoSig:(NSData *)stableInfoSig
219 reply:(void (^)(NSData* voucher, NSData* voucherSig, NSError * _Nullable error))reply
220 {
221 #if OCTAGON
222 [[self getConnection: ^(NSError* error) {
223 reply(nil, nil, error);
224 }] rpcVoucherWithConfiguration:config peerID:peerID permanentInfo:permanentInfo permanentInfoSig:permanentInfoSig stableInfo:stableInfo stableInfoSig:stableInfoSig reply:^(NSData* voucher, NSData* voucherSig, NSError * _Nullable error) {
225 reply(voucher, voucherSig, error);
226 }];
227 #else
228 reply(NULL, NULL, NULL);
229 #endif
230 }
231
232 - (void)rpcJoinWithConfiguration:(OTJoiningConfiguration*)config
233 vouchData:(NSData*)vouchData
234 vouchSig:(NSData*)vouchSig
235 reply:(void (^)(NSError * _Nullable error))reply
236 {
237 #if OCTAGON
238 [[self getConnection: ^(NSError* error) {
239 reply(error);
240 }] rpcJoinWithConfiguration:config vouchData:vouchData vouchSig:vouchSig reply:^(NSError* e) {
241 reply(e);
242 }];
243 #else
244 reply(NULL);
245 #endif
246 }
247
248 - (void)preflightBottledPeer:(NSString*)contextID
249 dsid:(NSString*)dsid
250 reply:(void (^)(NSData* _Nullable entropy,
251 NSString* _Nullable bottleID,
252 NSData* _Nullable signingPublicKey,
253 NSError* _Nullable error))reply
254 {
255 [[self getConnection: ^(NSError* error) {
256 reply(nil, nil, nil, error);
257 }] preflightBottledPeer:contextID dsid:dsid reply:^(NSData* _Nullable entropy,
258 NSString* _Nullable bottleID,
259 NSData* _Nullable signingPublicKey,
260 NSError* _Nullable error) {
261 reply(entropy, bottleID, signingPublicKey, error);
262 }];
263 }
264
265 - (void)launchBottledPeer:(NSString*)contextID
266 bottleID:(NSString*)bottleID
267 reply:(void (^ _Nullable)(NSError* _Nullable))reply
268 {
269 [[self getConnection: ^(NSError* error) {
270 reply(error);
271 }] launchBottledPeer:contextID bottleID:bottleID reply:^(NSError * _Nullable error) {
272 reply(error);
273 }];
274 }
275
276 - (void)scrubBottledPeer:(NSString*)contextID
277 bottleID:(NSString*)bottleID
278 reply:(void (^ _Nullable)(NSError* _Nullable))reply
279 {
280 [[self getConnection: ^(NSError* error) {
281 reply(error);
282 }] scrubBottledPeer:contextID bottleID:bottleID reply:reply];
283 }
284
285 - (void)status:(NSString* _Nullable)container
286 context:(NSString*)context
287 reply:(void (^)(NSDictionary* _Nullable result, NSError* _Nullable error))reply
288 {
289 [[self getConnection: ^(NSError* error) {
290 reply(nil, error);
291 }] status:container context:context reply:reply];
292 }
293
294 - (void)fetchEgoPeerID:(NSString* _Nullable)container
295 context:(NSString*)context
296 reply:(void (^)(NSString* _Nullable peerID, NSError* _Nullable error))reply
297 {
298 [[self getConnection: ^(NSError* error) {
299 reply(nil, error);
300 }] fetchEgoPeerID:container context:context reply:reply];
301 }
302
303 - (void)fetchCliqueStatus:(NSString* _Nullable)container
304 context:(NSString*)context
305 configuration:(OTOperationConfiguration*)configuration
306 reply:(void (^)(CliqueStatus cliqueStatus, NSError* _Nullable error))reply
307 {
308 [[self getConnection: ^(NSError* error) {
309 reply(CliqueStatusError, error);
310 }] fetchCliqueStatus:container context:context configuration:configuration reply:reply];
311 }
312
313 - (void)fetchTrustStatus:(NSString* _Nullable)container
314 context:(NSString*)context
315 configuration:(OTOperationConfiguration *)configuration
316 reply:(void (^)(CliqueStatus status, NSString* peerID, NSNumber * _Nullable numberOfOctagonPeers, BOOL isExcluded, NSError * _Nullable error))reply
317 {
318 [[self getConnection: ^(NSError* error) {
319 reply(CliqueStatusError, false, NULL, false, error);
320 }] fetchTrustStatus:container context:context configuration:configuration reply:reply];
321 }
322
323 - (void)startOctagonStateMachine:(NSString* _Nullable)container
324 context:(NSString*)context
325 reply:(void (^)(NSError* _Nullable error))reply
326 {
327 [[self getConnection: ^(NSError* error) {
328 reply(error);
329 }] startOctagonStateMachine:container context:context reply:reply];
330 }
331
332 - (void)resetAndEstablish:(NSString* _Nullable)container
333 context:(NSString*)context
334 altDSID:(NSString*)altDSID
335 resetReason:(CuttlefishResetReason)resetReason
336 reply:(void (^)(NSError* _Nullable error))reply
337 {
338 [[self getConnection: ^(NSError* error) {
339 reply(error);
340 }] resetAndEstablish:container context:context altDSID:altDSID resetReason:resetReason reply:reply];
341 }
342
343 - (void)establish:(NSString* _Nullable)container
344 context:(NSString*)context
345 altDSID:(NSString*)altDSID
346 reply:(void (^)(NSError* _Nullable error))reply
347 {
348 [[self getConnection: ^(NSError* error) {
349 reply(error);
350 }] establish:container context:context altDSID:altDSID reply:reply];
351 }
352
353 - (void)leaveClique:(NSString* _Nullable)container
354 context:(NSString*)context
355 reply:(void (^)(NSError* _Nullable error))reply
356 {
357 [[self getConnection: ^(NSError* error) {
358 reply(error);
359 }] leaveClique:container context:context reply:reply];
360 }
361
362 - (void)removeFriendsInClique:(NSString* _Nullable)container
363 context:(NSString*)context
364 peerIDs:(NSArray<NSString*>*)peerIDs
365 reply:(void (^)(NSError* _Nullable error))reply
366 {
367 [[self getConnection: ^(NSError* error) {
368 reply(error);
369 }] removeFriendsInClique:container context:context peerIDs:peerIDs reply:reply];
370 }
371
372 - (void)peerDeviceNamesByPeerID:(NSString* _Nullable)container
373 context:(NSString*)context
374 reply:(void (^)(NSDictionary<NSString*, NSString*>* _Nullable peers, NSError* _Nullable error))reply
375 {
376 [[self getConnection: ^(NSError* error) {
377 reply(nil, error);
378 }] peerDeviceNamesByPeerID:container context:context reply:reply];
379 }
380
381 - (void)fetchAllViableBottles:(NSString* _Nullable)container
382 context:(NSString*)context
383 reply:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs, NSArray<NSString*> * _Nullable sortedPartialBottleIDs, NSError* _Nullable error))reply
384 {
385 [[self getConnection:^(NSError *error) {
386 reply(nil, nil, error);
387 }] fetchAllViableBottles:container context:context reply:reply];
388 }
389
390 -(void)restore:(NSString* _Nullable)containerName
391 contextID:(NSString *)contextID
392 bottleSalt:(NSString *)bottleSalt
393 entropy:(NSData *)entropy
394 bottleID:(NSString *)bottleID
395 reply:(void (^)(NSError * _Nullable))reply
396 {
397 [[self getConnection:^(NSError *error) {
398 reply(error);
399 }] restore:containerName contextID:contextID bottleSalt:bottleSalt entropy:entropy bottleID:bottleID reply:reply];
400 }
401
402 - (void)fetchEscrowContents:(NSString* _Nullable)containerName
403 contextID:(NSString *)contextID
404 reply:(void (^)(NSData* _Nullable entropy,
405 NSString* _Nullable bottleID,
406 NSData* _Nullable signingPublicKey,
407 NSError* _Nullable error))reply
408 {
409 [[self getConnection:^(NSError *error) {
410 reply(nil, nil, nil, error);
411 }] fetchEscrowContents:containerName contextID:contextID reply:reply];
412 }
413
414 - (void) createRecoveryKey:(NSString* _Nullable)containerName
415 contextID:(NSString *)contextID
416 recoveryKey:(NSString *)recoveryKey
417 reply:(void (^)( NSError * error))reply
418 {
419 [[self getConnection:^(NSError *error) {
420 reply(error);
421 }] createRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:reply];
422 }
423
424 - (void) joinWithRecoveryKey:(NSString* _Nullable)containerName
425 contextID:(NSString *)contextID
426 recoveryKey:(NSString*)recoveryKey
427 reply:(void (^)(NSError * _Nullable))reply
428 {
429 [[self getConnection:^(NSError *error) {
430 reply(error);
431 }] joinWithRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:reply];
432 }
433
434 - (void)healthCheck:(NSString *)container
435 context:(NSString *)context
436 skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
437 reply:(void (^)(NSError *_Nullable error))reply
438 {
439 [[self getConnection: ^(NSError* error) {
440 reply(error);
441 }] healthCheck:container context:context skipRateLimitingCheck:skipRateLimitingCheck reply:reply];
442 }
443
444 - (void)waitForOctagonUpgrade:(NSString* _Nullable)container
445 context:(NSString*)context
446 reply:(void (^)(NSError* _Nullable error))reply
447 {
448 [[self getConnection: ^(NSError* error) {
449 reply(error);
450 }] waitForOctagonUpgrade:container context:context reply:reply];
451 }
452
453 - (void)postCDPFollowupResult:(BOOL)success
454 type:(OTCliqueCDPContextType)type
455 error:(NSError * _Nullable)error
456 containerName:(NSString* _Nullable)containerName
457 contextName:(NSString *)contextName
458 reply:(void (^)(NSError* _Nullable error))reply
459 {
460 [[self getConnection: ^(NSError* connectionError) {
461 reply(connectionError);
462 }] postCDPFollowupResult:success type:type error:[SecXPCHelper cleanseErrorForXPC:error] containerName:containerName contextName:contextName reply:reply];
463 }
464
465 - (void)tapToRadar:(NSString *)action
466 description:(NSString *)description
467 radar:(NSString *)radar
468 reply:(void (^)(NSError* _Nullable error))reply
469 {
470 [[self getConnection: ^(NSError* connectionError) {
471 reply(connectionError);
472 }] tapToRadar:action description:description radar:radar reply:reply];
473 }
474
475 - (void)refetchCKKSPolicy:(NSString* _Nullable)container
476 contextID:(NSString*)contextID
477 reply:(void (^)(NSError* _Nullable error))reply
478 {
479 [[self getConnection: ^(NSError* error) {
480 reply(error);
481 }] refetchCKKSPolicy:container contextID:contextID reply:reply];
482 }
483
484 - (void)setCDPEnabled:(NSString* _Nullable)containerName
485 contextID:(NSString*)contextID
486 reply:(void (^)(NSError* _Nullable error))reply
487 {
488 [[self getConnection: ^(NSError* connectionError) {
489 reply(connectionError);
490 }] setCDPEnabled:containerName contextID:contextID reply:reply];
491 }
492
493 - (void)getCDPStatus:(NSString* _Nullable)containerName
494 contextID:(NSString*)contextID
495 reply:(void (^)(OTCDPStatus status, NSError* _Nullable error))reply
496 {
497 [[self getConnection: ^(NSError* connectionError) {
498 reply(OTCDPStatusUnknown, connectionError);
499 }] getCDPStatus:containerName contextID:contextID reply:reply];
500 }
501
502 - (void)fetchEscrowRecords:(NSString * _Nullable)container
503 contextID:(NSString*)contextID
504 forceFetch:(BOOL)forceFetch
505 reply:(void (^)(NSArray<NSData*>* _Nullable records,
506 NSError* _Nullable error))reply
507 {
508 [[self getConnection: ^(NSError* connectionError) {
509 reply(nil, connectionError);
510 }] fetchEscrowRecords:container contextID:contextID forceFetch:forceFetch reply:reply];
511 }
512
513 - (void)setUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
514 contextID:(NSString*)contextID
515 enabled:(BOOL)enabled
516 reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
517 {
518 [[self getConnection: ^(NSError* connectionError) {
519 reply(NO, connectionError);
520 }] setUserControllableViewsSyncStatus:containerName contextID:contextID enabled:enabled reply:reply];
521
522 }
523
524 - (void)fetchUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
525 contextID:(NSString*)contextID
526 reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
527 {
528 [[self getConnection: ^(NSError* connectionError) {
529 reply(NO, connectionError);
530 }] fetchUserControllableViewsSyncStatus:containerName contextID:contextID reply:reply];
531 }
532
533 - (void)invalidateEscrowCache:(NSString * _Nullable)containerName
534 contextID:(NSString*)contextID
535 reply:(nonnull void (^)(NSError * _Nullable error))reply
536 {
537 [[self getConnection: ^(NSError* connectionError) {
538 reply(connectionError);
539 }] invalidateEscrowCache:containerName contextID:contextID reply:reply];
540 }
541
542 + (OTControl*)controlObject:(NSError* __autoreleasing *)error {
543 return [OTControl controlObject:false error:error];
544 }
545
546 + (OTControl*)controlObject:(bool)sync error:(NSError**)error
547 {
548 NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:@(kSecuritydOctagonServiceName) options:0];
549
550 if (connection == nil) {
551 if(error) {
552 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"Couldn't create connection (no reason given)"}];
553 }
554 return nil;
555 }
556
557 NSXPCInterface *interface = OTSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(OTControlProtocol)]);
558 connection.remoteObjectInterface = interface;
559 [connection resume];
560
561 OTControl* c = [[OTControl alloc] initWithConnection:connection sync:sync];
562 return c;
563 }
564
565 @end
566
567 #endif // __OBJC2__