2015-11-30 16:38:55 +01:00
|
|
|
use mio::*;
|
|
|
|
use mio::tcp::*;
|
|
|
|
use hash::*;
|
2015-12-02 12:07:46 +01:00
|
|
|
use bytes::Bytes;
|
2015-11-30 16:38:55 +01:00
|
|
|
use crypto::*;
|
|
|
|
use crypto;
|
2015-12-17 11:42:30 +01:00
|
|
|
use network::connection::{Connection};
|
2015-11-30 16:38:55 +01:00
|
|
|
use network::host::{NodeId, Host, HostInfo};
|
|
|
|
use network::Error;
|
|
|
|
|
2015-12-17 11:42:30 +01:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
2015-11-30 16:38:55 +01:00
|
|
|
enum HandshakeState {
|
|
|
|
New,
|
|
|
|
ReadingAuth,
|
|
|
|
ReadingAck,
|
|
|
|
StartSession,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Handshake {
|
|
|
|
pub id: NodeId,
|
|
|
|
pub connection: Connection,
|
|
|
|
state: HandshakeState,
|
2015-12-02 12:07:46 +01:00
|
|
|
pub originated: bool,
|
2015-11-30 16:38:55 +01:00
|
|
|
idle_timeout: Option<Timeout>,
|
2015-12-02 12:07:46 +01:00
|
|
|
pub ecdhe: KeyPair,
|
|
|
|
pub nonce: H256,
|
|
|
|
pub remote_public: Public,
|
|
|
|
pub remote_nonce: H256,
|
|
|
|
pub auth_cipher: Bytes,
|
|
|
|
pub ack_cipher: Bytes
|
2015-11-30 16:38:55 +01:00
|
|
|
}
|
|
|
|
|
2015-12-02 12:07:46 +01:00
|
|
|
const AUTH_PACKET_SIZE:usize = 307;
|
|
|
|
const ACK_PACKET_SIZE:usize = 210;
|
|
|
|
|
2015-11-30 16:38:55 +01:00
|
|
|
impl Handshake {
|
|
|
|
pub fn new(token: Token, id: &NodeId, socket: TcpStream, nonce: &H256) -> Result<Handshake, Error> {
|
|
|
|
Ok(Handshake {
|
|
|
|
id: id.clone(),
|
|
|
|
connection: Connection::new(token, socket),
|
2015-12-02 12:07:46 +01:00
|
|
|
originated: false,
|
2015-11-30 16:38:55 +01:00
|
|
|
state: HandshakeState::New,
|
|
|
|
idle_timeout: None,
|
|
|
|
ecdhe: try!(KeyPair::create()),
|
|
|
|
nonce: nonce.clone(),
|
|
|
|
remote_public: Public::new(),
|
2015-12-02 12:07:46 +01:00
|
|
|
remote_nonce: H256::new(),
|
|
|
|
auth_cipher: Bytes::new(),
|
|
|
|
ack_cipher: Bytes::new(),
|
2015-11-30 16:38:55 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-12-02 12:07:46 +01:00
|
|
|
pub fn start(&mut self, host: &HostInfo, originated: bool) -> Result<(), Error> {
|
|
|
|
self.originated = originated;
|
2015-11-30 16:38:55 +01:00
|
|
|
if originated {
|
2015-12-02 12:07:46 +01:00
|
|
|
try!(self.write_auth(host));
|
2015-12-03 15:11:40 +01:00
|
|
|
}
|
2015-11-30 16:38:55 +01:00
|
|
|
else {
|
2015-12-02 12:07:46 +01:00
|
|
|
self.state = HandshakeState::ReadingAuth;
|
|
|
|
self.connection.expect(AUTH_PACKET_SIZE);
|
2015-11-30 16:38:55 +01:00
|
|
|
};
|
2015-12-02 12:07:46 +01:00
|
|
|
Ok(())
|
2015-11-30 16:38:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn done(&self) -> bool {
|
|
|
|
self.state == HandshakeState::StartSession
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn readable(&mut self, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<(), Error> {
|
|
|
|
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
|
2015-12-02 12:07:46 +01:00
|
|
|
match self.state {
|
|
|
|
HandshakeState::ReadingAuth => {
|
|
|
|
match try!(self.connection.readable()) {
|
2015-12-03 15:11:40 +01:00
|
|
|
Some(data) => {
|
|
|
|
try!(self.read_auth(host, &data));
|
|
|
|
try!(self.write_ack());
|
2015-12-02 12:07:46 +01:00
|
|
|
},
|
|
|
|
None => {}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
HandshakeState::ReadingAck => {
|
|
|
|
match try!(self.connection.readable()) {
|
2015-12-03 15:11:40 +01:00
|
|
|
Some(data) => {
|
|
|
|
try!(self.read_ack(host, &data));
|
2015-12-02 12:07:46 +01:00
|
|
|
self.state = HandshakeState::StartSession;
|
|
|
|
},
|
|
|
|
None => {}
|
|
|
|
};
|
|
|
|
},
|
2015-12-17 11:42:30 +01:00
|
|
|
_ => { panic!("Unexpected state"); }
|
2015-12-02 12:07:46 +01:00
|
|
|
}
|
2015-12-03 15:11:40 +01:00
|
|
|
if self.state != HandshakeState::StartSession {
|
|
|
|
try!(self.connection.reregister(event_loop));
|
|
|
|
}
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-12-02 12:07:46 +01:00
|
|
|
pub fn writable(&mut self, event_loop: &mut EventLoop<Host>, _host: &HostInfo) -> Result<(), Error> {
|
2015-11-30 16:38:55 +01:00
|
|
|
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
|
2015-12-17 11:42:30 +01:00
|
|
|
try!(self.connection.writable());
|
2015-12-03 15:11:40 +01:00
|
|
|
if self.state != HandshakeState::StartSession {
|
|
|
|
try!(self.connection.reregister(event_loop));
|
|
|
|
}
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), Error> {
|
|
|
|
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
|
|
|
|
self.idle_timeout = event_loop.timeout_ms(self.connection.token, 1800).ok();
|
2015-12-02 12:07:46 +01:00
|
|
|
try!(self.connection.register(event_loop));
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-12-02 12:07:46 +01:00
|
|
|
fn read_auth(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), Error> {
|
|
|
|
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
|
|
|
|
assert!(data.len() == AUTH_PACKET_SIZE);
|
|
|
|
self.auth_cipher = data.to_vec();
|
|
|
|
let auth = try!(ecies::decrypt(host.secret(), data));
|
|
|
|
let (sig, rest) = auth.split_at(65);
|
|
|
|
let (hepubk, rest) = rest.split_at(32);
|
|
|
|
let (pubk, rest) = rest.split_at(64);
|
|
|
|
let (nonce, _) = rest.split_at(32);
|
|
|
|
self.remote_public.clone_from_slice(pubk);
|
|
|
|
self.remote_nonce.clone_from_slice(nonce);
|
|
|
|
let shared = try!(ecdh::agree(host.secret(), &self.remote_public));
|
2016-01-08 13:32:52 +01:00
|
|
|
let signature = Signature::from_slice(sig);
|
2015-12-02 12:07:46 +01:00
|
|
|
let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce)));
|
|
|
|
if &spub.sha3()[..] != hepubk {
|
|
|
|
trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr());
|
|
|
|
return Err(Error::Auth);
|
|
|
|
};
|
|
|
|
self.write_ack()
|
2015-11-30 16:38:55 +01:00
|
|
|
}
|
|
|
|
|
2015-12-02 12:07:46 +01:00
|
|
|
fn read_ack(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), Error> {
|
|
|
|
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
|
|
|
|
assert!(data.len() == ACK_PACKET_SIZE);
|
|
|
|
self.ack_cipher = data.to_vec();
|
|
|
|
let ack = try!(ecies::decrypt(host.secret(), data));
|
2015-12-03 15:11:40 +01:00
|
|
|
self.remote_public.clone_from_slice(&ack[0..64]);
|
|
|
|
self.remote_nonce.clone_from_slice(&ack[64..(64+32)]);
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_auth(&mut self, host: &HostInfo) -> Result<(), Error> {
|
2015-12-02 12:07:46 +01:00
|
|
|
trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr());
|
2015-11-30 16:38:55 +01:00
|
|
|
let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants
|
|
|
|
let len = data.len();
|
|
|
|
{
|
|
|
|
data[len - 1] = 0x0;
|
|
|
|
let (sig, rest) = data.split_at_mut(65);
|
|
|
|
let (hepubk, rest) = rest.split_at_mut(32);
|
2015-12-02 12:07:46 +01:00
|
|
|
let (pubk, rest) = rest.split_at_mut(64);
|
|
|
|
let (nonce, _) = rest.split_at_mut(32);
|
2015-12-03 15:11:40 +01:00
|
|
|
|
2015-11-30 16:38:55 +01:00
|
|
|
// E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
|
|
|
|
let shared = try!(crypto::ecdh::agree(host.secret(), &self.id));
|
2015-12-02 12:07:46 +01:00
|
|
|
try!(crypto::ec::sign(self.ecdhe.secret(), &(&shared ^ &self.nonce))).copy_to(sig);
|
2015-11-30 16:38:55 +01:00
|
|
|
self.ecdhe.public().sha3_into(hepubk);
|
2015-12-02 12:07:46 +01:00
|
|
|
host.id().copy_to(pubk);
|
2015-11-30 16:38:55 +01:00
|
|
|
self.nonce.copy_to(nonce);
|
|
|
|
}
|
|
|
|
let message = try!(crypto::ecies::encrypt(&self.id, &data));
|
2015-12-02 20:11:13 +01:00
|
|
|
self.auth_cipher = message.clone();
|
|
|
|
self.connection.send(message);
|
2015-12-17 11:42:30 +01:00
|
|
|
self.connection.expect(ACK_PACKET_SIZE);
|
|
|
|
self.state = HandshakeState::ReadingAck;
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_ack(&mut self) -> Result<(), Error> {
|
2015-12-02 12:07:46 +01:00
|
|
|
trace!(target:"net", "Sending handshake ack to {:?}", self.connection.socket.peer_addr());
|
|
|
|
let mut data = [0u8; 1 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32]; //TODO: use associated constants
|
|
|
|
let len = data.len();
|
|
|
|
{
|
|
|
|
data[len - 1] = 0x0;
|
|
|
|
let (epubk, rest) = data.split_at_mut(64);
|
|
|
|
let (nonce, _) = rest.split_at_mut(32);
|
|
|
|
self.ecdhe.public().copy_to(epubk);
|
|
|
|
self.nonce.copy_to(nonce);
|
|
|
|
}
|
|
|
|
let message = try!(crypto::ecies::encrypt(&self.id, &data));
|
2015-12-02 20:11:13 +01:00
|
|
|
self.ack_cipher = message.clone();
|
|
|
|
self.connection.send(message);
|
2015-12-17 11:42:30 +01:00
|
|
|
self.state = HandshakeState::StartSession;
|
2015-11-30 16:38:55 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|