From 64d71949f95fca95e2b9fb438f66b0ace7363f5a Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 10 Dec 2024 21:49:20 +0100 Subject: [PATCH] fixed #1150 - send ssh-rsa client key when insecure algorithms are enabled --- tests/conftest.py | 9 ++- tests/ssh-keys/wg/client-rsa | 84 ++++++++++---------- tests/ssh-keys/wg/client-rsa.pub | 1 + tests/test_ssh_proto.py | 55 ++++++++++++- warpgate-protocol-ssh/examples/export_pub.rs | 8 ++ warpgate-protocol-ssh/src/client/mod.rs | 5 ++ warpgate-protocol-ssh/src/keys.rs | 10 ++- 7 files changed, 126 insertions(+), 46 deletions(-) create mode 100644 tests/ssh-keys/wg/client-rsa.pub create mode 100644 warpgate-protocol-ssh/examples/export_pub.rs diff --git a/tests/conftest.py b/tests/conftest.py index 47a8f22d9..82620f28b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -83,7 +83,7 @@ def stop(self): pass p.kill() - def start_ssh_server(self, trusted_keys=[]): + def start_ssh_server(self, trusted_keys=[], extra_config=''): port = alloc_port() data_dir = self.ctx.tmpdir / f"sshd-{uuid.uuid4()}" data_dir.mkdir(parents=True) @@ -105,6 +105,8 @@ def start_ssh_server(self, trusted_keys=[]): PermitRootLogin yes HostKey /ssh-keys/id_ed25519 Subsystem sftp /usr/lib/ssh/sftp-server + LogLevel DEBUG3 + {extra_config} """ ) ) @@ -368,6 +370,11 @@ def wg_c_ed25519_pubkey(): return Path(os.getcwd()) / "ssh-keys/wg/client-ed25519.pub" +@pytest.fixture(scope="session") +def wg_c_rsa_pubkey(): + return Path(os.getcwd()) / "ssh-keys/wg/client-rsa.pub" + + @pytest.fixture(scope="session") def otp_key_base64(): return "Isj0ekwF1YsKW8VUUQiU4awp/9dMnyMcTPH9rlr1OsE=" diff --git a/tests/ssh-keys/wg/client-rsa b/tests/ssh-keys/wg/client-rsa index 26a541ad4..5fa84b0ea 100644 --- a/tests/ssh-keys/wg/client-rsa +++ b/tests/ssh-keys/wg/client-rsa @@ -1,45 +1,45 @@ -----BEGIN PRIVATE KEY----- -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 -----END PRIVATE KEY----- diff --git a/tests/ssh-keys/wg/client-rsa.pub b/tests/ssh-keys/wg/client-rsa.pub new file mode 100644 index 000000000..35e62cd27 --- /dev/null +++ b/tests/ssh-keys/wg/client-rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAADHJzYS1zaGEyLTI1NgAAAAMBAAEAAAIBAK+6SGPicZ/aXmd46OWiWe3H7jbJo7PzCYrNzyFEyDw3sasjie0ZwrueSB8C431rg34AhqW4CM8V4kC0ZIai+0uujgBScWyskxU3xPl4SFKATjySj4uKaLcliwLRV/1gedWHy3uiKh6uJIu7IDJNafKSZAhlxiBbWvduDztj2oIhx5clDByMz3tzM2ByTFHiTxr2Nr/yS/eyk1w0WXs1HuhnhzI59uern4UkI+iE2i+JqEy2rJXAZW4heF9NJ2gZF7qZFtsfIra4AfDYxQtRfgTXy/vZwYMjG5Y2puZ2MmjOVgpp/7HKRVnr6O/5auwvOIqaz1JZzDnjM26FHZhmf3b/Jb5ucGoyO2xkXGC8MEcQzQohlS69tXzhX+GyTAUCjfHI2nL3HouGUnXv8yQoqZ8Z5DbtGOwjxgkWaZqSBIfOmDr16qV1/iSCwAav8z1Thk0Tiet9CcpRjwA37rymnygpgVO2scnybQFjzVIYzHKemM0Qk8cG/uBgMNQljyoCHKkg/inEdGiEm7pKITU4SiXhm1DMTNIoozHGWRt6tq0S/NwKrqXt3UpLbVyZ4B22XuNIxVhOKPvsHawOeyaTk8Pvr3ABYlTlPwlovhsmJ3jn5Qp5nPxVDHd7maJL/JoaPW5oPqvKFcJnBCHR/2Eu+ik4Y0wSbTrerPfeW8HKz5MP diff --git a/tests/test_ssh_proto.py b/tests/test_ssh_proto.py index 1b3a10125..3d5ecb055 100644 --- a/tests/test_ssh_proto.py +++ b/tests/test_ssh_proto.py @@ -25,10 +25,14 @@ def ssh_port(processes, wg_c_ed25519_pubkey): def setup_user_and_target( - processes: ProcessManager, wg: WarpgateProcess, wg_c_ed25519_pubkey + processes: ProcessManager, + wg: WarpgateProcess, + warpgate_client_key, + extra_config='', ): ssh_port = processes.start_ssh_server( - trusted_keys=[wg_c_ed25519_pubkey.read_text()] + trusted_keys=[warpgate_client_key.read_text()], + extra_config=extra_config, ) wait_port(ssh_port) @@ -315,3 +319,50 @@ def test_sftp( ) assert "root:x:0:0:root" in open(f + "/passwd").read() + + def test_insecure_protos( + self, + processes: ProcessManager, + timeout, + wg_c_rsa_pubkey, + shared_wg: WarpgateProcess, + ): + user, ssh_target = setup_user_and_target( + processes, shared_wg, wg_c_rsa_pubkey, + extra_config=''' + PubkeyAcceptedKeyTypes=ssh-rsa + ''', + ) + + ssh_client = processes.start_ssh_client( + f"{user.username}:{ssh_target.name}@localhost", + "-p", + str(shared_wg.ssh_port), + *common_args, + "echo", "123", + password="123", + stderr=subprocess.PIPE, + ) + + ssh_client.wait(timeout=timeout) + assert ssh_client.returncode != 0 + + ssh_target.options.actual_instance.allow_insecure_algos = True + url = f"https://localhost:{shared_wg.http_port}" + with admin_client(url) as api: + api.update_target(ssh_target.id, sdk.TargetDataRequest( + name=ssh_target.name, + options=ssh_target.options, + )) + + ssh_client = processes.start_ssh_client( + f"{user.username}:{ssh_target.name}@localhost", + "-p", + str(shared_wg.ssh_port), + *common_args, + "echo", "123", + password="123", + ) + + stdout, _ = ssh_client.communicate(timeout=timeout) + assert b"123\n" == stdout diff --git a/warpgate-protocol-ssh/examples/export_pub.rs b/warpgate-protocol-ssh/examples/export_pub.rs new file mode 100644 index 000000000..3b79a6d4f --- /dev/null +++ b/warpgate-protocol-ssh/examples/export_pub.rs @@ -0,0 +1,8 @@ +use russh; +use warpgate_protocol_ssh::helpers::PublicKeyAsOpenSSH; + +fn main() { + let path = std::env::args().nth(1).unwrap(); + let key = russh::keys::load_secret_key(path, None).unwrap(); + println!("{}", key.as_openssh()); +} diff --git a/warpgate-protocol-ssh/src/client/mod.rs b/warpgate-protocol-ssh/src/client/mod.rs index 6404cb2d0..f0edad1bb 100644 --- a/warpgate-protocol-ssh/src/client/mod.rs +++ b/warpgate-protocol-ssh/src/client/mod.rs @@ -497,6 +497,11 @@ impl RemoteClient { #[allow(clippy::explicit_auto_deref)] let keys = load_client_keys(&*self.services.config.lock().await)?; for key in keys.into_iter() { + // Skip insecure RSA key signature algo + if Preferred::default().key.iter().find(|x| x.0 == key.name()).is_none() && !ssh_options.allow_insecure_algos.unwrap_or(false) { + continue + } + let key_str = key.as_openssh(); auth_result = session .authenticate_publickey(ssh_options.username.clone(), Arc::new(key)) diff --git a/warpgate-protocol-ssh/src/keys.rs b/warpgate-protocol-ssh/src/keys.rs index b9e7b0ad5..51a566daa 100644 --- a/warpgate-protocol-ssh/src/keys.rs +++ b/warpgate-protocol-ssh/src/keys.rs @@ -98,7 +98,15 @@ pub fn load_client_keys(config: &WarpgateConfig) -> Result, russh:: keys.push(load_and_maybe_resave_ed25519_key(key_path)?); let key_path = path.join("client-rsa"); - keys.push(load_secret_key(key_path, None)?); + let key = load_secret_key(key_path, None)?; + + #[allow(clippy::unwrap_used)] + { + // unwrap only fails for non-RSA keys + keys.push(key.with_signature_hash(SignatureHash::SHA2_512).unwrap()); + keys.push(key.with_signature_hash(SignatureHash::SHA2_256).unwrap()); + keys.push(key.with_signature_hash(SignatureHash::SHA1).unwrap()); + } Ok(keys) }