diff --git a/.gitignore b/.gitignore index 224c1f1..7a9e878 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ review-client review-server.arm.static + +review.log diff --git a/Cargo.lock b/Cargo.lock index d6caf13..01d5ac3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,41 +8,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" version = "0.8.12" @@ -50,7 +15,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "const-random", "getrandom 0.3.4", "once_cell", "version_check", @@ -140,31 +104,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures", - "password-hash", -] - -[[package]] -name = "async-ssh2-tokio" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5413179dd42bcd858cdfd2e13637c81e8b2c15203c90ccacb3c37cfba0f7a68c" -dependencies = [ - "log", - "russh", - "russh-sftp", - "thiserror 2.0.17", - "tokio", -] - [[package]] name = "atomic_refcell" version = "0.1.13" @@ -177,29 +116,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-lc-rs" -version = "1.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e84ce723ab67259cfeb9877c6a639ee9eb7a27b28123abd71db7f0d5d0cc9d86" -dependencies = [ - "aws-lc-sys", - "untrusted", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a442ece363113bd4bd4c8b18977a7798dd4d3c3383f34fb61936960e8f4ad8" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "base16ct" version = "0.2.0" @@ -218,17 +134,6 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" -[[package]] -name = "bcrypt-pbkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" -dependencies = [ - "blowfish", - "pbkdf2", - "sha2", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -240,9 +145,6 @@ name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -dependencies = [ - "serde_core", -] [[package]] name = "bitvec" @@ -256,41 +158,13 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -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", + "generic-array", ] [[package]] @@ -333,15 +207,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.2.52" @@ -349,8 +214,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] @@ -370,12 +233,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "cgmath" version = "0.18.0" @@ -386,17 +243,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "chrono" version = "0.4.43" @@ -404,9 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", - "js-sys", "num-traits", - "wasm-bindgen", "windows-link", ] @@ -460,15 +304,6 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -481,43 +316,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom 0.2.17", - "once_cell", - "tiny-keccak", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-models" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0940496e5c83c54f3b753d5317daec82e8edac71c33aaa1f666d76f518de2444" -dependencies = [ - "hax-lib", - "pastey 0.1.1", - "rand 0.9.2", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -536,19 +340,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - [[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", + "generic-array", "rand_core 0.6.4", "subtle", "zeroize", @@ -560,19 +358,10 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -586,7 +375,6 @@ dependencies = [ "fiat-crypto", "rustc_version", "subtle", - "zeroize", ] [[package]] @@ -600,23 +388,6 @@ dependencies = [ "syn", ] -[[package]] -name = "data-encoding" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" - -[[package]] -name = "delegate" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "der" version = "0.7.10" @@ -624,7 +395,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", - "pem-rfc7468", "zeroize", ] @@ -650,10 +420,20 @@ dependencies = [ ] [[package]] -name = "dunce" -version = "1.0.5" +name = "dsa" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2", + "signature", + "zeroize", +] [[package]] name = "ecdsa" @@ -675,7 +455,6 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", "signature", ] @@ -687,11 +466,8 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", - "serde", "sha2", "subtle", - "zeroize", ] [[package]] @@ -710,10 +486,8 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array 0.14.7", + "generic-array", "group", - "hkdf", - "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -721,18 +495,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "enum_dispatch" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "env_filter" version = "0.1.4" @@ -789,7 +551,7 @@ dependencies = [ "bitvec", "cfg-if", "libc", - "nix 0.23.2", + "nix", "thiserror 1.0.69", ] @@ -825,24 +587,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flurry" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5efcf77a4da27927d3ab0509dec5b0954bb3bc59da5a1de9e52642ebd4cdf9" -dependencies = [ - "ahash", - "num_cpus", - "parking_lot", - "seize", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "funty" version = "2.0.0" @@ -958,17 +702,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "generic-array" -version = "1.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" -dependencies = [ - "generic-array 0.14.7", - "rustversion", - "typenum", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -976,10 +709,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -996,16 +727,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "gio-sys" version = "0.21.5" @@ -1105,7 +826,7 @@ dependencies = [ "num-integer", "num-rational", "option-operations", - "pastey 0.2.1", + "pastey", "pin-project-lite", "smallvec", "thiserror 2.0.17", @@ -1215,76 +936,18 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -[[package]] -name = "hax-lib" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d9ba66d1739c68e0219b2b2238b5c4145f491ebf181b9c6ab561a19352ae86" -dependencies = [ - "hax-lib-macros", - "num-bigint", - "num-traits", -] - -[[package]] -name = "hax-lib-macros" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba777a231a58d1bce1d68313fa6b6afcc7966adef23d60f45b8a2b9b688bf1" -dependencies = [ - "hax-lib-macros-types", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "hax-lib-macros-types" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "867e19177d7425140b417cd27c2e05320e727ee682e98368f88b7194e80ad515" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_json", - "uuid", -] - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" 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" @@ -1294,15 +957,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "iana-time-zone" version = "0.1.64" @@ -1343,36 +997,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "block-padding", - "generic-array 0.14.7", -] - -[[package]] -name = "internal-russh-forked-ssh-key" -version = "0.6.11+upstream-0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a77eae781ed6a7709fb15b64862fcca13d886b07c7e2786f5ed34e5e2b9187" -dependencies = [ - "argon2", - "bcrypt-pbkdf", - "ecdsa", - "ed25519-dalek", - "hex", - "hmac", - "num-bigint-dig", - "p256", - "p384", - "p521", - "rand_core 0.6.4", - "rsa", - "sec1", - "sha1", - "sha2", - "signature", - "ssh-cipher", - "ssh-encoding", - "subtle", - "zeroize", + "generic-array", ] [[package]] @@ -1396,16 +1021,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - [[package]] name = "js-sys" version = "0.3.85" @@ -1440,72 +1055,6 @@ version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" -[[package]] -name = "libcrux-intrinsics" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9ee7ef66569dd7516454fe26de4e401c0c62073929803486b96744594b9632" -dependencies = [ - "core-models", - "hax-lib", -] - -[[package]] -name = "libcrux-ml-kem" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6a88086bf11bd2ec90926c749c4a427f2e59841437dbdede8cde8a96334ab" -dependencies = [ - "hax-lib", - "libcrux-intrinsics", - "libcrux-platform", - "libcrux-secrets", - "libcrux-sha3", - "libcrux-traits", - "rand 0.9.2", - "tls_codec", -] - -[[package]] -name = "libcrux-platform" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778" -dependencies = [ - "libc", -] - -[[package]] -name = "libcrux-secrets" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4dbbf6bc9f2bc0f20dc3bea3e5c99adff3bdccf6d2a40488963da69e2ec307" -dependencies = [ - "hax-lib", -] - -[[package]] -name = "libcrux-sha3" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2400bec764d1c75b8a496d5747cffe32f1fb864a12577f0aca2f55a92021c962" -dependencies = [ - "hax-lib", - "libcrux-intrinsics", - "libcrux-platform", - "libcrux-traits", -] - -[[package]] -name = "libcrux-traits" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adfd58e79d860f6b9e40e35127bfae9e5bd3ade33201d1347459011a2add034" -dependencies = [ - "libcrux-secrets", - "rand 0.9.2", -] - [[package]] name = "libm" version = "0.2.15" @@ -1532,15 +1081,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -1565,12 +1105,6 @@ dependencies = [ "regex-automata", ] -[[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.6" @@ -1626,18 +1160,6 @@ dependencies = [ "memoffset", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1647,17 +1169,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[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 0.8.5", -] - [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1676,9 +1187,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -1720,16 +1231,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1742,19 +1243,13 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "option-operations" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aca39cf52b03268400c16eeb9b56382ea3c3353409309b63f5c8f0b1faf42754" dependencies = [ - "pastey 0.2.1", + "pastey", ] [[package]] @@ -1795,81 +1290,12 @@ dependencies = [ "sha2", ] -[[package]] -name = "pageant" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b537f975f6d8dcf48db368d7ec209d583b015713b5df0f5d92d2631e4ff5595" -dependencies = [ - "byteorder", - "bytes", - "delegate", - "futures", - "log", - "rand 0.8.5", - "sha2", - "thiserror 1.0.69", - "tokio", - "windows", - "windows-strings", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "pastey" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" - [[package]] name = "pastey" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1902,21 +1328,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] - [[package]] name = "pkcs8" version = "0.10.2" @@ -1924,8 +1335,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", - "pkcs5", - "rand_core 0.6.4", "spki", ] @@ -1935,29 +1344,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1975,42 +1361,20 @@ dependencies = [ [[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-macro-crate" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "proc-macro2", - "quote", + "elliptic-curve", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-crate" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn", + "toml_edit", ] [[package]] @@ -2073,7 +1437,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -2126,15 +1489,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.10.0", -] - [[package]] name = "regex-automata" version = "0.4.13" @@ -2157,7 +1511,6 @@ name = "review-client" version = "0.1.0" dependencies = [ "anyhow", - "async-ssh2-tokio", "bson", "clap", "futures", @@ -2168,7 +1521,8 @@ dependencies = [ "lz4_flex", "review-server", "serde", - "serde_json", + "ssh-encoding", + "ssh-key", "test-log", "tokio", "tokio-util", @@ -2188,8 +1542,10 @@ dependencies = [ "libremarkable", "lz4_flex", "procfs", + "rand 0.9.2", "serde", - "serde_json", + "ssh-encoding", + "ssh-key", "test-log", "tokio", "tokio-util", @@ -2228,110 +1584,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "russh" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b4d036bb45d7bbe99dbfef4ec60eaeb614708d22ff107124272f8ef6b54548" -dependencies = [ - "aes", - "aws-lc-rs", - "bitflags 2.10.0", - "block-padding", - "byteorder", - "bytes", - "cbc", - "ctr", - "curve25519-dalek", - "data-encoding", - "delegate", - "der", - "digest", - "ecdsa", - "ed25519-dalek", - "elliptic-curve", - "enum_dispatch", - "flate2", - "futures", - "generic-array 1.3.5", - "getrandom 0.2.17", - "hex-literal", - "hmac", - "home", - "inout", - "internal-russh-forked-ssh-key", - "libcrux-ml-kem", - "log", - "md5", - "num-bigint", - "p256", - "p384", - "p521", - "pageant", - "pbkdf2", - "pkcs1", - "pkcs5", - "pkcs8", - "rand 0.8.5", - "rand_core 0.6.4", - "rsa", - "russh-cryptovec", - "russh-util", - "sec1", - "sha1", - "sha2", - "signature", - "spki", - "ssh-encoding", - "subtle", - "thiserror 1.0.69", - "tokio", - "typenum", - "zeroize", -] - -[[package]] -name = "russh-cryptovec" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb0ed583ff0f6b4aa44c7867dd7108df01b30571ee9423e250b4cc939f8c6cf" -dependencies = [ - "libc", - "log", - "nix 0.29.0", - "ssh-encoding", - "winapi", -] - -[[package]] -name = "russh-sftp" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb94393cafad0530145b8f626d8687f1ee1dedb93d7ba7740d6ae81868b13b5" -dependencies = [ - "bitflags 2.10.0", - "bytes", - "chrono", - "flurry", - "log", - "serde", - "thiserror 2.0.17", - "tokio", - "tokio-util", -] - -[[package]] -name = "russh-util" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6" -dependencies = [ - "chrono", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", -] - [[package]] name = "rustc_version" version = "0.4.1" @@ -2360,32 +1612,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2", -] - [[package]] name = "sec1" version = "0.7.3" @@ -2394,18 +1620,12 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array", "pkcs8", "subtle", "zeroize", ] -[[package]] -name = "seize" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "689224d06523904ebcc9b482c6a3f4f7fb396096645c4cd10c0d2ff7371a34d3" - [[package]] name = "semver" version = "1.0.27" @@ -2452,19 +1672,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - [[package]] name = "serde_spanned" version = "1.0.4" @@ -2577,15 +1784,8 @@ 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]] @@ -2600,6 +1800,31 @@ dependencies = [ "sha2", ] +[[package]] +name = "ssh-key" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" +dependencies = [ + "dsa", + "ed25519-dalek", + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core 0.6.4", + "rsa", + "sec1", + "serde", + "sha1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2727,9 +1952,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -2742,50 +1967,20 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tls_codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" -dependencies = [ - "tls_codec_derive", - "zeroize", -] - -[[package]] -name = "tls_codec_derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tokio" version = "1.49.0" @@ -2955,22 +2150,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2979,9 +2158,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" dependencies = [ "getrandom 0.3.4", "js-sys", @@ -3035,20 +2214,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" -dependencies = [ - "cfg-if", - "futures-util", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.108" @@ -3081,59 +2246,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -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 = "windows" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" -dependencies = [ - "windows-core", -] - [[package]] name = "windows-core" version = "0.62.2" @@ -3147,17 +2259,6 @@ dependencies = [ "windows-strings", ] -[[package]] -name = "windows-future" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" -dependencies = [ - "windows-core", - "windows-link", - "windows-threading", -] - [[package]] name = "windows-implement" version = "0.60.2" @@ -3186,16 +2287,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" -dependencies = [ - "windows-core", - "windows-link", -] - [[package]] name = "windows-result" version = "0.4.1" @@ -3249,15 +2340,6 @@ dependencies = [ "windows_x86_64_msvc", ] -[[package]] -name = "windows-threading" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" -dependencies = [ - "windows-link", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" @@ -3355,23 +2437,3 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/README.org b/README.org index bc616b5..ee48193 100644 --- a/README.org +++ b/README.org @@ -1,9 +1,28 @@ -#+title: Readme +#+title: reView -Based on [[https://github.com/rien/reStream][reStream]] +Live stream and take snapshots of the contents of your [[https://remarkable.com/][reMarkable tablet]]. +Based on [[https://github.com/rien/reStream][reStream]]. + +#+BEGIN_HTML +

+ + + + + + + + + +

+#+END_HTML Please note that this project is still under heavy development. -If you run this program, anyone on your network could connect to your reMarkable and stream the contents of your screen. +The server will open a port (6680 per default) on your reMarkable tablet. +It authorizes incoming connections based via SSH. +I am not a cybersecurity expert, please DON'T rely on the correctnes of the implementation. +Also, the content of the connection is NOT encrypted. +Refer to the SSH section. #+BEGIN_HTML

@@ -16,10 +35,13 @@ If you run this program, anyone on your network could connect to your reMarkable

#+END_HTML -* Dependencies +* Prequisites You need +- A private SSH key that was authorized by the reMarkable. + Follow [[https://remarkable.guide/guide/access/ssh.html#ssh-access][this]] manual. + - Gstreamer - Gstreamer Plugins Base - Gstreamer Plugins Good @@ -40,7 +62,7 @@ sudo zypper install gstreamer gstreamer-plugins-base gstreamer-plugins-good ** Server -The must be running. +The server must be running. To install it, first build (see later in this document) and then copy it to your reMarkable. @@ -64,8 +86,6 @@ TODO: Install it as service Options for the client can be set as command line options or environment variables. Command line options override the environment variables. -Values with no default value in their description have to be set (for example =--ssh-key=). - *** Command Line Options #+begin_src @@ -74,8 +94,8 @@ Usage: review-client [OPTIONS] Options: --remarkable-ip IP of the reMarkable tablet (default: 10.11.99.1) --tcp-port TCP port for video stream (default: 6680) + --ssh-key Private SSH key file path. If not specified, attempting all keys in the SSH directory --framerate Framerate (default: 50) - --dark-mode Dark mode - invert colors (default: false) --show-cursor Show cursor (default: false) -h, --help Print help -V, --version Print version @@ -86,9 +106,8 @@ Options: Corresponding keys: - =REMARKABLE_IP= - =REMARKABLE_TCP_PORT= -# - =REMARKABLE_SSH_KEY_PATH= +- =REMARKABLE_SSH_KEY_PATH= - =REMARKABLE_FRAMERATE= -- =REMARKABLE_DARK_MODE= - =REMARKABLE_SHOW_CURSOR= * Building @@ -125,3 +144,16 @@ dagger call build-server --source . export --path review-server.arm.static sudo zypper in gstreamer-devel gstreamer-plugins-base-devel #+end_src +* SSH + +SSH is only used for authorization, not encryption. + +** Authentification + +1. The server send a randomly generated 128 byte authorization token to the client. +2. The client signs this token with either the explicitly specified private SSH key, + or all the private SSH keys in the default SSH directory (=~/.ssh=). + Then it sends the signatures to the server. +3. The server verifies each one of the signatures with each authorized keys in the default authorized keys file (=/home/root/.ssh/authorized_keys=), until one of the authorized keys matches the signature. + +You can explicitly set the private SSH key to be used via a command line option or an environment variable. diff --git a/client/Cargo.toml b/client/Cargo.toml index 10d0a10..d50e637 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -7,10 +7,8 @@ edition = "2024" [dependencies] tokio = { version = "1.49.0", features = ["macros", "net", "rt-multi-thread"] } -async-ssh2-tokio = "0.12.1" clap = { version = "4.5", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.149" anyhow = "1.0" itertools = "0.14.0" tracing = "0.1.44" @@ -23,4 +21,6 @@ lz4_flex = "0.12.0" tokio-util = { version = "0.7.18", features = ["io", "io-util", "codec"] } review-server = { path = "../server" } futures = "0.3.31" +ssh-key = { version = "0.6.7", features = ["p256", "p384", "p521", "dsa", "ed25519", "rsa", "serde"] } +ssh-encoding = { version = "0.2.0", features = ["bytes"] } bson = { version = "3.1.0", features = ["serde"] } diff --git a/client/src/config.rs b/client/src/config.rs index 9365a5f..64cff55 100644 --- a/client/src/config.rs +++ b/client/src/config.rs @@ -1,10 +1,14 @@ -use std::env::{self, VarError}; +use std::{ + env::{self, VarError}, + path::PathBuf, + str::FromStr, +}; use anyhow::{Context, Error}; use clap::Parser; +use tracing::trace; const DEFAULT_IP: &str = "10.11.99.1"; -const DEFAULT_SSH_PORT: u16 = 22; const DEFAULT_TCP_PORT: u16 = 6680; const DEFAULT_FRAMERATE: f32 = 50.; @@ -20,18 +24,17 @@ pub struct CliOptions { #[arg(long, name = "tcp-port")] tcp_port: Option, - /* - /// Private SSH key file path + /// Private SSH key file path. If not specified, attempting all keys in the SSH directory #[arg(long, name = "ssh-key")] ssh_key: Option, - */ + /// Framerate (default: 50) #[arg(long, name = "framerate")] framerate: Option, /// Dark mode - invert colors (default: false) - #[arg(long, name = "dark-mode")] - dark_mode: bool, + //#[arg(long, name = "dark-mode")] + //dark_mode: bool, /// Show cursor (default: false) #[arg(long, name = "show-cursor")] @@ -41,8 +44,9 @@ pub struct CliOptions { #[derive(Debug, Clone)] pub struct ClientOptions { pub remarkable_ip: String, - //pub ssh_key: PathBuf, - pub dark_mode: bool, + pub ssh_key: Option, + // TODO: implement dark mode + // pub dark_mode: bool, pub tcp_port: u16, pub show_cursor: bool, pub framerate: f32, @@ -56,7 +60,6 @@ impl From for ClientOptions { "REMARKABLE_IP", DEFAULT_IP.to_string(), ), - //ssh_key: must_resolve_option(value.ssh_key, "REMARKABLE_SSH_KEY_PATH"), tcp_port: resolve_with( value.tcp_port, "REMARKABLE_TCP_PORT", @@ -67,6 +70,9 @@ impl From for ClientOptions { }, DEFAULT_TCP_PORT, ), + ssh_key: resolve_with_optional(value.ssh_key, "REMARKABLE_SSH_KEY_PATH", |string| { + PathBuf::from_str(&string).context("could not parse path of private SSH key") + }), framerate: resolve_with( value.framerate, "REMARKABLE_FRAMERATE", @@ -77,7 +83,7 @@ impl From for ClientOptions { }, DEFAULT_FRAMERATE, ), - dark_mode: resolve_boolean_option(value.dark_mode, "REMARKABLE_DARK_MODE", false), + //dark_mode: resolve_boolean_option(value.dark_mode, "REMARKABLE_DARK_MODE", false), show_cursor: resolve_boolean_option(value.show_cursor, "REMARKABLE_SHOW_CURSOR", false), } } @@ -92,10 +98,6 @@ fn resolve_option>(cli_value: Option, variable_name: &str, de ) } -fn must_resolve_option>(cli_value: Option, variable_name: &str) -> T { - must_resolve_with(cli_value, variable_name, |env_value| Ok(env_value.into())) -} - fn resolve_boolean_option(cli_value: bool, variable_name: &str, default: bool) -> bool { let cli_value = if cli_value { Some(true) } else { None }; resolve_with( @@ -131,31 +133,40 @@ fn resolve_with( return default; } - parse(env_string.expect(&format!( - "could not get environment varialbe '{}'", - variable_name, - ))) - .expect(&format!( - "could not parse environemt variable '{}'", - variable_name, - )) + trace!( + "read environment variable '{}': {:?}", + variable_name, env_string, + ); + parse( + env_string + .unwrap_or_else(|_| panic!("could not get environment varialbe '{}'", variable_name)), + ) + .unwrap_or_else(|_| panic!("could not parse environemt variable '{}'", variable_name)) } -fn must_resolve_with( +fn resolve_with_optional( cli_value: Option, variable_name: &str, parse: impl FnOnce(String) -> Result, -) -> T { +) -> Option { if let Some(cli_value) = cli_value { - return cli_value; + return Some(cli_value); } - let env_string = env::var(variable_name).expect(&format!( - "could not get environment varialbe '{}'", - variable_name, - )); - parse(env_string).expect(&format!( - "could not parse environemt variable '{}'", - variable_name, - )) + let env_string = env::var(variable_name); + if let Ok(env_string) = env_string { + if env_string.is_empty() { + return None; + } + + trace!( + "read environment variable '{}': {}", + variable_name, env_string, + ); + return Some(parse(env_string).unwrap_or_else(|_| { + panic!("could not parse environemt variable '{}'", variable_name) + })); + } + + None } diff --git a/client/src/connection/mod.rs b/client/src/connection/mod.rs index a30afb2..7620644 100644 --- a/client/src/connection/mod.rs +++ b/client/src/connection/mod.rs @@ -1,13 +1,20 @@ +mod ssh; pub mod video; +use std::any::type_name; + use anyhow::{Context, Error}; use futures::{SinkExt, StreamExt}; use review_server::{ config::{StreamConfig, device::DeviceConfig}, version::VersionInfo, }; +use serde::{Serialize, de::DeserializeOwned}; use tokio::net::TcpStream; -use tokio_util::codec::{Framed, LengthDelimitedCodec}; +use tokio_util::{ + bytes::{Bytes, BytesMut}, + codec::{Framed, LengthDelimitedCodec}, +}; use tracing::info; use crate::config::ClientOptions; @@ -22,38 +29,103 @@ impl Connection { info!("setting up TCP connection"); let stream = TcpStream::connect(format!( "{}:{}", - client_options.remarkable_ip, client_options.tcp_port + client_options.remarkable_ip, client_options.tcp_port, )) .await .context("could not connect to TCP stream")?; + stream.set_nodelay(true).context("could not set nodelay")?; + let framed = Framed::new(stream, LengthDelimitedCodec::new()); Ok(Connection { framed }) } - pub async fn receive_version_info(&mut self) -> Result { + pub async fn initialize_communication( + &mut self, + client_options: ClientOptions, + ) -> Result { + self.authenticate(client_options.clone()) + .await + .context("error while authenticating")?; + + let version_info: VersionInfo = self + .receive() + .await + .context("could not receive version info")?; + + info!("received version information: {}", version_info); + + let device_config = DeviceConfig::new(version_info).context(format!( + "could not get device configuration for version {}", + version_info, + ))?; + + let stream_config = StreamConfig { + device_config: device_config.clone(), + framerate: client_options.framerate, + show_cursor: client_options.show_cursor, + }; + + info!("sending out stream config {:?}", &stream_config); + + self.send(&stream_config) + .await + .context("could not send device config")?; + + Ok(device_config) + } + + async fn receive(&mut self) -> Result { let msg = self .framed .next() .await - .context("connection was dropped before version info was communicated")? - .context("could not receive version info message")?; + .context(format!( + "connection closed before message of type {} was received", + type_name::(), + ))? + .context(format!( + "could not receive message of type {}", + type_name::() + ))?; + + let stream_config = bson::deserialize_from_slice(&msg).context(format!( + "could not deserialize message of type {}", + type_name::(), + ))?; - let version_info = - bson::deserialize_from_slice(&msg).context("could not deserialize version info")?; + Ok(stream_config) + } - Ok(version_info) + async fn receive_raw(&mut self) -> Result { + self.framed + .next() + .await + .context("connection closed before raw message was received".to_string())? + .context("could not receive raw message".to_string()) } - pub async fn send_stream_config(&mut self, stream_config: StreamConfig) -> Result<(), Error> { - let msg = - bson::serialize_to_vec(&stream_config).context("could not serialize stream config")?; + async fn send(&mut self, value: &T) -> Result<(), Error> { + let msg = bson::serialize_to_vec(value) + .context(format!("could not serialize type {}", type_name::()))?; self.framed .send(msg.into()) .await - .context("could not send stream config") + .context(format!( + "could not send serialized message of type {}", + type_name::() + )) + .map(|_| ()) + } + + #[allow(unused)] + async fn send_raw(&mut self, msg: Bytes) -> Result<(), Error> { + self.framed + .send(msg) + .await + .context("could not send raw message".to_string()) .map(|_| ()) } } diff --git a/client/src/connection/ssh/keys.rs b/client/src/connection/ssh/keys.rs new file mode 100644 index 0000000..ad01885 --- /dev/null +++ b/client/src/connection/ssh/keys.rs @@ -0,0 +1,84 @@ +use std::{env::home_dir, fs::read_to_string, path::PathBuf}; + +use anyhow::{Context, Error, anyhow}; +use ssh_key::PrivateKey; +use tracing::{debug, trace, warn}; + +pub fn get_keys_to_check(private_key_path: &Option) -> Result, Error> { + if let Some(private_key_path) = private_key_path { + debug!( + "private key at {} explicitly defined, only loading this key", + private_key_path.to_string_lossy() + ); + return Ok(vec![ + load_private_key(private_key_path) + .context("could not load explicitly specified private SSH key")?, + ]); + } + debug!("no private key explicitly defined, loading keys from .ssh directory"); + + let ssh_directory = home_dir() + .context("could not get home directory")? + .join(".ssh"); + + if !ssh_directory.exists() || ssh_directory.is_file() { + return Err(anyhow!( + "SSH directory '{}' does not exist or is a file", + ssh_directory.to_string_lossy() + )); + } + + let dir_entries = ssh_directory + .read_dir() + .context("could not read the SSH directory")?; + + Ok(dir_entries + .filter_map(|entry| entry.ok()) + .filter_map(|entry| { + let name = entry.file_name(); + let name = name.to_str()?; + let path = ssh_directory.join(name); + + trace!( + "attemting to parse {} as a private SSH key", + path.to_string_lossy() + ); + let private_key = load_private_key(&path) + .map_err(|err| { + let filename = path.file_name()?.to_string_lossy(); + if !(path.ends_with(".pub") + || &filename == "known_hosts" + || &filename == "authorized_keys") + { + warn!( + "could not load private key {}: {:?}", + path.to_string_lossy(), + err, + ) + }; + + Some(()) + }) + .ok()?; + trace!( + "successfully parsed {} as a private SSH key", + path.to_string_lossy() + ); + + Some(private_key) + }) + .collect()) +} + +fn load_private_key(path: &PathBuf) -> Result { + let content = read_to_string(path).context(format!( + "could not read private SSH key file {}", + path.to_string_lossy() + ))?; + let key = PrivateKey::from_openssh(content).context(format!( + "could not parse private key from file {}", + path.to_string_lossy() + ))?; + + Ok(key) +} diff --git a/client/src/connection/ssh/mod.rs b/client/src/connection/ssh/mod.rs new file mode 100644 index 0000000..e73f136 --- /dev/null +++ b/client/src/connection/ssh/mod.rs @@ -0,0 +1,85 @@ +mod keys; + +use anyhow::{Context, Error, anyhow}; +use itertools::Itertools; +use review_server::connection::ssh::{ + AuthentificationToken, AuthorizedPublicKey, SIGNATURE_NAMESPACE, Signatures, +}; +use ssh_key::{HashAlg, PrivateKey}; +use tracing::{info, warn}; + +use super::Connection; +use crate::config::ClientOptions; +use keys::get_keys_to_check; + +impl Connection { + pub async fn authenticate(&mut self, client_options: ClientOptions) -> Result<(), Error> { + let token: AuthentificationToken = self + .receive() + .await + .context("could not receive authentification token")?; + + let keys_to_check = get_keys_to_check(&client_options.ssh_key) + .context("could not get private keys to check")?; + info!("found {} private SSH keys to check", keys_to_check.len()); + + let priv_key = self + .find_authorized_key(keys_to_check, token.token) + .await + .context("could not find an authorized private key")?; + + info!( + "the private SSH key '{}' with algorithm '{:?}' is authorized", + priv_key.comment(), + priv_key.algorithm(), + ); + + Ok(()) + } + + async fn find_authorized_key( + &mut self, + keys_to_check: Vec, + token: Vec, + ) -> Result { + if keys_to_check.is_empty() { + return Err(anyhow!("no private SSH keys to authenticate with")); + } + + let signatures = keys_to_check + .iter() + .filter_map(|priv_key| { + match priv_key.sign(SIGNATURE_NAMESPACE, HashAlg::Sha512, &token) { + Ok(signature) => Some(signature), + Err(err) => { + warn!( + "private key '{}' could not sign authentification token: {:?}", + priv_key.comment(), + err, + ); + None + } + } + }) + .collect_vec(); + + if signatures.is_empty() { + return Err(anyhow!( + "none of the private SSH keys could sign the authentification token", + )); + } + + let signatures: Signatures = signatures.try_into()?; + + self.send(&signatures) + .await + .context("could not send over all public keys to check")?; + + let authorized_key: AuthorizedPublicKey = self + .receive() + .await + .context("could not receive authorized key index")?; + + Ok(keys_to_check[authorized_key.index].clone()) + } +} diff --git a/client/src/connection/video.rs b/client/src/connection/video.rs index f16cf57..b16e2e8 100644 --- a/client/src/connection/video.rs +++ b/client/src/connection/video.rs @@ -1,7 +1,6 @@ use anyhow::{Context, Error}; -use futures::stream::StreamExt; use lz4_flex::decompress_size_prepended; -use tracing::debug; +use tracing::trace; use crate::display::Display; @@ -23,17 +22,15 @@ impl VideoConnection { pub async fn run(&mut self) -> Result<(), Error> { loop { - debug!("attempting to read data from TCP stream"); + trace!("attempting to read data from TCP stream"); let compressed_frame = self .conn - .framed - .next() + .receive_raw() .await - .context("TCP stream was closed")? - .context("could not read from TCP stream")?; + .context("could not reveive next frame")?; - debug!( + trace!( "read one compressed frame from TCP stream ({} bytes)", compressed_frame.len(), ); @@ -41,7 +38,7 @@ impl VideoConnection { let frame = decompress_size_prepended(&compressed_frame) .context("could not decompress received frame")?; - debug!("decompressed: {} bytes", frame.len()); + trace!("decompressed: {} bytes", frame.len()); self.display .push_frame(frame) diff --git a/client/src/display/mod.rs b/client/src/display/mod.rs index 67e06b7..d28bfd1 100644 --- a/client/src/display/mod.rs +++ b/client/src/display/mod.rs @@ -1,18 +1,14 @@ -use super::config::*; - -use std::{io::Read as _, thread::sleep, time::Duration}; - use anyhow::{Context, Error}; use gstreamer_app::AppSrc; use gstreamer_video::VideoFormat; use review_server::config::device::{PixelFormat, VideoConfig}; -use tracing::{debug, info}; use gstreamer::{Pipeline, prelude::*}; #[derive(Debug)] pub struct Display { - pipeline: Pipeline, + #[allow(unused)] + pipeline: Pipeline, // only for keeping alive (TODO: check if realy needed) appsrc: AppSrc, } diff --git a/client/src/main.rs b/client/src/main.rs index 3a646d2..127f7c5 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -6,7 +6,6 @@ use anyhow::{Context, Error}; use clap::Parser; use config::{CliOptions, ClientOptions}; use connection::{Connection, video::VideoConnection}; -use review_server::config::{StreamConfig, device::DeviceConfig}; use tracing::{debug, info}; #[tokio::main] @@ -27,29 +26,10 @@ async fn main() -> Result<(), Error> { .await .context("could not initialize TCP connection")?; - let version_info = conn - .receive_version_info() + let device_config = conn + .initialize_communication(client_options.clone()) .await - .context("could not receive version info")?; - - info!("received version information: {}", version_info); - - let device_config = DeviceConfig::new(version_info).context(format!( - "could not get device configuration for version {}", - version_info, - ))?; - - let stream_config = StreamConfig { - device_config: device_config.clone(), - framerate: client_options.framerate, - show_cursor: client_options.show_cursor, - }; - - info!("sending out stream config {:?}", &stream_config); - - conn.send_stream_config(stream_config) - .await - .context("could not send device config")?; + .context("error during initializing the communication")?; let mut video_connection = VideoConnection::new(conn, device_config.video_config) .context("could not initialize video connection")?; diff --git a/dagger/main.go b/dagger/main.go index 43d4265..a3593ea 100644 --- a/dagger/main.go +++ b/dagger/main.go @@ -31,6 +31,12 @@ func (m *ReView) CheckAndTestAll(ctx context.Context, source *dagger.Directory) } output = output + "\n\n" + o + o, err = linuxContainer(source).WithExec([]string{"cargo", "clippy", "--", "-D", "warnings"}).Stdout(ctx) + if err != nil { + return o, err + } + output = output + "\n\n" + o + return "ok", nil } @@ -51,6 +57,9 @@ func linuxContainer(source *dagger.Directory) *dagger.Container { return dag.Container(). From("rust:"+RustVersion+"-trixie"). WithExec([]string{"apt", "update"}). + WithExec([]string{ + "rustup", "component", "add", "clippy", + }). WithExec([]string{ "apt", "install", "-y", "libgstreamer1.0-dev", diff --git a/server/Cargo.toml b/server/Cargo.toml index f8f711b..7955e7d 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,6 @@ tokio = { version = "1.49.0", features = ["macros", "net", "rt-multi-thread", "t libremarkable = { version = "0.7", features = ["input"], default-features = false } clap = { version = "4.5", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.149" anyhow = "1.0" tracing = "0.1.44" tracing-subscriber = "0.3.22" @@ -18,6 +17,9 @@ test-log = { version = "0.2.19", features = ["trace"] } lz4_flex = { version = "0.12.0", features = ["frame"] } tokio-util = { version = "0.7.18", features = ["codec"] } futures = "0.3.31" -bson = { version = "3.1.0", features = ["serde"] } procfs = "0.18.0" itertools = "0.14.0" +ssh-key = { version = "0.6.7", features = ["p256", "p384", "p521", "dsa", "ed25519", "rsa", "serde", "std"] } +ssh-encoding = { version = "0.2.0", features = ["bytes"] } +rand = "0.9.2" +bson = { version = "3.1.0", features = ["serde"] } diff --git a/server/src/config/device.rs b/server/src/config/device.rs index 3259678..7bae551 100644 --- a/server/src/config/device.rs +++ b/server/src/config/device.rs @@ -52,6 +52,7 @@ pub struct DeviceConfig { } impl DeviceConfig { + #[allow(unused)] pub fn new(version_info: VersionInfo) -> Result { let height = 1872; let width = 1404; diff --git a/server/src/connection/mod.rs b/server/src/connection/mod.rs index f5504a5..b892c12 100644 --- a/server/src/connection/mod.rs +++ b/server/src/connection/mod.rs @@ -1,9 +1,15 @@ +pub mod ssh; pub mod video; +use std::any::type_name; + use anyhow::{Context, Error}; use futures::{StreamExt, sink::SinkExt}; +use serde::{Serialize, de::DeserializeOwned}; use tokio::net::TcpStream; +use tokio_util::bytes::{Bytes, BytesMut}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; +use tracing::info; use crate::config::StreamConfig; use crate::version::VersionInfo; @@ -20,28 +26,85 @@ impl Connection { Connection { framed } } - pub async fn send_version_info(&mut self, version_info: VersionInfo) -> Result<(), Error> { - let msg = bson::serialize_to_vec(&version_info) - .context("could not serialize version information")?; + pub async fn initialize_communication(&mut self) -> Result { + self.authenticate() + .await + .context("error while authenticating client")?; - self.framed - .send(msg.into()) + let version_info = + VersionInfo::get_from_device().context("could not get version information")?; + + info!( + "got version information: hardware {:?}, firmware {}", + version_info.hardware, version_info.firmware, + ); + + info!("sending out version information"); + + self.send(&version_info) .await - .context("could not send serialized version information") - .map(|_| ()) + .context("could not send out version information")?; + + let stream_config: StreamConfig = self + .receive() + .await + .context("could not receive stream config")?; + + info!("received stream config {:?}", &stream_config); + + Ok(stream_config) } - pub async fn receive_stream_config(&mut self) -> Result { + async fn receive(&mut self) -> Result { let msg = self .framed .next() .await - .context("connection closed before stream configuration was sent")? - .context("could not message with stream configuration")?; + .context(format!( + "connection closed before message of type {} was received", + type_name::(), + ))? + .context(format!( + "could not receive message of type {}", + type_name::() + ))?; - let stream_config = - bson::deserialize_from_slice(&msg).context("could not deserialize stream config")?; + let stream_config = bson::deserialize_from_slice(&msg).context(format!( + "could not deserialize message of type {}", + type_name::(), + ))?; Ok(stream_config) } + + #[allow(unused)] + async fn receive_raw(&mut self) -> Result { + self.framed + .next() + .await + .context("connection closed before raw message was received".to_string())? + .context("could not receive raw message".to_string()) + } + + async fn send(&mut self, value: &T) -> Result<(), Error> { + let msg = bson::serialize_to_vec(value) + .context(format!("could not serialize type {}", type_name::()))?; + + self.framed + .send(msg.into()) + .await + .context(format!( + "could not send serialized message of type {}", + type_name::() + )) + .map(|_| ()) + } + + async fn send_raw(&mut self, msg: Bytes) -> Result<(), Error> { + self.framed + .send(msg) + .await + .context("could not send raw message".to_string()) + .map(|_| ()) + } } diff --git a/server/src/connection/ssh/mod.rs b/server/src/connection/ssh/mod.rs new file mode 100644 index 0000000..691a582 --- /dev/null +++ b/server/src/connection/ssh/mod.rs @@ -0,0 +1,147 @@ +use std::{path::PathBuf, str::FromStr}; + +use anyhow::{Context, Error}; +use rand::{Rng, SeedableRng, rngs::StdRng}; +use serde::{Deserialize, Serialize}; +use ssh_encoding::{Decode, Encode}; +use ssh_key::{AuthorizedKeys, PublicKey, SshSig, authorized_keys::Entry}; + +use super::Connection; + +pub const SIGNATURE_NAMESPACE: &str = "review"; + +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthentificationToken { + pub token: Vec, +} + +const TOKEN_SIZE: usize = 256; + +impl AuthentificationToken { + fn new() -> Self { + let mut rng = StdRng::from_os_rng(); + let token: [u8; TOKEN_SIZE] = rng.random(); + let token = token.to_vec(); + + Self { token } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Signatures { + pub encoded_signatures: Vec>, +} + +impl TryFrom> for Signatures { + type Error = Error; + + fn try_from(signatures: Vec) -> Result { + let encoded_signatures = signatures + .iter() + .map(|signature| -> Result<_, Error> { + let mut encoded_signature = vec![]; + signature + .encode(&mut encoded_signature) + .context("could not encode signature")?; + + Ok(encoded_signature) + }) + .collect::>()?; + + Ok(Self { encoded_signatures }) + } +} + +impl TryInto> for Signatures { + type Error = Error; + + fn try_into(self) -> Result, Self::Error> { + self.encoded_signatures + .iter() + .map(|signature_bytes| { + let mut signature_bytes = signature_bytes.as_slice(); + SshSig::decode(&mut signature_bytes).context("could not decode signature") + }) + .collect() + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthorizedPublicKey { + pub index: usize, +} + +impl Connection { + pub async fn authenticate(&mut self) -> Result { + let token = AuthentificationToken::new(); + self.send(&token) + .await + .context("could not send authentification token to client")?; + + let pub_key = self + .find_authorized_key(&token) + .await + .context("could not find an authorized key")?; + + Ok(pub_key) + } + + async fn find_authorized_key( + &mut self, + token: &AuthentificationToken, + ) -> Result { + let authorized_keys = get_authorized_keys().context("could not get authorized keys")?; + + let signatures: Signatures = self + .receive() + .await + .context("could not receive public keys")?; + let signatures: Vec = signatures.try_into()?; + + let (authorized_key_index, pub_key) = signatures + .iter() + .enumerate() + .filter_map(|(index, signature)| { + get_authorized_key_matching_signature(token, signature, &authorized_keys) + .map(|pub_key| (index, pub_key)) + }) + .next() + .context("none of the provided public keys is authorized")?; + + let authorized_key_message = AuthorizedPublicKey { + index: authorized_key_index, + }; + + self.send(&authorized_key_message) + .await + .context("could not send index of authorized key")?; + + Ok(pub_key) + } +} + +fn get_authorized_key_matching_signature( + token: &AuthentificationToken, + signature: &SshSig, + authorized_keys: &[Entry], +) -> Option { + authorized_keys + .iter() + .filter_map(|entry| { + let pub_key = entry.public_key(); + pub_key + .verify(SIGNATURE_NAMESPACE, &token.token, signature) + .ok() + .map(|_| pub_key) + }) + .next() + .cloned() +} + +fn get_authorized_keys() -> Result, Error> { + AuthorizedKeys::read_file( + PathBuf::from_str("/home/root/.ssh/authorized_keys") + .context("could not build path of authorized keys")?, + ) + .context("could not read authorized keys file") +} diff --git a/server/src/connection/video.rs b/server/src/connection/video.rs index dbe63d1..c466b3d 100644 --- a/server/src/connection/video.rs +++ b/server/src/connection/video.rs @@ -1,7 +1,6 @@ use std::time::Duration; use anyhow::{Context, Error}; -use futures::SinkExt; use lz4_flex::compress_prepend_size; use tokio::time::{MissedTickBehavior, interval}; use tracing::{debug, trace}; @@ -49,10 +48,9 @@ impl VideoConnection { ); self.conn - .framed - .send(encoded_buffer.into()) + .send_raw(encoded_buffer.into()) .await - .context("could not write frame to the stream")?; + .context("could not send next frame")?; debug!("wrote the data to the output stream"); } diff --git a/server/src/framebuffer/process.rs b/server/src/framebuffer/process.rs index f4e7882..8ad6126 100644 --- a/server/src/framebuffer/process.rs +++ b/server/src/framebuffer/process.rs @@ -1,9 +1,7 @@ use std::fs::File; use anyhow::{Context, Error, anyhow}; -use itertools::Itertools; use procfs::process::{MMapPath, MemoryMap, Process, all_processes}; -use tracing::trace; pub fn get_xochitl_memory_file() -> Result<(File, usize), Error> { let process = get_process().context("could not get xochitl process")?; @@ -25,7 +23,7 @@ fn get_process() -> Result { let process = processes.next().context("no xochitl process found")?; - if let Some(_) = processes.next() { + if processes.next().is_some() { return Err(anyhow!("found more than one xochitl process")); } @@ -39,18 +37,17 @@ fn get_framebuffer_offset_in_process_memory(process: &Process) -> Result Result<(), Error> { @@ -21,17 +20,9 @@ async fn main() -> Result<(), Error> { let cli_options = CliOptions::parse(); - let version_info = - VersionInfo::get_from_device().context("could not get version information")?; - - info!( - "got version information: hardware {:?}, firmware {}", - version_info.hardware, version_info.firmware, - ); - info!("setting up TCP server"); - let mut server = Server::new(cli_options, version_info) + let mut server = Server::new(cli_options) .await .context("could not create new server")?; @@ -43,19 +34,15 @@ async fn main() -> Result<(), Error> { #[derive(Debug)] pub struct Server { listener: TcpListener, - version_info: VersionInfo, } impl Server { - async fn new(cli_options: CliOptions, version_info: VersionInfo) -> Result { + async fn new(cli_options: CliOptions) -> Result { let listener = TcpListener::bind(&format!("0.0.0.0:{}", cli_options.port)) .await .context(format!("could not bind to port {}", cli_options.port))?; - Ok(Self { - listener, - version_info, - }) + Ok(Self { listener }) } async fn run(&mut self) -> Result<(), Error> { @@ -66,31 +53,24 @@ impl Server { .await .context("error while waiting for a TCP connection")?; + stream.set_nodelay(true).context("could not set nodelay")?; + info!("new connection from {}", addr); let conn = Connection::new(stream); - let version_info = self.version_info; spawn(async move { - if let Err(error) = Self::task(conn, version_info).await { - error!("connection terminated with error {}", error); + if let Err(error) = Self::task(conn).await { + error!("connection terminated with error {:?}", error); } }); } } - async fn task(mut conn: Connection, version_info: VersionInfo) -> Result<(), Error> { - info!("sending out version information"); - - conn.send_version_info(version_info) - .await - .context("could not send out version information")?; - + async fn task(mut conn: Connection) -> Result<(), Error> { let stream_config = conn - .receive_stream_config() + .initialize_communication() .await - .context("could not receive stream config")?; - - info!("received stream config {:?}", &stream_config); + .context("error during initializing the communication")?; let mut video_conn = VideoConnection::new(conn, stream_config) .context("could not initialize video connection")?; diff --git a/server/src/version/mod.rs b/server/src/version/mod.rs index 12be871..ad9c433 100644 --- a/server/src/version/mod.rs +++ b/server/src/version/mod.rs @@ -44,7 +44,7 @@ impl FromStr for HardwareVersion { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct FirmwareVersion { pub version: usize, pub major: usize, @@ -54,19 +54,25 @@ pub struct FirmwareVersion { impl PartialOrd for FirmwareVersion { fn partial_cmp(&self, other: &Self) -> Option { - match self.version.partial_cmp(&other.version) { - Some(core::cmp::Ordering::Equal) => {} + Some(self.cmp(other)) + } +} + +impl Ord for FirmwareVersion { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match self.version.cmp(&other.version) { + core::cmp::Ordering::Equal => {} ord => return ord, } - match self.major.partial_cmp(&other.major) { - Some(core::cmp::Ordering::Equal) => {} + match self.major.cmp(&other.major) { + core::cmp::Ordering::Equal => {} ord => return ord, } - match self.minor.partial_cmp(&other.minor) { - Some(core::cmp::Ordering::Equal) => {} + match self.minor.cmp(&other.minor) { + core::cmp::Ordering::Equal => {} ord => return ord, } - self.patch.partial_cmp(&other.patch) + self.patch.cmp(&other.patch) } }