Trust an identity with its scannable safety numbers from the other device

Attention, the scannable fingerprints are asymetric, so the scannable
fingerprints from the local listIdentities command can't be used to trust
an identity. The scannable fingerprint must come from the other device.
This commit is contained in:
AsamK 2021-08-22 19:23:49 +02:00
parent 0a5e836ab6
commit 4f67ac674b
2 changed files with 82 additions and 42 deletions

View file

@ -81,6 +81,9 @@ import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.ecc.ECPublicKey; import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.fingerprint.Fingerprint;
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
@ -2668,6 +2671,25 @@ public class Manager implements Closeable {
TrustLevel.TRUSTED_VERIFIED); TrustLevel.TRUSTED_VERIFIED);
} }
/**
* Trust this the identity with this scannable safety number
*
* @param name username of the identity
* @param safetyNumber Scannable safety number
*/
public boolean trustIdentityVerifiedSafetyNumber(String name, byte[] safetyNumber) throws InvalidNumberException {
var recipientId = canonicalizeAndResolveRecipient(name);
var address = account.getRecipientStore().resolveServiceAddress(recipientId);
return trustIdentity(recipientId, identityKey -> {
final var fingerprint = computeSafetyNumberFingerprint(address, identityKey);
try {
return fingerprint != null && fingerprint.getScannableFingerprint().compareTo(safetyNumber);
} catch (FingerprintVersionMismatchException | FingerprintParsingException e) {
return false;
}
}, TrustLevel.TRUSTED_VERIFIED);
}
/** /**
* Trust all keys of this identity without verification * Trust all keys of this identity without verification
* *
@ -2717,21 +2739,23 @@ public class Manager implements Closeable {
} }
public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) {
final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(), final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey);
account.getSelfAddress(),
getIdentityKeyPair().getPublicKey(),
theirAddress,
theirIdentityKey);
return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText(); return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText();
} }
public byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { public byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) {
final var fingerprint = Utils.computeSafetyNumber(capabilities.isUuid(), final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey);
return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized();
}
private Fingerprint computeSafetyNumberFingerprint(
final SignalServiceAddress theirAddress, final IdentityKey theirIdentityKey
) {
return Utils.computeSafetyNumber(capabilities.isUuid(),
account.getSelfAddress(), account.getSelfAddress(),
getIdentityKeyPair().getPublicKey(), getIdentityKeyPair().getPublicKey(),
theirAddress, theirAddress,
theirIdentityKey); theirIdentityKey);
return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized();
} }
@Deprecated @Deprecated

View file

@ -11,6 +11,7 @@ import org.asamk.signal.manager.Manager;
import org.asamk.signal.util.Hex; import org.asamk.signal.util.Hex;
import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.util.Base64;
import java.util.Locale; import java.util.Locale;
public class TrustCommand implements JsonRpcLocalCommand { public class TrustCommand implements JsonRpcLocalCommand {
@ -49,7 +50,11 @@ public class TrustCommand implements JsonRpcLocalCommand {
} }
} else { } else {
var safetyNumber = ns.getString("verified-safety-number"); var safetyNumber = ns.getString("verified-safety-number");
if (safetyNumber != null) { if (safetyNumber == null) {
throw new UserErrorException(
"You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER");
}
safetyNumber = safetyNumber.replaceAll(" ", ""); safetyNumber = safetyNumber.replaceAll(" ", "");
if (safetyNumber.length() == 66) { if (safetyNumber.length() == 66) {
byte[] fingerprintBytes; byte[] fingerprintBytes;
@ -81,12 +86,23 @@ public class TrustCommand implements JsonRpcLocalCommand {
"Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct."); "Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct.");
} }
} else { } else {
final byte[] scannableSafetyNumber;
try {
scannableSafetyNumber = Base64.getDecoder().decode(safetyNumber);
} catch (IllegalArgumentException e) {
throw new UserErrorException( throw new UserErrorException(
"Safety number has invalid format, either specify the old hex fingerprint or the new safety number"); "Safety number has invalid format, either specify the old hex fingerprint or the new safety number");
} }
} else { boolean res;
try {
res = m.trustIdentityVerifiedSafetyNumber(number, scannableSafetyNumber);
} catch (InvalidNumberException e) {
throw new UserErrorException("Failed to parse recipient: " + e.getMessage());
}
if (!res) {
throw new UserErrorException( throw new UserErrorException(
"You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER"); "Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct.");
}
} }
} }
} }