Compare commits

..

8 Commits

Author SHA1 Message Date
Karolin Varner
c539af8696 chore: cargo fmt 2024-02-16 19:14:20 +01:00
Karolin Varner
c4e56b890f feat: Docker setup for rosenpass with brokers 2024-02-16 19:14:00 +01:00
Karolin Varner
f07fedabc5 feat: Use --psk-broker PATH and --psk-broker-fd FD args in rosenpass root 2024-02-16 10:54:43 +01:00
Karolin Varner
058069e41f feat: Error printing using debug formatter 2024-02-14 12:31:51 +01:00
Karolin Varner
3a4df6d41b feat: Connecting to unix listen sockets for psk broker 2024-02-14 12:31:51 +01:00
wucke13
a7a2ddb982 feat: add early wip based podman demonstrator 2024-02-13 20:32:42 +01:00
Karolin Varner
83d3e39dc3 feat: First version of broker based WireGuard PSK interface
This allows us to run with minimal priviledges in the Rosenpass process itself
2024-02-13 20:32:42 +01:00
Beau McDermott
639541ab4f fix: Grammatical typo in cli.rs
Fixes #236
2024-02-10 17:45:20 +01:00
27 changed files with 922 additions and 252 deletions

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
examples/
target/
flake.*
.ci
.direnv
.git
.github

385
Cargo.lock generated
View File

@@ -245,6 +245,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cast"
version = "0.3.0"
@@ -425,6 +431,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "command-fds"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f190f3c954f7bca3c6296d0ec561c739bdbe6c7e990294ed168d415f6e1b5b01"
dependencies = [
"nix",
"thiserror",
]
[[package]]
name = "cpufeatures"
version = "0.2.12"
@@ -434,15 +450,6 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "criterion"
version = "0.4.0"
@@ -657,43 +664,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "filetime"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"windows-sys 0.52.0",
]
[[package]]
name = "flate2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -773,17 +749,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f54046de71e77899abc5fee9a9ada4b6299e0829cf26cf47cdfe2163be3d33a"
dependencies = [
"flate2",
"tar",
"ureq",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -820,16 +785,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -979,6 +934,17 @@ dependencies = [
"autocfg",
]
[[package]]
name = "memsec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa0916b001582d253822171bd23f4a0229d32b9507fae236f5da8cad515ba7c"
dependencies = [
"getrandom",
"libc",
"windows-sys 0.45.0",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1031,6 +997,17 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@@ -1050,6 +1027,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi 0.3.3",
"libc",
]
[[package]]
name = "object"
version = "0.32.1"
@@ -1095,6 +1082,29 @@ version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.48.5",
]
[[package]]
name = "paste"
version = "1.0.14"
@@ -1108,10 +1118,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "percent-encoding"
version = "2.3.1"
name = "pin-project-lite"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "plotters"
@@ -1283,29 +1293,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "ring"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
dependencies = [
"cc",
"getrandom",
"libc",
"spin",
"untrusted",
"windows-sys 0.48.0",
]
[[package]]
name = "rosenpass"
version = "0.2.1"
dependencies = [
"anyhow",
"clap 4.4.10",
"command-fds",
"criterion",
"env_logger",
"hermit",
"log",
"memoffset",
"mio",
@@ -1319,6 +1315,7 @@ dependencies = [
"rosenpass-to",
"rosenpass-util",
"rosenpass-wireguard-broker",
"rustix",
"serde",
"stacker",
"static_assertions",
@@ -1351,6 +1348,7 @@ dependencies = [
name = "rosenpass-constant-time"
version = "0.1.0"
dependencies = [
"memsec",
"rosenpass-to",
]
@@ -1394,6 +1392,7 @@ dependencies = [
"allocator-api2-tests",
"anyhow",
"log",
"memsec",
"rand",
"rosenpass-to",
"rosenpass-util",
@@ -1413,6 +1412,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"base64",
"rustix",
"static_assertions",
"typenum",
]
@@ -1431,6 +1431,7 @@ dependencies = [
"rosenpass-to",
"rosenpass-util",
"thiserror",
"tokio",
"wireguard-uapi",
]
@@ -1468,28 +1469,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustls"
version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
"rustls-webpki",
"sct",
]
[[package]]
name = "rustls-webpki"
version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.15"
@@ -1511,16 +1490,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "semver"
version = "1.0.21"
@@ -1573,6 +1542,31 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "socket2"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "spin"
version = "0.9.8"
@@ -1641,17 +1635,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tar"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "termcolor"
version = "1.4.0"
@@ -1704,19 +1687,34 @@ dependencies = [
]
[[package]]
name = "tinyvec"
version = "1.6.0"
name = "tokio"
version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
dependencies = [
"tinyvec_macros",
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
name = "tokio-macros"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "toml"
@@ -1758,27 +1756,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "universal-hash"
version = "0.5.1"
@@ -1789,39 +1772,6 @@ dependencies = [
"subtle",
]
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97"
dependencies = [
"base64",
"flate2",
"log",
"once_cell",
"rustls",
"rustls-webpki",
"url",
"webpki-roots",
]
[[package]]
name = "url"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
@@ -1914,12 +1864,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webpki-roots"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
[[package]]
name = "which"
version = "4.4.2"
@@ -1963,6 +1907,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -1981,6 +1934,21 @@ dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
@@ -2011,6 +1979,12 @@ dependencies = [
"windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
@@ -2023,6 +1997,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
@@ -2035,6 +2015,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
@@ -2047,6 +2033,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
@@ -2059,6 +2051,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
@@ -2071,6 +2069,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
@@ -2083,6 +2087,12 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
@@ -2116,15 +2126,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "xattr"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc6ab6ec1907d1a901cdbcd2bd4cb9e7d64ce5c9739cbb97d3c391acd8c7fae"
dependencies = [
"libc",
]
[[package]]
name = "zeroize"
version = "1.7.0"

View File

@@ -50,15 +50,19 @@ toml = "0.7.8"
static_assertions = "1.1.0"
allocator-api2 = "0.2.14"
allocator-api2-tests = "0.2.14"
memsec = "0.6.3"
rand = "0.8.5"
wireguard-uapi = "3.0.0"
command-fds = "0.2.3"
rustix = { version = "0.38.27", features = ["net"] }
tokio = { version = "1.34.0", features = ["sync", "full", "mio"] }
typenum = "1.17.0"
log = { version = "0.4.20" }
clap = { version = "4.4.10", features = ["derive"] }
serde = { version = "1.0.193", features = ["derive"] }
arbitrary = { version = "1.3.2", features = ["derive"] }
anyhow = { version = "1.0.75", features = ["backtrace", "std"] }
mio = { version = "0.8.9", features = ["net"] }
mio = { version = "0.8.9", features = ["net", "os-poll"] }
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
blake2 = "0.10.6"
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [ "std", "heapless" ] }

View File

@@ -13,3 +13,4 @@ readme = "readme.md"
[dependencies]
rosenpass-to = { workspace = true }
memsec = { workspace = true }

View File

@@ -29,13 +29,14 @@ pub fn xor(src: &[u8]) -> impl To<[u8], ()> + '_ {
#[inline]
pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
a == b
a.len() == b.len()
&& unsafe { memsec::memeq(a.as_ptr() as *const u8, b.as_ptr() as *const u8, a.len()) }
}
#[inline]
pub fn compare(a: &[u8], b: &[u8]) -> i32 {
assert!(a.len() == b.len());
a.cmp(b) as i32
unsafe { memsec::memcmp(a.as_ptr(), b.as_ptr(), a.len()) }
}
/// Interpret the given slice as a little-endian unsigned integer

View File

@@ -0,0 +1,109 @@
# Multi Device Isolation
On supported systems (just Linux, state Feb. 2024), Rosenpass uses a so-called broker architecture where multiple operating system processes work together to negotiate a key using post quantum cryptography and then send it to WireGuard to run an actual VPN. This is similar to the sandboxes used by web browsers to prevent websites accessing the rest of the computer.
These processes communicate using what is called a "unix socket"; a special file that can be used by to processes to send data back and forth. There are tools to forward data from a unix socket one one host to a unix socket on another host. By using one of these tools, you can run most of Rosenpass' processes on one host while running just the process that forwards keys from Rosenpass to WireGuard on the device that establishes the WireGuard tunnel.
This type of setup can provide a very high degree of isolation. When set up correctly, a critical bug in the Rosenpass code can not affect the host running WireGuard and vice versa. Keep in mind though that for this goal to be reached, the method to connect both hosts must be sufficiently secured: If the WireGuard host is allowed to perform arbitrary commands on the Rosenpass host, then an attacker with access to the WireGuard device can also take over the Rosenpass device.
You can use the instructions from [Unix Domain Socket Forwarding with OpenSSH](https://www.skreutz.com/posts/unix-domain-socket-forwarding-with-openssh/) to harden the connection between the two devices after following the instructions from this tutorial.
## Instructions
In this manual, we are dealing with three hosts:
- The **local peer**: The local host running WireGuard
- The **remote peer**: The remote host we are connecting to.
- The **the rosenpass device**: The dedicated host running rosenpass. It connects with *local peer* to supply WireGuard with keys and it connects with remote peer to perform key exchanges.
Lets assume, that you are starting from a working Rosenpass setup on *local peer* and *remote peer*, running rosenpass and WireGuard on each host. Both setups use configuration files. We will move the rosenpass instance running on *local peer* to the *rosenpass device* in this tutorial.
### Step 0: Setup Rosenpass
If you do not have a functioning rosenpass deployment on the local and remote peer at this point, you can create one by using the configuration files from the configuration-examples directory.
You will need to set up the WireGuard device manually using instructions for your linux distribution. You can use the tutorial on the [arch wiki](https://wiki.archlinux.org/title/WireGuard) for reference.
Make sure to set a random pre-shared key during creation of the WireGuard setup on both hosts at startup. Random pre-shared keys can be generated by using `wg genpks` on each host.
For the broker based setup to work, you might have to assign the broker process the CAP_NET_ADMIN linux capability:
```bash
sudo setcap CAP_NET_ADMIN=+eip ./target/debug/rosenpass-wireguard-broker-privileged
```
Make sure the broker binaries are in your system path when starting rosenpass:
```bash
PATH="$PWD/target/debug:$PATH" ./target/debug/rosenpass exchange-config ./path/to/config/file.toml
```
You will also need to setup rosenpass on the rosenpass device.
### Step 1: Verify that your rosenpass setup is working
Start rosenpass on both peers using the following command.
```bash
PATH="$PWD/target/debug:$PATH" rosenpass exchange-config ./path/to/config/file.toml
```
Now you can verify that rosenpass inserted a pre-shared key on both hosts:
```bash
wg show wgRpTest preshared-keys
```
The shell output will look similar to this:
```
tdnV/wa/0Uf8Nrm3cZkKXOm4atrOEPzv1+dvaG7p7y0= 5235LJ/ONgrO8XuxECtLPzGOyWSvuzHcexzcgoHubfs=
```
The first value is the peer's public key, the second in the pre-shared key. The pre-shared keys should match.
### Step 2: Manually start the broker
Rosenpass starts the psk-broker internally by default. We are looking to manually start it instead.
On the *local peer*, first start the broker manually:
```bash
rm -fv broker.sock; PATH="target/debug" ./target/debug/rosenpass-wireguard-broker-socket-handler --listen-path broker.sock
```
Now you should call rosenpass while make use of the created socket. Use the `psk_broker` configuration key. Your configuration will now look something like this:
```bash
PATH="$PWD/target/debug:$PATH" rosenpass --psk-broker broker.sock exchange-config ./path/to/config/file.toml
```
### Step 2: Forward the unix socket to the rosenpass device
OpenSSH socket forwarding can be used; on the local peer you can execute something like the following command:
```bash
ssh -vgMR path/to/rosenpass/broker.sock:./broker.sock -L user@rosenpass_device
```
### Step 3: Start rosenpass on the rosenpass device
You may need to copy your configuration files to the rosenpass device:
```bash
scp ./path/to/config/file.toml ./path/to/peer/pk ./path/to/pk ./path/to/sk user@rosenpass_device:path/to/rosenpass/
```
Now you can start rosenpass on the rosenpass device:
```bash
PATH="$PWD/target/debug:$PATH" ./target/debug/rosenpass exchange-config ./path/to/config.toml
```
### Step 4: Harden the setup
This tutorial is in a very rough state; it currently provides enough hints to advanced users to convey how the setup is supposed work. For a real production setup it needs to be adapted.
In particular, you can use the guide from from [Unix Domain Socket Forwarding with OpenSSH](https://www.skreutz.com/posts/unix-domain-socket-forwarding-with-openssh/) to make sure neither the *local peer* nor the *rosenpass device* can execute arbitrary commands on each other. The socat tutorial used in this setup can be used to achieve a diversity of setups, such as forwarding the unix socket via a plain TCP socket without encryption to the rosenpass device, if a trusted network setup is used to connect the two. Other setups such as securing the connection using TLS or forwarding the connection via a serial connection can be achieved.
You should also make sure that the rosenpass secret key is at no point in time stored in the *local peer*, so if you followed this tutorial you might want to regenerate the keypair on the *rosenpass device* itself.

View File

@@ -0,0 +1,9 @@
public_key = "./pk1"
secret_key = "./sk1"
listen = ["[::]:9999"]
verbosity = "Verbose"
[[peers]]
public_key = "./pk2"
device = "YOUR WIREGUARD DEVICE"
peer = "YOUR PEER PK"

View File

@@ -0,0 +1,26 @@
version: "3.8"
services:
rosenpass:
build: ../rosenpass/
command: rosenpass
ports:
- name: rosenpass-ipv4
target: 9999
host_ip: 127.0.0.1
published: 9999
protocol: udp
mode: host
- name: rosenpass-ipv4
target: 9999
host_ip: '[::1]'
published: 9999
protocol: udp
mode: host
environment:
RUST_LOG: info
#DEBUG_ENTRYPOINT: 1
cap_add:
- NET_ADMIN
volumes:
- ../socket:/socket:ro
- ../config:/config:ro

View File

@@ -0,0 +1,14 @@
version: "3.8"
services:
rosenpass:
build: ../rosenpass
command: psk_broker
environment:
RUST_LOG: info
USER_GAINS_CAP_NET_ADMIN: 1
#DEBUG_ENTRYPOINT: 1
cap_add:
- NET_ADMIN
volumes:
- ../socket:/socket:rw
network_mode: host

View File

@@ -0,0 +1,35 @@
FROM rust:slim as build
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
libclang-dev \
libcap2-bin \
git \
inotify-tools
RUN adduser --system --uid 768 --group rosenpass --home /var/lib/rosenpass
USER rosenpass:rosenpass
RUN cd ~rosenpass \
&& git clone --depth 1 "https://github.com/rosenpass/rosenpass" -b dev/broker-architecture rosenpass-source \
&& cd rosenpass-source \
&& mkdir -p ~rosenpass/usr \
&& cargo install --path rosenpass --root ~rosenpass/usr --bins \
&& cargo install --path wireguard-broker --root ~rosenpass/usr --bins \
&& cd ~rosenpass \
&& rm -R rosenpass-source
USER root:root
# TODO: Is this proper handling of ambient capabilities?
RUN setcap CAP_NET_ADMIN=+ep ~rosenpass/usr/bin/rosenpass-wireguard-broker-privileged
VOLUME /config
COPY ./entrypoint.sh /usr/local/sbin/docker_entrypoint
COPY ./fd_passing.pl /usr/local/sbin/fd_passing
RUN chmod a+x /usr/local/sbin/docker_entrypoint /usr/local/sbin/fd_passing
ENTRYPOINT ["/usr/local/sbin/docker_entrypoint"]
VOLUME /socket
CMD rosenpass config.toml

View File

@@ -0,0 +1,187 @@
#! /bin/bash
set -e # Needed by bail()
log() {
local lvl; lvl="${1}"; shift || bail "log()" "USAGE: log LEVEL CONTEXT MSG..."
local ctx; ctx="${1}"; shift || bail "log()" "USAGE: log LEVEL CONTEXT MSG..."
echo >&2 "[entrypoint.sh/${ctx} ${lvl}]:" "$@"
}
log_debug() {
if [[ -n "${DEBUG_ENTRYPOINT}" ]]; then
log "DEBUG" "$@"
fi
}
log_info() {
log "INFO" "$@"
}
log_err() {
log "ERROR" "$@"
}
exc() {
local ctx; ctx="${1}"; shift || bail "exc()" "USAGE: exc CONTEXT CMD..."
log_debug '$' "$@"
"$@"
}
bail() {
local ctx; ctx="${1}"; shift || bail "bail()" "USAGE: bail CONTEXT MSG..."
(( "$#" != 0 )) || bail "${ctx}" $'USAGE: bail CONTEXT MSG... # Bail called without parameters! Please use error messages dear developer.'
log_err "${ctx}" "$@"
return 1
}
join() {
local delim; delim="$1"; shift || bail "join()" "USAGE: join DELIM ELMS..."
local tmp fst
fst="true"
for tmp in "$@"; do
if [[ "${fst}" = "true" ]]; then
printf "%s" "${tmp}"
fst=""
else
printf "%s%s" "${delim}" "${tmp}"
fi
done
}
# Shred files after they where red (recursively)
# USAGE: $ burn_after_reading DIR
burn_after_reading() {
local dir; dir="$1"; shift || bail "join()" "USAGE: burn_after_reading DIR"
log_info burn_after_reading "Started for ${dir}"
# Load the list of configuration files
local -a files_arr # Array
readarray -td $'\0' files_arr < <(find "${dir}" -type f -print0)
# Convert configuration file list to associative array
local file
local -A files_todo # Associative array
for file in "${files_arr[@]}"; do
files_todo["${file}"]="1"
done
# Watch for closed files
local file
# The --exclude '/$' excludes directories
inotifywait --quiet --monitor --event close_nowrite --exclude '/$' --recursive . --no-newline --format "%w%f%0" \
| while read -d $'\0' -r file; do
# Check if the file is in the todo list, if yes, erase it
if [[ "${files_todo["${file}"]+1}" = "1" ]]; then
log_info burn_after_reading "File loaded from configuration; removing now: ${file}";
shred "${file}"
# Clear from the todo list; What in the devils name is this quoting style bash
unset 'files_todo["${file}"]'
fi
# We're done if the todo list is empty
if (( "${#files_todo[@]}" == 0 )); then
return
fi
done
}
as_user() {
local -a cmd_prefix
if [[ "$1" = "--exec" ]]; then
cmd_prefix=("exec")
shift
fi
local user; user="$1"; shift || bail "as_user()" "USAGE: as_user USER CMD..."
(( "$#" > 0 )) || bail "as_user()" "USAGE: as_user USER CMD..."
if [[ -n "${USER_GAINS_CAP_NET_ADMIN}" ]]; then # TODO: Dirty to do this here; use --cap-net-admin or something?
exc "as_user()" "${cmd_prefix[@]}" \
capsh --caps="cap_net_admin+eip cap_setuid,cap_setgid+ep" --keep=1 \
--user="${user}" --addamb=cap_net_admin -- -c 'exec "$@"' -- "$@"
elif [[ "${user}" = "$(whoami)" ]]; then
exc "as_user()" "${cmd_prefix[@]}" "$@"
else
exc "as_user()" "${cmd_prefix[@]}" runuser -u "${user}" -- "$@"
fi
}
usage() {
bail "USAGE: ${SCRIPT} rosenpass|psk_broker"
}
cmd_internal() {
"$@"
}
cmd_run_command() {
exc "run_command()" as_user --exec "${SWITCH_USER}" "$@"
}
cmd_psk_broker() {
exc "psk_broker()" exec \
fd_passing --listen /socket/psk_broker.sock \
"$SCRIPT" internal as_user --exec "${SWITCH_USER}" \
rosenpass-wireguard-broker-socket-handler --listen-fd
}
rosenpass_start_with_socket_fd() {
local fd; fd="$1"; shift || bail "rosenpass_start_with_socket_fd()" "USAGE: rosenpass_start_with_socket_fd PSK_BROKER_FD"
exc "rosenpass_start_with_socket_fd()" exec \
rosenpass --psk-broker-fd "$fd" exchange-config /config/config.toml
}
cmd_rosenpass() {
test -z "${USER_GAINS_CAP_NET_ADMIN}" || bail "rosenpass()" "USER_GAINS_CAP_NET_ADMIN should be unset. The rosenpass instance doing key exchanges should not have network admin privileges!"
exc "psk_broker()" exec \
fd_passing --connect /socket/psk_broker.sock \
"$SCRIPT" internal as_user --exec "${SWITCH_USER}" \
"$SCRIPT" internal rosenpass_start_with_socket_fd
}
main() {
local command; command="$1"; shift || usage
case "${command}" in
internal) cmd_internal "$@" ;;
run_command) ;;
psk_broker) ;;
rosenpass) ;;
*) usage;;
esac
exc "main()" umask u=rw,og=
exc "main()" cp -R "${CONFIG_MOUNT}" "${CONFIG_TMP}"
exc "main()" chmod -R u+X "${CONFIG_TMP}"
exc "main()" chown -R rosenpass:rosenpass "${CONFIG_TMP}"
# TODO: How can we do this? We should probably use a dedicated config broker.
#exc "main()" umount "${CONFIG_MOUNT}"
exc "main()" cd "${CONFIG_TMP}"
if [[ -n "${BURN_AFTER_READING}" ]]; then
( burn_after_reading /dev/shm/rosenpass-config )&
fi
local -a path_cpy extra_path_cpy
mapfile -td ':' path_cpy < <(echo -n "$PATH")
mapfile -td ':' extra_path_cpy < <(echo -n "$EXTRA_PATH")
PATH="$(join ":" "${extra_path_cpy[@]}" "${path_cpy[@]}")"
export PATH
exc "main()" "cmd_${command}" "$@"
}
SCRIPT="$0"
# Config
CONFIG_MOUNT="${CONFIG_MOUNT:-/config}"
CONFIG_TMP="${CONFIG_TMP:-/dev/shm/rosenpass-config}"
BURN_AFTER_READING="${BURN_AFTER_READING:-true}"
SWITCH_USER="${SWITCH_USER:-rosenpass}"
#USER_GAINS_CAP_NET_ADMIN="${USER_GAINS_CAP_NET_ADMIN}"
EXTRA_PATH="${EXTRA_PATH:-"$(eval echo ~rosenpass)/usr/bin"}"
main "$@"

View File

@@ -0,0 +1,38 @@
#! /usr/bin/perl
use Fcntl;
use IO::Socket::UNIX;
my $usage = "[$0] Usage: $0 SOCKETPATH [--connect|--listen] CMD...";
my $mode = shift or die($usage);
my $sopath = shift or die($usage);
my $listen;
if ($mode eq "--listen") {
$listen = 1;
} elsif ($mode eq "--connect") {
$listen = 0;
} else {
die($usage);
}
my $socket;
if ($listen == 1) {
$socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM(),
Local => $sopath,
Listen => 1,
) or die "[$0] Error listening on socket socket: $!";
} else {
$socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM(),
Peer => $sopath,
) or die "[$0] Error listening on socket socket: $!";
}
my $fd_flags = $socket->fcntl(F_GETFD, 0) or die "[$0] fcntl F_GETFD: $!";
$socket->fcntl(F_SETFD, $fd_flags & ~FD_CLOEXEC) or die "[$0] fcntl F_SETFD: $!";
exec(@ARGV, $socket->fileno); # pass it on the command line

View File

View File

@@ -34,9 +34,8 @@ toml = { workspace = true }
clap = { workspace = true }
mio = { workspace = true }
rand = { workspace = true }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit = { version = "0.8", features = ["pci", "pci-ids", "acpi", "fsgsbase", "tcp", "rtl8139"]}
command-fds = { workspace = true }
rustix = { workspace = true }
[build-dependencies]
anyhow = { workspace = true }

View File

@@ -1,6 +1,7 @@
use std::cell::{Cell, RefCell};
use std::io::{ErrorKind, Write};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, TcpStream};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::slice;
use std::time::Duration;
@@ -352,7 +353,7 @@ impl AppServer {
sk: SSk,
pk: SPk,
addrs: Vec<SocketAddr>,
psk_broker_socket: TcpStream,
psk_broker_socket: UnixStream,
verbosity: Verbosity,
) -> anyhow::Result<Self> {
// setup mio
@@ -362,7 +363,7 @@ impl AppServer {
// Create the Wireguard broker connection
let psk_broker = {
let mut sock = mio::net::TcpStream::from_std(psk_broker_socket);
let mut sock = mio::net::UnixStream::from_std(psk_broker_socket);
mio_poll.registry().register(
&mut sock,
dispenser.get_token(),

View File

@@ -1,15 +1,22 @@
use std::io::{BufReader, Read};
use std::net::TcpStream;
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::process::Command;
use std::thread;
use anyhow::{bail, ensure, Context};
use clap::Parser;
use clap::{ArgGroup, Parser, Subcommand};
use command_fds::{CommandFdExt, FdMapping};
use log::{error, info};
use rustix::fd::AsRawFd;
use rustix::net::{socketpair, AddressFamily, SocketFlags, SocketType};
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_secret_memory::Public;
use rosenpass_util::b64::b64_reader;
use rosenpass_util::fd::claim_fd;
use rosenpass_util::file::{LoadValue, LoadValueB64};
use crate::app_server;
@@ -19,8 +26,29 @@ use crate::protocol::{SPk, SSk, SymKey};
use super::config;
#[derive(Parser, Debug)]
#[command(author, version, about)]
#[clap(group(
ArgGroup::new("psk_broker_specs")
.args(&["psk_broker", "psk_broker_fd"]),
))]
pub struct Cli {
// Path of the wireguard_psk broker socket to connect to
#[arg(long)]
psk_broker: Option<PathBuf>,
/// When this command is called from another process, the other process can open and bind the
/// unix socket for the psk broker connectionto use themselves, passing it to this process. In Rust this can be achieved
/// using the [command-fds](https://docs.rs/command-fds/latest/command_fds/) crate.
#[arg(long)]
psk_broker_fd: Option<i32>,
#[command(subcommand)]
pub command: CliCommand,
}
#[derive(Subcommand, Debug)]
#[command(author, version, about, long_about)]
pub enum Cli {
pub enum CliCommand {
/// Start Rosenpass in server mode and carry on with the key exchange
///
/// This will parse the configuration file and perform the key exchange
@@ -115,9 +143,9 @@ impl Cli {
pub fn run() -> anyhow::Result<()> {
let cli = Self::parse();
use Cli::*;
use CliCommand::*;
match cli {
Man => {
Cli { command: Man, .. } => {
let man_cmd = std::process::Command::new("man")
.args(["1", "rosenpass"])
.status();
@@ -126,7 +154,10 @@ impl Cli {
println!(include_str!(env!("ROSENPASS_MAN")));
}
}
GenConfig { config_file, force } => {
Cli {
command: GenConfig { config_file, force },
..
} => {
ensure!(
force || !config_file.exists(),
"config file {config_file:?} already exists"
@@ -136,7 +167,10 @@ impl Cli {
}
// Deprecated - use gen-keys instead
Keygen { args } => {
Cli {
command: Keygen { args },
..
} => {
log::warn!("The 'keygen' command is deprecated. Please use the 'gen-keys' command instead.");
let mut public_key: Option<PathBuf> = None;
@@ -169,11 +203,15 @@ impl Cli {
generate_and_save_keypair(secret_key.unwrap(), public_key.unwrap())?;
}
GenKeys {
config_file,
public_key,
secret_key,
force,
Cli {
command:
GenKeys {
config_file,
public_key,
secret_key,
force,
},
..
} => {
// figure out where the key file is specified, in the config file or directly as flag?
let (pkf, skf) = match (config_file, public_key, secret_key) {
@@ -213,7 +251,10 @@ impl Cli {
generate_and_save_keypair(skf, pkf)?;
}
ExchangeConfig { config_file } => {
ref cli @ Cli {
command: ExchangeConfig { ref config_file },
..
} => {
ensure!(
config_file.exists(),
"config file '{config_file:?}' does not exist"
@@ -221,33 +262,41 @@ impl Cli {
let config = config::Rosenpass::load(config_file)?;
config.validate()?;
Self::event_loop(config)?;
Self::event_loop(&cli, &config)?;
}
Exchange {
first_arg,
mut rest_of_args,
config_file,
ref cli @ Cli {
command:
Exchange {
ref first_arg,
ref rest_of_args,
ref config_file,
},
..
} => {
rest_of_args.insert(0, first_arg);
let args = rest_of_args;
let mut args = Vec::new();
args.push(first_arg.clone());
args.extend_from_slice(&rest_of_args[..]);
let mut config = config::Rosenpass::parse_args(args)?;
if let Some(p) = config_file {
if let Some(p) = &config_file {
config.store(&p)?;
config.config_file_path = p;
config.config_file_path = p.clone();
}
config.validate()?;
Self::event_loop(config)?;
Self::event_loop(&cli, &config)?;
}
Validate { config_files } => {
Cli {
command: Validate { config_files },
..
} => {
for file in config_files {
match config::Rosenpass::load(&file) {
Ok(config) => {
eprintln!("{file:?} is valid TOML and conforms to the expected schema");
match config.validate() {
Ok(_) => eprintln!("{file:?} is passed all logical checks"),
Ok(_) => eprintln!("{file:?} has passed all logical checks"),
Err(_) => eprintln!("{file:?} contains logical errors"),
}
}
@@ -260,30 +309,83 @@ impl Cli {
Ok(())
}
fn event_loop(config: config::Rosenpass) -> anyhow::Result<()> {
fn event_loop(cli: &Cli, config: &config::Rosenpass) -> anyhow::Result<()> {
// load own keys
let sk = SSk::load(&config.secret_key)?;
let pk = SPk::load(&config.public_key)?;
// Spawn the psk broker and use socketpair(2) to connect with them
let psk_broker_socket = TcpStream::connect("127.0.0.1:8001")?;
// Connect to the psk broker unix socket if one was specified
// OR OTHERWISE pawn the psk broker and use socketpair(2) to connect with them
let psk_broker_socket = if let Some(ref broker_path) = cli.psk_broker {
let sock = UnixStream::connect(broker_path)?;
sock.set_nonblocking(true)?;
sock
} else if let Some(broker_fd) = cli.psk_broker_fd {
let sock = UnixStream::from(claim_fd(broker_fd)?);
sock.set_nonblocking(true)?;
sock
} else {
let (ours, theirs) = socketpair(
AddressFamily::UNIX,
SocketType::STREAM,
SocketFlags::empty(),
None,
)?;
// Setup our end of the socketpair
let ours = UnixStream::from(ours);
ours.set_nonblocking(true)?;
// Start the PSK broker
let mut child = Command::new("rosenpass-wireguard-broker-socket-handler")
.args(&["--stream-fd", "3"])
.fd_mappings(vec![FdMapping {
parent_fd: theirs.as_raw_fd(),
child_fd: 3,
}])?
.spawn()?;
// Handle the PSK broker crashing
thread::spawn(move || {
let status = child.wait();
if let Ok(status) = status {
if status.success() {
// Maybe they are doing double forking?
info!("PSK broker exited.");
} else {
error!("PSK broker exited with an error ({status:?})");
}
} else {
error!("Wait on PSK broker process failed ({status:?})");
}
});
ours
};
// start an application server
let mut srv = std::boxed::Box::<AppServer>::new(AppServer::new(
sk,
pk,
config.listen,
config.listen.clone(),
psk_broker_socket,
config.verbosity,
config.verbosity.clone(),
)?);
for cfg_peer in config.peers {
for cfg_peer in config.peers.iter().by_ref() {
srv.add_peer(
// psk, pk, outfile, outwg, tx_addr
cfg_peer.pre_shared_key.map(SymKey::load_b64).transpose()?,
cfg_peer
.pre_shared_key
.as_ref()
.map(SymKey::load_b64)
.transpose()?,
SPk::load(&cfg_peer.public_key)?,
cfg_peer.key_out,
cfg_peer.key_out.clone(),
cfg_peer
.wg
.as_ref()
.map(|cfg| -> anyhow::Result<_> {
let b64pk = &cfg.peer;
let mut pk = Public::zero();
@@ -295,8 +397,8 @@ impl Cli {
Ok(app_server::WireguardOut {
pk,
dev: cfg.device,
extra_params: cfg.extra_params,
dev: cfg.device.clone(),
extra_params: cfg.extra_params.clone(),
})
})
.transpose()?,

View File

@@ -26,7 +26,7 @@ pub struct Rosenpass {
pub config_file_path: PathBuf,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub enum Verbosity {
Quiet,
Verbose,

View File

@@ -2,9 +2,6 @@ use log::error;
use rosenpass::cli::Cli;
use std::process::exit;
#[cfg(target_os = "hermit")]
use hermit as _;
/// Catches errors, prints them through the logger, then exits
pub fn main() {
// default to displaying warning and error log messages only
@@ -13,7 +10,7 @@ pub fn main() {
match Cli::run() {
Ok(_) => {}
Err(e) => {
error!("{e}");
error!("{e:?}");
exit(1);
}
}

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "1.74.1"

View File

@@ -15,6 +15,7 @@ rosenpass-to = { workspace = true }
rosenpass-util = { workspace = true }
zeroize = { workspace = true }
rand = { workspace = true }
memsec = { workspace = true }
allocator-api2 = { workspace = true }
log = { workspace = true }

View File

@@ -1,7 +1,7 @@
use std::fmt;
use std::ptr::NonNull;
use allocator_api2::alloc::{AllocError, Allocator, Layout, Global};
use allocator_api2::alloc::{AllocError, Allocator, Layout};
#[derive(Copy, Clone, Default)]
struct MemsecAllocatorContents;
@@ -9,7 +9,7 @@ struct MemsecAllocatorContents;
/// Memory allocation using using the memsec crate
#[derive(Copy, Clone, Default)]
pub struct MemsecAllocator {
global: Global
_dummy_private_data: MemsecAllocatorContents,
}
/// A box backed by the memsec allocator
@@ -29,18 +29,40 @@ pub fn memsec_vec<T>() -> MemsecVec<T> {
impl MemsecAllocator {
pub fn new() -> Self {
Self {
global: Global
_dummy_private_data: MemsecAllocatorContents,
}
}
}
unsafe impl Allocator for MemsecAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.global.allocate(layout)
// Call memsec allocator
let mem: Option<NonNull<[u8]>> = unsafe { memsec::malloc_sized(layout.size()) };
// Unwrap the option
let Some(mem) = mem else {
log::error!("Allocation {layout:?} was requested but memsec returned a null pointer");
return Err(AllocError);
};
// Ensure the right alignment is used
let off = (mem.as_ptr() as *const u8).align_offset(layout.align());
if off != 0 {
log::error!("Allocation {layout:?} was requested but memsec returned allocation \
with offset {off} from the requested alignment. Memsec always allocates values \
at the end of a memory page for security reasons, custom alignments are not supported. \
You could try allocating an oversized value.");
unsafe { memsec::free(mem) };
return Err(AllocError);
};
Ok(mem)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
unsafe { self.global.deallocate(ptr, _layout) }
unsafe {
memsec::free(ptr);
}
}
}

View File

@@ -14,5 +14,6 @@ readme = "readme.md"
[dependencies]
base64 = { workspace = true }
anyhow = { workspace = true }
rustix = { workspace = true }
typenum = { workspace = true }
static_assertions = { workspace = true }

View File

@@ -0,0 +1,12 @@
use std::os::fd::{OwnedFd, RawFd};
/// Clone some file descriptor
///
/// If the file descriptor is invalid, an error will be raised.
pub fn claim_fd(fd: RawFd) -> anyhow::Result<OwnedFd> {
use rustix::{fd::BorrowedFd, io::dup};
// This is safe since [dup] will simply raise
let fd = unsafe { dup(BorrowedFd::borrow_raw(fd))? };
Ok(fd)
}

View File

@@ -19,6 +19,7 @@ wireguard-uapi = { workspace = true }
# Socket handler only
rosenpass-to = { workspace = true }
tokio = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true }
env_logger = { workspace = true }

View File

@@ -17,7 +17,7 @@ pub struct MioBrokerClient {
#[derive(Debug)]
struct MioBrokerClientIo {
socket: mio::net::TcpStream,
socket: mio::net::UnixStream,
send_buf: VecDeque<u8>,
receiving_size: bool,
recv_buf: Vec<u8>,
@@ -25,7 +25,7 @@ struct MioBrokerClientIo {
}
impl MioBrokerClient {
pub fn new(socket: mio::net::TcpStream) -> Self {
pub fn new(socket: mio::net::UnixStream) -> Self {
let io = MioBrokerClientIo {
socket,
send_buf: VecDeque::new(),
@@ -155,7 +155,7 @@ impl MioBrokerClientIo {
}
}
fn raw_send(mut socket: &mio::net::TcpStream, data: &[u8]) -> anyhow::Result<usize> {
fn raw_send(mut socket: &mio::net::UnixStream, data: &[u8]) -> anyhow::Result<usize> {
let mut off = 0;
socket.try_io(|| {
@@ -179,7 +179,7 @@ fn raw_send(mut socket: &mio::net::TcpStream, data: &[u8]) -> anyhow::Result<usi
return Ok(off);
}
fn raw_recv(mut socket: &mio::net::TcpStream, out: &mut [u8]) -> anyhow::Result<usize> {
fn raw_recv(mut socket: &mio::net::UnixStream, out: &mut [u8]) -> anyhow::Result<usize> {
let mut off = 0;
socket.try_io(|| {

View File

@@ -12,3 +12,4 @@ pub trait WireGuardBroker {
}
pub mod api;
pub mod netlink;

View File

@@ -0,0 +1,103 @@
use wireguard_uapi::linux as wg;
use crate::api::msgs;
use crate::WireGuardBroker;
#[derive(thiserror::Error, Debug)]
pub enum ConnectError {
#[error(transparent)]
ConnectError(#[from] wg::err::ConnectError),
}
#[derive(thiserror::Error, Debug)]
pub enum NetlinkError {
#[error(transparent)]
SetDevice(#[from] wg::err::SetDeviceError),
#[error(transparent)]
GetDevice(#[from] wg::err::GetDeviceError),
}
#[derive(thiserror::Error, Debug)]
pub enum SetPskError {
#[error("The indicated wireguard interface does not exist")]
NoSuchInterface,
#[error("The indicated peer does not exist on the wireguard interface")]
NoSuchPeer,
#[error(transparent)]
NetlinkError(#[from] NetlinkError),
}
impl From<wg::err::SetDeviceError> for SetPskError {
fn from(err: wg::err::SetDeviceError) -> Self {
NetlinkError::from(err).into()
}
}
impl From<wg::err::GetDeviceError> for SetPskError {
fn from(err: wg::err::GetDeviceError) -> Self {
NetlinkError::from(err).into()
}
}
use msgs::SetPskError as SetPskMsgsError;
use SetPskError as SetPskNetlinkError;
impl From<SetPskNetlinkError> for SetPskMsgsError {
fn from(err: SetPskError) -> Self {
match err {
SetPskNetlinkError::NoSuchPeer => SetPskMsgsError::NoSuchPeer,
_ => SetPskMsgsError::InternalError,
}
}
}
pub struct NetlinkWireGuardBroker {
sock: wg::WgSocket,
}
impl NetlinkWireGuardBroker {
pub fn new() -> Result<Self, ConnectError> {
let sock = wg::WgSocket::connect()?;
Ok(Self { sock })
}
}
impl WireGuardBroker for NetlinkWireGuardBroker {
type Error = SetPskError;
fn set_psk(
&mut self,
interface: &str,
peer_id: [u8; 32],
psk: [u8; 32],
) -> Result<(), Self::Error> {
// Ensure that the peer exists by querying the device configuration
// TODO: Use InvalidInterfaceError
let state = self
.sock
.get_device(wg::DeviceInterface::from_name(interface.to_owned()))?;
if state
.peers
.iter()
.find(|p| &p.public_key == &peer_id)
.is_none()
{
return Err(SetPskError::NoSuchPeer);
}
// Peer update description
let mut set_peer = wireguard_uapi::set::Peer::from_public_key(&peer_id);
set_peer
.flags
.push(wireguard_uapi::linux::set::WgPeerF::UpdateOnly);
set_peer.preshared_key = Some(&psk);
// Device update description
let mut set_dev = wireguard_uapi::set::Device::from_ifname(interface.to_owned());
set_dev.peers.push(set_peer);
self.sock.set_device(set_dev)?;
Ok(())
}
}