Use a new SVR2 enclave.

This commit is contained in:
AsamK 2023-12-10 19:30:36 +01:00
parent 2535cd9c2c
commit 4dcdffda0a
7 changed files with 99 additions and 61 deletions

View file

@ -20,12 +20,15 @@ import java.util.Optional;
import okhttp3.Dns;
import okhttp3.Interceptor;
import static org.asamk.signal.manager.api.ServiceEnvironment.LIVE;
class LiveConfig {
private static final byte[] UNIDENTIFIED_SENDER_TRUST_ROOT = Base64.getDecoder()
.decode("BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF");
private static final String CDSI_MRENCLAVE = "0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57";
private static final String SVR2_MRENCLAVE = "6ee1042f9e20f880326686dd4ba50c25359f01e9f733eeba4382bca001d45094";
private static final String SVR2_MRENCLAVE = "a6622ad4656e1abcd0bc0ff17c229477747d2ded0495c4ebee7ed35c1789fa97";
private static final String SVR2_MRENCLAVE_DEPRECATED = "6ee1042f9e20f880326686dd4ba50c25359f01e9f733eeba4382bca001d45094";
private static final String URL = "https://chat.signal.org";
private static final String CDN_URL = "https://cdn.signal.org";
@ -69,12 +72,12 @@ class LiveConfig {
}
}
static String getCdsiMrenclave() {
return CDSI_MRENCLAVE;
}
static String getSvr2Mrenclave() {
return SVR2_MRENCLAVE;
static ServiceEnvironmentConfig getServiceEnvironmentConfig(List<Interceptor> interceptors) {
return new ServiceEnvironmentConfig(LIVE,
createDefaultServiceConfiguration(interceptors),
getUnidentifiedSenderTrustRoot(),
CDSI_MRENCLAVE,
List.of(SVR2_MRENCLAVE, SVR2_MRENCLAVE_DEPRECATED));
}
private LiveConfig() {

View file

@ -43,16 +43,8 @@ public class ServiceConfig {
final var interceptors = List.of(userAgentInterceptor);
return switch (serviceEnvironment) {
case LIVE -> new ServiceEnvironmentConfig(serviceEnvironment,
LiveConfig.createDefaultServiceConfiguration(interceptors),
LiveConfig.getUnidentifiedSenderTrustRoot(),
LiveConfig.getCdsiMrenclave(),
LiveConfig.getSvr2Mrenclave());
case STAGING -> new ServiceEnvironmentConfig(serviceEnvironment,
StagingConfig.createDefaultServiceConfiguration(interceptors),
StagingConfig.getUnidentifiedSenderTrustRoot(),
StagingConfig.getCdsiMrenclave(),
StagingConfig.getSvr2Mrenclave());
case LIVE -> LiveConfig.getServiceEnvironmentConfig(interceptors);
case STAGING -> StagingConfig.getServiceEnvironmentConfig(interceptors);
};
}
}

View file

@ -4,10 +4,12 @@ import org.asamk.signal.manager.api.ServiceEnvironment;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
import java.util.List;
public record ServiceEnvironmentConfig(
ServiceEnvironment type,
SignalServiceConfiguration signalServiceConfiguration,
ECPublicKey unidentifiedSenderTrustRoot,
String cdsiMrenclave,
String svr2Mrenclave
List<String> svr2Mrenclaves
) {}

View file

@ -20,12 +20,15 @@ import java.util.Optional;
import okhttp3.Dns;
import okhttp3.Interceptor;
import static org.asamk.signal.manager.api.ServiceEnvironment.STAGING;
class StagingConfig {
private static final byte[] UNIDENTIFIED_SENDER_TRUST_ROOT = Base64.getDecoder()
.decode("BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx");
private static final String CDSI_MRENCLAVE = "0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57";
private static final String SVR2_MRENCLAVE = "a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95";
private static final String SVR2_MRENCLAVE = "acb1973aa0bbbd14b3b4e06f145497d948fd4a98efc500fcce363b3b743ec482";
private static final String SVR2_MRENCLAVE_DEPRECATED = "a8a261420a6bb9b61aa25bf8a79e8bd20d7652531feb3381cbffd446d270be95";
private static final String URL = "https://chat.staging.signal.org";
private static final String CDN_URL = "https://cdn-staging.signal.org";
@ -69,12 +72,12 @@ class StagingConfig {
}
}
static String getCdsiMrenclave() {
return CDSI_MRENCLAVE;
}
static String getSvr2Mrenclave() {
return SVR2_MRENCLAVE;
static ServiceEnvironmentConfig getServiceEnvironmentConfig(List<Interceptor> interceptors) {
return new ServiceEnvironmentConfig(STAGING,
createDefaultServiceConfiguration(interceptors),
getUnidentifiedSenderTrustRoot(),
CDSI_MRENCLAVE,
List.of(SVR2_MRENCLAVE, SVR2_MRENCLAVE_DEPRECATED));
}
private StagingConfig() {

View file

@ -5,39 +5,49 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV2;
import org.whispersystems.signalservice.internal.push.AuthCredentials;
import org.whispersystems.signalservice.internal.push.LockedException;
import java.io.IOException;
import java.util.List;
public class PinHelper {
private static final Logger logger = LoggerFactory.getLogger(PinHelper.class);
private final SecureValueRecoveryV2 secureValueRecoveryV2;
private final List<SecureValueRecovery> secureValueRecoveries;
public PinHelper(final SecureValueRecoveryV2 secureValueRecoveryV2) {
this.secureValueRecoveryV2 = secureValueRecoveryV2;
public PinHelper(final List<SecureValueRecovery> secureValueRecoveries) {
this.secureValueRecoveries = secureValueRecoveries;
}
public void setRegistrationLockPin(
String pin, MasterKey masterKey
) throws IOException {
final var backupResponse = secureValueRecoveryV2.setPin(pin, masterKey).execute();
switch (backupResponse) {
case SecureValueRecovery.BackupResponse.Success success -> {
IOException exception = null;
for (final var secureValueRecovery : secureValueRecoveries) {
try {
final var backupResponse = secureValueRecovery.setPin(pin, masterKey).execute();
switch (backupResponse) {
case SecureValueRecovery.BackupResponse.Success success -> {
}
case SecureValueRecovery.BackupResponse.ServerRejected serverRejected ->
logger.warn("Backup svr2 failed: ServerRejected");
case SecureValueRecovery.BackupResponse.EnclaveNotFound enclaveNotFound ->
logger.warn("Backup svr2 failed: EnclaveNotFound");
case SecureValueRecovery.BackupResponse.ExposeFailure exposeFailure ->
logger.warn("Backup svr2 failed: ExposeFailure");
case SecureValueRecovery.BackupResponse.ApplicationError error ->
throw new IOException(error.getException());
case SecureValueRecovery.BackupResponse.NetworkError error -> throw error.getException();
case null, default -> throw new AssertionError("Unexpected response");
}
} catch (IOException e) {
exception = e;
}
case SecureValueRecovery.BackupResponse.ServerRejected serverRejected ->
logger.warn("Backup svr2 failed: ServerRejected");
case SecureValueRecovery.BackupResponse.EnclaveNotFound enclaveNotFound ->
logger.warn("Backup svr2 failed: EnclaveNotFound");
case SecureValueRecovery.BackupResponse.ExposeFailure exposeFailure ->
logger.warn("Backup svr2 failed: ExposeFailure");
case SecureValueRecovery.BackupResponse.ApplicationError error ->
throw new IOException(error.getException());
case SecureValueRecovery.BackupResponse.NetworkError error -> throw error.getException();
case null, default -> throw new AssertionError("Unexpected response");
}
if (exception != null) {
throw exception;
}
}
@ -46,27 +56,47 @@ public class PinHelper {
}
public void removeRegistrationLockPin() throws IOException {
final var deleteResponse = secureValueRecoveryV2.deleteData();
switch (deleteResponse) {
case SecureValueRecovery.DeleteResponse.Success success -> {
IOException exception = null;
for (final var secureValueRecovery : secureValueRecoveries) {
try {
final var deleteResponse = secureValueRecovery.deleteData();
switch (deleteResponse) {
case SecureValueRecovery.DeleteResponse.Success success -> {
}
case SecureValueRecovery.DeleteResponse.ServerRejected serverRejected ->
logger.warn("Delete svr2 failed: ServerRejected");
case SecureValueRecovery.DeleteResponse.EnclaveNotFound enclaveNotFound ->
logger.warn("Delete svr2 failed: EnclaveNotFound");
case SecureValueRecovery.DeleteResponse.ApplicationError error ->
throw new IOException(error.getException());
case SecureValueRecovery.DeleteResponse.NetworkError error -> throw error.getException();
case null, default -> throw new AssertionError("Unexpected response");
}
} catch (IOException e) {
exception = e;
}
case SecureValueRecovery.DeleteResponse.ServerRejected serverRejected ->
logger.warn("Delete svr2 failed: ServerRejected");
case SecureValueRecovery.DeleteResponse.EnclaveNotFound enclaveNotFound ->
logger.warn("Delete svr2 failed: EnclaveNotFound");
case SecureValueRecovery.DeleteResponse.ApplicationError error ->
throw new IOException(error.getException());
case SecureValueRecovery.DeleteResponse.NetworkError error -> throw error.getException();
case null, default -> throw new AssertionError("Unexpected response");
}
if (exception != null) {
throw exception;
}
}
public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
String pin, LockedException e
String pin, LockedException lockedException
) throws IOException, IncorrectPinException {
var svr2Credentials = e.getSvr2Credentials();
var svr2Credentials = lockedException.getSvr2Credentials();
if (svr2Credentials != null) {
return getRegistrationLockData(secureValueRecoveryV2, svr2Credentials, pin);
IOException exception = null;
for (final var secureValueRecovery : secureValueRecoveries) {
try {
return getRegistrationLockData(secureValueRecovery, svr2Credentials, pin);
} catch (IOException e) {
exception = e;
}
}
if (exception != null) {
throw exception;
}
}
return null;

View file

@ -45,6 +45,7 @@ import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException;
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
@ -90,7 +91,10 @@ public class RegistrationManagerImpl implements RegistrationManager {
userAgent,
groupsV2Operations,
ServiceConfig.AUTOMATIC_NETWORK_RETRY);
final var secureValueRecoveryV2 = accountManager.getSecureValueRecoveryV2(serviceEnvironmentConfig.svr2Mrenclave());
final var secureValueRecoveryV2 = serviceEnvironmentConfig.svr2Mrenclaves()
.stream()
.map(mr -> (SecureValueRecovery) accountManager.getSecureValueRecoveryV2(mr))
.toList();
this.pinHelper = new PinHelper(secureValueRecoveryV2);
}

View file

@ -16,13 +16,14 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV2;
import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
@ -50,7 +51,7 @@ public class SignalDependencies {
private SignalServiceMessageReceiver messageReceiver;
private SignalServiceMessageSender messageSender;
private SecureValueRecoveryV2 secureValueRecoveryV2;
private List<SecureValueRecovery> secureValueRecoveryV2;
private ProfileService profileService;
private SignalServiceCipher cipher;
@ -192,9 +193,12 @@ public class SignalDependencies {
pushServiceSocket));
}
public SecureValueRecoveryV2 getSecureValueRecoveryV2() {
public List<SecureValueRecovery> getSecureValueRecoveryV2() {
return getOrCreate(() -> secureValueRecoveryV2,
() -> secureValueRecoveryV2 = getAccountManager().getSecureValueRecoveryV2(serviceEnvironmentConfig.svr2Mrenclave()));
() -> secureValueRecoveryV2 = serviceEnvironmentConfig.svr2Mrenclaves()
.stream()
.map(mr -> (SecureValueRecovery) getAccountManager().getSecureValueRecoveryV2(mr))
.toList());
}
public ProfileService getProfileService() {