mirror of https://github.com/dswd/vpncloud.git
Compare commits
No commits in common. "36f0b94514368d5dd3815743044a755d04c1b344" and "a4ec6e73c148fe302ccb7c869b5aab46867ac77e" have entirely different histories.
36f0b94514
...
a4ec6e73c1
|
@ -0,0 +1,197 @@
|
||||||
|
// VpnCloud - Peer-to-Peer VPN
|
||||||
|
// Copyright (C) 2015-2020 Dennis Schwerdel
|
||||||
|
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||||
|
|
||||||
|
use test::Bencher;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket},
|
||||||
|
str::FromStr
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
cloud::GenericCloud,
|
||||||
|
config::{Config, CryptoConfig},
|
||||||
|
device::{TunTapDevice, Type},
|
||||||
|
ethernet::{self, SwitchTable},
|
||||||
|
ip::Packet,
|
||||||
|
net::MockSocket,
|
||||||
|
old_crypto::{CryptoMethod, OldCrypto},
|
||||||
|
poll::WaitImpl,
|
||||||
|
types::{Address, Protocol, Table},
|
||||||
|
udpmessage::{decode, encode, Message},
|
||||||
|
util::{MockTimeSource, SystemTimeSource, TimeSource}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn crypto_chacha20(b: &mut Bencher) {
|
||||||
|
let mut crypto = OldCrypto::from_shared_key(CryptoMethod::ChaCha20, "test");
|
||||||
|
let mut payload = [0; 1500];
|
||||||
|
let header = [0; 8];
|
||||||
|
let mut nonce_bytes = [0; 12];
|
||||||
|
b.iter(|| {
|
||||||
|
let len = crypto.encrypt(&mut payload, 1400, &mut nonce_bytes, &header);
|
||||||
|
assert!(crypto.decrypt(&mut payload[..len], &nonce_bytes, &header).is_ok())
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn crypto_aes256(b: &mut Bencher) {
|
||||||
|
let mut crypto = OldCrypto::from_shared_key(CryptoMethod::AES256, "test");
|
||||||
|
let mut payload = [0; 1500];
|
||||||
|
let header = [0; 8];
|
||||||
|
let mut nonce_bytes = [0; 12];
|
||||||
|
b.iter(|| {
|
||||||
|
let len = crypto.encrypt(&mut payload, 1400, &mut nonce_bytes, &header);
|
||||||
|
assert!(crypto.decrypt(&mut payload[..len], &nonce_bytes, &header).is_ok());
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn crypto_aes128(b: &mut Bencher) {
|
||||||
|
let mut crypto = OldCrypto::from_shared_key(CryptoMethod::AES128, "test");
|
||||||
|
let mut payload = [0; 1500];
|
||||||
|
let header = [0; 8];
|
||||||
|
let mut nonce_bytes = [0; 12];
|
||||||
|
b.iter(|| {
|
||||||
|
let len = crypto.encrypt(&mut payload, 1400, &mut nonce_bytes, &header);
|
||||||
|
assert!(crypto.decrypt(&mut payload[..len], &nonce_bytes, &header).is_ok());
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn message_encode(b: &mut Bencher) {
|
||||||
|
let mut crypto = OldCrypto::None;
|
||||||
|
let mut payload = [0; 1600];
|
||||||
|
let mut msg = Message::Data(&mut payload, 64, 1464);
|
||||||
|
let mut buf = [0; 1600];
|
||||||
|
b.iter(|| {
|
||||||
|
encode(&mut msg, &mut buf[..], &mut crypto);
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn message_decode(b: &mut Bencher) {
|
||||||
|
let mut crypto = OldCrypto::None;
|
||||||
|
let mut payload = [0; 1600];
|
||||||
|
let mut msg = Message::Data(&mut payload, 64, 1464);
|
||||||
|
let mut buf = [0; 1600];
|
||||||
|
let mut res = encode(&mut msg, &mut buf[..], &mut crypto);
|
||||||
|
b.iter(|| {
|
||||||
|
decode(&mut res, &mut crypto).unwrap();
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn switch_learn(b: &mut Bencher) {
|
||||||
|
let mut table = SwitchTable::<SystemTimeSource>::new(10, 0);
|
||||||
|
let addr = Address::from_str("12:34:56:78:90:ab").unwrap();
|
||||||
|
let peer = "1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap();
|
||||||
|
b.iter(|| {
|
||||||
|
table.learn(addr.clone(), None, peer);
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn switch_lookup(b: &mut Bencher) {
|
||||||
|
let mut table = SwitchTable::<SystemTimeSource>::new(10, 0);
|
||||||
|
let addr = Address::from_str("12:34:56:78:90:ab").unwrap();
|
||||||
|
let peer = "1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap();
|
||||||
|
table.learn(addr.clone(), None, peer);
|
||||||
|
b.iter(|| {
|
||||||
|
table.lookup(&addr);
|
||||||
|
});
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn ethernet_parse(b: &mut Bencher) {
|
||||||
|
let mut data = [0; 1500];
|
||||||
|
data[5] = 45;
|
||||||
|
b.iter(|| ethernet::Frame::parse(&data).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn ipv4_parse(b: &mut Bencher) {
|
||||||
|
let mut data = [0; 1500];
|
||||||
|
data[0] = 4 * 16;
|
||||||
|
b.iter(|| Packet::parse(&data).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn ipv6_parse(b: &mut Bencher) {
|
||||||
|
let mut data = [0; 1500];
|
||||||
|
data[0] = 6 * 16;
|
||||||
|
b.iter(|| Packet::parse(&data).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn now(b: &mut Bencher) {
|
||||||
|
b.iter(|| SystemTimeSource::now());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn epoll_wait(b: &mut Bencher) {
|
||||||
|
let socket = UdpSocket::bind("[::]:0").unwrap();
|
||||||
|
let device = TunTapDevice::dummy("dummy", "/dev/zero", Type::Dummy).unwrap();
|
||||||
|
let mut waiter = WaitImpl::testing(&socket, &device, 1000).unwrap();
|
||||||
|
b.iter(|| assert!(waiter.next().is_some()));
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestNode = GenericCloud<TunTapDevice, ethernet::Frame, SwitchTable<MockTimeSource>, MockSocket, MockTimeSource>;
|
||||||
|
|
||||||
|
fn create_test_node() -> TestNode {
|
||||||
|
TestNode::new(
|
||||||
|
&Config {
|
||||||
|
crypto: CryptoConfig { password: Some("test".to_string()), ..CryptoConfig::default() },
|
||||||
|
..Config::default()
|
||||||
|
},
|
||||||
|
TunTapDevice::dummy("dummy", "/dev/null", Type::Tap).unwrap(),
|
||||||
|
SwitchTable::new(1800, 10),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
vec![],
|
||||||
|
OldCrypto::None,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn handle_interface_data(b: &mut Bencher) {
|
||||||
|
let mut node = create_test_node();
|
||||||
|
let mut data = [0; 1500];
|
||||||
|
data[105] = 45;
|
||||||
|
b.iter(|| node.handle_interface_data(&mut data, 100, 1400).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn handle_net_message(b: &mut Bencher) {
|
||||||
|
let mut node = create_test_node();
|
||||||
|
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1));
|
||||||
|
let mut data = [0; 1500];
|
||||||
|
data[105] = 45;
|
||||||
|
b.iter(|| node.handle_net_message(addr.clone(), Message::Data(&mut data, 0, 1400)).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn udp_send(b: &mut Bencher) {
|
||||||
|
let sock = UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||||
|
let data = [0; 1400];
|
||||||
|
let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1);
|
||||||
|
b.iter(|| sock.send_to(&data, &addr).unwrap());
|
||||||
|
b.bytes = 1400;
|
||||||
|
}
|
15
src/cloud.rs
15
src/cloud.rs
|
@ -738,15 +738,22 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
||||||
self.traffic.count_in_traffic(src, buffer.len());
|
self.traffic.count_in_traffic(src, buffer.len());
|
||||||
if let Err(e) = self.handle_net_message(src, buffer) {
|
if let Err(e) = self.handle_net_message(src, buffer) {
|
||||||
error!("Error: {}", e);
|
error!("Error: {}", e);
|
||||||
if let Error::CryptoInit(_) = e {
|
match e {
|
||||||
info!("Closing pending connection to {} due to error", addr_nice(src));
|
Error::Crypto(_) => {
|
||||||
self.pending_inits.remove(&src);
|
info!("Closing connection to {} due to error", addr_nice(src));
|
||||||
|
self.remove_peer(src);
|
||||||
|
}
|
||||||
|
Error::CryptoInit(_) => {
|
||||||
|
info!("Closing pending connection to {} due to error", addr_nice(src));
|
||||||
|
self.pending_inits.remove(&src);
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_device_event(&mut self, buffer: &mut MsgBuffer) {
|
fn handle_device_event(&mut self, buffer: &mut MsgBuffer) {
|
||||||
try_fail!(self.device.read(buffer), "Failed to read from device: {}");
|
try_fail!(self.device.read(buffer), "Failed to read from tap device: {}");
|
||||||
if let Err(e) = self.handle_interface_data(buffer) {
|
if let Err(e) = self.handle_interface_data(buffer) {
|
||||||
error!("Error: {}", e);
|
error!("Error: {}", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,13 +176,13 @@ impl CryptoCore {
|
||||||
|
|
||||||
fn decrypt_with_key<'a>(key: &mut CryptoKey, nonce: Nonce, data_and_tag: &'a mut [u8]) -> Result<(), Error> {
|
fn decrypt_with_key<'a>(key: &mut CryptoKey, nonce: Nonce, data_and_tag: &'a mut [u8]) -> Result<(), Error> {
|
||||||
if nonce < key.min_nonce {
|
if nonce < key.min_nonce {
|
||||||
return Err(Error::Crypto("Old nonce rejected"))
|
return Err(Error::Unauthorized("Old nonce rejected"))
|
||||||
}
|
}
|
||||||
// decrypt
|
// decrypt
|
||||||
let crypto_nonce = aead::Nonce::assume_unique_for_key(*nonce.as_bytes());
|
let crypto_nonce = aead::Nonce::assume_unique_for_key(*nonce.as_bytes());
|
||||||
key.key
|
key.key
|
||||||
.open_in_place(crypto_nonce, aead::Aad::empty(), data_and_tag)
|
.open_in_place(crypto_nonce, aead::Aad::empty(), data_and_tag)
|
||||||
.map_err(|_| Error::Crypto("Failed to decrypt data"))?;
|
.map_err(|_| Error::Unauthorized("Failed to decrypt data"))?;
|
||||||
// last seen nonce
|
// last seen nonce
|
||||||
if key.seen_nonce < nonce {
|
if key.seen_nonce < nonce {
|
||||||
key.seen_nonce = nonce;
|
key.seen_nonce = nonce;
|
||||||
|
@ -230,17 +230,12 @@ impl CryptoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn create_dummy_pair(algo: &'static aead::Algorithm) -> (CryptoCore, CryptoCore) {
|
|
||||||
let key_data = random_data(algo.key_len());
|
|
||||||
let sender = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), true);
|
|
||||||
let receiver = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), false);
|
|
||||||
(sender, receiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_speed(algo: &'static aead::Algorithm, max_time: &Duration) -> f64 {
|
pub fn test_speed(algo: &'static aead::Algorithm, max_time: &Duration) -> f64 {
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.set_length(1000);
|
buffer.set_length(1000);
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let key_data = random_data(algo.key_len());
|
||||||
|
let mut sender = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), true);
|
||||||
|
let mut receiver = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), false);
|
||||||
let mut iterations = 0;
|
let mut iterations = 0;
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
while (Instant::now() - start).as_nanos() < max_time.as_nanos() {
|
while (Instant::now() - start).as_nanos() < max_time.as_nanos() {
|
||||||
|
@ -261,6 +256,14 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ring::aead::{self, LessSafeKey, UnboundKey};
|
use ring::aead::{self, LessSafeKey, UnboundKey};
|
||||||
|
|
||||||
|
|
||||||
|
fn setup_pair(algo: &'static aead::Algorithm) -> (CryptoCore, CryptoCore) {
|
||||||
|
let key = random_data(algo.key_len());
|
||||||
|
let crypto1 = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key).unwrap()), false);
|
||||||
|
let crypto2 = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key).unwrap()), true);
|
||||||
|
(crypto1, crypto2)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonce() {
|
fn test_nonce() {
|
||||||
let mut nonce = Nonce::zero();
|
let mut nonce = Nonce::zero();
|
||||||
|
@ -272,7 +275,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encrypt_decrypt(algo: &'static aead::Algorithm) {
|
fn test_encrypt_decrypt(algo: &'static aead::Algorithm) {
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let (mut sender, mut receiver) = setup_pair(algo);
|
||||||
let plain = random_data(1000);
|
let plain = random_data(1000);
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.clone_from(&plain);
|
buffer.clone_from(&plain);
|
||||||
|
@ -300,7 +303,7 @@ mod tests {
|
||||||
|
|
||||||
|
|
||||||
fn test_tampering(algo: &'static aead::Algorithm) {
|
fn test_tampering(algo: &'static aead::Algorithm) {
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let (mut sender, mut receiver) = setup_pair(algo);
|
||||||
let plain = random_data(1000);
|
let plain = random_data(1000);
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.clone_from(&plain);
|
buffer.clone_from(&plain);
|
||||||
|
@ -340,7 +343,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_nonce_pinning(algo: &'static aead::Algorithm) {
|
fn test_nonce_pinning(algo: &'static aead::Algorithm) {
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let (mut sender, mut receiver) = setup_pair(algo);
|
||||||
let plain = random_data(1000);
|
let plain = random_data(1000);
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.clone_from(&plain);
|
buffer.clone_from(&plain);
|
||||||
|
@ -381,7 +384,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_key_rotation(algo: &'static aead::Algorithm) {
|
fn test_key_rotation(algo: &'static aead::Algorithm) {
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let (mut sender, mut receiver) = setup_pair(algo);
|
||||||
let plain = random_data(1000);
|
let plain = random_data(1000);
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.clone_from(&plain);
|
buffer.clone_from(&plain);
|
||||||
|
@ -463,7 +466,9 @@ mod benches {
|
||||||
fn crypto_bench(b: &mut Bencher, algo: &'static aead::Algorithm) {
|
fn crypto_bench(b: &mut Bencher, algo: &'static aead::Algorithm) {
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
buffer.set_length(1400);
|
buffer.set_length(1400);
|
||||||
let (mut sender, mut receiver) = create_dummy_pair(algo);
|
let key_data = random_data(algo.key_len());
|
||||||
|
let mut sender = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), true);
|
||||||
|
let mut receiver = CryptoCore::new(LessSafeKey::new(UnboundKey::new(algo, &key_data).unwrap()), false);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
sender.encrypt(&mut buffer);
|
sender.encrypt(&mut buffer);
|
||||||
receiver.decrypt(&mut buffer).unwrap();
|
receiver.decrypt(&mut buffer).unwrap();
|
||||||
|
|
|
@ -84,6 +84,7 @@ pub type SaltedNodeIdHash = [u8; SALTED_NODE_ID_HASH_LEN];
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum InitMsg {
|
pub enum InitMsg {
|
||||||
|
// TODO: include only salted hashes of node_id and use public_key for leader election
|
||||||
Ping {
|
Ping {
|
||||||
salted_node_id_hash: SaltedNodeIdHash,
|
salted_node_id_hash: SaltedNodeIdHash,
|
||||||
ecdh_public_key: EcdhPublicKey,
|
ecdh_public_key: EcdhPublicKey,
|
||||||
|
@ -152,7 +153,7 @@ impl InitMsg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found_key {
|
if !found_key {
|
||||||
return Err(Error::Crypto("untrusted peer"))
|
return Err(Error::Unauthorized("untrusted peer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stage = None;
|
let mut stage = None;
|
||||||
|
@ -232,7 +233,7 @@ impl InitMsg {
|
||||||
let signed_data = &r.into_inner()[0..pos];
|
let signed_data = &r.into_inner()[0..pos];
|
||||||
let public_key = signature::UnparsedPublicKey::new(&ED25519, &public_key_data);
|
let public_key = signature::UnparsedPublicKey::new(&ED25519, &public_key_data);
|
||||||
if public_key.verify(&signed_data, &signature).is_err() {
|
if public_key.verify(&signed_data, &signature).is_err() {
|
||||||
return Err(Error::Crypto("invalid signature"))
|
return Err(Error::Unauthorized("invalid signature"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let stage = match stage {
|
let stage = match stage {
|
||||||
|
@ -419,15 +420,17 @@ impl<P: Payload> InitState<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_ping(&mut self, out: &mut MsgBuffer) {
|
pub fn send_ping(&mut self, out: &mut MsgBuffer) -> Result<(), Error> {
|
||||||
// create ecdh ephemeral key
|
// create ecdh ephemeral key
|
||||||
let (ecdh_private_key, ecdh_public_key) = self.create_ecdh_keypair();
|
let (ecdh_private_key, ecdh_public_key) = self.create_ecdh_keypair();
|
||||||
self.ecdh_private_key = Some(ecdh_private_key);
|
self.ecdh_private_key = Some(ecdh_private_key);
|
||||||
|
|
||||||
// create stage 1 msg
|
// create stage 1 msg
|
||||||
self.send_message(STAGE_PING, Some(ecdh_public_key), out);
|
self.send_message(STAGE_PING, Some(ecdh_public_key), out)?;
|
||||||
|
|
||||||
self.next_stage = STAGE_PONG;
|
self.next_stage = STAGE_PONG;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stage(&self) -> u8 {
|
pub fn stage(&self) -> u8 {
|
||||||
|
@ -446,7 +449,7 @@ impl<P: Payload> InitState<P> {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if self.failed_retries < 5 {
|
} else if self.failed_retries < 5 {
|
||||||
self.failed_retries += 1;
|
self.failed_retries += 1;
|
||||||
self.repeat_last_message(out);
|
self.repeat_last_message(out)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::CryptoInit("Initialization timeout"))
|
Err(Error::CryptoInit("Initialization timeout"))
|
||||||
|
@ -470,13 +473,13 @@ impl<P: Payload> InitState<P> {
|
||||||
(ecdh_private_key, ecdh_public_key)
|
(ecdh_private_key, ecdh_public_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encrypt_payload(&mut self) -> MsgBuffer {
|
fn encrypt_payload(&mut self) -> Result<MsgBuffer, Error> {
|
||||||
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
let mut buffer = MsgBuffer::new(EXTRA_LEN);
|
||||||
self.payload.write_to(&mut buffer);
|
self.payload.write_to(&mut buffer);
|
||||||
if let Some(crypto) = &mut self.crypto {
|
if let Some(crypto) = &mut self.crypto {
|
||||||
crypto.encrypt(&mut buffer);
|
crypto.encrypt(&mut buffer);
|
||||||
}
|
}
|
||||||
buffer
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(&mut self, data: &mut MsgBuffer) -> Result<P, Error> {
|
fn decrypt(&mut self, data: &mut MsgBuffer) -> Result<P, Error> {
|
||||||
|
@ -496,7 +499,7 @@ impl<P: Payload> InitState<P> {
|
||||||
|
|
||||||
fn send_message(
|
fn send_message(
|
||||||
&mut self, stage: u8, ecdh_public_key: Option<EcdhPublicKey>, out: &mut MsgBuffer
|
&mut self, stage: u8, ecdh_public_key: Option<EcdhPublicKey>, out: &mut MsgBuffer
|
||||||
) {
|
) -> Result<(), Error> {
|
||||||
debug!("Sending init with stage={}", stage);
|
debug!("Sending init with stage={}", stage);
|
||||||
assert!(out.is_empty());
|
assert!(out.is_empty());
|
||||||
let mut public_key = [0; ED25519_PUBLIC_KEY_LEN];
|
let mut public_key = [0; ED25519_PUBLIC_KEY_LEN];
|
||||||
|
@ -514,13 +517,13 @@ impl<P: Payload> InitState<P> {
|
||||||
salted_node_id_hash: self.salted_node_id_hash,
|
salted_node_id_hash: self.salted_node_id_hash,
|
||||||
ecdh_public_key: ecdh_public_key.unwrap(),
|
ecdh_public_key: ecdh_public_key.unwrap(),
|
||||||
algorithms: self.algorithms.clone(),
|
algorithms: self.algorithms.clone(),
|
||||||
encrypted_payload: self.encrypt_payload()
|
encrypted_payload: self.encrypt_payload()?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STAGE_PENG => {
|
STAGE_PENG => {
|
||||||
InitMsg::Peng {
|
InitMsg::Peng {
|
||||||
salted_node_id_hash: self.salted_node_id_hash,
|
salted_node_id_hash: self.salted_node_id_hash,
|
||||||
encrypted_payload: self.encrypt_payload()
|
encrypted_payload: self.encrypt_payload()?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
|
@ -529,15 +532,17 @@ impl<P: Payload> InitState<P> {
|
||||||
let len = msg.write_to(&mut bytes, &self.key_pair).expect("Buffer too small");
|
let len = msg.write_to(&mut bytes, &self.key_pair).expect("Buffer too small");
|
||||||
self.last_message = Some(bytes[0..len].to_vec());
|
self.last_message = Some(bytes[0..len].to_vec());
|
||||||
out.set_length(len);
|
out.set_length(len);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repeat_last_message(&self, out: &mut MsgBuffer) {
|
fn repeat_last_message(&self, out: &mut MsgBuffer) -> Result<(), Error> {
|
||||||
if let Some(ref bytes) = self.last_message {
|
if let Some(ref bytes) = self.last_message {
|
||||||
debug!("Repeating last init message");
|
debug!("Repeating last init message");
|
||||||
let buffer = out.buffer();
|
let buffer = out.buffer();
|
||||||
buffer[0..bytes.len()].copy_from_slice(bytes);
|
buffer[0..bytes.len()].copy_from_slice(bytes);
|
||||||
out.set_length(bytes.len());
|
out.set_length(bytes.len());
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_algorithm(&self, peer_algos: &Algorithms) -> Result<Option<(&'static Algorithm, f32)>, Error> {
|
fn select_algorithm(&self, peer_algos: &Algorithms) -> Result<Option<(&'static Algorithm, f32)>, Error> {
|
||||||
|
@ -592,7 +597,7 @@ impl<P: Payload> InitState<P> {
|
||||||
} else if self.next_stage == CLOSING {
|
} else if self.next_stage == CLOSING {
|
||||||
return Ok(InitResult::Continue)
|
return Ok(InitResult::Continue)
|
||||||
} else if self.last_message.is_some() {
|
} else if self.last_message.is_some() {
|
||||||
self.repeat_last_message(out);
|
self.repeat_last_message(out)?;
|
||||||
return Ok(InitResult::Continue)
|
return Ok(InitResult::Continue)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::CryptoInit("Received invalid stage as first message"))
|
return Err(Error::CryptoInit("Received invalid stage as first message"))
|
||||||
|
@ -612,7 +617,7 @@ impl<P: Payload> InitState<P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and send stage 2 reply
|
// create and send stage 2 reply
|
||||||
self.send_message(STAGE_PONG, Some(my_ecdh_public_key), out);
|
self.send_message(STAGE_PONG, Some(my_ecdh_public_key), out)?;
|
||||||
|
|
||||||
self.next_stage = STAGE_PENG;
|
self.next_stage = STAGE_PENG;
|
||||||
Ok(InitResult::Continue)
|
Ok(InitResult::Continue)
|
||||||
|
@ -631,7 +636,7 @@ impl<P: Payload> InitState<P> {
|
||||||
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInit("Failed to decrypt payload"))?;
|
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInit("Failed to decrypt payload"))?;
|
||||||
|
|
||||||
// create and send stage 3 reply
|
// create and send stage 3 reply
|
||||||
self.send_message(STAGE_PENG, None, out);
|
self.send_message(STAGE_PENG, None, out)?;
|
||||||
|
|
||||||
self.next_stage = WAITING_TO_CLOSE;
|
self.next_stage = WAITING_TO_CLOSE;
|
||||||
self.close_time = 60;
|
self.close_time = 60;
|
||||||
|
@ -696,7 +701,7 @@ mod tests {
|
||||||
fn normal_init() {
|
fn normal_init() {
|
||||||
let (mut sender, mut receiver) = create_pair();
|
let (mut sender, mut receiver) = create_pair();
|
||||||
let mut out = MsgBuffer::new(8);
|
let mut out = MsgBuffer::new(8);
|
||||||
sender.send_ping(&mut out);
|
sender.send_ping(&mut out).unwrap();
|
||||||
assert_eq!(sender.stage(), STAGE_PONG);
|
assert_eq!(sender.stage(), STAGE_PONG);
|
||||||
let result = receiver.handle_init(&mut out).unwrap();
|
let result = receiver.handle_init(&mut out).unwrap();
|
||||||
assert_eq!(receiver.stage(), STAGE_PENG);
|
assert_eq!(receiver.stage(), STAGE_PENG);
|
||||||
|
|
|
@ -258,7 +258,7 @@ impl<P: Payload> PeerCrypto<P> {
|
||||||
if init.stage() != init::STAGE_PING {
|
if init.stage() != init::STAGE_PING {
|
||||||
Err(Error::InvalidCryptoState("Initialization already ongoing"))
|
Err(Error::InvalidCryptoState("Initialization already ongoing"))
|
||||||
} else {
|
} else {
|
||||||
init.send_ping(out);
|
init.send_ping(out)?;
|
||||||
out.prepend_byte(INIT_MESSAGE_FIRST_BYTE);
|
out.prepend_byte(INIT_MESSAGE_FIRST_BYTE);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,12 @@ use std::io;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Crypto init error, this is fatal and the init needs to be aborted
|
#[error("Unauthorized message: {0}")]
|
||||||
|
Unauthorized(&'static str),
|
||||||
|
|
||||||
#[error("Crypto initialization error: {0}")]
|
#[error("Crypto initialization error: {0}")]
|
||||||
CryptoInit(&'static str),
|
CryptoInit(&'static str),
|
||||||
|
|
||||||
/// Crypto error with this one message, no permanent error
|
|
||||||
#[error("Crypto error: {0}")]
|
#[error("Crypto error: {0}")]
|
||||||
Crypto(&'static str),
|
Crypto(&'static str),
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub mod util;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod tests;
|
mod tests;
|
||||||
pub mod beacon;
|
pub mod beacon;
|
||||||
|
#[cfg(feature = "bench")] mod benches;
|
||||||
pub mod cloud;
|
pub mod cloud;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
|
|
Loading…
Reference in New Issue