Skip to content

Commit 8812948

Browse files
golf1052Sanders Lauture
authored andcommitted
Support for contact discovery service - Part 2
Reflects signalapp/libsignal-service-java@c06f838
1 parent cc9cbfe commit 8812948

File tree

8 files changed

+173
-126
lines changed

8 files changed

+173
-126
lines changed

libsignal-service-dotnet/SignalServiceAccountManager.cs

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
using libsignalservice.push.http;
1515
using libsignalservice.util;
1616
using libsignalservice.websocket;
17+
using Microsoft.Extensions.Logging;
1718
using org.whispersystems.curve25519;
1819
using Org.BouncyCastle.Crypto;
1920
using Strilanc.Value;
2021
using System;
2122
using System.Collections.Generic;
23+
using System.IO;
2224
using System.Text;
2325
using System.Threading;
2426
using System.Threading.Tasks;
@@ -31,6 +33,7 @@ namespace libsignalservice
3133
/// </summary>
3234
public class SignalServiceAccountManager
3335
{
36+
private readonly ILogger Logger = LibsignalLogging.CreateLogger<SignalServiceAccountManager>();
3437
private PushServiceSocket PushServiceSocket;
3538
private static ProvisioningSocket ProvisioningSocket;
3639
private SignalServiceConfiguration Configuration;
@@ -260,13 +263,13 @@ public async Task<IList<string>> GetRegisteredUsers(IList<string> e164numbers, s
260263
}
261264
try
262265
{
263-
string authorizationToken = await PushServiceSocket.GetContactDiscoveryAuthorization(token);
266+
string authorization = await PushServiceSocket.GetContactDiscoveryAuthorization(token);
264267
Curve25519 curve = Curve25519.getInstance(Curve25519.BEST);
265268
org.whispersystems.curve25519.Curve25519KeyPair keyPair = curve.generateKeyPair();
266269

267270
ContactDiscoveryCipher cipher = new ContactDiscoveryCipher();
268271
RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey());
269-
(RemoteAttestationResponse, IList<string>) attestationResponse = await PushServiceSocket.GetContactDiscoveryRemoteAttestation(authorizationToken, attestationRequest, mrenclave, token);
272+
(RemoteAttestationResponse, IList<string>) attestationResponse = await PushServiceSocket.GetContactDiscoveryRemoteAttestation(authorization, attestationRequest, mrenclave, token);
270273

271274
RemoteAttestationKeys keys = new RemoteAttestationKeys(keyPair, attestationResponse.Item1.ServerEphemeralPublic!, attestationResponse.Item1.ServerStaticPublic!);
272275
Quote quote = new Quote(attestationResponse.Item1.Quote!);
@@ -284,7 +287,7 @@ public async Task<IList<string>> GetRegisteredUsers(IList<string> e164numbers, s
284287
}
285288

286289
DiscoveryRequest request = cipher.CreateDiscoveryRequest(addressBook, remoteAttestation);
287-
DiscoveryResponse response = await PushServiceSocket.GetContactDiscoveryRegisteredUsers(authorizationToken, request, attestationResponse.Item2, mrenclave, token);
290+
DiscoveryResponse response = await PushServiceSocket.GetContactDiscoveryRegisteredUsers(authorization, request, attestationResponse.Item2, mrenclave, token);
288291
byte[] data = cipher.GetDiscoveryResponseData(response, remoteAttestation);
289292

290293
IEnumerator<string> addressBookIterator = addressBook.GetEnumerator();
@@ -307,6 +310,74 @@ public async Task<IList<string>> GetRegisteredUsers(IList<string> e164numbers, s
307310
}
308311
}
309312

313+
public async Task ReportContactDiscoveryServiceMatch(CancellationToken? token = null)
314+
{
315+
if (token == null)
316+
{
317+
token = CancellationToken.None;
318+
}
319+
320+
try
321+
{
322+
await PushServiceSocket.ReportContactDiscoveryServiceMatch(token);
323+
}
324+
catch (IOException ex)
325+
{
326+
Logger.LogInformation(new EventId(), ex, "Request to indicate a contact discovery result match failed. Ignoring.");
327+
}
328+
}
329+
330+
public async Task ReportContactDiscoveryServiceMismatch(CancellationToken? token = null)
331+
{
332+
if (token == null)
333+
{
334+
token = CancellationToken.None;
335+
}
336+
337+
try
338+
{
339+
await PushServiceSocket.ReportContactDiscoveryServiceMismatch();
340+
}
341+
catch (IOException ex)
342+
{
343+
Logger.LogInformation(new EventId(), ex, "Request to indicate a contact discovery result mismatch failed. Ignoring.");
344+
}
345+
}
346+
347+
public async Task ReportContactDiscoveryServiceAttestationError(CancellationToken? token = null)
348+
{
349+
if (token == null)
350+
{
351+
token = CancellationToken.None;
352+
}
353+
354+
try
355+
{
356+
await PushServiceSocket.ReportContactDiscoveryServiceAttestationError(token);
357+
}
358+
catch (IOException ex)
359+
{
360+
Logger.LogInformation(new EventId(), ex, "Request to indicate a contact discovery attestation error failed. Ignoring.");
361+
}
362+
}
363+
364+
public async Task ReportContactDiscoveryServiceUnexpectedError(CancellationToken? token = null)
365+
{
366+
if (token == null)
367+
{
368+
token = CancellationToken.None;
369+
}
370+
371+
try
372+
{
373+
await PushServiceSocket.ReportContactDiscoveryServiceUnexpectedError(token);
374+
}
375+
catch (IOException ex)
376+
{
377+
Logger.LogInformation(new EventId(), ex, "Request to indicate a contact discovery unexpected error failed. Ignoring.");
378+
}
379+
}
380+
310381
/// <summary>
311382
/// Request a UUID from the server for linking as a new device.
312383
/// Called by the new device.

libsignal-service-dotnet/contacts/ContactDiscoveryClient.cs

Lines changed: 0 additions & 94 deletions
This file was deleted.

libsignal-service-dotnet/contacts/crypto/ContactDiscoveryCipher.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ namespace libsignalservice.contacts.crypto
1616
{
1717
public class ContactDiscoveryCipher
1818
{
19+
private const int TAG_LENGTH_BYTES = 16;
20+
private const int TAG_LENGTH_BITS = TAG_LENGTH_BYTES * 8;
21+
1922
public DiscoveryRequest CreateDiscoveryRequest(IList<string> addressBook, RemoteAttestation remoteAttestation)
2023
{
2124
try
@@ -32,16 +35,19 @@ public DiscoveryRequest CreateDiscoveryRequest(IList<string> addressBook, Remote
3235
byte[] nonce = Util.GetSecretBytes(12);
3336
GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
3437

35-
cipher.Init(true, new AeadParameters(new KeyParameter(remoteAttestation.Keys.ClientKey), 128, nonce));
38+
cipher.Init(true, new AeadParameters(new KeyParameter(remoteAttestation.Keys.ClientKey), TAG_LENGTH_BITS, nonce));
3639
cipher.ProcessAadBytes(remoteAttestation.RequestId, 0, remoteAttestation.RequestId.Length);
3740

38-
byte[] ciphertext = new byte[cipher.GetUpdateOutputSize(requestData.Length)];
39-
cipher.ProcessBytes(requestData, 0, requestData.Length, ciphertext, 0);
41+
byte[] cipherText1 = new byte[cipher.GetUpdateOutputSize(requestData.Length)];
42+
cipher.ProcessBytes(requestData, 0, requestData.Length, cipherText1, 0);
43+
44+
byte[] cipherText2 = new byte[cipher.GetOutputSize(0)];
45+
cipher.DoFinal(cipherText2, 0);
4046

41-
byte[] tag = new byte[cipher.GetOutputSize(0)];
42-
cipher.DoFinal(tag, 0);
47+
byte[] cipherText = ByteUtil.combine(cipherText1, cipherText2);
48+
byte[][] parts = ByteUtil.split(cipherText, cipherText.Length - TAG_LENGTH_BYTES, TAG_LENGTH_BYTES);
4349

44-
return new DiscoveryRequest(addressBook.Count, remoteAttestation.RequestId, nonce, ciphertext, tag);
50+
return new DiscoveryRequest(addressBook.Count, remoteAttestation.RequestId, nonce, parts[0], parts[1]);
4551
}
4652
catch (Exception ex) when (ex is IOException || ex is InvalidCipherTextException)
4753
{
@@ -112,6 +118,11 @@ public void VerifyServerQuote(Quote quote, byte[] serverPublicStatic, string mre
112118

113119
public void VerifyIasSignature(string certificates, string signatureBody, string signature, Quote quote)
114120
{
121+
if (string.IsNullOrWhiteSpace(certificates))
122+
{
123+
throw new CryptographicException("No certificates.");
124+
}
125+
115126
try
116127
{
117128
SigningCertificate signingCertificate = new SigningCertificate(certificates);
@@ -124,7 +135,9 @@ public void VerifyIasSignature(string certificates, string signatureBody, string
124135
throw new CryptographicException($"Signed quote is not the same as RA quote: {Hex.ToStringCondensed(signatureBodyEntity.IsvEnclaveQuoteBody!)} vs {Hex.ToStringCondensed(quote.QuoteBytes)}");
125136
}
126137

127-
if ("OK" != signatureBodyEntity.IsvEnclaveQuoteStatus)
138+
// TODO: "GROUP_OUT_OF_DATE" should only be allowed during testing
139+
if ("OK" != signatureBodyEntity.IsvEnclaveQuoteStatus && "GROUP_OUT_OF_DATE" != signatureBodyEntity.IsvEnclaveQuoteStatus)
140+
//if ("OK" != signatureBodyEntity.IsvEnclaveQuoteStatus)
128141
{
129142
throw new CryptographicException($"Quote status is: {signatureBodyEntity.IsvEnclaveQuoteStatus}");
130143
}

libsignal-service-dotnet/contacts/entities/DiscoveryRequest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using libsignalservice.util;
12
using Newtonsoft.Json;
23

34
namespace libsignalservice.contacts.entities
@@ -34,7 +35,7 @@ public DiscoveryRequest(int addressCount, byte[] requestId, byte[] iv, byte[] da
3435

3536
public override string ToString()
3637
{
37-
return $"{{addressCount: {AddressCount}, ticket: {HelperMethods.ByteArrayToHexString(RequestId)}, iv: {HelperMethods.ByteArrayToHexString(Iv)}, data: {HelperMethods.ByteArrayToHexString(Data)}, mac: {HelperMethods.ByteArrayToHexString(Mac)}}}";
38+
return $"{{addressCount: {AddressCount}, ticket: {Hex.ToString(RequestId!)}, iv: {Hex.ToString(Iv!)}, data: {Hex.ToString(Data!)}, mac: {Hex.ToString(Mac!)}}}";
3839
}
3940
}
4041
}

libsignal-service-dotnet/contacts/entities/DiscoveryResponse.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using libsignalservice.util;
12
using Newtonsoft.Json;
23

34
namespace libsignalservice.contacts.entities
@@ -26,7 +27,7 @@ public DiscoveryResponse(byte[] iv, byte[] data, byte[] mac)
2627

2728
public override string ToString()
2829
{
29-
return $"{{iv: {(Iv == null ? null : HelperMethods.ByteArrayToHexString(Iv))}, data: {(Data == null ? null : HelperMethods.ByteArrayToHexString(Data))}, mac: {(Mac == null ? null : HelperMethods.ByteArrayToHexString(Mac))}}}";
30+
return $"{{iv: {(Iv == null ? null : Hex.ToString(Iv))}, data: {(Data == null ? null : Hex.ToString(Data))}, mac: {(Mac == null ? null : Hex.ToString(Mac))}}}";
3031
}
3132
}
3233
}

libsignal-service-dotnet/push/AuthorizationToken.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Newtonsoft.Json;
2+
3+
namespace libsignalservice.push
4+
{
5+
public class ContactDiscoveryCredentials
6+
{
7+
[JsonProperty("username")]
8+
public string? Username { get; set; }
9+
10+
[JsonProperty("password")]
11+
public string? Password { get; set; }
12+
}
13+
}

0 commit comments

Comments
 (0)