Refactor protobuf validation exceptions.

fork-5.53.8
Greyson Parrelli 2021-08-06 14:47:43 -04:00 zatwierdzone przez GitHub
rodzic 570b4d7150
commit 0762a93787
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 98 dodań i 50 usunięć

Wyświetl plik

@ -47,6 +47,7 @@ import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.protocol.DecryptionErrorMessage;
import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
@ -110,7 +111,7 @@ public final class MessageDecryptionUtil {
} catch (ProtocolDuplicateMessageException e) {
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e);
return DecryptionResult.forError(MessageState.DUPLICATE_MESSAGE, toExceptionMetadata(e), jobs);
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException e) {
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException | InvalidMessageStructureException e) {
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e);
return DecryptionResult.forNoop(jobs);
} catch (SelfSendException e) {

Wyświetl plik

@ -0,0 +1,44 @@
package org.whispersystems.signalservice.api;
import org.whispersystems.libsignal.util.guava.Optional;
/**
* An exception thrown when something about the proto is malformed. e.g. one of the fields has an invalid value.
*/
public final class InvalidMessageStructureException extends Exception {
private final Optional<String> sender;
private final Optional<Integer> device;
public InvalidMessageStructureException(String message) {
super(message);
this.sender = Optional.absent();
this.device = Optional.absent();
}
public InvalidMessageStructureException(String message, String sender, int device) {
super(message);
this.sender = Optional.fromNullable(sender);
this.device = Optional.of(device);
}
public InvalidMessageStructureException(Exception e, String sender, int device) {
super(e);
this.sender = Optional.fromNullable(sender);
this.device = Optional.of(device);
}
public InvalidMessageStructureException(Exception e) {
super(e);
this.sender = Optional.absent();
this.device = Optional.absent();
}
public Optional<String> getSender() {
return sender;
}
public Optional<Integer> getDevice() {
return device;
}
}

Wyświetl plik

@ -41,6 +41,7 @@ import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
import org.whispersystems.libsignal.protocol.SignalMessage;
import org.whispersystems.libsignal.state.SignalProtocolStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
@ -135,7 +136,7 @@ public class SignalServiceCipher {
ProtocolUntrustedIdentityException, ProtocolNoSessionException,
ProtocolInvalidVersionException, ProtocolInvalidMessageException,
ProtocolInvalidKeyException, ProtocolDuplicateMessageException,
SelfSendException, UnsupportedDataMessageException
SelfSendException, UnsupportedDataMessageException, InvalidMessageStructureException
{
try {
if (envelope.hasLegacyMessage()) {
@ -174,7 +175,7 @@ public class SignalServiceCipher {
ProtocolLegacyMessageException, ProtocolInvalidKeyException,
ProtocolInvalidVersionException, ProtocolInvalidMessageException,
ProtocolInvalidKeyIdException, ProtocolNoSessionException,
SelfSendException
SelfSendException, InvalidMessageStructureException
{
try {
@ -182,7 +183,7 @@ public class SignalServiceCipher {
SignalServiceMetadata metadata;
if (!envelope.hasSource() && !envelope.isUnidentifiedSender()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Non-UD envelope is missing a source!"), null, 0);
throw new InvalidMessageStructureException("Non-UD envelope is missing a source!");
}
if (envelope.isPreKeySignalMessage()) {

Wyświetl plik

@ -3,6 +3,7 @@ package org.whispersystems.signalservice.api.messages;
import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
/**
@ -43,14 +44,14 @@ public final class SignalServiceAttachmentRemoteId {
}
}
public static SignalServiceAttachmentRemoteId from(AttachmentPointer attachmentPointer) throws ProtocolInvalidMessageException {
public static SignalServiceAttachmentRemoteId from(AttachmentPointer attachmentPointer) throws InvalidMessageStructureException {
switch (attachmentPointer.getAttachmentIdentifierCase()) {
case CDNID:
return new SignalServiceAttachmentRemoteId(attachmentPointer.getCdnId());
case CDNKEY:
return new SignalServiceAttachmentRemoteId(attachmentPointer.getCdnKey());
case ATTACHMENTIDENTIFIER_NOT_SET:
throw new ProtocolInvalidMessageException(new InvalidMessageException("AttachmentPointer CDN location not set"), null, 0);
throw new InvalidMessageStructureException("AttachmentPointer CDN location not set");
}
return null;
}

Wyświetl plik

@ -21,6 +21,7 @@ import org.whispersystems.libsignal.logging.Log;
import org.whispersystems.libsignal.protocol.DecryptionErrorMessage;
import org.whispersystems.libsignal.protocol.SenderKeyDistributionMessage;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.InvalidMessageStructureException;
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
@ -370,7 +371,7 @@ public final class SignalServiceContent {
SignalServiceContentProto signalServiceContentProto = SignalServiceContentProto.parseFrom(data);
return createFromProto(signalServiceContentProto);
} catch (InvalidProtocolBufferException | ProtocolInvalidMessageException | ProtocolInvalidKeyException | UnsupportedDataMessageException e) {
} catch (InvalidProtocolBufferException | ProtocolInvalidMessageException | ProtocolInvalidKeyException | UnsupportedDataMessageException | InvalidMessageStructureException e) {
// We do not expect any of these exceptions if this byte[] has come from serialize.
throw new AssertionError(e);
}
@ -380,7 +381,7 @@ public final class SignalServiceContent {
* Takes internal protobuf serialization format and processes it into a {@link SignalServiceContent}.
*/
public static SignalServiceContent createFromProto(SignalServiceContentProto serviceContentProto)
throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException
throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException, InvalidMessageStructureException
{
SignalServiceMetadata metadata = SignalServiceMetadataProtobufSerializer.fromProtobuf(serviceContentProto.getMetadata());
SignalServiceAddress localAddress = SignalServiceAddressProtobufSerializer.fromProtobuf(serviceContentProto.getLocalAddress());
@ -502,7 +503,7 @@ public final class SignalServiceContent {
private static SignalServiceDataMessage createSignalServiceMessage(SignalServiceMetadata metadata,
SignalServiceProtos.DataMessage content)
throws ProtocolInvalidMessageException, UnsupportedDataMessageException
throws UnsupportedDataMessageException, InvalidMessageStructureException
{
SignalServiceGroup groupInfoV1 = createGroupV1Info(content);
SignalServiceGroupV2 groupInfoV2 = createGroupV2Info(content);
@ -511,7 +512,7 @@ public final class SignalServiceContent {
try {
groupContext = SignalServiceGroupContext.createOptional(groupInfoV1, groupInfoV2);
} catch (InvalidMessageException e) {
throw new ProtocolInvalidMessageException(e, null, 0);
throw new InvalidMessageStructureException(e);
}
@ -537,12 +538,7 @@ public final class SignalServiceContent {
groupContext);
}
SignalServiceDataMessage.Payment payment;
try {
payment = createPayment(content);
} catch (InvalidMessageException e) {
throw new ProtocolInvalidMessageException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
SignalServiceDataMessage.Payment payment = createPayment(content);
if (content.getRequiredProtocolVersion() > SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT.getNumber()) {
throw new UnsupportedDataMessageProtocolVersionException(SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT.getNumber(),
@ -557,9 +553,9 @@ public final class SignalServiceContent {
}
if (content.hasTimestamp() && content.getTimestamp() != metadata.getTimestamp()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Timestamps don't match: " + content.getTimestamp() + " vs " + metadata.getTimestamp()),
metadata.getSender().getIdentifier(),
metadata.getSenderDevice());
throw new InvalidMessageStructureException("Timestamps don't match: " + content.getTimestamp() + " vs " + metadata.getTimestamp(),
metadata.getSender().getIdentifier(),
metadata.getSenderDevice());
}
return new SignalServiceDataMessage(metadata.getTimestamp(),
@ -585,7 +581,7 @@ public final class SignalServiceContent {
private static SignalServiceSyncMessage createSynchronizeMessage(SignalServiceMetadata metadata,
SignalServiceProtos.SyncMessage content)
throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException
throws ProtocolInvalidKeyException, UnsupportedDataMessageException, InvalidMessageStructureException
{
if (content.hasSent()) {
Map<SignalServiceAddress, Boolean> unidentifiedStatuses = new HashMap<>();
@ -596,7 +592,7 @@ public final class SignalServiceContent {
: Optional.<SignalServiceAddress>absent();
if (!address.isPresent() && !dataMessage.getGroupContext().isPresent()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("SyncMessage missing both destination and group ID!"), null, 0);
throw new InvalidMessageStructureException("SyncMessage missing both destination and group ID!");
}
for (SignalServiceProtos.SyncMessage.Sent.UnidentifiedDeliveryStatus status : sentContent.getUnidentifiedStatusList()) {
@ -656,7 +652,7 @@ public final class SignalServiceContent {
ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(address, content.getViewOnceOpen().getTimestamp());
return SignalServiceSyncMessage.forViewOnceOpen(timerRead);
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("ViewOnceOpen message has no sender!"), null, 0);
throw new InvalidMessageStructureException("ViewOnceOpen message has no sender!");
}
}
@ -676,8 +672,9 @@ public final class SignalServiceContent {
} else if (verified.getState() == SignalServiceProtos.Verified.State.UNVERIFIED) {
verifiedState = VerifiedMessage.VerifiedState.UNVERIFIED;
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Unknown state: " + verified.getState().getNumber()),
metadata.getSender().getIdentifier(), metadata.getSenderDevice());
throw new InvalidMessageStructureException("Unknown state: " + verified.getState().getNumber(),
metadata.getSender().getIdentifier(),
metadata.getSenderDevice());
}
return SignalServiceSyncMessage.forVerified(new VerifiedMessage(destination, identityKey, verifiedState, System.currentTimeMillis()));
@ -685,7 +682,7 @@ public final class SignalServiceContent {
throw new ProtocolInvalidKeyException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Verified message has no sender!"), null, 0);
throw new InvalidMessageStructureException("Verified message has no sender!");
}
}
@ -786,7 +783,7 @@ public final class SignalServiceContent {
if (address.isPresent()) {
responseMessage = MessageRequestResponseMessage.forIndividual(address.get(), type);
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Message request response has an invalid thread identifier!"), null, 0);
throw new InvalidMessageStructureException("Message request response has an invalid thread identifier!");
}
}
@ -868,15 +865,15 @@ public final class SignalServiceContent {
return new SignalServiceReceiptMessage(type, content.getTimestampList(), metadata.getTimestamp());
}
private static DecryptionErrorMessage createDecryptionErrorMessage(SignalServiceMetadata metadata, ByteString content) throws ProtocolInvalidMessageException {
private static DecryptionErrorMessage createDecryptionErrorMessage(SignalServiceMetadata metadata, ByteString content) throws InvalidMessageStructureException {
try {
return new DecryptionErrorMessage(content.toByteArray());
} catch (InvalidMessageException e) {
throw new ProtocolInvalidMessageException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
throw new InvalidMessageStructureException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
}
private static SignalServiceTypingMessage createTypingMessage(SignalServiceMetadata metadata, SignalServiceProtos.TypingMessage content) throws ProtocolInvalidMessageException {
private static SignalServiceTypingMessage createTypingMessage(SignalServiceMetadata metadata, SignalServiceProtos.TypingMessage content) throws InvalidMessageStructureException {
SignalServiceTypingMessage.Action action;
if (content.getAction() == SignalServiceProtos.TypingMessage.Action.STARTED) action = SignalServiceTypingMessage.Action.STARTED;
@ -884,9 +881,9 @@ public final class SignalServiceContent {
else action = SignalServiceTypingMessage.Action.UNKNOWN;
if (content.hasTimestamp() && content.getTimestamp() != metadata.getTimestamp()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Timestamps don't match: " + content.getTimestamp() + " vs " + metadata.getTimestamp()),
metadata.getSender().getIdentifier(),
metadata.getSenderDevice());
throw new InvalidMessageStructureException("Timestamps don't match: " + content.getTimestamp() + " vs " + metadata.getTimestamp(),
metadata.getSender().getIdentifier(),
metadata.getSenderDevice());
}
return new SignalServiceTypingMessage(action, content.getTimestamp(),
@ -894,7 +891,9 @@ public final class SignalServiceContent {
Optional.<byte[]>absent());
}
private static SignalServiceDataMessage.Quote createQuote(SignalServiceProtos.DataMessage content, boolean isGroupV2) throws ProtocolInvalidMessageException {
private static SignalServiceDataMessage.Quote createQuote(SignalServiceProtos.DataMessage content, boolean isGroupV2)
throws InvalidMessageStructureException
{
if (!content.hasQuote()) return null;
List<SignalServiceDataMessage.Quote.QuotedAttachment> attachments = new LinkedList<>();
@ -919,7 +918,7 @@ public final class SignalServiceContent {
}
}
private static List<SignalServiceDataMessage.Preview> createPreviews(SignalServiceProtos.DataMessage content) throws ProtocolInvalidMessageException {
private static List<SignalServiceDataMessage.Preview> createPreviews(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (content.getPreviewCount() <= 0) return null;
List<SignalServiceDataMessage.Preview> results = new LinkedList<>();
@ -941,7 +940,9 @@ public final class SignalServiceContent {
return results;
}
private static List<SignalServiceDataMessage.Mention> createMentions(List<SignalServiceProtos.DataMessage.BodyRange> bodyRanges, String body, boolean isGroupV2) throws ProtocolInvalidMessageException {
private static List<SignalServiceDataMessage.Mention> createMentions(List<SignalServiceProtos.DataMessage.BodyRange> bodyRanges, String body, boolean isGroupV2)
throws InvalidMessageStructureException
{
if (bodyRanges == null || bodyRanges.isEmpty() || body == null) {
return null;
}
@ -953,19 +954,19 @@ public final class SignalServiceContent {
try {
mentions.add(new SignalServiceDataMessage.Mention(UuidUtil.parseOrThrow(bodyRange.getMentionUuid()), bodyRange.getStart(), bodyRange.getLength()));
} catch (IllegalArgumentException e) {
throw new ProtocolInvalidMessageException(new InvalidMessageException(e), null, 0);
throw new InvalidMessageStructureException("Invalid body range!");
}
}
}
if (mentions.size() > 0 && !isGroupV2) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Mentions received in non-GV2 message"), null, 0);
throw new InvalidMessageStructureException("Mentions received in non-GV2 message");
}
return mentions;
}
private static SignalServiceDataMessage.Sticker createSticker(SignalServiceProtos.DataMessage content) throws ProtocolInvalidMessageException {
private static SignalServiceDataMessage.Sticker createSticker(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (!content.hasSticker() ||
!content.getSticker().hasPackId() ||
!content.getSticker().hasPackKey() ||
@ -1027,7 +1028,7 @@ public final class SignalServiceContent {
return new SignalServiceDataMessage.GroupCallUpdate(groupCallUpdate.getEraId());
}
private static SignalServiceDataMessage.Payment createPayment(SignalServiceProtos.DataMessage content) throws InvalidMessageException {
private static SignalServiceDataMessage.Payment createPayment(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (!content.hasPayment()) {
return null;
}
@ -1036,17 +1037,17 @@ public final class SignalServiceContent {
switch (payment.getItemCase()) {
case NOTIFICATION: return new SignalServiceDataMessage.Payment(createPaymentNotification(payment));
default : throw new InvalidMessageException("Unknown payment item");
default : throw new InvalidMessageStructureException("Unknown payment item");
}
}
private static SignalServiceDataMessage.PaymentNotification createPaymentNotification(SignalServiceProtos.DataMessage.Payment content)
throws InvalidMessageException
throws InvalidMessageStructureException
{
if (!content.hasNotification() ||
content.getNotification().getTransactionCase() != SignalServiceProtos.DataMessage.Payment.Notification.TransactionCase.MOBILECOIN)
{
throw new InvalidMessageException();
throw new InvalidMessageStructureException("Badly-formatted payment notification!");
}
SignalServiceProtos.DataMessage.Payment.Notification payment = content.getNotification();
@ -1054,7 +1055,7 @@ public final class SignalServiceContent {
return new SignalServiceDataMessage.PaymentNotification(payment.getMobileCoin().getReceipt().toByteArray(), payment.getNote());
}
private static List<SharedContact> createSharedContacts(SignalServiceProtos.DataMessage content) throws ProtocolInvalidMessageException {
private static List<SharedContact> createSharedContacts(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (content.getContactCount() <= 0) return null;
List<SharedContact> results = new LinkedList<>();
@ -1149,7 +1150,7 @@ public final class SignalServiceContent {
return results;
}
private static SignalServiceAttachmentPointer createAttachmentPointer(SignalServiceProtos.AttachmentPointer pointer) throws ProtocolInvalidMessageException {
private static SignalServiceAttachmentPointer createAttachmentPointer(SignalServiceProtos.AttachmentPointer pointer) throws InvalidMessageStructureException {
return new SignalServiceAttachmentPointer(pointer.getCdnNumber(),
SignalServiceAttachmentRemoteId.from(pointer),
pointer.getContentType(),
@ -1168,7 +1169,7 @@ public final class SignalServiceContent {
}
private static SignalServiceGroup createGroupV1Info(SignalServiceProtos.DataMessage content) throws ProtocolInvalidMessageException {
private static SignalServiceGroup createGroupV1Info(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (!content.hasGroup()) return null;
SignalServiceGroup.Type type;
@ -1197,7 +1198,7 @@ public final class SignalServiceContent {
if (SignalServiceAddress.isValidAddress(null, member.getE164())) {
members.add(new SignalServiceAddress(null, member.getE164()));
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("GroupContext.Member had no address!"), null, 0);
throw new InvalidMessageStructureException("GroupContext.Member had no address!");
}
}
} else if (content.getGroup().getMembersE164Count() > 0) {
@ -1233,15 +1234,15 @@ public final class SignalServiceContent {
return new SignalServiceGroup(content.getGroup().getId().toByteArray());
}
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.DataMessage content) throws ProtocolInvalidMessageException {
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
if (!content.hasGroupV2()) return null;
SignalServiceProtos.GroupContextV2 groupV2 = content.getGroupV2();
if (!groupV2.hasMasterKey()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("No GV2 master key on message"), null, 0);
throw new InvalidMessageStructureException("No GV2 master key on message");
}
if (!groupV2.hasRevision()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("No GV2 revision on message"), null, 0);
throw new InvalidMessageStructureException("No GV2 revision on message");
}
SignalServiceGroupV2.Builder builder;
@ -1249,7 +1250,7 @@ public final class SignalServiceContent {
builder = SignalServiceGroupV2.newBuilder(new GroupMasterKey(groupV2.getMasterKey().toByteArray()))
.withRevision(groupV2.getRevision());
} catch (InvalidInputException e) {
throw new ProtocolInvalidMessageException(new InvalidMessageException(e), null, 0);
throw new InvalidMessageStructureException("Invalid GV2 input!");
}
if (groupV2.hasGroupChange() && !groupV2.getGroupChange().isEmpty()) {