#[cfg(test)] mod negotiation_tests { use super::*; fn server(lists: &[&[u8];8], follows: bool) -> Vec { let mut p = vec![20]; p.extend([7;16]); for list in lists { string(&mut p, list); } string(&mut p, b""); string(&mut p, b""); p.push(u8::from(follows)); uint(&mut p, 0); p } const NIXOS: &[u8] = b"hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com"; #[test] fn nixos_selection_directionality_and_wrong_guess() { let mut lists = [KEX, HOST, CIPHER, CIPHER, NIXOS, NIXOS, b"none", b"none"]; let n = negotiate(&server(&lists, false)).unwrap(); // Client order wins over server preference for SHA-512. assert_eq!(n.send, MacAlgorithm::Sha256Etm); assert_eq!(n.recv, n.send); assert!(!n.wrong_guess); lists[4] = b"hmac-sha2-512-etm@openssh.com"; lists[5] = b"hmac-sha2-256"; let n = negotiate(&server(&lists, true)).unwrap(); assert_eq!(n.send, MacAlgorithm::Sha512Etm); assert_eq!(n.recv, MacAlgorithm::Sha256); assert!(!n.wrong_guess); lists[0] = b"unknown-kex,curve25519-sha256"; assert!(negotiate(&server(&lists, true)).unwrap().wrong_guess); lists[0] = KEX; lists[1] = b"unknown-host,ssh-ed25519"; assert!(negotiate(&server(&lists, true)).unwrap().wrong_guess); } #[test] fn mismatch_names_both_offers_and_direction() { let lists = [KEX, HOST, CIPHER, CIPHER, MAC, MAC, b"none", b"none"]; let categories = ["kex", "host-key", "cipher client-to-server", "cipher server-to-client", "MAC client-to-server", "MAC server-to-client", "compression client-to-server", "compression server-to-client"]; for (i, category) in categories.into_iter().enumerate() { let mut bad = lists; bad[i] = b"unsupported-one,unsupported-two"; let error = negotiate(&server(&bad, false)).unwrap_err().to_string(); assert!(error.contains(category), "{error}"); assert!(error.contains(&format!("client offered {:?}", String::from_utf8_lossy(lists[i]))), "{error}"); assert!(error.contains("server offered \"unsupported-one,unsupported-two\""), "{error}"); } let valid = server(&lists, false); for end in 0..valid.len() { assert!(negotiate(&valid[..end]).is_err()); } } #[test] fn sha512_mac_key_uses_rfc4253_sha256_expansion() { // Independent OpenSSL/Node fixture, including an original session id != H. let key = derive_len(&[0,0,0,3,1,2,3], &[6;32], b'E', &[7;32], 64); let hex: String = key.iter().map(|b| format!("{b:02x}")).collect(); assert_eq!(hex, "2a9e79189e2902184e372b346241650ef74c7c339fd779556f7c09c1c0cc646e1c94097a9ede9b16f621e18b672f1a126c6530502a27032c85018b243cbde381"); assert_eq!(&key[..32], derive(&[0,0,0,3,1,2,3], &[6;32], b'E', &[7;32])); assert_eq!(derive_len(&[0,0,0,3,1,2,3], &[6;32], b'E', &[7;32], 16), key[..16]); } }