]> git.saurik.com Git - apple/security.git/blob - keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m
Security-59306.41.2.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 self = [super init];
71 if (self) {
72 self.remoteVersionContext = peerVersionContext;
73 self.initiator = initiator;
74 self.device = device;
75 self.channel = [[KCPairingChannel alloc] initAsInitiator:initiator version:peerVersionContext];
76 #if SECD_SERVER
77 [self.channel setXPCConnectionObject:(NSXPCConnection *)[[NSXPCConnectionMock alloc] initWithRealObject:SOSControlServerInternalClient()]];
78 #endif
79 }
80
81 return self;
82 }
83
84 - (void)exchangePacket:(NSData *)data complete:(void (^)(bool complete, NSData *result, NSError *error))complete
85 {
86 os_log(NULL, "[%@] exchangePacket", self.device.name);
87
88 if (self.haveHandshakeCompleted || self.channel == NULL) {
89 abort();
90 }
91 [self.channel exchangePacket:data complete:^void(BOOL handshakeComplete, NSData *packet, NSError *error) {
92 self.haveHandshakeCompleted = handshakeComplete;
93 os_log(NULL, "[%@] exchangePacket:complete: %d", self.device.name, handshakeComplete);
94 complete(handshakeComplete, packet, error);
95 }];
96 }
97
98 - (void)validateStart:(void(^)(bool result, NSError *error))complete
99 {
100 if (self.channel == NULL) {
101 abort();
102 }
103 [self.channel validateStart:^(bool result, NSError *error) {
104 complete(result, error);
105 }];
106 }
107 @end
108
109
110 @implementation SecRemoteDevice
111
112 - (void)secItemAdd:(NSDictionary *)input complete:(void (^)(OSStatus, NSDictionary *))reply
113 {
114 NSMutableDictionary *attributes = [input mutableCopy];
115 CFTypeRef data = NULL;
116
117 attributes[(__bridge NSString *)kSecReturnAttributes] = @YES;
118 attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES;
119 attributes[(__bridge NSString *)kSecReturnData] = @YES;
120
121 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, &data);
122 NSDictionary *returnData = CFBridgingRelease(data);
123
124 reply(status, returnData);
125 }
126
127 - (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(OSStatus, NSArray<NSDictionary *>*))reply
128 {
129 NSMutableDictionary *attributes = [input mutableCopy];
130 CFTypeRef data = NULL;
131
132 attributes[(__bridge NSString *)kSecReturnAttributes] = @YES;
133 attributes[(__bridge NSString *)kSecReturnData] = @YES;
134 attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES;
135 attributes[(__bridge NSString *)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
136
137 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &data);
138 NSArray<NSDictionary *>* array = CFBridgingRelease(data);
139 NSMutableArray *result = [NSMutableArray array];
140 for (NSDictionary *d in array) {
141 NSMutableDictionary *r = [d mutableCopy];
142 r[@"accc"] = nil;
143 [result addObject:r];
144 }
145
146 reply(status, result);
147 }
148
149 - (void)setUserCredentials:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete
150 {
151 CFErrorRef cferror = NULL;
152 bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)username,
153 (__bridge CFDataRef)[password dataUsingEncoding:NSUTF8StringEncoding],
154 CFSTR("1"), &cferror);
155 complete(result, (__bridge NSError *)cferror);
156 CFReleaseNull(cferror);
157 }
158
159 - (void)setupSOSCircle:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete
160 {
161 CFErrorRef cferror = NULL;
162 bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)username,
163 (__bridge CFDataRef)[password dataUsingEncoding:NSUTF8StringEncoding],
164 CFSTR("1"), &cferror);
165 if (result) {
166 result = SOSCCResetToOffering(&cferror);
167 }
168 complete(result, (__bridge NSError *)cferror);
169 CFReleaseNull(cferror);
170 }
171
172 - (void)sosCircleStatus:(void(^)(SOSCCStatus status, NSError *error))complete
173 {
174 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
175 CFErrorRef cferror = NULL;
176 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
177 complete(status, (__bridge NSError *)cferror);
178 CFReleaseNull(cferror);
179 });
180 }
181
182 - (void)sosCircleStatusNonCached:(void(^)(SOSCCStatus status, NSError *error))complete
183 {
184 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
185 CFErrorRef cferror = NULL;
186 SOSCCStatus status = SOSCCThisDeviceIsInCircleNonCached(&cferror);
187 complete(status, (__bridge NSError *)cferror);
188 CFReleaseNull(cferror);
189 });
190 }
191
192
193 - (void)sosViewStatus:(NSString *) viewName withCompletion: (void(^)(SOSViewResultCode status, NSError *error))complete
194 {
195 CFErrorRef cferror = NULL;
196 SOSViewResultCode status = SOSCCView((__bridge CFStringRef)(viewName), kSOSCCViewQuery, &cferror);
197 complete(status, (__bridge NSError *)cferror);
198 CFReleaseNull(cferror);
199 }
200
201
202 - (void)sosICKStatus: (void(^)(bool status))complete
203 {
204 CFErrorRef cferror = NULL;
205 bool status = SOSCCIsIcloudKeychainSyncing();
206 complete(status);
207 CFReleaseNull(cferror);
208 }
209
210 - (void)sosPeerID:(void (^)(NSString *))complete
211 {
212 CFErrorRef cferror = NULL;
213 CFStringRef peerID = NULL;
214 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
215 if (peerInfo)
216 peerID = SOSPeerInfoGetPeerID(peerInfo);
217
218 complete((__bridge NSString *)peerID);
219 CFReleaseNull(peerInfo);
220 }
221
222 - (void)sosPeerSerial:(void(^)(NSString * _Nullable peerSerial))complete {
223 CFErrorRef cferror = NULL;
224 CFStringRef peerSerial = NULL;
225 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
226 if (peerInfo)
227 peerSerial = SOSPeerInfoCopySerialNumber(peerInfo);
228 complete((__bridge NSString *)peerSerial);
229 CFReleaseNull(peerSerial);
230 CFReleaseNull(peerInfo);
231 }
232
233 - (void)sosCirclePeerIDs:(void (^)(NSArray<NSString *> *))complete
234 {
235 CFErrorRef error = NULL;
236 NSArray *array = CFBridgingRelease(SOSCCCopyConcurringPeerPeerInfo(&error));
237 NSMutableArray<NSString *> *peerIDs = [NSMutableArray new];
238
239 if (array) {
240 [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
241 SOSPeerInfoRef peerInfo = (__bridge SOSPeerInfoRef)obj;
242 NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
243 [peerIDs addObject:peerID];
244 }];
245 }
246 complete(peerIDs);
247 }
248
249 - (void)sosRequestToJoin:(void(^)(bool success, NSString *peerID, NSError *error))complete
250 {
251 CFErrorRef cferror = NULL;
252
253 os_log(NULL, "[%@] sosRequestToJoin", self.name);
254
255 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
256 if (status == kSOSCCCircleAbsent) {
257 cferror = CFErrorCreate(NULL, CFSTR("MDCircleAbsent"), 1, NULL);
258 complete(false, NULL, (__bridge NSError *)cferror);
259 CFReleaseNull(cferror);
260 } else if (status == kSOSCCNotInCircle) {
261 CFReleaseNull(cferror);
262 NSString *peerID = NULL;
263 bool result = SOSCCRequestToJoinCircle(&cferror);
264 if (result) {
265 SOSPeerInfoRef peerInfo = SOSCCCopyMyPeerInfo(&cferror);
266 if (peerInfo) {
267 peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
268 }
269 CFReleaseNull(peerInfo);
270 CFReleaseNull(cferror);
271 }
272 complete(result, peerID, (__bridge NSError *)cferror);
273 CFReleaseNull(cferror);
274 } else {
275 if(!cferror) {
276 cferror = CFErrorCreate(NULL, CFSTR("MDGeneralJoinError"), 1, NULL);
277 }
278 complete(false, NULL, (__bridge NSError *)cferror);
279 CFReleaseNull(cferror);
280 }
281 }
282
283 - (void)sosLeaveCircle: (void(^)(bool success, NSError *error))complete {
284 CFErrorRef cferror = NULL;
285 bool retval = false;
286
287 os_log(NULL, "[%@] sosLeaveCircle", self.name);
288
289 SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
290 if(status == kSOSCCInCircle || status == kSOSCCRequestPending) {
291 retval = SOSCCRemoveThisDeviceFromCircle(&cferror);
292 }
293 complete(retval, (__bridge NSError *) cferror);
294 CFReleaseNull(cferror);
295 }
296
297
298 - (void)sosApprovePeer:(NSString *)peerID complete:(void(^)(BOOL success, NSError *error))complete
299 {
300 CFErrorRef cferror = NULL;
301 os_log(NULL, "[%@] sosApprovePeer: %@", self.name, peerID);
302 NSArray *applicants = CFBridgingRelease(SOSCCCopyApplicantPeerInfo(&cferror));
303 if ([applicants count] == 0) {
304 CFReleaseNull(cferror);
305 cferror = CFErrorCreate(NULL, CFSTR("MDNoApplicant"), 1, NULL);
306 complete(false, (__bridge NSError *)cferror);
307 CFReleaseNull(cferror);
308 return;
309 }
310 NSMutableArray *approvedApplicants = [NSMutableArray array];
311 for (id peer in applicants) {
312 SOSPeerInfoRef peerInfo = (__bridge SOSPeerInfoRef)peer;
313 NSString *applicantPeerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peerInfo);
314 if (peerID == NULL || [peerID isEqualToString:applicantPeerID]){
315 [approvedApplicants addObject:(__bridge id)peerInfo];
316 }
317 }
318 bool result = false;
319 if ([approvedApplicants count]) {
320 result = SOSCCAcceptApplicants((__bridge CFArrayRef)approvedApplicants, &cferror);
321 } else {
322 cferror = CFErrorCreate(NULL, CFSTR("MDNoApplicant"), 1, NULL);
323 }
324 complete(result, (__bridge NSError *)cferror);
325 CFReleaseNull(cferror);
326 }
327
328 - (void)sosGhostBust:(SOSAccountGhostBustingOptions)options complete:(void(^)(bool busted, NSError *error))complete {
329 os_log(NULL, "[%@] sosGhostBust", self.name);
330 SOSCCGhostBust(options, ^(bool busted, NSError *error) {
331 os_log(NULL, "[%@] sosGhostBust: %sbusted error: %@", self.name, busted ? "" : "no ", error);
332 complete(busted, error);
333 });
334 }
335
336 - (void)sosCircleHash: (void(^)(NSString *data, NSError * _Nullable error))complete
337 {
338 NSError *error = NULL;
339 NSString *hash = SOSCCCircleHash(&error);
340 complete(hash, error);
341 }
342
343
344 - (void)sosWaitForInitialSync:(void(^)(bool success, NSError *error))complete
345 {
346 CFErrorRef cferror = NULL;
347 bool success = SOSCCWaitForInitialSync(&cferror);
348 complete(success, (__bridge NSError *)cferror);
349 CFReleaseNull(cferror);
350 }
351
352 - (void)sosEnableAllViews:(void(^)(BOOL success, NSError *error))complete
353 {
354 CFMutableSetRef viewsToEnable = SOSViewCopyViewSet(kViewSetAll);
355 CFMutableSetRef viewsToDisable = CFSetCreateMutable(NULL, 0, NULL);
356
357 bool success = SOSCCViewSet(viewsToEnable, viewsToDisable);
358 CFRelease(viewsToEnable);
359 CFRelease(viewsToDisable);
360 complete(success, NULL);
361
362 }
363
364 - (void) sosCachedViewBitmask: (void(^)(uint64_t bitmask))complete {
365 uint64_t result = SOSCachedViewBitmask();
366 complete(result);
367 }
368
369 - (void) deviceInfo:(nonnull void (^)(NSString * _Nullable, NSString * _Nullable, NSError * _Nullable))complete {
370 #if SECD_SERVER
371 __block NSString *deviceSerial = @"";
372 [self sosPeerSerial:^(NSString * _Nullable peerSerial) {
373 deviceSerial = peerSerial;
374 }];
375 complete([SOSAuthKitHelpers machineID], deviceSerial, NULL);
376 #else
377 complete(@"", @"", NULL);
378 #endif
379
380 }
381
382
383 // MARK: - Pairing
384
385 - (void)pairingChannelSetup:(bool)initiator pairingContext:(KCPairingChannelContext *)context complete:(void (^)(id<DevicePairingProtocol>, NSError *))complete {
386
387 DevicePairingSimulator *pairingSim = [[DevicePairingSimulator alloc] initAsInitiator:initiator version:context device:self];
388 complete(pairingSim, nil);
389 }
390
391 // MARK: - Diagnostics
392
393 - (void)diagnosticsLeaks:(void(^)(bool success, NSString *outout, NSError *error))complete
394 {
395 complete(true, NULL, NULL);
396 }
397
398 - (void)diagnosticsCPUUsage:(void(^)(bool success, uint64_t user_usec, uint64_t sys_usec, NSError *error))complete
399 {
400 struct rusage usage;
401 getrusage(RUSAGE_SELF, &usage);
402 uint64_t user_usec = usage.ru_utime.tv_sec * USEC_PER_SEC + usage.ru_utime.tv_usec;
403 uint64_t sys_usec = usage.ru_stime.tv_sec * USEC_PER_SEC + usage.ru_stime.tv_usec;
404
405 complete(true, user_usec, sys_usec, NULL);
406 }
407
408 - (void)diagnosticsDiskUsage:(void(^)(bool success, uint64_t usage, NSError *error))complete
409 {
410 rusage_info_current rusage;
411
412 if (proc_pid_rusage(getpid(), RUSAGE_INFO_CURRENT, (rusage_info_t *)&rusage) == 0) {
413 complete(true, rusage.ri_logical_writes, NULL);
414 } else {
415 complete(false, 0, NULL);
416 }
417 }
418
419 // MARK: - CKKS
420 - (void)selfPeersForView:(NSString *)view complete:(void (^)(NSArray<NSDictionary *> *result, NSError *error))complete
421 {
422 complete(@[], NULL);
423 }
424
425 // MARK: - Octagon
426 - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success, NSError *_Nullable error))complete
427 {
428 #if OCTAGON
429 OTControl *ot = [self OTControl];
430
431 [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID resetReason:CuttlefishResetReasonTestGenerated reply:^(NSError * _Nullable error) {
432 complete(error == NULL, error);
433 }];
434 #else
435 complete(false, [self octagonNotAvailableError]);
436 #endif
437 }
438
439 - (void)otPeerID:(NSString *)altDSID complete:(void (^)(NSString *peerID, NSError *_Nullable error))complete
440 {
441 #if OCTAGON
442 OTControl *ot = [self OTControl];
443 [ot fetchEgoPeerID:nil context:OTDefaultContext reply:^(NSString * _Nullable peerID, NSError * _Nullable error) {
444 complete(peerID, error);
445 }];
446 #else
447 complete(false, [self octagonNotAvailableError]);
448 #endif
449
450 }
451
452 - (void)otInCircle:(NSString *)altDSID complete:(void (^)(bool inCircle, NSError *_Nullable error))complete
453 {
454 #if OCTAGON
455 OTControl *ot = [self OTControl];
456 OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
457 [ot fetchCliqueStatus:nil context:OTDefaultContext configuration:configuration reply:^(CliqueStatus cliqueStatus, NSError * _Nullable error) {
458 os_log(NULL, "[%@] otInCircle: clique: %d error: %@", self.name, (int)cliqueStatus, error);
459 complete(cliqueStatus == CliqueStatusIn, error);
460 }];
461 #else
462 complete(false, [self octagonNotAvailableError]);
463 #endif
464 }
465
466
467 //MARK: - Misc helpers
468
469 #if OCTAGON
470
471 - (OTControl *)OTControl
472 {
473 #if SECD_SERVER
474 return [[OTControl alloc] initWithConnection:(NSXPCConnection *)[[NSXPCConnectionMock alloc] initWithRealObject:[OTManager manager]] sync:true];
475 #else
476 NSError *error = NULL;
477 return [OTControl controlObject:true error:&error];
478 #endif
479 }
480
481 #else /* !OCTAGON */
482
483 - (NSError *)octagonNotAvailableError
484 {
485 return [NSError errorWithDomain:@"DeviceSimulator" code:1 description:@"no octagon available"];
486 }
487 #endif
488
489 @end