From f4728140134c20524e2efef67bfe73e8087faa84 Mon Sep 17 00:00:00 2001 From: Yujia Qiao Date: Thu, 23 Dec 2021 23:40:20 +0800 Subject: [PATCH] feat: add noise protocol support --- Cargo.lock | 436 +++++++++++++++++++++++++++++++++- Cargo.toml | 2 + docs/security.md | 8 + examples/noise_nk/client.toml | 11 + examples/noise_nk/server.toml | 11 + src/client.rs | 8 +- src/config.rs | 20 ++ src/server.rs | 8 +- src/transport/mod.rs | 7 +- src/transport/noise.rs | 82 +++++++ src/transport/tcp.rs | 4 +- src/transport/tls.rs | 6 +- 12 files changed, 584 insertions(+), 19 deletions(-) create mode 100644 docs/security.md create mode 100644 examples/noise_nk/client.toml create mode 100644 examples/noise_nk/server.toml create mode 100644 src/transport/noise.rs diff --git a/Cargo.lock b/Cargo.lock index 42d20aa..d08aee6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,41 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -52,13 +87,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fe17f59a06fe8b87a6fc8bf53bb70b3aba76d7685f432487a68cd5552853625" dependencies = [ "futures-core", - "getrandom", + "getrandom 0.2.3", "instant", "pin-project", "rand", "tokio", ] +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bincode" version = "1.3.3" @@ -74,6 +115,26 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.0" @@ -83,6 +144,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.1.0" @@ -104,6 +171,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08493fa7707effc63254c66c6ea908675912493cd67952eda23c09fae2610b1" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6547abe025f4027edacd9edaa357aded014eecec42a5070d9b885c3c334aba2" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.19" @@ -116,6 +208,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + [[package]] name = "clap" version = "3.0.0-rc.7" @@ -180,13 +281,54 @@ dependencies = [ "generic-array", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" dependencies = [ - "block-buffer", + "block-buffer 0.10.0", "crypto-common", "generic-array", ] @@ -221,6 +363,37 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" +[[package]] +name = "futures-macro" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" + +[[package]] +name = "futures-util" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -231,6 +404,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -239,7 +423,17 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", ] [[package]] @@ -426,6 +620,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.38" @@ -493,6 +693,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pin-project" version = "1.0.8" @@ -519,12 +728,41 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.15" @@ -581,7 +819,7 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.3", "rand_hc", ] @@ -592,7 +830,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -601,7 +848,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom", + "getrandom 0.2.3", ] [[package]] @@ -610,7 +857,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core", + "rand_core 0.6.3", ] [[package]] @@ -620,6 +867,7 @@ dependencies = [ "anyhow", "async-trait", "backoff", + "base64", "bincode", "bytes", "clap", @@ -628,7 +876,8 @@ dependencies = [ "lazy_static", "rand", "serde", - "sha2", + "sha2 0.10.0", + "snowstorm", "socket2", "tokio", "tokio-native-tls", @@ -679,6 +928,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.9" @@ -724,6 +982,24 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.132" @@ -755,6 +1031,19 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.0" @@ -763,7 +1052,7 @@ checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.1", ] [[package]] @@ -784,12 +1073,49 @@ dependencies = [ "libc", ] +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + [[package]] name = "smallvec" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +[[package]] +name = "snow" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6142f7c25e94f6fd25a32c3348ec230df9109b463f59c8c7acc4bd34936babb7" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "rand", + "rand_core 0.6.3", + "rustc_version", + "sha2 0.9.8", + "subtle", + "x25519-dalek", +] + +[[package]] +name = "snowstorm" +version = "0.1.1" +source = "git+https://github.com/black-binary/snowstorm#42fe84ce2305f02960fb1e295eaa768da055e6e0" +dependencies = [ + "bytes", + "futures-util", + "pin-project", + "rand", + "snow", + "thiserror", + "tokio", +] + [[package]] name = "socket2" version = "0.4.2" @@ -806,6 +1132,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.82" @@ -817,6 +1149,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.2.0" @@ -846,6 +1190,26 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.3" @@ -985,6 +1349,12 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-segmentation" version = "1.8.0" @@ -997,6 +1367,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -1009,6 +1389,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -1045,3 +1431,35 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x25519-dalek" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +dependencies = [ + "curve25519-dalek", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 635a1c7..6745b43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,3 +41,5 @@ socket2 = "0.4" fdlimit = "0.2.1" tokio-native-tls = { version = "0.3.0", optional = true } async-trait = "0.1.52" +snowstorm = { git = "https://github.com/black-binary/snowstorm" } +base64 = "0.13.0" diff --git a/docs/security.md b/docs/security.md new file mode 100644 index 0000000..a7aabd8 --- /dev/null +++ b/docs/security.md @@ -0,0 +1,8 @@ +# Security + +## How to use the default noise transport + +The default noise protocol pattern is `Noise_NK_25519_ChaChaPoly_BLAKE2s`. So a Curve25519 keypair is required. + +### Generate a Curve25519 keypair +https://stackoverflow.com/questions/43546712/how-to-generate-a-curve25519-key-pair-in-terminal diff --git a/examples/noise_nk/client.toml b/examples/noise_nk/client.toml new file mode 100644 index 0000000..3eb3339 --- /dev/null +++ b/examples/noise_nk/client.toml @@ -0,0 +1,11 @@ +[client] +remote_addr = "localhost:2333" +default_token = "123" + +[client.transport] +type = "noise" +[client.transport.noise] +remote_public_key = "xrpknQcAagcd/b9foMwxSCD+EindWxq450NEONk8XQo=" + +[client.services.foo1] +local_addr = "127.0.0.1:80" diff --git a/examples/noise_nk/server.toml b/examples/noise_nk/server.toml new file mode 100644 index 0000000..070c24b --- /dev/null +++ b/examples/noise_nk/server.toml @@ -0,0 +1,11 @@ +[server] +bind_addr = "0.0.0.0:2333" +default_token = "123" + +[server.transport] +type = "noise" +[server.transport.noise] +local_private_key = "QLYMByBnjgM254zT6YKaBVvuAA61swyZfFxoA/SKZHM=" + +[server.services.foo1] +bind_addr = "0.0.0.0:5202" diff --git a/src/client.rs b/src/client.rs index 453aa58..a703ca2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -5,7 +5,7 @@ use crate::protocol::{ self, read_ack, read_control_cmd, read_data_cmd, read_hello, Ack, Auth, ControlChannelCmd, DataChannelCmd, UdpTraffic, CURRENT_PROTO_VRESION, HASH_WIDTH_IN_BYTES, }; -use crate::transport::{TcpTransport, Transport}; +use crate::transport::{NoiseTransport, TcpTransport, Transport}; use anyhow::{anyhow, bail, Context, Result}; use backoff::ExponentialBackoff; use bytes::{Bytes, BytesMut}; @@ -46,6 +46,10 @@ pub async fn run_client(config: &Config, shutdown_rx: broadcast::Receiver) #[cfg(not(feature = "tls"))] crate::helper::feature_not_compile("tls") } + TransportType::Noise => { + let mut client = Client::::from(config).await?; + client.run(shutdown_rx).await + } } } @@ -66,7 +70,7 @@ impl<'a, T: 'static + Transport> Client<'a, T> { config, service_handles: HashMap::new(), transport: Arc::new( - *T::new(&config.transport) + T::new(&config.transport) .await .with_context(|| "Failed to create the transport")?, ), diff --git a/src/config.rs b/src/config.rs index 1966dab..6bc4d5b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,6 +10,8 @@ pub enum TransportType { Tcp, #[serde(rename = "tls")] Tls, + #[serde(rename = "noise")] + Noise, } impl Default for TransportType { @@ -58,11 +60,25 @@ pub struct TlsConfig { pub pkcs12_password: Option, } +fn default_noise_pattern() -> String { + String::from("Noise_NK_25519_ChaChaPoly_BLAKE2s") +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct NoiseConfig { + #[serde(default = "default_noise_pattern")] + pub pattern: String, + pub local_private_key: Option, + pub remote_public_key: Option, + // TODO: Maybe psk can be added +} + #[derive(Debug, Serialize, Deserialize, Default)] pub struct TransportConfig { #[serde(rename = "type")] pub transport_type: TransportType, pub tls: Option, + pub noise: Option, } fn default_transport() -> TransportConfig { @@ -169,6 +185,10 @@ impl Config { } Ok(()) } + TransportType::Noise => { + // The check is done in transport + Ok(()) + } } } diff --git a/src/server.rs b/src/server.rs index a2990ec..61809c0 100644 --- a/src/server.rs +++ b/src/server.rs @@ -8,7 +8,7 @@ use crate::protocol::{ }; #[cfg(feature = "tls")] use crate::transport::TlsTransport; -use crate::transport::{TcpTransport, Transport}; +use crate::transport::{NoiseTransport, TcpTransport, Transport}; use anyhow::{anyhow, bail, Context, Result}; use backoff::backoff::Backoff; use backoff::ExponentialBackoff; @@ -55,6 +55,10 @@ pub async fn run_server(config: &Config, shutdown_rx: broadcast::Receiver) #[cfg(not(feature = "tls"))] crate::helper::feature_not_compile("tls") } + TransportType::Noise => { + let mut server = Server::::from(config).await?; + server.run(shutdown_rx).await?; + } } Ok(()) @@ -97,7 +101,7 @@ impl<'a, T: 'static + Transport> Server<'a, T> { config, services: Arc::new(RwLock::new(generate_service_hashmap(config))), control_channels: Arc::new(RwLock::new(ControlChannelMap::new())), - transport: Arc::new(*(T::new(&config.transport).await?)), + transport: Arc::new(T::new(&config.transport).await?), }) } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 9d447c7..85abe30 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -12,7 +12,9 @@ pub trait Transport: Debug + Send + Sync { type Acceptor: Send + Sync; type Stream: 'static + AsyncRead + AsyncWrite + Unpin + Send + Sync + Debug; - async fn new(config: &TransportConfig) -> Result>; + async fn new(config: &TransportConfig) -> Result + where + Self: Sized; async fn bind(&self, addr: T) -> Result; async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::Stream, SocketAddr)>; async fn connect(&self, addr: &str) -> Result; @@ -24,3 +26,6 @@ pub use tcp::TcpTransport; mod tls; #[cfg(feature = "tls")] pub use tls::TlsTransport; + +mod noise; +pub use noise::NoiseTransport; diff --git a/src/transport/noise.rs b/src/transport/noise.rs new file mode 100644 index 0000000..832a45e --- /dev/null +++ b/src/transport/noise.rs @@ -0,0 +1,82 @@ +use std::net::SocketAddr; + +use super::Transport; +use crate::config::{NoiseConfig, TransportConfig}; +use anyhow::{anyhow, Context, Result}; +use async_trait::async_trait; +use snowstorm::{Builder, NoiseParams, NoiseStream}; +use tokio::net::{TcpListener, TcpStream, ToSocketAddrs}; + +pub struct NoiseTransport { + config: NoiseConfig, + params: NoiseParams, + local_private_key: Vec, + remote_public_key: Option>, +} + +impl std::fmt::Debug for NoiseTransport { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{:?}", self.config) + } +} + +impl NoiseTransport { + fn builder(&self) -> Builder { + let builder = Builder::new(self.params.clone()).local_private_key(&self.local_private_key); + match &self.remote_public_key { + Some(x) => builder.remote_public_key(x), + None => builder, + } + } +} + +#[async_trait] +impl Transport for NoiseTransport { + type Acceptor = TcpListener; + type Stream = snowstorm::stream::NoiseStream; + + async fn new(config: &TransportConfig) -> Result { + let config = match &config.noise { + Some(v) => v.clone(), + None => return Err(anyhow!("Missing noise config")), + }; + let builder = Builder::new(config.pattern.parse()?); + + let remote_public_key = match &config.remote_public_key { + Some(x) => { + Some(base64::decode(x).with_context(|| "Failed to decode remote_public_key")?) + } + None => None, + }; + + let local_private_key = match &config.local_private_key { + Some(x) => base64::decode(x).with_context(|| "Failed to decode local_private_key")?, + None => builder.generate_keypair()?.private, + }; + + let params: NoiseParams = config.pattern.clone().parse()?; + + Ok(NoiseTransport { + config, + params, + local_private_key, + remote_public_key, + }) + } + + async fn bind(&self, addr: T) -> Result { + Ok(TcpListener::bind(addr).await?) + } + + async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::Stream, SocketAddr)> { + let (conn, addr) = a.accept().await?; + let conn = NoiseStream::handshake(conn, self.builder().build_responder()?).await?; + Ok((conn, addr)) + } + + async fn connect(&self, addr: &str) -> Result { + let conn = TcpStream::connect(addr).await?; + let conn = NoiseStream::handshake(conn, self.builder().build_initiator()?).await?; + return Ok(conn); + } +} diff --git a/src/transport/tcp.rs b/src/transport/tcp.rs index ebbcf08..c44210e 100644 --- a/src/transport/tcp.rs +++ b/src/transport/tcp.rs @@ -16,8 +16,8 @@ impl Transport for TcpTransport { type Acceptor = TcpListener; type Stream = TcpStream; - async fn new(_config: &TransportConfig) -> Result> { - Ok(Box::new(TcpTransport {})) + async fn new(_config: &TransportConfig) -> Result { + Ok(TcpTransport {}) } async fn bind(&self, addr: T) -> Result { diff --git a/src/transport/tls.rs b/src/transport/tls.rs index 20b14ab..517122a 100644 --- a/src/transport/tls.rs +++ b/src/transport/tls.rs @@ -22,7 +22,7 @@ impl Transport for TlsTransport { type Acceptor = (TcpListener, TlsAcceptor); type Stream = TlsStream; - async fn new(config: &TransportConfig) -> Result> { + async fn new(config: &TransportConfig) -> Result { let config = match &config.tls { Some(v) => v, None => { @@ -45,10 +45,10 @@ impl Transport for TlsTransport { None => None, }; - Ok(Box::new(TlsTransport { + Ok(TlsTransport { config: config.clone(), connector, - })) + }) } async fn bind(&self, addr: A) -> Result {