Sync the PNI identity used in sent transcripts.

This commit is contained in:
Greyson Parrelli 2024-03-06 15:25:28 -05:00 committed by Alex Hart
parent b4ced5278e
commit 891c130e12
4 changed files with 67 additions and 5 deletions

View file

@ -395,7 +395,7 @@ object MessageDecryptor {
val aciAddress = SignalProtocolAddress(aci.toString(), deviceId) val aciAddress = SignalProtocolAddress(aci.toString(), deviceId)
val pniAddress = SignalProtocolAddress(pni.toString(), deviceId) val pniAddress = SignalProtocolAddress(pni.toString(), deviceId)
val aciIdentity = protocolStore.getAciStore().getIdentity(aciAddress) val aciIdentity = protocolStore.getAciStore().getIdentity(aciAddress)
val pniIdentity = protocolStore.getAciStore().getIdentity(pniAddress) var pniIdentity = protocolStore.getAciStore().getIdentity(pniAddress)
if (aciIdentity == null) { if (aciIdentity == null) {
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for ACI address $aciAddress") Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for ACI address $aciAddress")
@ -404,7 +404,18 @@ object MessageDecryptor {
if (pniIdentity == null) { if (pniIdentity == null) {
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for PNI address $pniAddress") Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No identity found for PNI address $pniAddress")
return if (deviceId != SignalServiceAddress.DEFAULT_DEVICE_ID) {
pniIdentity = protocolStore.getAciStore().getIdentity(SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID))
if (pniIdentity != null) {
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] Found PNI identity when looking up device 1. Using that.")
} else {
Log.w(TAG, "${logPrefix(envelope, aci)}[validatePniSignature] No PNI identity when looking up device 1 either.")
return
}
} else {
return
}
} }
if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature!!.toByteArray())) { if (pniIdentity.verifyAlternateIdentity(aciIdentity, pniSignatureMessage.signature!!.toByteArray())) {

View file

@ -6,6 +6,9 @@ import com.mobilecoin.lib.exceptions.SerializationException
import okio.ByteString import okio.ByteString
import org.signal.core.util.Hex import org.signal.core.util.Hex
import org.signal.core.util.orNull import org.signal.core.util.orNull
import org.signal.libsignal.protocol.IdentityKey
import org.signal.libsignal.protocol.InvalidKeyException
import org.signal.libsignal.protocol.SignalProtocolAddress
import org.signal.libsignal.protocol.util.Pair import org.signal.libsignal.protocol.util.Pair
import org.signal.ringrtc.CallException import org.signal.ringrtc.CallException
import org.signal.ringrtc.CallLinkRootKey import org.signal.ringrtc.CallLinkRootKey
@ -96,6 +99,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPoin
import org.whispersystems.signalservice.api.push.DistributionId import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.storage.StorageKey import org.whispersystems.signalservice.api.storage.StorageKey
import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.Content
@ -169,6 +173,8 @@ object SyncMessageProcessor {
log(envelope.timestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}") log(envelope.timestamp!!, "Processing sent transcript for message with ID ${sent.timestamp!!}")
try { try {
handlePniIdentityKeys(envelope, sent)
if (sent.storyMessage != null || sent.storyMessageRecipients.isNotEmpty()) { if (sent.storyMessage != null || sent.storyMessageRecipients.isNotEmpty()) {
handleSynchronizeSentStoryMessage(envelope, sent) handleSynchronizeSentStoryMessage(envelope, sent)
return return
@ -246,6 +252,34 @@ object SyncMessageProcessor {
} }
} }
private fun handlePniIdentityKeys(envelope: Envelope, sent: Sent) {
for (status in sent.unidentifiedStatus) {
if (status.destinationIdentityKey == null) {
continue
}
val pni = PNI.parsePrefixedOrNull(status.destinationServiceId)
if (pni == null) {
continue
}
val address = SignalProtocolAddress(pni.toString(), SignalServiceAddress.DEFAULT_DEVICE_ID)
if (ApplicationDependencies.getProtocolStore().aci().identities().getIdentity(address) != null) {
log(envelope.timestamp!!, "Ignoring identity on sent transcript for $pni because we already have one.")
continue
}
try {
log(envelope.timestamp!!, "Saving identity from sent transcript for $pni")
val identityKey = IdentityKey(status.destinationIdentityKey!!.toByteArray())
ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(address, identityKey)
} catch (e: InvalidKeyException) {
warn(envelope.timestamp!!, "Failed to deserialize identity key for $pni")
}
}
}
private fun getSyncMessageDestination(message: Sent): Recipient { private fun getSyncMessageDestination(message: Sent): Recipient {
return if (message.message.hasGroupContext) { return if (message.message.hasGroupContext) {
Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.message!!.groupV2!!.groupMasterKey)) Recipient.externalPossiblyMigratedGroup(GroupId.v2(message.message!!.groupV2!!.groupMasterKey))

View file

@ -7,6 +7,7 @@ package org.whispersystems.signalservice.api;
import org.signal.core.util.Base64; import org.signal.core.util.Base64;
import org.signal.libsignal.metadata.certificate.SenderCertificate; import org.signal.libsignal.metadata.certificate.SenderCertificate;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.InvalidRegistrationIdException; import org.signal.libsignal.protocol.InvalidRegistrationIdException;
@ -1399,9 +1400,21 @@ public class SignalServiceMessageSender {
List<SyncMessage.Sent.UnidentifiedDeliveryStatus> unidentifiedDeliveryStatuses = new ArrayList<>(sendMessageResults.size()); List<SyncMessage.Sent.UnidentifiedDeliveryStatus> unidentifiedDeliveryStatuses = new ArrayList<>(sendMessageResults.size());
for (SendMessageResult result : sendMessageResults) { for (SendMessageResult result : sendMessageResults) {
if (result.getSuccess() != null) { if (result.getSuccess() != null) {
ByteString identity = null;
if (result.getAddress().getServiceId() instanceof PNI) {
IdentityKey identityKey = aciStore.getIdentity(result.getAddress().getServiceId().toProtocolAddress(SignalServiceAddress.DEFAULT_DEVICE_ID));
if (identityKey != null) {
identity = ByteString.of(identityKey.getPublicKey().serialize());
} else {
Log.w(TAG, "[" + timestamp + "] Could not find an identity for PNI when sending sync message! " + result.getAddress().getServiceId());
}
}
unidentifiedDeliveryStatuses.add(new SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder() unidentifiedDeliveryStatuses.add(new SyncMessage.Sent.UnidentifiedDeliveryStatus.Builder()
.destinationServiceId(result.getAddress().getServiceId().toString()) .destinationServiceId(result.getAddress().getServiceId().toString())
.unidentified(result.getSuccess().isUnidentified()) .unidentified(result.getSuccess().isUnidentified())
.destinationIdentityKey(identity)
.build()); .build());
} }
} }

View file

@ -439,9 +439,11 @@ message Verified {
message SyncMessage { message SyncMessage {
message Sent { message Sent {
message UnidentifiedDeliveryStatus { message UnidentifiedDeliveryStatus {
reserved /*destinationE164*/ 1; reserved /*destinationE164*/ 1;
optional string destinationServiceId = 3; optional string destinationServiceId = 3;
optional bool unidentified = 2; optional bool unidentified = 2;
reserved /*destinationPni*/ 4;
optional bytes destinationIdentityKey = 5;
} }
message StoryMessageRecipient { message StoryMessageRecipient {
@ -460,6 +462,8 @@ message SyncMessage {
optional StoryMessage storyMessage = 8; optional StoryMessage storyMessage = 8;
repeated StoryMessageRecipient storyMessageRecipients = 9; repeated StoryMessageRecipient storyMessageRecipients = 9;
optional EditMessage editMessage = 10; optional EditMessage editMessage = 10;
reserved /*destinationPni*/ 11;
// NEXT ID: 12
} }
message Contacts { message Contacts {