From bd15f426f98b4ba5c20bec88be5a40ac6c68ed26 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 22 Nov 2018 15:15:28 +1100 Subject: [PATCH 1/4] Attack a type to preKeyBundleMessage. --- libtextsecure/outgoing_message.js | 9 ++++++++- protos/SignalService.proto | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 39fbfab87..8fa8aab9e 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -43,9 +43,10 @@ function OutgoingMessage( this.failoverNumbers = []; this.unidentifiedDeliveries = []; - const { numberInfo, senderCertificate } = options; + const { numberInfo, senderCertificate, preKeyBundleType } = options; this.numberInfo = numberInfo; this.senderCertificate = senderCertificate; + this.preKeyBundleType = preKeyBundleType || textsecure.protobuf.PreKeyBundleMessage.Type.UNKOWN; } OutgoingMessage.prototype = { @@ -290,6 +291,12 @@ OutgoingMessage.prototype = { if (this.attachPrekeys) { // Encrypt them with the fallback const preKeyBundleMessage = await libloki.getPreKeyBundleForNumber(number); + preKeyBundleMessage.type = this.preKeyBundleType; + + // If we have to use fallback encryption then this must be a friend request + if (this.fallBackEncryption) + preKeyBundleMessage.type = textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST; + const textBundle = this.convertMessageToText(preKeyBundleMessage); const encryptedBundle = await fallBackEncryption.encrypt(textBundle); preKeys = { preKeyBundleMessage: encryptedBundle.body }; diff --git a/protos/SignalService.proto b/protos/SignalService.proto index e0de8f732..4a9faa797 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -37,6 +37,13 @@ message Content { } message PreKeyBundleMessage { + enum Type { + UNKNOWN = 0; + FRIEND_REQUEST = 1; + FRIEND_REQUEST_ACCEPT = 2; + RESET_SESSION = 3; + RESET_SESSION_ACK = 4; + } optional bytes identityKey = 1; optional uint32 deviceId = 2; optional uint32 preKeyId = 3; @@ -44,6 +51,7 @@ message PreKeyBundleMessage { optional bytes preKey = 5; optional bytes signedKey = 6; optional bytes signature = 7; + optional Type type = 8; } message CallMessage { From 4bb93e6e3ceddc760582b477851e513ae5916964 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 22 Nov 2018 15:18:10 +1100 Subject: [PATCH 2/4] rename sendEmptyMessageWithPreKeys to sendFriendRequestAccepted. --- libloki/libloki-protocol.js | 10 +++++++--- libtextsecure/message_receiver.js | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libloki/libloki-protocol.js b/libloki/libloki-protocol.js index 3ae45e1ed..204a36c9c 100644 --- a/libloki/libloki-protocol.js +++ b/libloki/libloki-protocol.js @@ -143,7 +143,7 @@ await Promise.all([signedKeyPromise, preKeyPromise]); } - async function sendEmptyMessageWithPreKeys(pubKey) { + async function sendFriendRequestAccepted(pubKey) { // empty content message const content = new textsecure.protobuf.Content(); @@ -155,6 +155,9 @@ log.info('empty message sent successfully'); } }; + const options = { + preKeyBundleType: textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST_ACCEPT, + }; // send an empty message. The logic in ougoing_message will attach the prekeys. const outgoingMessage = new textsecure.OutgoingMessage( null, // server @@ -162,7 +165,8 @@ [pubKey], // numbers content, // message true, // silent - callback // callback + callback, // callback + options ); await outgoingMessage.sendToNumber(pubKey); } @@ -171,5 +175,5 @@ window.libloki.getPreKeyBundleForNumber = getPreKeyBundleForNumber; window.libloki.FallBackDecryptionError = FallBackDecryptionError; window.libloki.savePreKeyBundleForNumber = savePreKeyBundleForNumber; - window.libloki.sendEmptyMessageWithPreKeys = sendEmptyMessageWithPreKeys; + window.libloki.sendFriendRequestAccepted = sendFriendRequestAccepted; })(); diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index cb305fbda..dab71c94d 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1026,7 +1026,7 @@ MessageReceiver.prototype.extend({ } // Send a reply back - libloki.sendEmptyMessageWithPreKeys(pubKey); + libloki.sendFriendRequestAccepted(pubKey); } window.log.info(`Friend request for ${pubKey} was ${message.friendStatus}`, message); }, From 05f8a1c43a1970a4de39b7136873f17c78e9957b Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 22 Nov 2018 15:27:34 +1100 Subject: [PATCH 3/4] Handle pkb friend request accept. --- libtextsecure/message_receiver.js | 34 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index dab71c94d..21a5d1102 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -725,10 +725,19 @@ MessageReceiver.prototype.extend({ // We don't automatically save on a friend request because // we only want to save the preKeys when we click the accept button. if (envelope.type !== textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { - await this.handlePreKeyBundleMessage( - envelope.source, - envelope.preKeyBundleMessage - ); + try { + const conversation = window.ConversationController.get(envelope.source); + + // Make sure we only save the preKeys if we're friends + if (conversation.isFriend()) { + await this.handlePreKeyBundleMessage( + envelope.source, + envelope.preKeyBundleMessage + ); + } + } catch (e) { + window.log.info('Error saving preKeyBundleMessage from: ', envelope.source); + } } } @@ -1040,6 +1049,15 @@ MessageReceiver.prototype.extend({ window.log.info('Error getting conversation: ', envelope.source); } + // Check if the other user accepted our friend request + if ( + envelope.preKeyBundleMessage && + envelope.preKeyBundleMessage.type === textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST_ACCEPT && + conversation + ) { + await conversation.onFriendRequestAccepted(); + } + if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { return this.handleFriendRequestMessage(envelope, content.dataMessage); } else if ( @@ -1048,12 +1066,10 @@ MessageReceiver.prototype.extend({ // ref: libsignal-protocol.js:36120 envelope.type === textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE ) { - // We know for sure that keys are exchanged - if (conversation) { + // If we get a cipher and we're already friends + // then we set our key exchange to complete + if (conversation && conversation.isFriend()) { await conversation.setKeyExchangeCompleted(true); - - // TODO: We should probably set this based on the PKB type - await conversation.onFriendRequestAccepted(); } } From 149da3374adb744c42d3fffd886d3e237713b71e Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 23 Nov 2018 10:59:10 +1100 Subject: [PATCH 4/4] Fix pkb not being saved on the first cipher message. --- libtextsecure/message_receiver.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 87a650df5..28b3ad11c 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -725,19 +725,10 @@ MessageReceiver.prototype.extend({ // We don't automatically save on a friend request because // we only want to save the preKeys when we click the accept button. if (envelope.type !== textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { - try { - const conversation = window.ConversationController.get(envelope.source); - - // Make sure we only save the preKeys if we're friends - if (conversation.isFriend()) { - await this.handlePreKeyBundleMessage( - envelope.source, - envelope.preKeyBundleMessage - ); - } - } catch (e) { - window.log.info('Error saving preKeyBundleMessage from: ', envelope.source); - } + await this.handlePreKeyBundleMessage( + envelope.source, + envelope.preKeyBundleMessage + ); } }