Commit 41002a77 authored by Finn Herzfeld's avatar Finn Herzfeld 🌵

Save new identities from incoming messages that are untrusted

parent 3f449bbc
Pipeline #4042 passed with stages
in 7 minutes and 15 seconds
......@@ -301,7 +301,7 @@ class Manager {
public void createNewIdentity() {
IdentityKeyPair identityKey = KeyHelper.generateIdentityKeyPair();
int registrationId = KeyHelper.generateRegistrationId(false);
accountData.axolotlStore = new SignalProtocolStore(identityKey, registrationId, accountData::resolveAddress);
accountData.axolotlStore = new SignalProtocolStore(identityKey, registrationId, accountData.getResolver());
accountData.registered = false;
logger.info("Generating new identity pair");
}
......@@ -720,7 +720,7 @@ class Manager {
return null;
}
address = accountData.resolveAddress(address);
address = accountData.getResolver().resolve(address);
try {
SignalServiceMessageSender messageSender = getMessageSender();
......@@ -744,7 +744,7 @@ class Manager {
return Collections.emptyList();
}
recipients = accountData.resolveAddresses(recipients);
recipients = accountData.getResolver().resolve(recipients);
SignalServiceDataMessage message = null;
try {
......@@ -820,13 +820,16 @@ class Manager {
}
}
private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolInvalidKeyIdException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolNoSessionException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyException, ProtocolDuplicateMessageException, SelfSendException, UnsupportedDataMessageException {
private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolInvalidKeyIdException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolNoSessionException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyException, ProtocolDuplicateMessageException, SelfSendException, UnsupportedDataMessageException, org.whispersystems.libsignal.UntrustedIdentityException {
SignalServiceCipher cipher = new SignalServiceCipher(accountData.address.getSignalServiceAddress(), accountData.axolotlStore, getCertificateValidator());
try {
return cipher.decrypt(envelope);
} catch (ProtocolUntrustedIdentityException e) {
// TODO We don't get the new untrusted identity from ProtocolUntrustedIdentityException anymore ... we need to get it from somewhere else
// signalProtocolStore.saveIdentity(e.getSource(), e, TrustLevel.UNTRUSTED);
if(e.getCause() instanceof org.whispersystems.libsignal.UntrustedIdentityException) {
org.whispersystems.libsignal.UntrustedIdentityException identityException = (org.whispersystems.libsignal.UntrustedIdentityException) e.getCause();
accountData.axolotlStore.saveIdentity(identityException.getName(), identityException.getUntrustedIdentity(), TrustLevel.UNTRUSTED);
throw identityException;
}
throw e;
}
}
......
......@@ -93,15 +93,20 @@ public class AccountData {
a.deviceId = registration.getDeviceId();
a.signalingKey = signalingKey;
a.axolotlStore = new SignalProtocolStore(registration.getIdentity(), registrationId, a::resolveAddress);
a.axolotlStore = new SignalProtocolStore(registration.getIdentity(), registrationId, a.getResolver());
a.registered = true;
a.init();
a.save();
}
@JsonIgnore
public AddressResolver getResolver() {
return new Resolver();
}
public void initProtocolStore() {
axolotlStore.sessionStore.setResolver(this::resolveAddress);
axolotlStore.identityKeyStore.setResolver(this::resolveAddress);
axolotlStore.sessionStore.setResolver(getResolver());
axolotlStore.identityKeyStore.setResolver(getResolver());
}
private void update() {
......@@ -182,6 +187,7 @@ public class AccountData {
public void setProfileKey(ProfileKey key) {
if(key == null) {
profileKey = "";
return;
}
profileKey = Base64.encodeBytes(key.serialize());
}
......@@ -205,36 +211,6 @@ public class AccountData {
return address.getUUID();
}
public SignalServiceAddress resolveAddress(String identifier) {
SignalServiceAddress address = AddressUtil.fromIdentifier(identifier);
return resolveAddress(address);
}
public SignalServiceAddress resolveAddress(SignalServiceAddress a) {
if (a.matches(address.getSignalServiceAddress())) {
return address.getSignalServiceAddress();
}
for(JsonAddress i : recipientStore) {
if(i.getSignalServiceAddress().matches(a)) {
i.update(a);
return i.getSignalServiceAddress();
}
}
return a;
}
public Collection<SignalServiceAddress> resolveAddresses(Collection<SignalServiceAddress> partials) {
Collection <SignalServiceAddress> full = new ArrayList<>();
for(SignalServiceAddress p : partials) {
full.add(resolveAddress(p));
}
return full;
}
// Jackson getters and setters
// migrate old threadStore which tracked expiration timers, now moved to groups and contacts
......@@ -254,4 +230,35 @@ public class AccountData {
}
}
}
public class Resolver implements AddressResolver {
public SignalServiceAddress resolve(String identifier) {
SignalServiceAddress address = AddressUtil.fromIdentifier(identifier);
return resolve(address);
}
public SignalServiceAddress resolve(SignalServiceAddress a) {
if (a.matches(address.getSignalServiceAddress())) {
return address.getSignalServiceAddress();
}
for(JsonAddress i : recipientStore) {
if(i.getSignalServiceAddress().matches(a)) {
i.update(a);
return i.getSignalServiceAddress();
}
}
return a;
}
public Collection<SignalServiceAddress> resolve(Collection<SignalServiceAddress> partials) {
Collection <SignalServiceAddress> full = new ArrayList<>();
for(SignalServiceAddress p : partials) {
full.add(resolve(p));
}
return full;
}
}
}
......@@ -19,6 +19,8 @@ package io.finn.signald.storage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.Collection;
// Based on signal-cli's SignalServiceAddressResolver
public interface AddressResolver {
......@@ -26,6 +28,21 @@ public interface AddressResolver {
* Get a SignalServiceAddress with number and/or uuid from an identifier name.
*
* @param identifier can be either a serialized uuid or a e164 phone number
* @return the full address
*/
SignalServiceAddress resolve(String identifier);
/**
* Attempt to create a full SignalServiceAddress with number and uuid from an address that may only have one of them
* @param partial the partial address. If the partial has a full set of identifiers it will be returned unmodified
* @return the full address
*/
SignalServiceAddress resolve(SignalServiceAddress partial);
/**
* Attempt to resolve a collection of addresses
* @param partials a list of addresses to resolve
* @return a list of resolved addresses
*/
SignalServiceAddress resolveSignalServiceAddress(String identifier);
Collection<SignalServiceAddress> resolve(Collection<SignalServiceAddress> partials);
}
\ No newline at end of file
......@@ -75,7 +75,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
}
public boolean saveIdentity(String identifier, IdentityKey identityKey, TrustLevel trustLevel) {
return saveIdentity(AddressUtil.fromIdentifier(identifier), identityKey, trustLevel);
return saveIdentity(resolver.resolve(identifier), identityKey, trustLevel);
}
public boolean saveIdentity(SignalServiceAddress address, IdentityKey identityKey, TrustLevel trustLevel) {
return saveIdentity(address, identityKey, trustLevel, null);
......@@ -86,7 +86,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
}
private List<Identity> getKeys(String identifier) {
return getKeys(resolver.resolveSignalServiceAddress(identifier));
return getKeys(resolver.resolve(identifier));
}
private List<Identity> getKeys(SignalServiceAddress other) {
......
......@@ -57,7 +57,7 @@ public class SessionStore implements org.whispersystems.libsignal.state.SessionS
private SignalServiceAddress resolveSignalServiceAddress(String identifier) {
if (resolver != null) {
return resolver.resolveSignalServiceAddress(identifier);
return resolver.resolve(identifier);
} else {
return AddressUtil.fromIdentifier(identifier);
}
......
......@@ -18,6 +18,7 @@
package io.finn.signald.storage;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.asamk.signal.TrustLevel;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyIdException;
......@@ -61,6 +62,10 @@ public class SignalProtocolStore implements org.whispersystems.libsignal.state.S
return identityKeyStore.saveIdentity(address, identityKey);
}
public boolean saveIdentity(String identifier, IdentityKey key, TrustLevel level) {
return identityKeyStore.saveIdentity(identifier, key, level);
}
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
return identityKeyStore.isTrustedIdentity(address, identityKey, direction);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment