|
|
|
@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
@interface RemoteAttestationAuth : NSObject
|
|
|
|
|
|
|
|
|
|
@property (nonatomic) NSString *username;
|
|
|
|
|
@property (nonatomic) NSString *password;
|
|
|
|
|
@property (nonatomic) NSString *authToken;
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
@ -135,9 +135,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return self.auth.username;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString *)password
|
|
|
|
|
- (NSString *)authToken
|
|
|
|
|
{
|
|
|
|
|
return self.auth.password;
|
|
|
|
|
return self.auth.authToken;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
@ -265,7 +265,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
[[TSNetworkManager sharedManager] makeRequest:request
|
|
|
|
|
success:^(NSURLSessionDataTask *task, id responseDict) {
|
|
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
|
|
|
RemoteAttestationAuth *_Nullable auth = [self parseAuthParams:responseDict];
|
|
|
|
|
RemoteAttestationAuth *_Nullable auth = [self parseAuthToken:responseDict];
|
|
|
|
|
if (!auth) {
|
|
|
|
|
DDLogError(@"%@ remote attestation auth could not be parsed: %@", self.logTag, responseDict);
|
|
|
|
|
NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
|
|
|
|
@ -283,16 +283,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (nullable RemoteAttestationAuth *)parseAuthParams:(id)response
|
|
|
|
|
- (nullable RemoteAttestationAuth *)parseAuthToken:(id)response
|
|
|
|
|
{
|
|
|
|
|
if (![response isKindOfClass:[NSDictionary class]]) {
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSDictionary *responseDict = response;
|
|
|
|
|
NSString *_Nullable password = [responseDict stringForKey:@"password"];
|
|
|
|
|
if (password.length < 1) {
|
|
|
|
|
OWSProdLogAndFail(@"%@ missing or empty password.", self.logTag);
|
|
|
|
|
NSString *_Nullable token = [responseDict stringForKey:@"token"];
|
|
|
|
|
if (token.length < 1) {
|
|
|
|
|
OWSProdLogAndFail(@"%@ missing or empty token.", self.logTag);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -304,7 +304,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
RemoteAttestationAuth *result = [RemoteAttestationAuth new];
|
|
|
|
|
result.username = username;
|
|
|
|
|
result.password = password;
|
|
|
|
|
result.authToken = token;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -320,7 +320,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
TSRequest *request = [OWSRequestFactory remoteAttestationRequest:keyPair
|
|
|
|
|
enclaveId:enclaveId
|
|
|
|
|
authUsername:auth.username
|
|
|
|
|
authPassword:auth.password];
|
|
|
|
|
authPassword:auth.authToken];
|
|
|
|
|
|
|
|
|
|
[[TSNetworkManager sharedManager] makeRequest:request
|
|
|
|
|
success:^(NSURLSessionDataTask *task, id responseJson) {
|
|
|
|
@ -470,29 +470,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ remote attestation complete.", self.logTag);
|
|
|
|
|
|
|
|
|
|
//+ RemoteAttestation remoteAttestation = new RemoteAttestation(requestId, keys);
|
|
|
|
|
//+ List<String> addressBook = new LinkedList<>();
|
|
|
|
|
//+
|
|
|
|
|
//+ for (String e164number : e164numbers) {
|
|
|
|
|
//+ addressBook.add(e164number.substring(1));
|
|
|
|
|
//+ }
|
|
|
|
|
//+
|
|
|
|
|
//+ DiscoveryRequest request = cipher.createDiscoveryRequest(addressBook, remoteAttestation);
|
|
|
|
|
//+ DiscoveryResponse response = this.pushServiceSocket.getContactDiscoveryRegisteredUsers(authorization,
|
|
|
|
|
//request, attestationResponse.second(), mrenclave);
|
|
|
|
|
//+ byte[] data = cipher.getDiscoveryResponseData(response, remoteAttestation);
|
|
|
|
|
//+
|
|
|
|
|
//+ Iterator<String> addressBookIterator = addressBook.iterator();
|
|
|
|
|
//+ List<String> results = new LinkedList<>();
|
|
|
|
|
//+
|
|
|
|
|
//+ for (byte aData : data) {
|
|
|
|
|
//+ String candidate = addressBookIterator.next();
|
|
|
|
|
//+
|
|
|
|
|
//+ if (aData != 0) results.add('+' + candidate);
|
|
|
|
|
//+ }
|
|
|
|
|
//+
|
|
|
|
|
//+ return results;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -679,39 +656,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return decryptedData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A successful (HTTP 200) response json object consists of:
|
|
|
|
|
// serverEphemeralPublic: (32 bytes, base64) an ephemeral curve25519 public key generated by the server
|
|
|
|
|
// serverStaticPublic: (32 bytes, base64) a static curve25519 public key generated by the server
|
|
|
|
|
// ciphertext: (variable length, base64) a "request id" to be decrypted by the client (see below for derivation
|
|
|
|
|
// of server_key) (ciphertext, tag) = AES-256-GCM(key=server_key, plaintext=requestId, AAD=(), iv) iv: (12
|
|
|
|
|
// bytes, base64) an IV for encrypted ciphertext tag: (16 bytes, base64) a MAC for encrypted ciphertext
|
|
|
|
|
// quote: (variable length, base64) a binary structure from an Intel CPU containing runtime information
|
|
|
|
|
// about a running enclave signatureBody: (json object) a response from Intel Attestation Services attesting to
|
|
|
|
|
// the genuineness of the Quote signature: (base64) a signature over signatureBody, with public key in
|
|
|
|
|
// corresponding signing certificate certificates: (url-encoded PEM) signing certificate chain The response also
|
|
|
|
|
// contains HTTP session cookies which must be preserved for exactly one corresponding Contact Discovery request.
|
|
|
|
|
//
|
|
|
|
|
// After this PUT response is received, the client must:
|
|
|
|
|
// parse and verify fields in quote (see sample client code for parsing details):
|
|
|
|
|
// report_data: (64 bytes) must equal (serverStaticPublic || 0 ...)
|
|
|
|
|
// mrenclave: (32 bytes) must equal the request's enclaveId
|
|
|
|
|
// flags: (8 bytes) debug flag must be unset, as well as being validated against expected values during
|
|
|
|
|
// parsing all other fields must be validated against a range of expected values during parsing (as shown in example
|
|
|
|
|
// parsing code), but are otherwise ignored See client/src/main/java/org/whispersystems/contactdiscovery/Quote.java parse
|
|
|
|
|
// and verify fields in signatureBody json object: isvEnclaveQuoteBody: (base64) must equal quote
|
|
|
|
|
// isvEnclaveQuoteStatus: (ascii) must equal "OK"
|
|
|
|
|
//"GROUP_OUT_OF_DATE" may be allowed for testing only
|
|
|
|
|
// timestamp: (ascii) UTC timestamp formatted as "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" which must fall within the
|
|
|
|
|
// last 24h verify validity of signature over signatureBody using the public key contained in the leaf signing
|
|
|
|
|
// certificate in certificates verify signing certificates chain, with fixed trust anchors to be hard-coded in clients
|
|
|
|
|
// client/src/main/java/org/whispersystems/contactdiscovery/SigningCertificate.java contains X.509 PKI certificate chain
|
|
|
|
|
// validation code to follow
|
|
|
|
|
//
|
|
|
|
|
// After Curve25519-DH/HKDF key derivation upon the three public keys (client ephemeral private key, server ephemeral
|
|
|
|
|
// public key, and server static public key, described below), the client can now decrypt the ciphertext in the Remote
|
|
|
|
|
// Attestation Response containing a requestId to be sent along with a Contact Discovery request, and encrypt the body of
|
|
|
|
|
// a Contact Discovery request using client_key, bound for the enclave it performed attestation with.
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_END
|
|
|
|
|