From 4f2b09d92c79775695a1781bc0ad8f5fd089635a Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Mon, 19 Oct 2020 22:38:32 +0200 Subject: [PATCH] More tests --- Cargo.lock | 16 +++--- src/crypto/init.rs | 139 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 143 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6547a1b..7056b78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "cc" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" +checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" [[package]] name = "cfg-if" @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ "itoa", "ryu", @@ -512,9 +512,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "standback" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a71ea1ea5f8747d1af1979bfb7e65c3a025a70609f04ceb78425bc5adad8e6" +checksum = "f4e0831040d2cf2bdfd51b844be71885783d489898a192f254ae25d57cce725c" dependencies = [ "version_check", ] @@ -600,9 +600,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" +checksum = "ea9c5432ff16d6152371f808fb5a871cd67368171b09bb21b43df8e4a47a3556" dependencies = [ "proc-macro2", "quote", diff --git a/src/crypto/init.rs b/src/crypto/init.rs index bd7c932..f5e19d8 100644 --- a/src/crypto/init.rs +++ b/src/crypto/init.rs @@ -388,6 +388,7 @@ pub struct InitState { last_message: Option>, crypto: Option, algorithms: Algorithms, + selected_algorithm: Option<&'static Algorithm>, failed_retries: usize } @@ -413,6 +414,7 @@ impl InitState

{ last_message: None, crypto: None, ecdh_private_key: None, + selected_algorithm: None, algorithms, failed_retries: 0, close_time: 60 @@ -605,6 +607,7 @@ impl InitState

{ // do ecdh agreement and derive master key let algorithm = self.select_algorithm(&algorithms)?; + self.selected_algorithm = algorithm.map(|a| a.0); if let Some((algorithm, _speed)) = algorithm { let master_key = self.derive_master_key(algorithm, my_ecdh_private_key, &ecdh_public_key); self.crypto = Some(CryptoCore::new(master_key, self.salted_node_id_hash > salted_node_id_hash)); @@ -620,6 +623,7 @@ impl InitState

{ // do ecdh agreement and derive master key let ecdh_private_key = self.ecdh_private_key.take().unwrap(); let algorithm = self.select_algorithm(&algorithms)?; + self.selected_algorithm = algorithm.map(|a| a.0); if let Some((algorithm, _speed)) = algorithm { let master_key = self.derive_master_key(algorithm, ecdh_private_key, &ecdh_public_key); self.crypto = Some(CryptoCore::new(master_key, self.salted_node_id_hash > salted_node_id_hash)); @@ -793,11 +797,138 @@ mod tests { assert_eq!(sender.stage(), CLOSING); } - // TODO Test: duplicated message or replay attacks + #[test] + fn untrusted_peer() { + let (mut sender, _) = create_pair(); + let (_, mut receiver) = create_pair(); + let mut out = MsgBuffer::new(8); + sender.send_ping(&mut out); + assert_eq!(sender.stage(), STAGE_PONG); + assert!(receiver.handle_init(&mut out).is_err()); + } - // TODO Test: untrusted peers + #[test] + fn manipulated_message() { + let (mut sender, mut receiver) = create_pair(); + let mut out = MsgBuffer::new(8); + sender.send_ping(&mut out); + assert_eq!(sender.stage(), STAGE_PONG); + out.message_mut()[10] ^= 0x01; + assert!(receiver.handle_init(&mut out).is_err()); + } - // TODO Test: manipulated message + #[test] + fn connect_to_self() { + let (mut sender, _) = create_pair(); + let mut out = MsgBuffer::new(8); + sender.send_ping(&mut out); + assert_eq!(sender.stage(), STAGE_PONG); + assert!(sender.handle_init(&mut out).is_err()); + } - // TODO Test: algorithm negotiation + fn test_algorithm_negotiation( + algos1: Algorithms, algos2: Algorithms, success: bool, selected: Option<&'static Algorithm> + ) { + let (mut sender, mut receiver) = create_pair(); + sender.algorithms = algos1; + receiver.algorithms = algos2; + let mut out = MsgBuffer::new(8); + sender.send_ping(&mut out); + let res = receiver.handle_init(&mut out); + assert_eq!(res.is_ok(), success); + if !success { + return + } + sender.handle_init(&mut out).unwrap(); + receiver.handle_init(&mut out).unwrap(); + assert_eq!(sender.selected_algorithm, selected); + assert_eq!(sender.selected_algorithm, receiver.selected_algorithm); + } + + #[test] + fn algorithm_negotiation() { + // Equal algorithms + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + true, + Some(&AES_128_GCM) + ); + + // Overlapping but different + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0)], + allow_unencrypted: false + }, + true, + Some(&AES_256_GCM) + ); + + // Select fastest pair + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 40.0), (&AES_256_GCM, 50.0), (&CHACHA20_POLY1305, 60.0)], + allow_unencrypted: false + }, + true, + Some(&CHACHA20_POLY1305) + ); + + // Select unencrypted if supported by both + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: true + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: true + }, + true, + None + ); + + // Do not select unencrypted if only supported by one + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: true + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0), (&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + true, + Some(&AES_128_GCM) + ); + + // Fail if no match + test_algorithm_negotiation( + Algorithms { + algorithm_speeds: smallvec![(&AES_128_GCM, 600.0)], + allow_unencrypted: true + }, + Algorithms { + algorithm_speeds: smallvec![(&AES_256_GCM, 500.0), (&CHACHA20_POLY1305, 400.0)], + allow_unencrypted: false + }, + false, + Some(&AES_128_GCM) + ); + } }