From 02d0c58e5ed1639d1c4fd22e545420b6e6c152e7 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 23 Jan 2015 11:19:29 -1000 Subject: [PATCH] Mostly done device-bringup stuff --- js/libtextsecure.js | 48 +++++++++++++++++-------------------- js/options.js | 21 ++++++++-------- libtextsecure/api.js | 2 +- libtextsecure/helpers.js | 17 +++++-------- libtextsecure/protobufs.js | 4 ++-- libtextsecure/protocol.js | 26 ++++++++++---------- options.html | 2 +- protos/DeviceMessages.proto | 17 +++++++------ 8 files changed, 64 insertions(+), 73 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 51f9acc7616..29ad09e6d3f 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -5694,8 +5694,8 @@ CryptoJS.lib.Cipher || (function (undefined) { WhisperMessage : protocolMessages.WhisperMessage, PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage, ProvisioningUuid : deviceMessages.ProvisioningUuid, - DeviceInit : deviceMessages.DeviceInit, - IdentityKey : deviceMessages.IdentityKey, + ProvisionEnvelope : deviceMessages.ProvisionEnvelope, + ProvisionMessage : deviceMessages.ProvisionMessage, DeviceControl : deviceMessages.DeviceControl, WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage, WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage, @@ -6190,13 +6190,9 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step }); } -window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, stepDone) { - var deviceInit = textsecure.protobuf.DeviceInit.decode(encodedDeviceInit, 'binary'); - return cryptoInfo.decryptAndHandleDeviceInit(deviceInit).then(function(identityKey) { - if (identityKey.server != textsecure.api.relay) - throw new Error("Unknown relay used by master"); - var number = identityKey.phoneNumber; - +window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) { + var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary'); + return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) { stepDone(1); var signalingKey = textsecure.crypto.getRandomBytes(32 + 20); @@ -6210,10 +6206,10 @@ window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, registrationId = registrationId & 0x3fff; textsecure.storage.putUnencrypted("registrationId", registrationId); - return textsecure.api.confirmCode(number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) { - var numberId = number + "." + result; + return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) { + var numberId = identityKey.number + "." + result.deviceId; textsecure.storage.putUnencrypted("number_id", numberId); - textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegion(number)); + textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number)); stepDone(2); return textsecure.protocol.generateKeys().then(function(keys) { @@ -6758,7 +6754,7 @@ window.textsecure.api = function () { URL_CALLS.devices = "/v1/devices"; URL_CALLS.keys = "/v2/keys"; URL_CALLS.push = "/v1/websocket"; - URL_CALLS.temp_push = "/v1/provisioning"; + URL_CALLS.temp_push = "/v1/websocket/provisioning"; URL_CALLS.messages = "/v1/messages"; URL_CALLS.attachment = "/v1/attachments"; @@ -7950,26 +7946,26 @@ window.textsecure.protocol = function() { var keyPair; socketInfo.decryptAndHandleDeviceInit = function(deviceInit) { - var masterEphemeral = toArrayBuffer(deviceInit.masterEphemeralPubKey); - var message = toArrayBuffer(deviceInit.identityKeyMessage); + var masterEphemeral = toArrayBuffer(deviceInit.publicKey); + var message = toArrayBuffer(deviceInit.body); return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) { - return HKDF(ecRes, masterEphemeral, "WhisperDeviceInit").then(function(keys) { - if (new Uint8Array(message)[0] != (3 << 4) | 3) - throw new Error("Bad version number on IdentityKeyMessage"); + return HKDF(ecRes, '', "TextSecure Provisioning Message").then(function(keys) { + if (new Uint8Array(message)[0] != 1) + throw new Error("Bad version number on ProvisioningMessage"); var iv = message.slice(1, 16 + 1); - var mac = message.slice(message.length - 32, message.length); - var ivAndCiphertext = message.slice(0, message.length - 32); - var ciphertext = message.slice(16 + 1, message.length - 32); + var mac = message.slice(message.byteLength - 32, message.byteLength); + var ivAndCiphertext = message.slice(0, message.byteLength - 32); + var ciphertext = message.slice(16 + 1, message.byteLength - 32); - return verifyMAC(ivAndCiphertext, ecRes[1], mac).then(function() { - window.textsecure.crypto.decrypt(ecRes[0], ciphertext, iv).then(function(plaintext) { - var identityKeyMsg = textsecure.protobuf.IdentityKey.decode(plaintext); + return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() { + return window.textsecure.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) { + var identityKeyMsg = textsecure.protobuf.ProvisionMessage.decode(plaintext); - textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKey)).then(function(identityKeyPair) { + return textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKeyPrivate)).then(function(identityKeyPair) { crypto_storage.putKeyPair("identityKey", identityKeyPair); - identityKeyMsg.identityKey = null; + identityKeyMsg.identityKeyPrivate = null; return identityKeyMsg; }); diff --git a/js/options.js b/js/options.js index 8c22ce603e9..84c25eda9a9 100644 --- a/js/options.js +++ b/js/options.js @@ -142,14 +142,13 @@ new WebSocketResource(socket, function(request) { if (request.path == "/v1/address" && request.verb == "PUT") { var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body); - qrCode.makeCode('textsecure-device-init:/' + - '?channel_uuid=' + proto.uuid + - '&channel_server=' + textsecure.api.relay + - '&publicKey=' + btoa(getString(cryptoInfo.publicKey))); + qrCode.makeCode('tsdevice:/' + + '?uuid=' + proto.uuid + + '&pub_key=' + btoa(getString(cryptoInfo.pubKey))); $('img').removeAttr('style'); $('#multi-device .status').text("Use your phone to scan the QR code.") request.respond(200, 'OK'); - } else { + } else if (request.path == "/v1/message" && request.verb == "PUT") { $('#init-setup').hide(); $('#verify1done').text(''); $('#verify2done').text(''); @@ -158,8 +157,7 @@ $('#verify5done').text(''); $('#verify').show().addClass('in'); - - textsecure.registerSecondDevice(message.body, cryptoInfo, function(step) { + textsecure.registerSecondDevice(request.body, cryptoInfo, function(step) { switch(step) { case 1: $('#verify1done').text('done'); @@ -171,16 +169,19 @@ $('#verify3done').text('done'); break; case 4: - //TODO: User needs to verify number before we continue - $('#complete-number').text(parsedNumber); + //XXX: User needs to verify number before we continue $('#verify4done').text('done'); + //$('#complete-number').text(parsedNumber); + textsecure.registration.done(); case 5: + //TODO: Do sync to get 5! $('#verify').hide(); $('#setup-complete').show().addClass('in'); textsecure.registration.done(); } }); - } + } else + console.log(request.path); }); }); }); diff --git a/libtextsecure/api.js b/libtextsecure/api.js index e2b47d44474..38380057872 100644 --- a/libtextsecure/api.js +++ b/libtextsecure/api.js @@ -37,7 +37,7 @@ window.textsecure.api = function () { URL_CALLS.devices = "/v1/devices"; URL_CALLS.keys = "/v2/keys"; URL_CALLS.push = "/v1/websocket"; - URL_CALLS.temp_push = "/v1/provisioning"; + URL_CALLS.temp_push = "/v1/websocket/provisioning"; URL_CALLS.messages = "/v1/messages"; URL_CALLS.attachment = "/v1/attachments"; diff --git a/libtextsecure/helpers.js b/libtextsecure/helpers.js index 22ae57d193e..14413652675 100644 --- a/libtextsecure/helpers.js +++ b/libtextsecure/helpers.js @@ -268,13 +268,9 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step }); } -window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, stepDone) { - var deviceInit = textsecure.protobuf.DeviceInit.decode(encodedDeviceInit, 'binary'); - return cryptoInfo.decryptAndHandleDeviceInit(deviceInit).then(function(identityKey) { - if (identityKey.server != textsecure.api.relay) - throw new Error("Unknown relay used by master"); - var number = identityKey.phoneNumber; - +window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) { + var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary'); + return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) { stepDone(1); var signalingKey = textsecure.crypto.getRandomBytes(32 + 20); @@ -288,17 +284,16 @@ window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, registrationId = registrationId & 0x3fff; textsecure.storage.putUnencrypted("registrationId", registrationId); - return textsecure.api.confirmCode(number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) { - var numberId = number + "." + result; + return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) { + var numberId = identityKey.number + "." + result.deviceId; textsecure.storage.putUnencrypted("number_id", numberId); - textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegion(number)); + textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number)); stepDone(2); return textsecure.protocol.generateKeys().then(function(keys) { stepDone(3); return textsecure.api.registerKeys(keys).then(function() { stepDone(4); - //TODO: Send DeviceControl.NEW_DEVICE_REGISTERED to all other devices }); }); }); diff --git a/libtextsecure/protobufs.js b/libtextsecure/protobufs.js index 30869a52482..84c5adef2c0 100644 --- a/libtextsecure/protobufs.js +++ b/libtextsecure/protobufs.js @@ -16,8 +16,8 @@ WhisperMessage : protocolMessages.WhisperMessage, PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage, ProvisioningUuid : deviceMessages.ProvisioningUuid, - DeviceInit : deviceMessages.DeviceInit, - IdentityKey : deviceMessages.IdentityKey, + ProvisionEnvelope : deviceMessages.ProvisionEnvelope, + ProvisionMessage : deviceMessages.ProvisionMessage, DeviceControl : deviceMessages.DeviceControl, WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage, WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage, diff --git a/libtextsecure/protocol.js b/libtextsecure/protocol.js index 42ffe860401..3c15519d891 100644 --- a/libtextsecure/protocol.js +++ b/libtextsecure/protocol.js @@ -762,26 +762,26 @@ window.textsecure.protocol = function() { var keyPair; socketInfo.decryptAndHandleDeviceInit = function(deviceInit) { - var masterEphemeral = toArrayBuffer(deviceInit.masterEphemeralPubKey); - var message = toArrayBuffer(deviceInit.identityKeyMessage); + var masterEphemeral = toArrayBuffer(deviceInit.publicKey); + var message = toArrayBuffer(deviceInit.body); return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) { - return HKDF(ecRes, masterEphemeral, "WhisperDeviceInit").then(function(keys) { - if (new Uint8Array(message)[0] != (3 << 4) | 3) - throw new Error("Bad version number on IdentityKeyMessage"); + return HKDF(ecRes, '', "TextSecure Provisioning Message").then(function(keys) { + if (new Uint8Array(message)[0] != 1) + throw new Error("Bad version number on ProvisioningMessage"); var iv = message.slice(1, 16 + 1); - var mac = message.slice(message.length - 32, message.length); - var ivAndCiphertext = message.slice(0, message.length - 32); - var ciphertext = message.slice(16 + 1, message.length - 32); + var mac = message.slice(message.byteLength - 32, message.byteLength); + var ivAndCiphertext = message.slice(0, message.byteLength - 32); + var ciphertext = message.slice(16 + 1, message.byteLength - 32); - return verifyMAC(ivAndCiphertext, ecRes[1], mac).then(function() { - window.textsecure.crypto.decrypt(ecRes[0], ciphertext, iv).then(function(plaintext) { - var identityKeyMsg = textsecure.protobuf.IdentityKey.decode(plaintext); + return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() { + return window.textsecure.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) { + var identityKeyMsg = textsecure.protobuf.ProvisionMessage.decode(plaintext); - textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKey)).then(function(identityKeyPair) { + return textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKeyPrivate)).then(function(identityKeyPair) { crypto_storage.putKeyPair("identityKey", identityKeyPair); - identityKeyMsg.identityKey = null; + identityKeyMsg.identityKeyPrivate = null; return identityKeyMsg; }); diff --git a/options.html b/options.html index 3c8bd86415d..672ab650822 100644 --- a/options.html +++ b/options.html @@ -73,7 +73,7 @@
-
Receiving identity key...
+
Receiving identity key...
Verifying number and setup code...
Generating keys...
Registering...
diff --git a/protos/DeviceMessages.proto b/protos/DeviceMessages.proto index 355e7f910bc..ded4cf0f914 100644 --- a/protos/DeviceMessages.proto +++ b/protos/DeviceMessages.proto @@ -4,17 +4,16 @@ message ProvisioningUuid { optional string uuid = 1; } -message DeviceInit { - required bytes masterEphemeralPubKey = 1; - required bytes identityKeyMessage = 2; // contains an IdentityKey + +message ProvisionEnvelope { + optional bytes publicKey = 1; + optional bytes body = 2; // Encrypted ProvisionMessage } -message IdentityKey { - required bytes identityKey = 1; - required string phoneNumber = 2; - required string server = 3; - required bool masterSupportsSms = 4; - required uint32 provisioningCode = 5; +message ProvisionMessage { + optional bytes identityKeyPrivate = 2; + optional string number = 3; + optional string provisioningCode = 4; } message DeviceControl {