openethereum/util/src/network/handshake.rs

279 lines
9.0 KiB
Rust
Raw Normal View History

2016-02-05 13:40:41 +01:00
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
2016-01-24 18:53:54 +01:00
use std::sync::Arc;
use mio::*;
use mio::tcp::*;
use hash::*;
2016-01-09 10:27:41 +01:00
use sha3::Hashable;
2015-12-02 12:07:46 +01:00
use bytes::Bytes;
use crypto::*;
use crypto;
2015-12-17 11:42:30 +01:00
use network::connection::{Connection};
use network::host::{HostInfo};
2016-02-14 01:03:48 +01:00
use network::node_table::NodeId;
use error::*;
use network::error::NetworkError;
2016-01-24 18:53:54 +01:00
use network::stats::NetworkStats;
2016-01-21 16:48:37 +01:00
use io::{IoContext, StreamToken};
2015-12-17 11:42:30 +01:00
#[derive(PartialEq, Eq, Debug)]
enum HandshakeState {
2016-01-10 22:42:27 +01:00
/// Just created
New,
2016-01-10 22:42:27 +01:00
/// Waiting for auth packet
ReadingAuth,
2016-01-10 22:42:27 +01:00
/// Waiting for ack packet
ReadingAck,
2016-01-10 22:42:27 +01:00
/// Ready to start a session
StartSession,
}
2016-01-10 22:42:27 +01:00
/// RLPx protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake
pub struct Handshake {
2016-01-10 22:42:27 +01:00
/// Remote node public key
pub id: NodeId,
2016-01-10 22:42:27 +01:00
/// Underlying connection
pub connection: Connection,
2016-01-10 22:42:27 +01:00
/// Handshake state
state: HandshakeState,
2016-01-10 22:42:27 +01:00
/// Outgoing or incoming connection
2015-12-02 12:07:46 +01:00
pub originated: bool,
2016-01-10 22:42:27 +01:00
/// ECDH ephemeral
2015-12-02 12:07:46 +01:00
pub ecdhe: KeyPair,
2016-01-10 22:42:27 +01:00
/// Connection nonce
2015-12-02 12:07:46 +01:00
pub nonce: H256,
2016-01-10 22:42:27 +01:00
/// Handshake public key
2015-12-02 12:07:46 +01:00
pub remote_public: Public,
2016-01-10 22:42:27 +01:00
/// Remote connection nonce.
2015-12-02 12:07:46 +01:00
pub remote_nonce: H256,
2016-01-10 22:42:27 +01:00
/// A copy of received encryped auth packet
2015-12-02 12:07:46 +01:00
pub auth_cipher: Bytes,
2016-01-10 22:42:27 +01:00
/// A copy of received encryped ack packet
2016-02-20 01:10:27 +01:00
pub ack_cipher: Bytes,
/// This Handshake is marked for deleteion flag
pub expired: bool,
}
2016-01-08 13:49:00 +01:00
const AUTH_PACKET_SIZE: usize = 307;
const ACK_PACKET_SIZE: usize = 210;
const HANDSHAKE_TIMEOUT: u64 = 5000;
2015-12-02 12:07:46 +01:00
impl Handshake {
2016-01-10 22:42:27 +01:00
/// Create a new handshake object
2016-01-24 18:53:54 +01:00
pub fn new(token: StreamToken, id: Option<&NodeId>, socket: TcpStream, nonce: &H256, stats: Arc<NetworkStats>) -> Result<Handshake, UtilError> {
Ok(Handshake {
2016-01-24 18:53:54 +01:00
id: if let Some(id) = id { id.clone()} else { NodeId::new() },
connection: Connection::new(token, socket, stats),
2015-12-02 12:07:46 +01:00
originated: false,
state: HandshakeState::New,
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(),
2016-02-20 01:10:27 +01:00
expired: false,
})
}
2016-02-12 09:52:32 +01:00
/// Get id of the remote node if known
pub fn id(&self) -> &NodeId {
&self.id
}
/// Get stream token id
pub fn token(&self) -> StreamToken {
self.connection.token()
}
2016-02-20 01:10:27 +01:00
/// Mark this handshake as inactive to be deleted lated.
pub fn set_expired(&mut self) {
self.expired = true;
}
/// Check if this handshake is expired.
pub fn expired(&self) -> bool {
self.expired
}
2016-01-10 22:42:27 +01:00
/// Start a handhsake
2016-01-21 16:48:37 +01:00
pub fn start<Message>(&mut self, io: &IoContext<Message>, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{
2015-12-02 12:07:46 +01:00
self.originated = originated;
2016-01-21 16:48:37 +01:00
io.register_timer(self.connection.token, HANDSHAKE_TIMEOUT).ok();
if originated {
2015-12-02 12:07:46 +01:00
try!(self.write_auth(host));
}
else {
2015-12-02 12:07:46 +01:00
self.state = HandshakeState::ReadingAuth;
self.connection.expect(AUTH_PACKET_SIZE);
};
2015-12-02 12:07:46 +01:00
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Check if handshake is complete
pub fn done(&self) -> bool {
self.state == HandshakeState::StartSession
}
2016-01-10 22:42:27 +01:00
/// Readable IO handler. Drives the state change.
2016-01-21 16:48:37 +01:00
pub fn readable<Message>(&mut self, io: &IoContext<Message>, host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone {
2016-02-20 01:10:27 +01:00
if !self.expired() {
io.clear_timer(self.connection.token).unwrap();
match self.state {
HandshakeState::ReadingAuth => {
if let Some(data) = try!(self.connection.readable()) {
try!(self.read_auth(host, &data));
try!(self.write_ack());
};
},
HandshakeState::ReadingAck => {
if let Some(data) = try!(self.connection.readable()) {
try!(self.read_ack(host, &data));
self.state = HandshakeState::StartSession;
};
},
HandshakeState::StartSession => {},
_ => { panic!("Unexpected state"); }
}
if self.state != HandshakeState::StartSession {
try!(io.update_registration(self.connection.token));
}
}
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Writabe IO handler.
2016-01-21 16:48:37 +01:00
pub fn writable<Message>(&mut self, io: &IoContext<Message>, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone {
2016-02-20 01:10:27 +01:00
if !self.expired() {
io.clear_timer(self.connection.token).unwrap();
try!(self.connection.writable());
if self.state != HandshakeState::StartSession {
io.update_registration(self.connection.token).unwrap();
}
}
Ok(())
}
2016-01-21 16:48:37 +01:00
/// Register the socket with the event loop
pub fn register_socket<Host:Handler<Timeout=Token>>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
2016-02-20 01:10:27 +01:00
if !self.expired() {
try!(self.connection.register_socket(reg, event_loop));
}
2016-01-21 16:48:37 +01:00
Ok(())
}
2016-02-21 16:52:25 +01:00
/// Update socket registration with the event loop.
2016-01-21 16:48:37 +01:00
pub fn update_socket<Host:Handler<Timeout=Token>>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
2016-02-20 01:10:27 +01:00
if !self.expired() {
try!(self.connection.update_socket(reg, event_loop));
}
Ok(())
}
2016-01-22 18:13:59 +01:00
/// Delete registration
pub fn deregister_socket<Host:Handler>(&self, event_loop: &mut EventLoop<Host>) -> Result<(), UtilError> {
try!(self.connection.deregister_socket(event_loop));
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Parse, validate and confirm auth message
fn read_auth(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> {
2015-12-02 12:07:46 +01:00
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
2016-01-24 18:53:54 +01:00
if data.len() != AUTH_PACKET_SIZE {
debug!(target:"net", "Wrong auth packet size");
return Err(From::from(NetworkError::BadProtocol));
}
2015-12-02 12:07:46 +01:00
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);
2016-01-24 18:53:54 +01:00
self.id.clone_from_slice(pubk);
2015-12-02 12:07:46 +01:00
self.remote_nonce.clone_from_slice(nonce);
2016-01-24 18:53:54 +01:00
let shared = try!(ecdh::agree(host.secret(), &self.id));
let signature = Signature::from_slice(sig);
2015-12-02 12:07:46 +01:00
let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce)));
2016-01-24 18:53:54 +01:00
self.remote_public = spub.clone();
2015-12-02 12:07:46 +01:00
if &spub.sha3()[..] != hepubk {
trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr());
return Err(From::from(NetworkError::Auth));
2015-12-02 12:07:46 +01:00
};
2016-01-24 18:53:54 +01:00
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Parse and validate ack message
fn read_ack(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> {
2015-12-02 12:07:46 +01:00
trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr());
2016-01-24 18:53:54 +01:00
if data.len() != ACK_PACKET_SIZE {
debug!(target:"net", "Wrong ack packet size");
return Err(From::from(NetworkError::BadProtocol));
}
2015-12-02 12:07:46 +01:00
self.ack_cipher = data.to_vec();
let ack = try!(ecies::decrypt(host.secret(), data));
self.remote_public.clone_from_slice(&ack[0..64]);
self.remote_nonce.clone_from_slice(&ack[64..(64+32)]);
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Sends auth message
fn write_auth(&mut self, host: &HostInfo) -> Result<(), UtilError> {
2015-12-02 12:07:46 +01:00
trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr());
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);
// 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);
self.ecdhe.public().sha3_into(hepubk);
2015-12-02 12:07:46 +01:00
host.id().copy_to(pubk);
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;
Ok(())
}
2016-01-10 22:42:27 +01:00
/// Sends ack message
fn write_ack(&mut self) -> Result<(), UtilError> {
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;
Ok(())
}
}