Remote attestation.

pull/1/head
Matthew Chen 7 years ago
parent 20284ebc84
commit f3ba6d4c27

@ -1108,6 +1108,8 @@ static NSTimeInterval launchStartedAt;
// Resume lazy restore.
[OWSBackupLazyRestoreJob runAsync];
#endif
[[ContactDiscoveryService sharedService] testService];
}
- (void)registrationStateDidChange

@ -0,0 +1,46 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
//#import "SignalRecipient.h"
NS_ASSUME_NONNULL_BEGIN
//@class Contact;
@interface ContactDiscoveryService : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedService;
- (void)testService;
//- (nullable SignalRecipient *)synchronousLookup:(NSString *)identifier error:(NSError **)error;
//
//// This asynchronously tries to verify whether or not a contact id
//// corresponds to a service account.
////
//// The failure callback is invoked if the lookup fails _or_ if the
//// contact id doesn't correspond to an account.
//- (void)lookupIdentifier:(NSString *)identifier
// success:(void (^)(SignalRecipient *recipient))success
// failure:(void (^)(NSError *error))failure;
//
//// This asynchronously tries to verify whether or not a group of possible
//// contact ids correspond to service accounts.
////
//// The failure callback is only invoked if the lookup fails. Otherwise,
//// the success callback is invoked with the (possibly empty) set of contacts
//// that were found.
//- (void)lookupIdentifiers:(NSArray<NSString *> *)identifiers
// success:(void (^)(NSArray<SignalRecipient *> *recipients))success
// failure:(void (^)(NSError *error))failure;
//
//- (void)updateSignalContactIntersectionWithABContacts:(NSArray<Contact *> *)abContacts
// success:(void (^)(void))success
// failure:(void (^)(NSError *error))failure;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,312 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "ContactDiscoveryService.h"
//#import "Contact.h"
//#import "Cryptography.h"
//#import "OWSError.h"
//#import "OWSPrimaryStorage.h"
#import "OWSRequestFactory.h"
//#import "PhoneNumber.h"
#import "TSNetworkManager.h"
//#import <YapDatabase/YapDatabase.h>
#import <Curve25519Kit/Curve25519.h>
NS_ASSUME_NONNULL_BEGIN
@implementation ContactDiscoveryService
+ (instancetype)sharedService {
static dispatch_once_t onceToken;
static id sharedInstance = nil;
dispatch_once(&onceToken, ^{
sharedInstance = [[ContactDiscoveryService alloc] initDefault];
});
return sharedInstance;
}
- (instancetype)initDefault
{
self = [super init];
if (!self) {
return self;
}
OWSSingletonAssert();
return self;
}
- (void)testService
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performRemoteAttestation];
});
}
- (void)performRemoteAttestation
{
ECKeyPair *keyPair = [Curve25519 generateKeyPair];
// TODO:
NSString *enclaveId = @"1";
TSRequest *request = [OWSRequestFactory remoteAttestationRequest:keyPair
enclaveId:enclaveId];
[[TSNetworkManager sharedManager] makeRequest:request
success:^(NSURLSessionDataTask *task, id responseDict) {
DDLogVerbose(@"%@ remote attestation success: %@", self.logTag, responseDict);
// NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary];
// NSArray *contactsArray = [(NSDictionary *)responseDict objectForKey:@"contacts"];
//
// // Map attributes to phone numbers
// if (contactsArray) {
// for (NSDictionary *dict in contactsArray) {
// NSString *hash = [dict objectForKey:@"token"];
// NSString *identifier = [phoneNumbersByHashes objectForKey:hash];
//
// if (!identifier) {
// DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag);
// break;
// }
//
// [attributesForIdentifier setObject:dict forKey:identifier];
// }
// }
//
// // Insert or update contact attributes
// [OWSPrimaryStorage.dbReadWriteConnection
// readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// for (NSString *identifier in attributesForIdentifier) {
// SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier
// withTransaction:transaction];
// if (!recipient) {
// recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier relay:nil];
// }
//
// NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
//
// recipient.relay = attributes[@"relay"];
//
// [recipient saveWithTransaction:transaction];
// }
// }];
//
// success([NSSet setWithArray:attributesForIdentifier.allKeys]);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
// if (!IsNSErrorNetworkFailure(error)) {
// OWSProdError([OWSAnalyticsEvents contactsErrorContactsIntersectionFailed]);
// }
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
DDLogVerbose(@"%@ remote attestation failure: %zd", self.logTag, response.statusCode);
// if (response.statusCode == 413) {
// failure(OWSErrorWithCodeDescription(
// OWSErrorCodeContactDiscoveryServiceRateLimit, @"Contacts Intersection Rate Limit"));
// } else {
// failure(error);
// }
}];
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// [self performRemoteAttestation];
// });
}
//- (nullable SignalRecipient *)synchronousLookup:(NSString *)identifier error:(NSError **)error
//{
// OWSAssert(error);
//
// DDLogInfo(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, identifier);
//
// dispatch_semaphore_t sema = dispatch_semaphore_create(0);
//
// __block SignalRecipient *recipient;
//
// // Assigning to a pointer parameter within the block is not preventing the referenced error from being dealloc
// // Instead, we avoid ambiguity in ownership by assigning to a local __block variable ensuring the error will be
// // retained until our error parameter can take ownership.
// __block NSError *retainedError;
// [self lookupIdentifier:identifier
// success:^(SignalRecipient *fetchedRecipient) {
// recipient = fetchedRecipient;
// dispatch_semaphore_signal(sema);
// }
// failure:^(NSError *lookupError) {
// DDLogError(
// @"%@ Could not find recipient for recipientId: %@, error: %@.", self.logTag, identifier, lookupError);
//
// retainedError = lookupError;
// dispatch_semaphore_signal(sema);
// }];
//
// dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
// *error = retainedError;
// return recipient;
//}
//
//- (void)lookupIdentifier:(NSString *)identifier
// success:(void (^)(SignalRecipient *recipient))success
// failure:(void (^)(NSError *error))failure
//{
// // This should never happen according to nullability annotations... but IIRC it does. =/
// if (!identifier) {
// OWSFail(@"%@ Cannot lookup nil identifier", self.logTag);
// failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup nil identifier"));
// return;
// }
//
// [self contactIntersectionWithSet:[NSSet setWithObject:identifier]
// success:^(NSSet<NSString *> *_Nonnull matchedIds) {
// if (matchedIds.count == 1) {
// success([SignalRecipient recipientWithTextSecureIdentifier:identifier]);
// } else {
// failure(OWSErrorMakeNoSuchSignalRecipientError());
// }
// }
// failure:failure];
//}
//
//- (void)lookupIdentifiers:(NSArray<NSString *> *)identifiers
// success:(void (^)(NSArray<SignalRecipient *> *recipients))success
// failure:(void (^)(NSError *error))failure
//{
// if (identifiers.count < 1) {
// OWSFail(@"%@ Cannot lookup zero identifiers", self.logTag);
// failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup zero identifiers"));
// return;
// }
//
// [self contactIntersectionWithSet:[NSSet setWithArray:identifiers]
// success:^(NSSet<NSString *> *_Nonnull matchedIds) {
// if (matchedIds.count > 0) {
// NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
// for (NSString *identifier in matchedIds) {
// [recipients addObject:[SignalRecipient recipientWithTextSecureIdentifier:identifier]];
// }
// success([recipients copy]);
// } else {
// failure(OWSErrorMakeNoSuchSignalRecipientError());
// }
// }
// failure:failure];
//}
//
//- (void)updateSignalContactIntersectionWithABContacts:(NSArray<Contact *> *)abContacts
// success:(void (^)(void))success
// failure:(void (^)(NSError *error))failure
//{
// NSMutableSet<NSString *> *abPhoneNumbers = [NSMutableSet set];
//
// for (Contact *contact in abContacts) {
// for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
// [abPhoneNumbers addObject:phoneNumber.toE164];
// }
// }
//
// NSMutableSet *recipientIds = [NSMutableSet set];
// [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
// NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
// [recipientIds addObjectsFromArray:allRecipientKeys];
// }];
//
// NSMutableSet<NSString *> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
//
// [self contactIntersectionWithSet:allContacts
// success:^(NSSet<NSString *> *matchedIds) {
// [recipientIds minusSet:matchedIds];
//
// // Cleaning up unregistered identifiers
// [OWSPrimaryStorage.dbReadWriteConnection
// readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// for (NSString *identifier in recipientIds) {
// SignalRecipient *recipient =
// [SignalRecipient fetchObjectWithUniqueID:identifier
// transaction:transaction];
//
// [recipient removeWithTransaction:transaction];
// }
// }];
//
// DDLogInfo(@"%@ successfully intersected contacts.", self.logTag);
// success();
// }
// failure:failure];
//}
//
//- (void)contactIntersectionWithSet:(NSSet<NSString *> *)idSet
// success:(void (^)(NSSet<NSString *> *matchedIds))success
// failure:(void (^)(NSError *error))failure {
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// NSMutableDictionary *phoneNumbersByHashes = [NSMutableDictionary dictionary];
// for (NSString *identifier in idSet) {
// [phoneNumbersByHashes setObject:identifier
// forKey:[Cryptography truncatedSHA1Base64EncodedWithoutPadding:identifier]];
// }
// NSArray *hashes = [phoneNumbersByHashes allKeys];
//
// TSRequest *request = [OWSRequestFactory contactsIntersectionRequestWithHashesArray:hashes];
// [[TSNetworkManager sharedManager] makeRequest:request
// success:^(NSURLSessionDataTask *tsTask, id responseDict) {
// NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary];
// NSArray *contactsArray = [(NSDictionary *)responseDict objectForKey:@"contacts"];
//
// // Map attributes to phone numbers
// if (contactsArray) {
// for (NSDictionary *dict in contactsArray) {
// NSString *hash = [dict objectForKey:@"token"];
// NSString *identifier = [phoneNumbersByHashes objectForKey:hash];
//
// if (!identifier) {
// DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag);
// break;
// }
//
// [attributesForIdentifier setObject:dict forKey:identifier];
// }
// }
//
// // Insert or update contact attributes
// [OWSPrimaryStorage.dbReadWriteConnection
// readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// for (NSString *identifier in attributesForIdentifier) {
// SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier
// withTransaction:transaction];
// if (!recipient) {
// recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier relay:nil];
// }
//
// NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
//
// recipient.relay = attributes[@"relay"];
//
// [recipient saveWithTransaction:transaction];
// }
// }];
//
// success([NSSet setWithArray:attributesForIdentifier.allKeys]);
// }
// failure:^(NSURLSessionDataTask *task, NSError *error) {
// if (!IsNSErrorNetworkFailure(error)) {
// OWSProdError([OWSAnalyticsEvents contactsErrorContactsIntersectionFailed]);
// }
//
// NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
// if (response.statusCode == 413) {
// failure(OWSErrorWithCodeDescription(
// OWSErrorCodeContactDiscoveryServiceRateLimit, @"Contacts Intersection Rate Limit"));
// } else {
// failure(error);
// }
// }];
// });
//}
@end
NS_ASSUME_NONNULL_END

@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@class PreKeyRecord;
@class SignedPreKeyRecord;
@class TSRequest;
@class ECKeyPair;
typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVoice = 1, TSVerificationTransportSMS };
@ -69,6 +70,9 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
signedPreKey:(SignedPreKeyRecord *)signedPreKey
preKeyLastResort:(PreKeyRecord *)preKeyLastResort;
+ (TSRequest *)remoteAttestationRequest:(ECKeyPair *)keyPair
enclaveId:(NSString *)enclaveId;
@end
NS_ASSUME_NONNULL_END

@ -11,6 +11,7 @@
#import "TSRequest.h"
#import <AxolotlKit/NSData+keyVersionByte.h>
#import <AxolotlKit/SignedPreKeyRecord.h>
#import <Curve25519Kit/Curve25519.h>
NS_ASSUME_NONNULL_BEGIN
@ -274,6 +275,20 @@ NS_ASSUME_NONNULL_BEGIN
};
}
+ (TSRequest *)remoteAttestationRequest:(ECKeyPair *)keyPair
enclaveId:(NSString *)enclaveId
{
OWSAssert(keyPair);
OWSAssert(enclaveId.length > 0);
NSString *path = [NSString stringWithFormat:@"/v1/attestation/%@", enclaveId];
return [TSRequest requestWithUrl:[NSURL URLWithString:path]
method:@"PUT"
parameters:@{
@"clientPublic" : [[keyPair.publicKey prependKeyType] base64EncodedStringWithOptions:0],
}];
}
@end
NS_ASSUME_NONNULL_END

@ -29,12 +29,12 @@ typedef NS_ENUM(NSInteger, TSWhisperMessageType) {
//#ifndef DEBUG
// Production
#define textSecureWebSocketAPI @"wss://textsecure-service.whispersystems.org/v1/websocket/"
#define textSecureServerURL @"https://textsecure-service.whispersystems.org/"
#define textSecureCDNServerURL @"https://cdn.signal.org"
// Use same reflector for service and CDN
#define textSecureServiceReflectorHost @"textsecure-service-reflected.whispersystems.org"
#define textSecureCDNReflectorHost @"textsecure-service-reflected.whispersystems.org"
//#define textSecureWebSocketAPI @"wss://textsecure-service.whispersystems.org/v1/websocket/"
//#define textSecureServerURL @"https://textsecure-service.whispersystems.org/"
//#define textSecureCDNServerURL @"https://cdn.signal.org"
//// Use same reflector for service and CDN
//#define textSecureServiceReflectorHost @"textsecure-service-reflected.whispersystems.org"
//#define textSecureCDNReflectorHost @"textsecure-service-reflected.whispersystems.org"
//#else
//
@ -47,6 +47,13 @@ typedef NS_ENUM(NSInteger, TSWhisperMessageType) {
//
//#endif
// Testing
#define textSecureWebSocketAPI @"wss://api.contact-discovery.acton-signal.org/v1/websocket/"
#define textSecureServerURL @"https://api.contact-discovery.acton-signal.org/"
#define textSecureCDNServerURL @"https://cdn-staging.signal.org"
#define textSecureServiceReflectorHost @"meek-signal-service-staging.appspot.com";
#define textSecureCDNReflectorHost @"meek-signal-cdn-staging.appspot.com";
#define textSecureAccountsAPI @"v1/accounts"
#define textSecureAttributesAPI @"/attributes/"

Loading…
Cancel
Save