Verify identity keys on outgoing messages.

If PreKeyEntity identity key doesn't match local DB, fail
outgoing message and queue "incoming" identity key update
message for manual user approval.
fork-5.53.8
Moxie Marlinspike 2014-02-16 15:23:49 -08:00
rodzic e2989373cd
commit e7e5bc0884
16 zmienionych plików z 172 dodań i 24 usunięć

Wyświetl plik

@ -264,6 +264,7 @@
<string name="SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process"> <string name="SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process">
Received message with unknown identity key. Click to process and display. Received message with unknown identity key. Click to process and display.
</string> </string>
<string name="SmsMessageRecord_received_updated_but_unknown_identity_information">Received updated but unknown identity information. Tap to validate identity.</string>
<!-- VerifyIdentityActivity --> <!-- VerifyIdentityActivity -->

Wyświetl plik

@ -358,6 +358,7 @@ public class ConversationItem extends LinearLayout {
intent.putExtra("thread_id", messageRecord.getThreadId()); intent.putExtra("thread_id", messageRecord.getThreadId());
intent.putExtra("message_id", messageRecord.getId()); intent.putExtra("message_id", messageRecord.getId());
intent.putExtra("is_bundle", messageRecord.isBundleKeyExchange()); intent.putExtra("is_bundle", messageRecord.isBundleKeyExchange());
intent.putExtra("is_identity_update", messageRecord.isIdentityUpdate());
intent.putExtra("master_secret", masterSecret); intent.putExtra("master_secret", masterSecret);
intent.putExtra("sent", messageRecord.isOutgoing()); intent.putExtra("sent", messageRecord.isOutgoing());
context.startActivity(intent); context.startActivity(intent);

Wyświetl plik

@ -47,6 +47,7 @@ import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage; import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;
import org.whispersystems.textsecure.util.Base64;
import java.io.IOException; import java.io.IOException;
@ -71,6 +72,7 @@ public class ReceiveKeyActivity extends Activity {
private MasterSecret masterSecret; private MasterSecret masterSecret;
private PreKeyWhisperMessage keyExchangeMessageBundle; private PreKeyWhisperMessage keyExchangeMessageBundle;
private KeyExchangeMessage keyExchangeMessage; private KeyExchangeMessage keyExchangeMessage;
private IdentityKey identityUpdateMessage;
@Override @Override
protected void onCreate(Bundle state) { protected void onCreate(Bundle state) {
@ -99,8 +101,11 @@ public class ReceiveKeyActivity extends Activity {
} }
private void initializeText() { private void initializeText() {
if (isTrusted(keyExchangeMessage, keyExchangeMessageBundle)) initializeTrustedText(); if (isTrusted(keyExchangeMessage, keyExchangeMessageBundle, identityUpdateMessage)) {
else initializeUntrustedText(); initializeTrustedText();
} else {
initializeUntrustedText();
}
} }
private void initializeTrustedText() { private void initializeTrustedText() {
@ -113,12 +118,16 @@ public class ReceiveKeyActivity extends Activity {
spannableString.setSpan(new ClickableSpan() { spannableString.setSpan(new ClickableSpan() {
@Override @Override
public void onClick(View widget) { public void onClick(View widget) {
IdentityKey remoteIdentity;
if (identityUpdateMessage != null) remoteIdentity = identityUpdateMessage;
else if (keyExchangeMessageBundle != null) remoteIdentity = keyExchangeMessageBundle.getIdentityKey();
else remoteIdentity = keyExchangeMessage.getIdentityKey();
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class); Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
intent.putExtra("recipient", recipient); intent.putExtra("recipient", recipient);
intent.putExtra("master_secret", masterSecret); intent.putExtra("master_secret", masterSecret);
intent.putExtra("remote_identity", intent.putExtra("remote_identity", remoteIdentity);
keyExchangeMessage == null ?
keyExchangeMessageBundle.getIdentityKey() : keyExchangeMessage.getIdentityKey());
startActivity(intent); startActivity(intent);
} }
}, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1, }, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1,
@ -128,7 +137,7 @@ public class ReceiveKeyActivity extends Activity {
descriptionText.setMovementMethod(LinkMovementMethod.getInstance()); descriptionText.setMovementMethod(LinkMovementMethod.getInstance());
} }
private boolean isTrusted(KeyExchangeMessage message, PreKeyWhisperMessage messageBundle) { private boolean isTrusted(KeyExchangeMessage message, PreKeyWhisperMessage messageBundle, IdentityKey identityUpdateMessage) {
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId);
if (message != null) { if (message != null) {
@ -138,6 +147,9 @@ public class ReceiveKeyActivity extends Activity {
} else if (messageBundle != null) { } else if (messageBundle != null) {
KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice); KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice);
return processor.isTrusted(messageBundle); return processor.isTrusted(messageBundle);
} else if (identityUpdateMessage != null) {
KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice);
return processor.isTrusted(identityUpdateMessage);
} }
return false; return false;
@ -154,6 +166,8 @@ public class ReceiveKeyActivity extends Activity {
byte[] body = transportDetails.getDecodedMessage(messageBody.getBytes()); byte[] body = transportDetails.getDecodedMessage(messageBody.getBytes());
this.keyExchangeMessageBundle = new PreKeyWhisperMessage(body); this.keyExchangeMessageBundle = new PreKeyWhisperMessage(body);
} else if (getIntent().getBooleanExtra("is_identity_update", false)) {
this.identityUpdateMessage = new IdentityKey(Base64.decodeWithoutPadding(messageBody), 0);
} else { } else {
this.keyExchangeMessage = KeyExchangeMessage.createFor(messageBody); this.keyExchangeMessage = KeyExchangeMessage.createFor(messageBody);
} }
@ -232,6 +246,11 @@ public class ReceiveKeyActivity extends Activity {
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this) DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
.markAsCorruptKeyExchange(messageId); .markAsCorruptKeyExchange(messageId);
} }
} else if (identityUpdateMessage != null) {
DatabaseFactory.getIdentityDatabase(ReceiveKeyActivity.this)
.saveIdentity(masterSecret, recipient.getRecipientId(), identityUpdateMessage);
DatabaseFactory.getSmsDatabase(ReceiveKeyActivity.this).markAsProcessedKeyExchange(messageId);
} }

Wyświetl plik

@ -55,6 +55,10 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor {
return isTrusted(message.getIdentityKey()); return isTrusted(message.getIdentityKey());
} }
public boolean isTrusted(PreKeyEntity entity) {
return isTrusted(entity.getIdentityKey());
}
public boolean isTrusted(KeyExchangeMessage message) { public boolean isTrusted(KeyExchangeMessage message) {
return message.hasIdentityKey() && isTrusted(message.getIdentityKey()); return message.hasIdentityKey() && isTrusted(message.getIdentityKey());
} }

Wyświetl plik

@ -35,6 +35,7 @@ public interface MmsSmsColumns {
protected static final long KEY_EXCHANGE_CORRUPTED_BIT = 0x1000; protected static final long KEY_EXCHANGE_CORRUPTED_BIT = 0x1000;
protected static final long KEY_EXCHANGE_INVALID_VERSION_BIT = 0x800; protected static final long KEY_EXCHANGE_INVALID_VERSION_BIT = 0x800;
protected static final long KEY_EXCHANGE_BUNDLE_BIT = 0x400; protected static final long KEY_EXCHANGE_BUNDLE_BIT = 0x400;
protected static final long KEY_EXCHANGE_IDENTITY_UPDATE_BIT = 0x200;
// Secure Message Information // Secure Message Information
protected static final long SECURE_MESSAGE_BIT = 0x800000; protected static final long SECURE_MESSAGE_BIT = 0x800000;
@ -98,6 +99,10 @@ public interface MmsSmsColumns {
return (type & KEY_EXCHANGE_BUNDLE_BIT) != 0; return (type & KEY_EXCHANGE_BUNDLE_BIT) != 0;
} }
public static boolean isIdentityUpdate(long type) {
return (type & KEY_EXCHANGE_IDENTITY_UPDATE_BIT) != 0;
}
public static boolean isSymmetricEncryption(long type) { public static boolean isSymmetricEncryption(long type) {
return (type & ENCRYPTION_SYMMETRIC_BIT) != 0; return (type & ENCRYPTION_SYMMETRIC_BIT) != 0;
} }

Wyświetl plik

@ -252,6 +252,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
else if (((IncomingKeyExchangeMessage)message).isCorrupted()) type |= Types.KEY_EXCHANGE_CORRUPTED_BIT; else if (((IncomingKeyExchangeMessage)message).isCorrupted()) type |= Types.KEY_EXCHANGE_CORRUPTED_BIT;
else if (((IncomingKeyExchangeMessage)message).isInvalidVersion()) type |= Types.KEY_EXCHANGE_INVALID_VERSION_BIT; else if (((IncomingKeyExchangeMessage)message).isInvalidVersion()) type |= Types.KEY_EXCHANGE_INVALID_VERSION_BIT;
else if (((IncomingKeyExchangeMessage)message).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT; else if (((IncomingKeyExchangeMessage)message).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT;
else if (((IncomingKeyExchangeMessage)message).isIdentityUpdate()) type |= Types.KEY_EXCHANGE_IDENTITY_UPDATE_BIT;
} else if (message.isSecureMessage()) { } else if (message.isSecureMessage()) {
type |= Types.SECURE_MESSAGE_BIT; type |= Types.SECURE_MESSAGE_BIT;
type |= Types.ENCRYPTION_REMOTE_BIT; type |= Types.ENCRYPTION_REMOTE_BIT;

Wyświetl plik

@ -111,6 +111,10 @@ public abstract class MessageRecord extends DisplayRecord {
return SmsDatabase.Types.isBundleKeyExchange(type); return SmsDatabase.Types.isBundleKeyExchange(type);
} }
public boolean isIdentityUpdate() {
return SmsDatabase.Types.isIdentityUpdate(type);
}
public boolean isCorruptedKeyExchange() { public boolean isCorruptedKeyExchange() {
return SmsDatabase.Types.isCorruptedKeyExchange(type); return SmsDatabase.Types.isCorruptedKeyExchange(type);
} }

Wyświetl plik

@ -65,6 +65,8 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version)); return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version));
} else if (isBundleKeyExchange()) { } else if (isBundleKeyExchange()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process)); return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process));
} else if (isIdentityUpdate()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_updated_but_unknown_identity_information));
} else if (isKeyExchange() && isOutgoing()) { } else if (isKeyExchange() && isOutgoing()) {
return new SpannableString(""); return new SpannableString("");
} else if (isKeyExchange() && !isOutgoing()) { } else if (isKeyExchange() && !isOutgoing()) {

Wyświetl plik

@ -30,10 +30,14 @@ import org.thoughtcrime.securesms.mms.MmsSendResult;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler; import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.transport.UniversalTransport; import org.thoughtcrime.securesms.transport.UniversalTransport;
import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.util.Base64;
import ws.com.google.android.mms.MmsException; import ws.com.google.android.mms.MmsException;
import ws.com.google.android.mms.pdu.SendReq; import ws.com.google.android.mms.pdu.SendReq;
@ -87,6 +91,11 @@ public class MmsSender {
database.markAsSentFailed(message.getDatabaseMessageId()); database.markAsSentFailed(message.getDatabaseMessageId());
Recipients recipients = threads.getRecipientsForThreadId(threadId); Recipients recipients = threads.getRecipientsForThreadId(threadId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId); MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
} catch (UntrustedIdentityException uie) {
IncomingTextMessage base = new IncomingTextMessage(message);
IncomingIdentityUpdateMessage identityUpdateMessage = new IncomingIdentityUpdateMessage(base, Base64.encodeBytesWithoutPadding(uie.getIdentityKey().serialize()));
DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, identityUpdateMessage);
database.markAsSentFailed(messageId);
} catch (RetryLaterException e) { } catch (RetryLaterException e) {
Log.w("MmsSender", e); Log.w("MmsSender", e);
database.markAsOutbox(message.getDatabaseMessageId()); database.markAsOutbox(message.getDatabaseMessageId());

Wyświetl plik

@ -30,9 +30,13 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler; import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.transport.UniversalTransport; import org.thoughtcrime.securesms.transport.UniversalTransport;
import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.util.Base64;
public class SmsSender { public class SmsSender {
@ -71,12 +75,21 @@ public class SmsSender {
else reader = database.getOutgoingMessages(masterSecret); else reader = database.getOutgoingMessages(masterSecret);
while (reader != null && (record = reader.getNext()) != null) { while (reader != null && (record = reader.getNext()) != null) {
database.markAsSending(record.getId()); try {
transport.deliver(record); database.markAsSending(record.getId());
transport.deliver(record);
} catch (UntrustedIdentityException e) {
Log.w("SmsSender", e);
IncomingTextMessage base = new IncomingTextMessage(record);
IncomingIdentityUpdateMessage identityUpdateMessage = new IncomingIdentityUpdateMessage(base, Base64.encodeBytesWithoutPadding(e.getIdentityKey().serialize()));
DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, identityUpdateMessage);
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
} catch (UndeliverableMessageException ude) {
Log.w("SmsSender", ude);
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
}
} }
} catch (UndeliverableMessageException ude) {
Log.w("SmsSender", ude);
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
} finally { } finally {
if (reader != null) if (reader != null)
reader.close(); reader.close();

Wyświetl plik

@ -0,0 +1,18 @@
package org.thoughtcrime.securesms.sms;
public class IncomingIdentityUpdateMessage extends IncomingKeyExchangeMessage {
public IncomingIdentityUpdateMessage(IncomingTextMessage base, String newBody) {
super(base, newBody);
}
@Override
public IncomingIdentityUpdateMessage withMessageBody(String messageBody) {
return new IncomingIdentityUpdateMessage(this, messageBody);
}
@Override
public boolean isIdentityUpdate() {
return true;
}
}

Wyświetl plik

@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.sms; package org.thoughtcrime.securesms.sms;
import org.whispersystems.textsecure.push.IncomingPushMessage;
public class IncomingPreKeyBundleMessage extends IncomingKeyExchangeMessage { public class IncomingPreKeyBundleMessage extends IncomingKeyExchangeMessage {
public IncomingPreKeyBundleMessage(IncomingTextMessage base, String newBody) { public IncomingPreKeyBundleMessage(IncomingTextMessage base, String newBody) {

Wyświetl plik

@ -4,12 +4,15 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.telephony.SmsMessage; import android.telephony.SmsMessage;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.push.IncomingPushMessage;
import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.RecipientDevice;
import java.util.List; import java.util.List;
import ws.com.google.android.mms.pdu.SendReq;
import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext;
public class IncomingTextMessage implements Parcelable { public class IncomingTextMessage implements Parcelable {
@ -121,6 +124,34 @@ public class IncomingTextMessage implements Parcelable {
this.groupActionArgument = fragments.get(0).getGroupActionArgument(); this.groupActionArgument = fragments.get(0).getGroupActionArgument();
} }
public IncomingTextMessage(SendReq record) {
this.message = "";
this.sender = record.getTo()[0].getString();
this.senderDeviceId = RecipientDevice.DEFAULT_DEVICE_ID;
this.protocol = 31338;
this.serviceCenterAddress = "Outgoing";
this.replyPathPresent = true;
this.pseudoSubject = "";
this.sentTimestampMillis = System.currentTimeMillis();
this.groupId = null;
this.groupAction = -1;
this.groupActionArgument = null;
}
public IncomingTextMessage(SmsMessageRecord record) {
this.message = record.getBody().getBody();
this.sender = record.getIndividualRecipient().getNumber();
this.senderDeviceId = RecipientDevice.DEFAULT_DEVICE_ID;
this.protocol = 31338;
this.serviceCenterAddress = "Outgoing";
this.replyPathPresent = true;
this.pseudoSubject = "";
this.sentTimestampMillis = System.currentTimeMillis();
this.groupId = null;
this.groupAction = -1;
this.groupActionArgument = null;
}
public long getSentTimestampMillis() { public long getSentTimestampMillis() {
return sentTimestampMillis; return sentTimestampMillis;
} }
@ -169,6 +200,10 @@ public class IncomingTextMessage implements Parcelable {
return false; return false;
} }
public boolean isIdentityUpdate() {
return false;
}
public String getGroupId() { public String getGroupId() {
return groupId; return groupId;
} }

Wyświetl plik

@ -73,7 +73,9 @@ public class PushTransport extends BaseTransport {
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
} }
public void deliver(SmsMessageRecord message) throws IOException { public void deliver(SmsMessageRecord message)
throws IOException, UntrustedIdentityException
{
try { try {
Recipient recipient = message.getIndividualRecipient(); Recipient recipient = message.getIndividualRecipient();
long threadId = message.getThreadId(); long threadId = message.getThreadId();
@ -97,7 +99,9 @@ public class PushTransport extends BaseTransport {
} }
} }
public void deliver(SendReq message, long threadId) throws IOException { public void deliver(SendReq message, long threadId)
throws IOException, UntrustedIdentityException
{
PushServiceSocket socket = PushServiceSocketFactory.create(context); PushServiceSocket socket = PushServiceSocketFactory.create(context);
byte[] plaintext = getPlaintextMessage(socket, message); byte[] plaintext = getPlaintextMessage(socket, message);
String destination = message.getTo()[0].getString(); String destination = message.getTo()[0].getString();
@ -147,6 +151,9 @@ public class PushTransport extends BaseTransport {
} catch (IOException e) { } catch (IOException e) {
Log.w("PushTransport", e); Log.w("PushTransport", e);
failures.add(recipient); failures.add(recipient);
} catch (UntrustedIdentityException e) {
Log.w("PushTransport", e);
failures.add(recipient);
} }
} }
@ -165,7 +172,7 @@ public class PushTransport extends BaseTransport {
} }
private void deliver(PushServiceSocket socket, Recipient recipient, long threadId, byte[] plaintext) private void deliver(PushServiceSocket socket, Recipient recipient, long threadId, byte[] plaintext)
throws IOException, InvalidNumberException throws IOException, InvalidNumberException, UntrustedIdentityException
{ {
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
try { try {
@ -274,7 +281,7 @@ public class PushTransport extends BaseTransport {
private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket, long threadId, private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket, long threadId,
Recipient recipient, byte[] plaintext) Recipient recipient, byte[] plaintext)
throws IOException, InvalidNumberException throws IOException, InvalidNumberException, UntrustedIdentityException
{ {
String e164number = Util.canonicalizeNumber(context, recipient.getNumber()); String e164number = Util.canonicalizeNumber(context, recipient.getNumber());
long recipientId = recipient.getRecipientId(); long recipientId = recipient.getRecipientId();
@ -296,7 +303,7 @@ public class PushTransport extends BaseTransport {
private PushBody getEncryptedMessage(PushServiceSocket socket, long threadId, private PushBody getEncryptedMessage(PushServiceSocket socket, long threadId,
PushAddress pushAddress, byte[] plaintext) PushAddress pushAddress, byte[] plaintext)
throws IOException throws IOException, UntrustedIdentityException
{ {
if (!SessionRecordV2.hasSession(context, masterSecret, pushAddress)) { if (!SessionRecordV2.hasSession(context, masterSecret, pushAddress)) {
try { try {
@ -306,7 +313,11 @@ public class PushTransport extends BaseTransport {
PushAddress device = PushAddress.create(context, pushAddress.getRecipientId(), pushAddress.getNumber(), preKey.getDeviceId()); PushAddress device = PushAddress.create(context, pushAddress.getRecipientId(), pushAddress.getNumber(), preKey.getDeviceId());
KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, device); KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, device);
processor.processKeyExchangeMessage(preKey, threadId); if (processor.isTrusted(preKey)) {
processor.processKeyExchangeMessage(preKey, threadId);
} else {
throw new UntrustedIdentityException("Untrusted identity key!", preKey.getIdentityKey());
}
} }
} catch (InvalidKeyException e) { } catch (InvalidKeyException e) {
throw new IOException(e); throw new IOException(e);

Wyświetl plik

@ -18,7 +18,6 @@ package org.thoughtcrime.securesms.transport;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.mms.MmsSendResult; import org.thoughtcrime.securesms.mms.MmsSendResult;
@ -54,7 +53,9 @@ public class UniversalTransport {
this.mmsTransport = new MmsTransport(context, masterSecret); this.mmsTransport = new MmsTransport(context, masterSecret);
} }
public void deliver(SmsMessageRecord message) throws UndeliverableMessageException { public void deliver(SmsMessageRecord message)
throws UndeliverableMessageException, UntrustedIdentityException
{
if (!TextSecurePreferences.isPushRegistered(context)) { if (!TextSecurePreferences.isPushRegistered(context)) {
smsTransport.deliver(message); smsTransport.deliver(message);
return; return;
@ -83,7 +84,7 @@ public class UniversalTransport {
} }
public MmsSendResult deliver(SendReq mediaMessage, long threadId) public MmsSendResult deliver(SendReq mediaMessage, long threadId)
throws UndeliverableMessageException, RetryLaterException throws UndeliverableMessageException, RetryLaterException, UntrustedIdentityException
{ {
if (Util.isEmpty(mediaMessage.getTo())) { if (Util.isEmpty(mediaMessage.getTo())) {
throw new UndeliverableMessageException("No destination specified"); throw new UndeliverableMessageException("No destination specified");
@ -97,14 +98,23 @@ public class UniversalTransport {
return mmsTransport.deliver(mediaMessage); return mmsTransport.deliver(mediaMessage);
} }
if (isPushTransport(mediaMessage.getTo()[0].getString())) { String destination;
try {
destination = Util.canonicalizeNumber(context, mediaMessage.getTo()[0].getString());
} catch (InvalidNumberException ine) {
Log.w("UniversalTransport", ine);
return mmsTransport.deliver(mediaMessage);
}
if (isPushTransport(destination)) {
try { try {
Log.w("UniversalTransport", "Delivering media message with GCM..."); Log.w("UniversalTransport", "Delivering media message with GCM...");
pushTransport.deliver(mediaMessage, threadId); pushTransport.deliver(mediaMessage, threadId);
return new MmsSendResult("push".getBytes("UTF-8"), 0, true); return new MmsSendResult("push".getBytes("UTF-8"), 0, true);
} catch (IOException ioe) { } catch (IOException ioe) {
Log.w("UniversalTransport", ioe); Log.w("UniversalTransport", ioe);
if (!GroupUtil.isEncodedGroup(mediaMessage.getTo()[0].getString())) { if (!GroupUtil.isEncodedGroup(destination)) {
return mmsTransport.deliver(mediaMessage); return mmsTransport.deliver(mediaMessage);
} else { } else {
throw new RetryLaterException(); throw new RetryLaterException();

Wyświetl plik

@ -0,0 +1,17 @@
package org.thoughtcrime.securesms.transport;
import org.whispersystems.textsecure.crypto.IdentityKey;
public class UntrustedIdentityException extends Exception {
private final IdentityKey identityKey;
public UntrustedIdentityException(String s, IdentityKey identityKey) {
super(s);
this.identityKey = identityKey;
}
public IdentityKey getIdentityKey() {
return identityKey;
}
}