--- /dev/null
+
+#import "FakeSOSControl.h"
+
+@implementation FakeNSXPCConnection
+- (instancetype) initWithControl:(id<SOSControlProtocol>)control
+{
+ self = [super init];
+ if (self) {
+ _control = control;
+ }
+ return self;
+}
+- (id)remoteObjectProxyWithErrorHandler:(void(^)(NSError * _Nonnull error))failureHandler
+{
+ (void)failureHandler;
+ return _control;
+}
+@end
+
+@implementation FCPairingFakeSOSControl
+
+- (instancetype)initWithRandomAccountKey:(bool)randomAccountKey circle:(SOSCircleRef)circle
+{
+ if ((self = [super init])) {
+ SecKeyRef publicKey = NULL;
+ NSDictionary* parameters = @{
+ (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC,
+ (__bridge NSString*)kSecAttrKeySizeInBits: @(256),
+ (__bridge NSString*)kSecUseDataProtectionKeychain : @YES,
+ (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
+ (__bridge id)kSecPrivateKeyAttrs : @{
+ (__bridge NSString*)kSecAttrLabel : @"delete me test case - private",
+ (__bridge NSString*)kSecAttrIsPermanent : @YES,
+ (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
+ },
+ (__bridge id)kSecPublicKeyAttrs : @{
+ (__bridge NSString*)kSecAttrLabel : @"delete me test case - public",
+ (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
+ }
+ };
+ if(SecKeyGeneratePair((__bridge CFDictionaryRef)parameters, &publicKey, &_deviceKey) != 0) {
+ NSLog(@"failed to create device key");
+ return nil;
+ }
+ CFReleaseNull(publicKey);
+
+ NSMutableDictionary* octagonParameters = [parameters mutableCopy];
+ octagonParameters[(__bridge NSString*)kSecAttrKeySizeInBits] = @(384);
+ if(SecKeyGeneratePair((__bridge CFDictionaryRef)octagonParameters, &publicKey, &_octagonSigningKey) != 0) {
+ NSLog(@"failed to create octagon signing key");
+ return nil;
+ }
+ CFReleaseNull(publicKey);
+
+ if(SecKeyGeneratePair((__bridge CFDictionaryRef)octagonParameters, &publicKey, &_octagonEncryptionKey) != 0) {
+ NSLog(@"failed to create octagon signing key");
+ return nil;
+ }
+ CFReleaseNull(publicKey);
+
+
+ _circle = (SOSCircleRef)CFRetain(circle);
+
+ CFErrorRef error = NULL;
+
+ CFDictionaryRef gestalt = (__bridge CFDictionaryRef)@{
+ @"ComputerName" : @"name",
+ };
+
+ _fullPeerInfo = SOSFullPeerInfoCreate(NULL, gestalt, NULL, _deviceKey, _octagonSigningKey, _octagonEncryptionKey, &error);
+ CFReleaseNull(error);
+
+ if (randomAccountKey) {
+
+ NSDictionary* accountParams = @{
+ (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC,
+ (__bridge NSString*)kSecAttrKeySizeInBits: @(256),
+ (__bridge NSString*)kSecUseDataProtectionKeychain : @YES,
+ (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
+ };
+
+ if(SecKeyGeneratePair((__bridge CFDictionaryRef)accountParams, &publicKey, &_accountPrivateKey) != 0) {
+ NSLog(@"failed to create account signing key");
+ return nil;
+ }
+ CFReleaseNull(publicKey);
+
+ _accountPublicKey = SecKeyCopyPublicKey(_accountPrivateKey);
+
+ [self signApplicationIfNeeded];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ if (_accountPrivateKey) {
+ SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_accountPrivateKey });
+ CFReleaseNull(_accountPrivateKey);
+ }
+ if (_deviceKey) {
+ SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_deviceKey });
+ CFReleaseNull(_deviceKey);
+ }
+ if (_octagonSigningKey) {
+ SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_octagonSigningKey });
+ CFReleaseNull(_octagonSigningKey);
+ }
+ if (_octagonEncryptionKey) {
+ SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_octagonEncryptionKey });
+ CFReleaseNull(_octagonEncryptionKey);
+ }
+ CFReleaseNull(_circle);
+ CFReleaseNull(_fullPeerInfo);
+}
+
+- (SOSPeerInfoRef)peerInfo
+{
+ return SOSFullPeerInfoGetPeerInfo(_fullPeerInfo);
+}
+
+- (void)signApplicationIfNeeded
+{
+ CFErrorRef error = NULL;
+
+ _application = SOSFullPeerInfoPromoteToApplication(_fullPeerInfo, _accountPrivateKey, &error);
+ if (!_application)
+ abort();
+}
+
+- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete
+{
+ complete(@[], NULL);
+}
+
+- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete
+{
+ complete(true, NULL);
+}
+
+- (void)triggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+{
+ complete(true, NULL);
+}
+
+//MARK - FCPairingFakeSOSControl SOSControlProtocol
+
+- (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))complete
+{
+ complete(false, NULL, NULL);
+}
+
+- (void)performanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *))complete
+{
+ complete(@{});
+}
+- (void)kvsPerformanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *))complete
+{
+ complete(@{});
+}
+
+- (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary <NSString *, NSString *> *))complete
+{
+ complete(@{});
+}
+- (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))complete
+{
+ NSData *publicKey = NULL;
+ NSError *error = NULL;
+ if (self.accountPrivateKey) {
+ publicKey = CFBridgingRelease(SecKeyCopySubjectPublicKeyInfo(self.accountPrivateKey));
+ } else {
+ error = [NSError errorWithDomain:@"FCPairingFakeSOSControl" code:2 userInfo:NULL];
+ }
+ complete(publicKey, error);
+}
+
+- (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))complete
+{
+ complete(self.accountPrivateKey != NULL, NULL);
+}
+
+- (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete
+{
+ NSData *key = NULL;
+ CFErrorRef error = NULL;
+ if (self.accountPrivateKey) {
+ key = CFBridgingRelease(SecKeyCopyExternalRepresentation(self.accountPrivateKey, &error));
+ } else {
+ error = (CFErrorRef)CFBridgingRetain([NSError errorWithDomain:@"FCPairingFakeSOSControl" code:1 userInfo:NULL]);
+ }
+ complete(key, (__bridge NSError *)error);
+ CFReleaseNull(error);
+}
+
+- (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete
+{
+ SecKeyRef accountPrivateKey = NULL;
+ CFErrorRef error = NULL;
+ NSDictionary *attributes = @{
+ (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate,
+ (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC,
+ };
+
+ accountPrivateKey = SecKeyCreateWithData((__bridge CFDataRef)credential, (__bridge CFDictionaryRef)attributes, &error);
+ if (accountPrivateKey == NULL) {
+ complete(false, (__bridge NSError *)error);
+ CFReleaseNull(error);
+ return;
+ }
+
+ _accountPrivateKey = accountPrivateKey;
+ _accountPublicKey = SecKeyCopyPublicKey(_accountPrivateKey);
+
+ [self signApplicationIfNeeded];
+
+ complete(true, NULL);
+}
+
+- (void)myPeerInfo:(void(^)(NSData *application, NSError *error))complete
+{
+ CFErrorRef error = NULL;
+
+ [self signApplicationIfNeeded];
+
+ NSData *application = CFBridgingRelease(SOSPeerInfoCopyEncodedData([self peerInfo], NULL, &error));
+ complete(application, (__bridge NSError *)error);
+
+ CFReleaseNull(error);
+}
+
+- (void)circleHash:(void (^)(NSString *, NSError *))complete
+{
+ NSString *data = CFBridgingRelease(SOSCircleCopyHashString(_circle));
+ complete(data, NULL);
+}
+
+- (void)circleJoiningBlob:(NSData *)applicantData complete:(void (^)(NSData *blob, NSError *))complete
+{
+ CFErrorRef error = NULL;
+ CFDataRef signature = NULL;
+ SOSCircleRef prunedCircle = SOSCircleCopyCircle(NULL, _circle, &error);
+ (void)SOSCirclePreGenerationSign(prunedCircle, _accountPublicKey, &error);
+
+ SOSGenCountRef gencount = SOSGenerationIncrementAndCreate(SOSCircleGetGeneration(prunedCircle));
+ if (gencount == NULL)
+ abort();
+
+
+ SOSPeerInfoRef applicant = SOSPeerInfoCreateFromData(NULL, &error, (__bridge CFDataRef)applicantData);
+ if (applicant == NULL)
+ abort();
+
+ signature = SOSCircleCopyNextGenSignatureWithPeerAdded(prunedCircle, applicant, _deviceKey, &error);
+ if(applicant) {
+ CFRelease(applicant);
+ applicant = NULL;
+ }
+
+ NSData *pbblob = CFBridgingRelease(SOSPiggyBackBlobCopyEncodedData(gencount, _deviceKey, signature, &error));
+
+ CFReleaseNull(signature);
+ CFReleaseNull(gencount);
+ CFReleaseNull(prunedCircle);
+
+ complete(pbblob, NULL);
+}
+
+- (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete
+{
+ SOSGenCountRef gencount = NULL;
+ SecKeyRef pubKey = NULL;
+ CFDataRef signature = NULL;
+ CFErrorRef error = NULL;
+ bool setInitialSyncTimeoutToV0 = false;
+
+ if (!SOSPiggyBackBlobCreateFromData(&gencount, &pubKey, &signature, (__bridge CFDataRef)blob, kPiggyV1, &setInitialSyncTimeoutToV0, &error)) {
+ complete(true, (__bridge NSError *)error);
+ CFReleaseNull(error);
+ return;
+ }
+
+ (void)SOSCircleAcceptPeerFromHSA2(_circle,
+ _accountPrivateKey,
+ gencount,
+ pubKey,
+ signature,
+ _fullPeerInfo,
+ &error);
+
+ CFReleaseNull(gencount);
+ CFReleaseNull(pubKey);
+ CFReleaseNull(signature);
+
+ complete(true, (__bridge NSError *)error);
+
+ CFReleaseNull(error);
+
+}
+
+- (void)getWatchdogParameters:(void (^)(NSDictionary*, NSError*))complete
+{
+ // intentionally left blank
+ // these are used by the security/2 tool and are only declared here to make the compiler happy about conforming the protocol we shoved the methods into
+}
+
+
+- (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError*))complete
+{
+ // intentionally left blank
+ // these are used by the security/2 tool and are only declared here to make the compiler happy about conforming the protocol we shoved the methods into
+}
+
+- (void)ghostBust:(SOSAccountGhostBustingOptions)options complete:(void (^)(bool, NSError *))complete {
+ complete(false, nil);
+}
+
+- (void)ghostBustPeriodic:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool busted, NSError *error))complete{
+ complete(false, nil);
+}
+
+- (void)ghostBustTriggerTimed:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool ghostBusted, NSError *error))complete {
+ complete(false, nil);
+}
+
+- (void) ghostBustInfo: (void(^)(NSData *json, NSError *error))complete {
+ complete(nil, nil);
+}
+
+@end