From 2b63150a6549246c4cd798f45816429920650fb3 Mon Sep 17 00:00:00 2001 From: Toni Peter Date: Thu, 26 Sep 2024 13:28:10 +0200 Subject: [PATCH] Add TestServer to test SSH connections. Also add a very basic test to check the ssh_connect NASL function. --- rust/Cargo.lock | 578 ++++++++++++++++++- rust/Cargo.toml | 4 +- rust/src/nasl/builtin/ssh/libssh/session.rs | 44 +- rust/src/nasl/builtin/ssh/libssh/sessions.rs | 21 +- rust/src/nasl/builtin/ssh/mod.rs | 3 + rust/src/nasl/builtin/ssh/tests/mod.rs | 50 ++ rust/src/nasl/builtin/ssh/tests/server.rs | 101 ++++ rust/src/nasl/test_utils.rs | 10 +- 8 files changed, 760 insertions(+), 51 deletions(-) create mode 100644 rust/src/nasl/builtin/ssh/tests/mod.rs create mode 100644 rust/src/nasl/builtin/ssh/tests/server.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b7b300353..306db9d83 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -211,6 +211,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.7" @@ -229,6 +235,17 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bcrypt-pbkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" +dependencies = [ + "blowfish", + "pbkdf2 0.12.2", + "sha2", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -312,6 +329,16 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "buffered-reader" version = "1.3.1" @@ -691,6 +718,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -721,6 +760,39 @@ dependencies = [ "cipher", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "dbl" version = "0.3.2" @@ -766,6 +838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -846,12 +919,72 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array 0.14.7", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "ena" version = "0.14.3" @@ -913,6 +1046,22 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1072,6 +1221,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1118,6 +1268,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -1196,6 +1357,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1752,6 +1928,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -1789,6 +1968,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.1.3" @@ -1900,6 +2085,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.7.4" @@ -2009,12 +2200,60 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2022,6 +2261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2121,6 +2361,44 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2144,6 +2422,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "password-hash" version = "0.5.0" @@ -2161,6 +2450,18 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash 0.4.2", + "sha2", +] + [[package]] name = "pbkdf2" version = "0.12.2" @@ -2169,7 +2470,7 @@ checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "hmac", - "password-hash", + "password-hash 0.5.0", ] [[package]] @@ -2253,6 +2554,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + [[package]] name = "pkcs5" version = "0.7.1" @@ -2262,7 +2574,7 @@ dependencies = [ "aes", "cbc", "der", - "pbkdf2", + "pbkdf2 0.12.2", "scrypt", "sha2", "spki", @@ -2405,6 +2717,17 @@ dependencies = [ "pnet_sys", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" version = "0.6.2" @@ -2448,6 +2771,15 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -2645,6 +2977,16 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.8" @@ -2669,6 +3011,131 @@ dependencies = [ "digest", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "russh" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a229f2a03daea3f62cee897b40329ce548600cca615906d98d58b8db3029b19" +dependencies = [ + "aes", + "aes-gcm", + "async-trait", + "bitflags 2.6.0", + "byteorder", + "cbc", + "chacha20", + "ctr", + "curve25519-dalek", + "des", + "digest", + "elliptic-curve", + "flate2", + "futures", + "generic-array 0.14.7", + "hex-literal", + "hmac", + "log", + "num-bigint", + "once_cell", + "p256", + "p384", + "p521", + "poly1305", + "rand", + "rand_core", + "russh-cryptovec", + "russh-keys", + "sha1", + "sha2", + "ssh-encoding", + "ssh-key", + "subtle", + "thiserror", + "tokio", +] + +[[package]] +name = "russh-cryptovec" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadd2c0ab350e21c66556f94ee06f766d8bdae3213857ba7610bfd8e10e51880" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "russh-keys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89757474f7c9ee30121d8cc7fe293a954ba10b204a82ccf5850a5352a532ebc7" +dependencies = [ + "aes", + "async-trait", + "bcrypt-pbkdf", + "block-padding", + "byteorder", + "cbc", + "ctr", + "data-encoding", + "der", + "digest", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "futures", + "hmac", + "home", + "inout", + "log", + "md5", + "num-integer", + "p256", + "p384", + "p521", + "pbkdf2 0.11.0", + "pkcs1", + "pkcs5", + "pkcs8", + "rand", + "rand_core", + "rsa", + "russh-cryptovec", + "sec1", + "serde", + "sha1", + "sha2", + "spki", + "ssh-encoding", + "ssh-key", + "thiserror", + "tokio", + "tokio-stream", + "typenum", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2681,6 +3148,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.36" @@ -2859,7 +3335,7 @@ dependencies = [ "nasl-c-lib", "nasl-function-proc-macro", "num_cpus", - "pbkdf2", + "pbkdf2 0.12.2", "pcap", "pkcs8", "pnet", @@ -2872,6 +3348,8 @@ dependencies = [ "redis", "regex", "ripemd", + "russh", + "russh-keys", "rustls 0.23.12", "rustls-pemfile 1.0.4", "rustls-pemfile 2.1.3", @@ -2917,7 +3395,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ - "pbkdf2", + "pbkdf2 0.12.2", "salsa20", "sha2", ] @@ -2932,6 +3410,20 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -2955,6 +3447,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "sequoia-ipc" version = "0.30.1" @@ -3137,6 +3635,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -3208,6 +3716,57 @@ dependencies = [ "der", ] +[[package]] +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "aes", + "aes-gcm", + "cbc", + "chacha20", + "cipher", + "ctr", + "poly1305", + "ssh-encoding", + "subtle", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2", +] + +[[package]] +name = "ssh-key" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca9b366a80cf18bb6406f4cf4d10aebfb46140a8c0c33f666a144c5c76ecbafc" +dependencies = [ + "bcrypt-pbkdf", + "ed25519-dalek", + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core", + "rsa", + "sec1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3492,6 +4051,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.12" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2aa8b410b..b68bed548 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -96,12 +96,14 @@ members = [ [dev-dependencies] tracing-test = "0.2.5" criterion = "0" +russh = "0.45.0" +russh-keys = "0.45.0" [features] dep-graph-parallel = ["rayon", "crossbeam-channel"] openvas_serde_support = [] serde_support = [] -default = ["dep-graph-parallel", "openvas_serde_support", "enforce-no-trailing-arguments", "serde_support"] +default = ["dep-graph-parallel", "openvas_serde_support", "enforce-no-trailing-arguments", "serde_support", "experimental"] nasl-builtin-raw-ip = ["pcap", "pnet_base", "pnet", "socket2", "pnet_macros", "pnet_macros_support",] nasl-builtin-ssh = ["libssh-rs"] diff --git a/rust/src/nasl/builtin/ssh/libssh/session.rs b/rust/src/nasl/builtin/ssh/libssh/session.rs index cc0aa36d8..8f8b0893e 100644 --- a/rust/src/nasl/builtin/ssh/libssh/session.rs +++ b/rust/src/nasl/builtin/ssh/libssh/session.rs @@ -1,6 +1,5 @@ use libssh_rs::{AuthMethods, AuthStatus, InteractiveAuthInfo, Session, Sftp, SshKey, SshOption}; use std::{os::fd::AsRawFd, time::Duration}; -use tokio::sync::MutexGuard; use tracing::{debug, info}; use crate::nasl::builtin::ssh::SessionId; @@ -36,45 +35,29 @@ impl SshSession { } } -pub struct BorrowedSession<'a> { - guard: MutexGuard<'a, SshSession>, -} - -impl<'a> BorrowedSession<'a> { - pub fn new(guard: MutexGuard<'a, SshSession>) -> Self { - Self { guard } - } - - fn borrow(&self) -> &SshSession { - &self.guard - } - - fn borrow_mut(&mut self) -> &mut SshSession { - &mut self.guard - } - +impl SshSession { fn session(&self) -> &Session { - &self.borrow().session + &self.session } pub fn id(&self) -> SessionId { - self.borrow().id + self.id } fn channel(&self) -> &Option { - &self.borrow().channel + &self.channel } pub fn set_channel(&mut self, channel: Channel) { - self.borrow_mut().channel = Some(channel); + self.channel = Some(channel); } fn authmethods(&self) -> Option { - self.borrow().authmethods + self.authmethods } fn user_set(&self) -> bool { - self.borrow().user_set + self.user_set } pub fn new_channel(&self) -> Result { @@ -115,7 +98,7 @@ impl<'a> BorrowedSession<'a> { debug!("Encountered error while closing channel: {}", e); } } - self.borrow_mut().channel = None; + self.channel = None; } pub fn ensure_user_set(&mut self, login: Option<&str>) -> Result<()> { @@ -136,12 +119,12 @@ impl<'a> BorrowedSession<'a> { let mut channel = self.new_channel()?; channel.open_session()?; self.request_ssh_shell(&mut channel, pty)?; - self.borrow_mut().channel = Some(channel); + self.channel = Some(channel); Ok(()) } pub fn disconnect(&mut self) -> Result<()> { - if let Some(ref channel) = self.borrow_mut().channel { + if let Some(ref channel) = self.channel { channel.close()?; } self.session().disconnect(); @@ -206,7 +189,7 @@ impl<'a> BorrowedSession<'a> { } } }; - self.borrow_mut().authmethods = Some(authmethods); + self.authmethods = Some(authmethods); Ok(authmethods) } } @@ -218,14 +201,13 @@ impl<'a> BorrowedSession<'a> { macro_rules! inherit_method { ($name: ident, $ret: ty, $err_variant: ident $(,)? $($arg: ident : $argtype: ty),*) => { pub fn $name(&self, $($arg: $argtype),*) -> Result<$ret> { - self.session() - .$name($($arg),*) + self.session.$name($($arg),*) .map_err(|e| SshError::$err_variant(self.id(), e)) } } } -impl<'a> BorrowedSession<'a> { +impl SshSession { inherit_method!(connect, (), Connect); inherit_method!(get_server_public_key, SshKey, GetServerPublicKey); inherit_method!(get_server_banner, String, GetServerBanner); diff --git a/rust/src/nasl/builtin/ssh/libssh/sessions.rs b/rust/src/nasl/builtin/ssh/libssh/sessions.rs index 0b111a9e4..387ee366f 100644 --- a/rust/src/nasl/builtin/ssh/libssh/sessions.rs +++ b/rust/src/nasl/builtin/ssh/libssh/sessions.rs @@ -6,12 +6,12 @@ use std::collections::{HashMap, HashSet}; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; use crate::nasl::builtin::ssh::SessionId; use super::super::error::{Result, SshError}; -use super::session::{BorrowedSession, SshSession}; +use super::session::SshSession; #[derive(Default)] pub struct Ssh { @@ -20,15 +20,16 @@ pub struct Ssh { sessions: HashMap>, } +type BorrowedSession<'a> = MutexGuard<'a, SshSession>; + impl Ssh { pub async fn get_by_id(&self, id: SessionId) -> Result { - Ok(BorrowedSession::new( - self.sessions - .get(&id) - .ok_or_else(|| SshError::InvalidSessionId(id))? - .lock() - .await, - )) + Ok(self + .sessions + .get(&id) + .ok_or_else(|| SshError::InvalidSessionId(id))? + .lock() + .await) } /// Return the next available session ID @@ -75,7 +76,7 @@ impl Ssh { let id = self.next_session_id()?; let session = Mutex::new(SshSession::new(id)?); { - let mut borrowed_session = BorrowedSession::new(session.lock().await); + let mut borrowed_session = session.lock().await; if let Err(e) = f(&mut borrowed_session) { borrowed_session.disconnect()?; return Err(e); diff --git a/rust/src/nasl/builtin/ssh/mod.rs b/rust/src/nasl/builtin/ssh/mod.rs index 6fbc231a3..350f7c973 100644 --- a/rust/src/nasl/builtin/ssh/mod.rs +++ b/rust/src/nasl/builtin/ssh/mod.rs @@ -1,5 +1,8 @@ mod error; mod libssh; +#[cfg(test)] +mod tests; + type SessionId = i32; pub use self::libssh::Ssh; diff --git a/rust/src/nasl/builtin/ssh/tests/mod.rs b/rust/src/nasl/builtin/ssh/tests/mod.rs new file mode 100644 index 000000000..fb030daf8 --- /dev/null +++ b/rust/src/nasl/builtin/ssh/tests/mod.rs @@ -0,0 +1,50 @@ +mod server; + +use std::sync::Arc; +use std::time::Duration; + +use russh::server::Server as _; +use server::TestServer; + +use crate::nasl::test_prelude::TestBuilder; +use crate::nasl::NoOpLoader; +use crate::storage::DefaultDispatcher; + +const PORT: u16 = 2223; + +#[tokio::test] +async fn ssh_connect() { + run_test(|mut t| { + t.ok(format!("id = ssh_connect(port:{});", PORT), 9000); + t.ok(format!("id = ssh_connect(port:{});", PORT), 9001); + }) + .await +} + +async fn run_test(f: impl Fn(TestBuilder) -> () + Send + 'static) { + let server = tokio::time::timeout(Duration::from_millis(2000), run_server()); + let client = tokio::task::spawn_blocking(move || { + std::thread::sleep(Duration::from_millis(1000)); + let t = TestBuilder::default(); + f(t) + }); + let (ser, res) = futures::join!(server, client); + assert!(ser.is_err()); + res.unwrap() +} + +async fn run_server() { + let config = russh::server::Config { + inactivity_timeout: Some(Duration::from_secs(3600)), + auth_rejection_time: Duration::from_secs(3), + auth_rejection_time_initial: Some(Duration::from_secs(0)), + keys: vec![russh_keys::key::KeyPair::generate_ed25519().unwrap()], + ..Default::default() + }; + let config = Arc::new(config); + let mut server = TestServer::default(); + server + .run_on_address(config, ("0.0.0.0", PORT)) + .await + .unwrap(); +} diff --git a/rust/src/nasl/builtin/ssh/tests/server.rs b/rust/src/nasl/builtin/ssh/tests/server.rs new file mode 100644 index 000000000..88a1405b9 --- /dev/null +++ b/rust/src/nasl/builtin/ssh/tests/server.rs @@ -0,0 +1,101 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use async_trait::async_trait; +use russh::keys::*; +use russh::server::{Msg, Session}; +use russh::*; +use tokio::sync::Mutex; + +#[derive(Clone, Default)] +pub struct TestServer { + clients: Arc>>, + id: usize, +} + +impl TestServer { + async fn post(&mut self, data: CryptoVec) { + let mut clients = self.clients.lock().await; + for ((id, channel), ref mut s) in clients.iter_mut() { + if *id != self.id { + let _ = s.data(*channel, data.clone()).await; + } + } + } +} + +impl server::Server for TestServer { + type Handler = Self; + + fn new_client(&mut self, _: Option) -> Self { + let s = self.clone(); + self.id += 1; + s + } + + fn handle_session_error(&mut self, _error: ::Error) { + eprintln!("Session error: {:#?}", _error); + } +} + +#[async_trait] +impl server::Handler for TestServer { + type Error = russh::Error; + + async fn channel_open_session( + &mut self, + channel: Channel, + session: &mut Session, + ) -> Result { + { + let mut clients = self.clients.lock().await; + clients.insert((self.id, channel.id()), session.handle()); + } + Ok(true) + } + + async fn auth_publickey( + &mut self, + _: &str, + _: &key::PublicKey, + ) -> Result { + Ok(server::Auth::Accept) + } + + async fn data( + &mut self, + channel: ChannelId, + data: &[u8], + session: &mut Session, + ) -> Result<(), Self::Error> { + // Sending Ctrl+C ends the session and disconnects the client + if data == [3] { + return Err(russh::Error::Disconnect); + } + + let data = CryptoVec::from(format!("Got data: {}\r\n", String::from_utf8_lossy(data))); + self.post(data.clone()).await; + session.data(channel, data); + Ok(()) + } + + async fn tcpip_forward( + &mut self, + address: &str, + port: &mut u32, + session: &mut Session, + ) -> Result { + let handle = session.handle(); + let address = address.to_string(); + let port = *port; + tokio::spawn(async move { + let channel = handle + .channel_open_forwarded_tcpip(address, port, "1.2.3.4", 1234) + .await + .unwrap(); + let _ = channel.data(&b"Hello from a forwarded port"[..]).await; + let _ = channel.eof().await; + }); + Ok(true) + } +} diff --git a/rust/src/nasl/test_utils.rs b/rust/src/nasl/test_utils.rs index 07e987446..e8de3287b 100644 --- a/rust/src/nasl/test_utils.rs +++ b/rust/src/nasl/test_utils.rs @@ -144,8 +144,8 @@ where S: Storage, { #[track_caller] - fn add_line(&mut self, line: &str, val: TestResult) -> &mut Self { - self.lines.push(line.to_string()); + fn add_line(&mut self, line: impl Into, val: TestResult) -> &mut Self { + self.lines.push(line.into()); self.results.push(val.into()); self } @@ -157,7 +157,7 @@ where /// t.ok("x = 3;", 3); /// ``` #[track_caller] - pub fn ok(&mut self, line: &str, val: impl ToNaslResult) -> &mut Self { + pub fn ok(&mut self, line: impl Into, val: impl ToNaslResult) -> &mut Self { self.add_line(line, TestResult::Ok(val.to_nasl_result().unwrap())) } @@ -174,7 +174,7 @@ where #[track_caller] pub fn check( &mut self, - line: &str, + line: impl Into, f: impl Fn(NaslResult) -> bool + 'static + Clone, ) -> &mut Self { self.add_line(line, TestResult::GenericCheck(Box::new(f))) @@ -182,7 +182,7 @@ where /// Run a `line` of NASL code without checking its result. #[track_caller] - pub fn run(&mut self, line: &str) -> &mut Self { + pub fn run(&mut self, line: impl Into) -> &mut Self { self.add_line(line, TestResult::None) }