2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #import <Foundation/NSXPCConnection_Private.h>
29 #import <Security/SecItemPriv.h>
30 #import <Security/SecXPCHelper.h>
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"
38 #include <security_utilities/debugging.h>
41 #import <SecurityFoundation/SFKey.h>
44 @interface OTControl ()
45 @property NSXPCConnection *connection;
49 @implementation OTControl
51 - (instancetype)initWithConnection:(NSXPCConnection*)connection sync:(bool)sync {
52 if(self = [super init]) {
53 _connection = connection;
60 [self.connection invalidate];
63 - (NSXPCConnection<OTControlProtocol>*)getConnection:(void (^)(NSError *error))handler
66 return [self.connection synchronousRemoteObjectProxyWithErrorHandler: handler];
68 return [self.connection remoteObjectProxyWithErrorHandler: handler];
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
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);
82 -(void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply
84 [[self getConnection: ^(NSError* error) {
86 }] reset:^(BOOL result, NSError * _Nullable error) {
91 - (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply
93 [self octagonSigningPublicKey:reply];
96 - (void)octagonSigningPublicKey:(nonnull void (^)(NSData * _Nullable, NSError * _Nullable))reply {
97 [[self getConnection: ^(NSError* error) {
99 }] octagonSigningPublicKey:^(NSData *signingKey, NSError * _Nullable error) {
100 reply(signingKey, error);
105 - (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply
107 [self octagonEncryptionPublicKey:reply];
110 - (void)octagonEncryptionPublicKey:(nonnull void (^)(NSData * _Nullable, NSError * _Nullable))reply
112 [[self getConnection: ^(NSError* error) {
114 }] octagonEncryptionPublicKey:^(NSData *encryptionKey, NSError * _Nullable error) {
115 reply(encryptionKey, error);
119 - (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply
121 [self listOfEligibleBottledPeerRecords:reply];
124 - (void)listOfEligibleBottledPeerRecords:(nonnull void (^)(NSArray * _Nullable, NSError * _Nullable))reply
126 [[self getConnection: ^(NSError* error) {
128 }] listOfEligibleBottledPeerRecords:^(NSArray *list, NSError * _Nullable error) {
134 - (void)signIn:(NSString*)altDSID container:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
136 [[self getConnection: ^(NSError* error) {
138 }] signIn:altDSID container:container context:contextID reply:^(NSError * _Nullable error) {
143 - (void)signOut:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
145 [[self getConnection: ^(NSError* error) {
147 }] signOut:container context:contextID reply:^(NSError * _Nullable error) {
152 - (void)notifyIDMSTrustLevelChangeForContainer:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply
154 [[self getConnection: ^(NSError* error) {
156 }] notifyIDMSTrustLevelChangeForContainer:container context:contextID reply:^(NSError * _Nullable error) {
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
168 [[self getConnection: ^(NSError* error) {
170 }] handleIdentityChangeForSigningKey:peerSigningKey ForEncryptionKey:encryptionKey ForPeerID:peerID reply:^(BOOL result, NSError* _Nullable error) {
171 reply(result, error);
178 - (void)rpcEpochWithConfiguration:(OTJoiningConfiguration*)config
179 reply:(void (^)(uint64_t epoch,
180 NSError * _Nullable error))reply
183 [[self getConnection: ^(NSError* error) {
185 }] rpcEpochWithConfiguration:config reply:^(uint64_t epoch,
186 NSError * _Nullable error) {
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
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);
209 reply(NULL, NULL, NULL, NULL, NULL, NULL);
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
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);
228 reply(NULL, NULL, NULL);
232 - (void)rpcJoinWithConfiguration:(OTJoiningConfiguration*)config
233 vouchData:(NSData*)vouchData
234 vouchSig:(NSData*)vouchSig
235 preapprovedKeys:(NSArray<NSData*>* _Nullable)preapprovedKeys
236 reply:(void (^)(NSError * _Nullable error))reply
239 [[self getConnection: ^(NSError* error) {
241 }] rpcJoinWithConfiguration:config vouchData:vouchData vouchSig:vouchSig preapprovedKeys:preapprovedKeys reply:^(NSError* e) {
249 - (void)preflightBottledPeer:(NSString*)contextID
251 reply:(void (^)(NSData* _Nullable entropy,
252 NSString* _Nullable bottleID,
253 NSData* _Nullable signingPublicKey,
254 NSError* _Nullable error))reply
256 [[self getConnection: ^(NSError* error) {
257 reply(nil, nil, nil, error);
258 }] preflightBottledPeer:contextID dsid:dsid reply:^(NSData* _Nullable entropy,
259 NSString* _Nullable bottleID,
260 NSData* _Nullable signingPublicKey,
261 NSError* _Nullable error) {
262 reply(entropy, bottleID, signingPublicKey, error);
266 - (void)launchBottledPeer:(NSString*)contextID
267 bottleID:(NSString*)bottleID
268 reply:(void (^ _Nullable)(NSError* _Nullable))reply
270 [[self getConnection: ^(NSError* error) {
272 }] launchBottledPeer:contextID bottleID:bottleID reply:^(NSError * _Nullable error) {
277 - (void)scrubBottledPeer:(NSString*)contextID
278 bottleID:(NSString*)bottleID
279 reply:(void (^ _Nullable)(NSError* _Nullable))reply
281 [[self getConnection: ^(NSError* error) {
283 }] scrubBottledPeer:contextID bottleID:bottleID reply:reply];
286 - (void)status:(NSString* _Nullable)container
287 context:(NSString*)context
288 reply:(void (^)(NSDictionary* _Nullable result, NSError* _Nullable error))reply
290 [[self getConnection: ^(NSError* error) {
292 }] status:container context:context reply:reply];
295 - (void)fetchEgoPeerID:(NSString* _Nullable)container
296 context:(NSString*)context
297 reply:(void (^)(NSString* _Nullable peerID, NSError* _Nullable error))reply
299 [[self getConnection: ^(NSError* error) {
301 }] fetchEgoPeerID:container context:context reply:reply];
304 - (void)fetchCliqueStatus:(NSString* _Nullable)container
305 context:(NSString*)context
306 configuration:(OTOperationConfiguration*)configuration
307 reply:(void (^)(CliqueStatus cliqueStatus, NSError* _Nullable error))reply
309 [[self getConnection: ^(NSError* error) {
310 reply(CliqueStatusError, error);
311 }] fetchCliqueStatus:container context:context configuration:configuration reply:reply];
314 - (void)fetchTrustStatus:(NSString* _Nullable)container
315 context:(NSString*)context
316 configuration:(OTOperationConfiguration *)configuration
317 reply:(void (^)(CliqueStatus status, NSString* peerID, NSNumber * _Nullable numberOfOctagonPeers, BOOL isExcluded, NSError * _Nullable error))reply
319 [[self getConnection: ^(NSError* error) {
320 reply(CliqueStatusError, false, NULL, false, error);
321 }] fetchTrustStatus:container context:context configuration:configuration reply:reply];
324 - (void)startOctagonStateMachine:(NSString* _Nullable)container
325 context:(NSString*)context
326 reply:(void (^)(NSError* _Nullable error))reply
328 [[self getConnection: ^(NSError* error) {
330 }] startOctagonStateMachine:container context:context reply:reply];
333 - (void)resetAndEstablish:(NSString* _Nullable)container
334 context:(NSString*)context
335 altDSID:(NSString*)altDSID
336 resetReason:(CuttlefishResetReason)resetReason
337 reply:(void (^)(NSError* _Nullable error))reply
339 [[self getConnection: ^(NSError* error) {
341 }] resetAndEstablish:container context:context altDSID:altDSID resetReason:resetReason reply:reply];
344 - (void)establish:(NSString* _Nullable)container
345 context:(NSString*)context
346 altDSID:(NSString*)altDSID
347 reply:(void (^)(NSError* _Nullable error))reply
349 [[self getConnection: ^(NSError* error) {
351 }] establish:container context:context altDSID:altDSID reply:reply];
354 - (void)leaveClique:(NSString* _Nullable)container
355 context:(NSString*)context
356 reply:(void (^)(NSError* _Nullable error))reply
358 [[self getConnection: ^(NSError* error) {
360 }] leaveClique:container context:context reply:reply];
363 - (void)removeFriendsInClique:(NSString* _Nullable)container
364 context:(NSString*)context
365 peerIDs:(NSArray<NSString*>*)peerIDs
366 reply:(void (^)(NSError* _Nullable error))reply
368 [[self getConnection: ^(NSError* error) {
370 }] removeFriendsInClique:container context:context peerIDs:peerIDs reply:reply];
373 - (void)peerDeviceNamesByPeerID:(NSString* _Nullable)container
374 context:(NSString*)context
375 reply:(void (^)(NSDictionary<NSString*, NSString*>* _Nullable peers, NSError* _Nullable error))reply
377 [[self getConnection: ^(NSError* error) {
379 }] peerDeviceNamesByPeerID:container context:context reply:reply];
382 - (void)fetchAllViableBottles:(NSString* _Nullable)container
383 context:(NSString*)context
384 reply:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs, NSArray<NSString*> * _Nullable sortedPartialBottleIDs, NSError* _Nullable error))reply
386 [[self getConnection:^(NSError *error) {
387 reply(nil, nil, error);
388 }] fetchAllViableBottles:container context:context reply:reply];
391 -(void)restore:(NSString* _Nullable)containerName
392 contextID:(NSString *)contextID
393 bottleSalt:(NSString *)bottleSalt
394 entropy:(NSData *)entropy
395 bottleID:(NSString *)bottleID
396 reply:(void (^)(NSError * _Nullable))reply
398 [[self getConnection:^(NSError *error) {
400 }] restore:containerName contextID:contextID bottleSalt:bottleSalt entropy:entropy bottleID:bottleID reply:reply];
403 - (void)fetchEscrowContents:(NSString* _Nullable)containerName
404 contextID:(NSString *)contextID
405 reply:(void (^)(NSData* _Nullable entropy,
406 NSString* _Nullable bottleID,
407 NSData* _Nullable signingPublicKey,
408 NSError* _Nullable error))reply
410 [[self getConnection:^(NSError *error) {
411 reply(nil, nil, nil, error);
412 }] fetchEscrowContents:containerName contextID:contextID reply:reply];
415 - (void) createRecoveryKey:(NSString* _Nullable)containerName
416 contextID:(NSString *)contextID
417 recoveryKey:(NSString *)recoveryKey
418 reply:(void (^)( NSError * error))reply
420 [[self getConnection:^(NSError *error) {
422 }] createRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:reply];
425 - (void) joinWithRecoveryKey:(NSString* _Nullable)containerName
426 contextID:(NSString *)contextID
427 recoveryKey:(NSString*)recoveryKey
428 reply:(void (^)(NSError * _Nullable))reply
430 [[self getConnection:^(NSError *error) {
432 }] joinWithRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:reply];
435 - (void)healthCheck:(NSString *)container
436 context:(NSString *)context
437 skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
438 reply:(void (^)(NSError *_Nullable error))reply
440 [[self getConnection: ^(NSError* error) {
442 }] healthCheck:container context:context skipRateLimitingCheck:skipRateLimitingCheck reply:reply];
445 - (void)attemptSosUpgrade:(NSString* _Nullable)container
446 context:(NSString*)context
447 reply:(void (^)(NSError* _Nullable error))reply
449 [[self getConnection: ^(NSError* error) {
451 }] attemptSosUpgrade:container context:context reply:reply];
454 - (void)waitForOctagonUpgrade:(NSString* _Nullable)container
455 context:(NSString*)context
456 reply:(void (^)(NSError* _Nullable error))reply
458 [[self getConnection: ^(NSError* error) {
460 }] waitForOctagonUpgrade:container context:context reply:reply];
463 - (void)postCDPFollowupResult:(BOOL)success
464 type:(OTCliqueCDPContextType)type
465 error:(NSError * _Nullable)error
466 containerName:(NSString* _Nullable)containerName
467 contextName:(NSString *)contextName
468 reply:(void (^)(NSError* _Nullable error))reply
470 [[self getConnection: ^(NSError* connectionError) {
471 reply(connectionError);
472 }] postCDPFollowupResult:success type:type error:[SecXPCHelper cleanseErrorForXPC:error] containerName:containerName contextName:contextName reply:reply];
475 - (void)tapToRadar:(NSString *)action
476 description:(NSString *)description
477 radar:(NSString *)radar
478 reply:(void (^)(NSError* _Nullable error))reply
480 [[self getConnection: ^(NSError* connectionError) {
481 reply(connectionError);
482 }] tapToRadar:action description:description radar:radar reply:reply];
485 + (OTControl*)controlObject:(NSError* __autoreleasing *)error {
486 return [OTControl controlObject:false error:error];
489 + (OTControl*)controlObject:(bool)sync error:(NSError**)error
491 NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:@(kSecuritydOctagonServiceName) options:0];
493 if (connection == nil) {
495 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"Couldn't create connection (no reason given)"}];
500 NSXPCInterface *interface = OTSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(OTControlProtocol)]);
501 connection.remoteObjectInterface = interface;
504 OTControl* c = [[OTControl alloc] initWithConnection:connection sync:sync];