From c49b05cd75dd8cee795859b6045fbec0040d4144 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 21 Dec 2020 14:56:37 +0100 Subject: [PATCH] Get UUIDs for unknown numbers from server --- .../asamk/signal/manager/IasTrustStore.java | 18 +++++++++ .../org/asamk/signal/manager/Manager.java | 38 +++++++++++++++++- .../asamk/signal/manager/ServiceConfig.java | 25 +++++++++++- .../org/asamk/signal/manager/ias.store | Bin 0 -> 1441 bytes 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/asamk/signal/manager/IasTrustStore.java create mode 100644 src/main/resources/org/asamk/signal/manager/ias.store diff --git a/src/main/java/org/asamk/signal/manager/IasTrustStore.java b/src/main/java/org/asamk/signal/manager/IasTrustStore.java new file mode 100644 index 00000000..f9bbb0b3 --- /dev/null +++ b/src/main/java/org/asamk/signal/manager/IasTrustStore.java @@ -0,0 +1,18 @@ +package org.asamk.signal.manager; + +import org.whispersystems.signalservice.api.push.TrustStore; + +import java.io.InputStream; + +class IasTrustStore implements TrustStore { + + @Override + public InputStream getKeyStoreInputStream() { + return IasTrustStore.class.getResourceAsStream("ias.store"); + } + + @Override + public String getKeyStorePassword() { + return "whisper"; + } +} diff --git a/src/main/java/org/asamk/signal/manager/Manager.java b/src/main/java/org/asamk/signal/manager/Manager.java index d15d164b..26f5abbc 100644 --- a/src/main/java/org/asamk/signal/manager/Manager.java +++ b/src/main/java/org/asamk/signal/manager/Manager.java @@ -120,6 +120,9 @@ import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.UptimeSleepTimer; import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration; +import org.whispersystems.signalservice.internal.contacts.crypto.Quote; +import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException; +import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException; import org.whispersystems.signalservice.internal.push.VerifyAccountResponse; @@ -142,6 +145,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.SignatureException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -151,6 +155,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -161,7 +166,9 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import static org.asamk.signal.manager.ServiceConfig.CDS_MRENCLAVE; import static org.asamk.signal.manager.ServiceConfig.capabilities; +import static org.asamk.signal.manager.ServiceConfig.getIasKeyStore; public class Manager implements Closeable { @@ -1279,10 +1286,39 @@ public class Manager implements Closeable { private Collection getSignalServiceAddresses(Collection numbers) throws InvalidNumberException { final Set signalServiceAddresses = new HashSet<>(numbers.size()); + final Set missingUuids = new HashSet<>(); for (String number : numbers) { - signalServiceAddresses.add(canonicalizeAndResolveSignalServiceAddress(number)); + final SignalServiceAddress resolvedAddress = canonicalizeAndResolveSignalServiceAddress(number); + if (resolvedAddress.getUuid().isPresent()) { + signalServiceAddresses.add(resolvedAddress); + } else { + missingUuids.add(resolvedAddress); + } } + + Map registeredUsers; + try { + registeredUsers = accountManager.getRegisteredUsers(getIasKeyStore(), + missingUuids.stream().map(a -> a.getNumber().get()).collect(Collectors.toSet()), + CDS_MRENCLAVE); + } catch (IOException | Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | SignatureException | UnauthenticatedResponseException e) { + System.err.println("Failed to resolve uuids from server: " + e.getMessage()); + registeredUsers = new HashMap<>(); + } + + for (SignalServiceAddress address : missingUuids) { + final String number = address.getNumber().get(); + if (registeredUsers.containsKey(number)) { + final SignalServiceAddress newAddress = resolveSignalServiceAddress(new SignalServiceAddress( + registeredUsers.get(number), + number)); + signalServiceAddresses.add(newAddress); + } else { + signalServiceAddresses.add(address); + } + } + return signalServiceAddresses; } diff --git a/src/main/java/org/asamk/signal/manager/ServiceConfig.java b/src/main/java/org/asamk/signal/manager/ServiceConfig.java index 7f7d5570..5721b166 100644 --- a/src/main/java/org/asamk/signal/manager/ServiceConfig.java +++ b/src/main/java/org/asamk/signal/manager/ServiceConfig.java @@ -13,6 +13,10 @@ import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl; import org.whispersystems.util.Base64; import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.util.Collections; import java.util.List; import java.util.Map; @@ -29,12 +33,16 @@ public class ServiceConfig { final static int MAX_ENVELOPE_SIZE = 0; final static long AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE = 10 * 1024 * 1024; + final static String CDS_MRENCLAVE = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15"; + private final static String URL = "https://textsecure-service.whispersystems.org"; private final static String CDN_URL = "https://cdn.signal.org"; private final static String CDN2_URL = "https://cdn2.signal.org"; + private final static String SIGNAL_CONTACT_DISCOVERY_URL = "https://api.directory.signal.org"; private final static String SIGNAL_KEY_BACKUP_URL = "https://api.backup.signal.org"; private final static String STORAGE_URL = "https://storage.signal.org"; private final static TrustStore TRUST_STORE = new WhisperTrustStore(); + private final static TrustStore IAS_TRUST_STORE = new IasTrustStore(); private final static Optional dns = Optional.absent(); @@ -71,7 +79,8 @@ public class ServiceConfig { return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)}, makeSignalCdnUrlMapFor(new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)}, new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}), - new SignalContactDiscoveryUrl[0], + new SignalContactDiscoveryUrl[]{new SignalContactDiscoveryUrl(SIGNAL_CONTACT_DISCOVERY_URL, + TRUST_STORE)}, new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)}, new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)}, interceptors, @@ -79,6 +88,20 @@ public class ServiceConfig { zkGroupServerPublicParams); } + static KeyStore getIasKeyStore() { + try { + TrustStore contactTrustStore = IAS_TRUST_STORE; + + KeyStore keyStore = KeyStore.getInstance("BKS"); + keyStore.load(contactTrustStore.getKeyStoreInputStream(), + contactTrustStore.getKeyStorePassword().toCharArray()); + + return keyStore; + } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) { + throw new AssertionError(e); + } + } + private static Map makeSignalCdnUrlMapFor( SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls ) { diff --git a/src/main/resources/org/asamk/signal/manager/ias.store b/src/main/resources/org/asamk/signal/manager/ias.store new file mode 100644 index 0000000000000000000000000000000000000000..e0b8ec8ccacc48459adb2384402b887682cf45da GIT binary patch literal 1441 zcmZQzU|?ckU=WcLo>6|#P&tUfG}q(0mH|~V zFtA4GnHpFEX@7$zR&RqQ=FJP3nHZUvI2kUom&F<_-Y~_0myJ`a&7dghg+ z<|sJl7Zv0eC6;97=NTFp=z-*zdDJ0t!R`?XjwL0j#U)^Qg`iZR(h`N>%=Em>ymSR; zM*{_MUPCiOLqiioQ)6>u!zc-UBLfplLnC7#GPN|dj2dtkHZd+j4m3tq2IeNleg=ak z#xABN#zuzuHYs&m%WZZC>Z%(Zxb7IYJ9NRXdH3{ECeD1;B)e1Ks$sb~XSrKeR-Aj= znM-$HUlEy`rJt-CH1{IU$#(M%<#VLiAI))JxQ@Zo!#&4izU$J3u~jGD99whDb?p}0 z_Vl@5=WtpdUGy?DC!``odiuOl?{G_zeW922zZ{r*UtMvg$=R8#>YIP+UGLwosgkwt zbfF60=Q+BC>|5MJqUwJOyk_IdSlQa3IL~Y%XHbU4q-#qbt>9pmv~wsmbnr9VESh9K zb5&D7iNo}eMfYEPU4QjovYh;(^%fix@->!ExOsQ}gM`Vmg~BHsZHQ&A{hBp1SbEyM z%zMUfm2wU$)CxFlJ-NEx!T-46fq(9qzo%Agyu)`S^Ocn9ga0!{I`Tec&Q^}z(o%cv zzr!}RXX5OW5B;98StO!<&R^Byr2DTna$8@zSysGo$zGQu!K=R1AN+Lr!snLnUTi<+ zaLngjc6R%pcP~yhN%e(%ieVAE*yGkbE51SK_g&lLzN$%;YY!c`8udS)P01-%nu(c_ zfpKx;NrT2?1_{8_Co9hqX%KD@x*&K#V4HtNNlAf~zJ5tjX>mzvN^xpYS!Qx-v0f%9 z>FOot=jtct1DSax`p!W<`oQF>kCa>?sTG=7ogMX(i*gKPK{oKQh_Q%NI9Hb~tJ`y7 zeVvo}YttI*cE&&(19_0NGK++PSOazid>{q9Px zoDrv>YgGS16DLEx@@1A&Zcd+i;+1Pzlg+EHiw`HBUy<}{$4aBiH#Y=Fu`^u=jW2ns z@R-@)vq{7AwI{EikW(lyblT5wRAU9Vn{ngc1g)my%t4K-o=#0Vv(?yd#RR)lZbr7o zujl%<>8+XL=-HuS^=8ti=#Mt{zrQ}C+4od>SCpy6wrsW2N1_7nG1#m%NHttr^YzMm z{tniQJB4jkgrhbeNs-d;;4qn6Y^)i_SN6{Ps8W$pQs1wJ>vJcq_OlgK`20KSqU71$ z5U+(-mbJxYhwobxUT9FKXS0)?cS*JPpN`B2BEqjYO RcZ)scQZTsQY7d+&%4M^ zza6~JavyCuJ*PQ@rPznB?pQ+1{qy=?EVo@LoL`{N$78?1|F+Pw(^?l-%gp-t1Bm$#Naxay6{qM3DBmjOA4C9ePg literal 0 HcmV?d00001