]> git.saurik.com Git - apple/security.git/blob - keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / Trieste / OctagonTestHarnessXPCService / SecRemoteDevice.m
1 /*
2 * Copyright (c) 2017 - 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
25 #import <Foundation/Foundation.h>
26 #import <Foundation/NSXPCConnection_Private.h>
27 #import "keychain/securityd/SOSCloudCircleServer.h"
28 #import <Security/SecureObjectSync/SOSPeerInfo.h>
29 #import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
30 #import <Security/SecureObjectSync/SOSViews.h>
31 #import "keychain/SecureObjectSync/SOSTypes.h"
32 #import "keychain/SecureObjectSync/SOSInternal.h"
33 #import "keychain/SecureObjectSync/SOSAuthKitHelpers.h"
34 #import "OSX/sec/Security/SecItemShim.h"
35
36 #import <stdlib.h>
37 #import <unistd.h>
38 #import <libproc.h>
39
40 #import "keychain/ckks/CKKS.h"
41 #import "keychain/ot/OTManager.h"
42 #import "keychain/ot/OT.h"
43 #import "keychain/ot/OTControl.h"
44 #import "keychain/ot/OTCuttlefishContext.h"
45 #import "keychain/categories/NSError+UsefulConstructors.h"
46 #import "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
47 #import "keychain/SecureObjectSync/SOSControlServer.h"
48 #import "KeychainCircle/PairingChannel.h"
49
50 #import "SharedMocks/NSXPCConnectionMock.h"
51
52 #import "SecRemoteDeviceProtocol.h"
53 #import "SecRemoteDevice.h"
54
55 @interface DevicePairingSimulator : NSObject <DevicePairingProtocol>
56 @property KCPairingChannelContext *remoteVersionContext;
57 @property KCPairingChannel *channel;
58 @property SecRemoteDevice *device;
59 @property (assign) bool initiator;
60 @property (assign) bool haveHandshakeCompleted;
61
62 - (instancetype)init NS_UNAVAILABLE;
63 - (instancetype)initAsInitiator:(bool)initiator version:(KCPairingChannelContext *)peerVersionContext device:(SecRemoteDevice *)device;
64 @end
65
66 @implementation DevicePairingSimulator
67
68 - (instancetype)initAsInitiator:(bool)initiator version:(KCPairingChannelContext *)peerVersionContext device:(SecRemoteDevice *)device
69 {
70 if ((self = [super init])) {
71 self.remoteVersionContext = peerVersionContext;
72 self.initiator = initiator;
73 self.device = device;
74 self.channel = [[KCPairingChannel alloc] initAsInitiator:initiator version:peerVersionContext];
75 #if SECD_SERVER
76 [self.channel setXPCConnectionObject:(NSXPCConnection *)[[NSXPCConnectionMock alloc] initWithRealObject:SOSControlServerInternalClient()]];
77 #endif
78 }
79
80 return self;
81 }
82
83 - (void)exchangePacket:(NSData *)data complete:(void (^)(bool complete, NSData *result, NSError *error))complete
84 {
85 os_log(NULL, "[%@] exchangePacket", self.device.name);
86
87 if (self.haveHandshakeCompleted || self.channel == NULL) {
88 abort();
89 }
90 [self.channel exchangePacket:data complete:^void(BOOL handshakeComplete, NSData *packet, NSError *error) {
91 self.haveHandshakeCompleted = handshakeComplete;
92 os_log(NULL, "[%@] exchangePacket:complete: %d", self.device.name, handshakeComplete);
93 complete(handshakeComplete, packet, error);
94 }];
95 }
96
97 - (void)validateStart:(void(^)(bool result, NSError *error))complete
98 {
99 if (self.channel == NULL) {
100 abort();
101 }
102 [self.channel validateStart:^(bool result, NSError *error) {
103 complete(result, error);
104 }];
105 }
106 @end
107
108
109 @implementation SecRemoteDevice
110
111
112 - (void)setUserCredentials:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete
113 {
114 CFErrorRef cferror = NULL;
115 bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)username,
116 (__bridge CFDataRef)[password dataUsingEncoding:NSUTF8StringEncoding],
117 CFSTR("1"), &cferror);
118 complete(result, (__bridge NSError *)cferror);
119 CFReleaseNull(cferror);
120 }
121
122 - (void)setupSOSCircle:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete
123 {
124 CFErrorRef cferror = NULL;
125 bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)username,
126 (__bridge CFDataRef)[password dataUsingEncoding:NSUTF8StringEncoding],
127 CFSTR("1"), &cferror);
128 if (result) {
129 result = SOSCCResetToOffering(&cferror);
130 }
131 complete(result, (__bridge NSError *)cferror);
132 CFReleaseNull(cferror);
133 }
134
135 - (void)sosCircleStatus:(void(^)(SOSCCStatus status, NSError *error))complete
136 {
137 SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
138 CFErrorRef cferror = NULL;
139 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
140 complete(status, (__bridge NSError *)cferror);
141 CFReleaseNull(cferror);
142 });
143 }
144
145 - (void)sosCircleStatusNonCached:(void(^)(SOSCCStatus status, NSError *error))complete
146 {
147 SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
148 CFErrorRef cferror = NULL;
149 SOSCCStatus status = SOSCCThisDeviceIsInCircleNonCached(&cferror);
150 complete(status, (__bridge NSError *)cferror);
151 CFReleaseNull(cferror);
152 });
153 }
154
155
156 - (void)sosViewStatus:(NSString *) viewName withCompletion: (void(^)(SOSViewResultCode status, NSError *error))complete
157 {
158 CFErrorRef cferror = NULL;
159 SOSViewResultCode status = SOSCCView((__bridge CFStringRef)(viewName), kSOSCCViewQuery, &cferror);
160 complete(status, (__bridge NSError *)cferror);
161 CFReleaseNull(cferror);
162 }
163
164
165 - (void)sosICKStatus: (void(^)(bool status))complete
166 {
167 CFErrorRef cferror = NULL;
168 bool status = SOSCCIsIcloudKeychainSyncing();
169 complete(status);
170 CFReleaseNull(cferror);
171 }
172
173 - (void)sosPeerID:(void (^)(NSString *))complete
174 {
175 CFErrorRef cferror = NULL;
176 CFStringRef peerID = NULL;
177 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
178 if (peerInfo)
179 peerID = SOSPeerInfoGetPeerID(peerInfo);
180
181 complete((__bridge NSString *)peerID);
182 CFReleaseNull(peerInfo);
183 }
184
185 - (void)sosPeerSerial:(void(^)(NSString * _Nullable peerSerial))complete {
186 CFErrorRef cferror = NULL;
187 CFStringRef peerSerial = NULL;
188 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
189 if (peerInfo)
190 peerSerial = SOSPeerInfoCopySerialNumber(peerInfo);
191 complete((__bridge NSString *)peerSerial);
192 CFReleaseNull(peerSerial);
193 CFReleaseNull(peerInfo);
194 }
195
196 - (void)sosCirclePeerIDs:(void (^)(NSArray<NSString *> *))complete
197 {
198 CFErrorRef error = NULL;
199 NSArray *array = CFBridgingRelease(SOSCCCopyConcurringPeerPeerInfo(&error));
200 NSMutableArray<NSString *> *peerIDs = [NSMutableArray new];
201
202 if (array) {
203 [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
204 SOSPeerInfoRef peerInfo = (__bridge SOSPeerInfoRef)obj;
205 NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
206 [peerIDs addObject:peerID];
207 }];
208 }
209 complete(peerIDs);
210 }
211
212 - (void)sosRequestToJoin:(void(^)(bool success, NSString *peerID, NSError *error))complete
213 {
214 CFErrorRef cferror = NULL;
215
216 os_log(NULL, "[%@] sosRequestToJoin", self.name);
217
218 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
219 if (status == kSOSCCCircleAbsent) {
220 cferror = CFErrorCreate(NULL, CFSTR("MDCircleAbsent"), 1, NULL);
221 complete(false, NULL, (__bridge NSError *)cferror);
222 CFReleaseNull(cferror);
223 } else if (status == kSOSCCNotInCircle) {
224 CFReleaseNull(cferror);
225 NSString *peerID = NULL;
226 bool result = SOSCCRequestToJoinCircle(&cferror);
227 if (result) {
228 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
229 if (peerInfo) {
230 peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
231 }
232 CFReleaseNull(peerInfo);
233 CFReleaseNull(cferror);
234 }
235 complete(result, peerID, (__bridge NSError *)cferror);
236 CFReleaseNull(cferror);
237 } else {
238 if(!cferror) {
239 cferror = CFErrorCreate(NULL, CFSTR("MDGeneralJoinError"), 1, NULL);
240 }
241 complete(false, NULL, (__bridge NSError *)cferror);
242 CFReleaseNull(cferror);
243 }
244 }
245
246 - (void)sosLeaveCircle: (void(^)(bool success, NSError *error))complete {
247 CFErrorRef cferror = NULL;
248 bool retval = false;
249
250 os_log(NULL, "[%@] sosLeaveCircle", self.name);
251
252 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
253 if(status == kSOSCCInCircle || status == kSOSCCRequestPending) {
254 retval = SOSCCRemoveThisDeviceFromCircle(&cferror);
255 }
256 complete(retval, (__bridge NSError *) cferror);
257 CFReleaseNull(cferror);
258 }
259
260
261 - (void)sosApprovePeer:(NSString *)peerID complete:(void(^)(BOOL success, NSError *error))complete
262 {
263 CFErrorRef cferror = NULL;
264 os_log(NULL, "[%@] sosApprovePeer: %@", self.name, peerID);
265 NSArray *applicants = CFBridgingRelease(SOSCCCopyApplicantPeerInfo(&cferror));
266 if ([applicants count] == 0) {
267 CFReleaseNull(cferror);
268 cferror = CFErrorCreate(NULL, CFSTR("MDNoApplicant"), 1, NULL);
269 complete(false, (__bridge NSError *)cferror);
270 CFReleaseNull(cferror);
271 return;
272 }
273 NSMutableArray *approvedApplicants = [NSMutableArray array];
274 for (id peer in applicants) {
275 SOSPeerInfoRef peerInfo = (__bridge SOSPeerInfoRef)peer;
276 NSString *applicantPeerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
277 if (peerID == NULL || [peerID isEqualToString:applicantPeerID]){
278 [approvedApplicants addObject:(__bridge id)peerInfo];
279 }
280 }
281 bool result = false;
282 if ([approvedApplicants count]) {
283 result = SOSCCAcceptApplicants((__bridge CFArrayRef)approvedApplicants, &cferror);
284 } else {
285 cferror = CFErrorCreate(NULL, CFSTR("MDNoApplicant"), 1, NULL);
286 }
287 complete(result, (__bridge NSError *)cferror);
288 CFReleaseNull(cferror);
289 }
290
291 - (void)sosGhostBust:(SOSAccountGhostBustingOptions)options complete:(void(^)(bool busted, NSError *error))complete {
292 os_log(NULL, "[%@] sosGhostBust", self.name);
293 SOSCCGhostBust(options, ^(bool busted, NSError *error) {
294 os_log(NULL, "[%@] sosGhostBust: %sbusted error: %@", self.name, busted ? "" : "no ", error);
295 complete(busted, error);
296 });
297 }
298
299 - (void)sosCircleHash: (void(^)(NSString *data, NSError * _Nullable error))complete
300 {
301 NSError *error = NULL;
302 NSString *hash = SOSCCCircleHash(&error);
303 complete(hash, error);
304 }
305
306
307 - (void)sosWaitForInitialSync:(void(^)(bool success, NSError *error))complete
308 {
309 CFErrorRef cferror = NULL;
310 bool success = SOSCCWaitForInitialSync(&cferror);
311 complete(success, (__bridge NSError *)cferror);
312 CFReleaseNull(cferror);
313 }
314
315 - (void)sosEnableAllViews:(void(^)(BOOL success, NSError *error))complete
316 {
317 CFMutableSetRef viewsToEnable = SOSViewCopyViewSet(kViewSetAll);
318 CFMutableSetRef viewsToDisable = CFSetCreateMutable(NULL, 0, NULL);
319
320 bool success = SOSCCViewSet(viewsToEnable, viewsToDisable);
321 CFRelease(viewsToEnable);
322 CFRelease(viewsToDisable);
323 complete(success, NULL);
324
325 }
326
327 - (void) sosCachedViewBitmask: (void(^)(uint64_t bitmask))complete {
328 uint64_t result = SOSCachedViewBitmask();
329 complete(result);
330 }
331
332 - (void) deviceInfo:(nonnull void (^)(NSString * _Nullable, NSString * _Nullable, NSError * _Nullable))complete {
333 complete(@"", @"", NULL);
334 }
335
336
337 // MARK: - Pairing
338
339 - (void)pairingChannelSetup:(bool)initiator pairingContext:(KCPairingChannelContext *)context complete:(void (^)(id<DevicePairingProtocol>, NSError *))complete {
340
341 DevicePairingSimulator *pairingSim = [[DevicePairingSimulator alloc] initAsInitiator:initiator version:context device:self];
342 complete(pairingSim, nil);
343 }
344
345 // MARK: - Diagnostics
346
347 - (void)diagnosticsLeaks:(void(^)(bool success, NSString *outout, NSError *error))complete
348 {
349 complete(true, NULL, NULL);
350 }
351
352 - (void)diagnosticsCPUUsage:(void(^)(bool success, uint64_t user_usec, uint64_t sys_usec, NSError *error))complete
353 {
354 struct rusage usage;
355 getrusage(RUSAGE_SELF, &usage);
356 uint64_t user_usec = usage.ru_utime.tv_sec * USEC_PER_SEC + usage.ru_utime.tv_usec;
357 uint64_t sys_usec = usage.ru_stime.tv_sec * USEC_PER_SEC + usage.ru_stime.tv_usec;
358
359 complete(true, user_usec, sys_usec, NULL);
360 }
361
362 - (void)diagnosticsDiskUsage:(void(^)(bool success, uint64_t usage, NSError *error))complete
363 {
364 rusage_info_current rusage;
365
366 if (proc_pid_rusage(getpid(), RUSAGE_INFO_CURRENT, (rusage_info_t *)&rusage) == 0) {
367 complete(true, rusage.ri_logical_writes, NULL);
368 } else {
369 complete(false, 0, NULL);
370 }
371 }
372
373 // MARK: - Octagon
374 - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success, NSError *_Nullable error))complete
375 {
376 #if OCTAGON
377 OTControl *ot = [self OTControl];
378
379 [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID resetReason:CuttlefishResetReasonTestGenerated reply:^(NSError * _Nullable error) {
380 complete(error == NULL, error);
381 }];
382 #else
383 complete(false, [self octagonNotAvailableError]);
384 #endif
385 }
386
387 - (void)otPeerID:(NSString *)altDSID complete:(void (^)(NSString *peerID, NSError *_Nullable error))complete
388 {
389 #if OCTAGON
390 OTControl *ot = [self OTControl];
391 [ot fetchEgoPeerID:nil context:OTDefaultContext reply:^(NSString * _Nullable peerID, NSError * _Nullable error) {
392 complete(peerID, error);
393 }];
394 #else
395 complete(false, [self octagonNotAvailableError]);
396 #endif
397
398 }
399
400 - (void)otInCircle:(NSString *)altDSID complete:(void (^)(bool inCircle, NSError *_Nullable error))complete
401 {
402 #if OCTAGON
403 OTControl *ot = [self OTControl];
404 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
405 [ot fetchCliqueStatus:nil context:OTDefaultContext configuration:configuration reply:^(CliqueStatus cliqueStatus, NSError * _Nullable error) {
406 os_log(NULL, "[%@] otInCircle: clique: %d error: %@", self.name, (int)cliqueStatus, error);
407 complete(cliqueStatus == CliqueStatusIn, error);
408 }];
409 #else
410 complete(false, [self octagonNotAvailableError]);
411 #endif
412 }
413
414
415 //MARK: - Misc helpers
416
417 #if OCTAGON
418
419 - (OTControl *)OTControl
420 {
421 #if SECD_SERVER
422 return [[OTControl alloc] initWithConnection:(NSXPCConnection *)[[NSXPCConnectionMock alloc] initWithRealObject:[OTManager manager]] sync:true];
423 #else
424 NSError *error = NULL;
425 return [OTControl controlObject:true error:&error];
426 #endif
427 }
428
429 #else /* !OCTAGON */
430
431 - (NSError *)octagonNotAvailableError
432 {
433 return [NSError errorWithDomain:@"DeviceSimulator" code:1 description:@"no octagon available"];
434 }
435 #endif
436
437 @end