Verify payment address identity key against local identity store.

This commit is contained in:
Greyson Parrelli
2026-04-08 19:20:49 +00:00
committed by jeffrey-signal
parent 9c18e3698e
commit 7665ae1464
3 changed files with 22 additions and 3 deletions

View File

@@ -21,7 +21,8 @@ public final class PaymentsAddressException extends Exception {
COULD_NOT_DECRYPT("Payment address could not be decrypted"),
INVALID_ADDRESS("Invalid MobileCoin address on payments address proto"),
INVALID_ADDRESS_SIGNATURE("Invalid MobileCoin address signature on payments address proto"),
NO_ADDRESS("No MobileCoin address on payments address proto");
NO_ADDRESS("No MobileCoin address on payments address proto"),
IDENTITY_MISMATCH("Server-provided identity key does not match locally-stored identity key");
private final String message;

View File

@@ -147,6 +147,7 @@ final class ConfirmPaymentViewModel extends ViewModel {
case INVALID_ADDRESS:
case INVALID_ADDRESS_SIGNATURE:
case NO_ADDRESS:
case IDENTITY_MISMATCH:
return ErrorType.NO_ADDRESS;
}

View File

@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil;
import org.thoughtcrime.securesms.database.RecipientTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.IdentityStoreRecord;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob;
@@ -207,11 +208,18 @@ public final class ProfileUtil {
}
try {
IdentityKey identityKey = new IdentityKey(Base64.decode(profileAndCredential.getProfile().getIdentityKey()), 0);
IdentityKey remoteIdentityKey = new IdentityKey(Base64.decode(profileAndCredential.getProfile().getIdentityKey()), 0);
IdentityKey localIdentityKey = getLocalIdentityKey(recipient);
if (localIdentityKey != null && !localIdentityKey.equals(remoteIdentityKey)) {
Log.w(TAG, "Server-provided identity key does not match locally-stored identity key for " + recipient.getId());
throw new PaymentsAddressException(PaymentsAddressException.Code.IDENTITY_MISMATCH);
}
ProfileCipher profileCipher = new ProfileCipher(profileKey);
byte[] decrypted = profileCipher.decryptWithLength(encryptedPaymentsAddress);
PaymentAddress paymentAddress = PaymentAddress.ADAPTER.decode(decrypted);
byte[] bytes = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(paymentAddress, identityKey);
byte[] bytes = MobileCoinPublicAddressProfileUtil.verifyPaymentsAddress(paymentAddress, localIdentityKey != null ? localIdentityKey : remoteIdentityKey);
MobileCoinPublicAddress mobileCoinPublicAddress = MobileCoinPublicAddress.fromBytes(bytes);
if (mobileCoinPublicAddress == null) {
@@ -228,6 +236,15 @@ public final class ProfileUtil {
}
}
private static @Nullable IdentityKey getLocalIdentityKey(@NonNull Recipient recipient) {
if (!recipient.getHasServiceId()) {
return null;
}
IdentityStoreRecord record = SignalDatabase.identities().getIdentityStoreRecord(recipient.requireServiceId());
return record != null ? record.getIdentityKey() : null;
}
private static ProfileKey getProfileKey(@NonNull Recipient recipient) throws IOException {
byte[] profileKeyBytes = recipient.getProfileKey();