Mostly done device-bringup stuff

This commit is contained in:
Matt Corallo 2015-01-23 11:19:29 -10:00 committed by lilia
parent c0a8c00884
commit 02d0c58e5e
8 changed files with 64 additions and 73 deletions

View file

@ -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;
});

View file

@ -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);
});
});
});

View file

@ -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";

View file

@ -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
});
});
});

View file

@ -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,

View file

@ -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;
});

View file

@ -73,7 +73,7 @@
<div class='row'>
<div class='col-xs-offset-1 col-md-6'>
<div id="verify" class="collapse narrow">
<div id="verify1">Receiving identity key...<span class="done"></span></div>
<div id="verify1">Receiving identity key...<span class="verify1done"></span></div>
<div id="verify2">Verifying number and setup code...<span class="done" id="verify2done"></span></div>
<div id="verify3">Generating keys...<span class="done" id="verify3done"></span></div>
<div id="verify4">Registering...<span class="done" id="verify4done"></span></div>

View file

@ -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 {