From ea5fd70db43bdb972ef9626c9161264264bf467d Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 31 Jul 2024 12:14:20 +0200 Subject: [PATCH] WIP: Upgrade versions of RustCrypto to pre Signed-off-by: Wiktor Kwapisiewicz --- Cargo.lock | 876 ++++---------------------- Cargo.toml | 15 +- examples/README.md | 49 -- examples/agent-socket-info.rs | 82 --- examples/extensions.rs | 161 ----- examples/key-storage.rs | 239 ------- examples/openpgp-card-agent.rs | 292 --------- examples/pgp-wrapper.rs | 490 -------------- examples/proto-dumper.rs | 124 ---- examples/ssh-agent-client-blocking.rs | 35 - examples/ssh-agent-client.rs | 31 - fuzz/.gitignore | 4 - fuzz/Cargo.toml | 22 - fuzz/README.md | 28 - fuzz/fuzz_targets/request_decode.rs | 9 - 15 files changed, 133 insertions(+), 2324 deletions(-) delete mode 100644 examples/README.md delete mode 100644 examples/agent-socket-info.rs delete mode 100644 examples/extensions.rs delete mode 100644 examples/key-storage.rs delete mode 100644 examples/openpgp-card-agent.rs delete mode 100644 examples/pgp-wrapper.rs delete mode 100644 examples/proto-dumper.rs delete mode 100644 examples/ssh-agent-client-blocking.rs delete mode 100644 examples/ssh-agent-client.rs delete mode 100644 fuzz/.gitignore delete mode 100644 fuzz/Cargo.toml delete mode 100644 fuzz/README.md delete mode 100644 fuzz/fuzz_targets/request_decode.rs diff --git a/Cargo.lock b/Cargo.lock index 09d7ee7..d0ff5b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,41 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[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 = "aho-corasick" version = "1.1.3" @@ -125,24 +90,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" - -[[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-lock" version = "2.8.0" @@ -201,39 +148,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bitfield" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" - [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[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" @@ -244,41 +170,12 @@ dependencies = [ ] [[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blowfish" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" -dependencies = [ - "byteorder", - "cipher", -] - -[[package]] -name = "bstr" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "buffer-redux" -version = "1.0.1" +name = "block-buffer" +version = "0.11.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9f8ddd22e0a12391d1e7ada69ec3b0da1914f1cec39c5cf977143c5b2854f5" +checksum = "17092d478f4fadfb35a7e082f62e49f0907fdf048801d9d706277e34f9df8a78" dependencies = [ - "memchr", + "crypto-common 0.2.0-rc.0", ] [[package]] @@ -299,16 +196,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" -[[package]] -name = "camellia" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" -dependencies = [ - "byteorder", - "cipher", -] - [[package]] name = "card-backend" version = "0.2.0" @@ -330,34 +217,11 @@ dependencies = [ "pcsc", ] -[[package]] -name = "cast5" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" -dependencies = [ - "jobserver", - "libc", - "once_cell", -] - -[[package]] -name = "cfb-mode" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" -dependencies = [ - "cipher", -] [[package]] name = "cfg-if" @@ -381,11 +245,11 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "c71c893d5a1e8257048dbb29954d2e1f85f091a150304f1defe4ca2806da5d3f" dependencies = [ - "crypto-common", + "crypto-common 0.2.0-rc.0", "inout", ] @@ -429,17 +293,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" -[[package]] -name = "cmac" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" -dependencies = [ - "cipher", - "dbl", - "digest", -] - [[package]] name = "colorchoice" version = "1.0.1" @@ -452,6 +305,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adcf94f05e094fca3005698822ec791cb4433ced416afda1c5ca3b8dfc05a2f" + [[package]] name = "const-str" version = "0.5.7" @@ -473,28 +332,14 @@ dependencies = [ "libc", ] -[[package]] -name = "crc24" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.6.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "e43027691f1c055da3da4f7d96af09fcec420d435d5616e51f29afd0811c56a7" dependencies = [ - "generic-array", + "hybrid-array", + "num-traits", "rand_core", "subtle", "zeroize", @@ -507,150 +352,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "darling" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "dbl" -version = "0.3.2" +name = "crypto-common" +version = "0.2.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" +checksum = "8c070b79a496dccd931229780ad5bbedd535ceff6c3565605a8e440e18e1aa2b" dependencies = [ - "generic-array", + "getrandom", + "hybrid-array", + "rand_core", ] [[package]] name = "der" -version = "0.7.9" +version = "0.8.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "05d9c07d3bd80cf0935ce478d07edf7e7a5b158446757f988f3e62082227b700" dependencies = [ - "const-oid", + "const-oid 0.10.0-rc.0", "pem-rfc7468", "zeroize", ] [[package]] -name = "derive_builder" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" -dependencies = [ - "derive_builder_core", - "syn", -] - -[[package]] -name = "des" -version = "0.8.1" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "cipher", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", ] [[package]] name = "digest" -version = "0.10.7" +version = "0.11.0-pre.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "cf2e3d6615d99707295a9673e889bf363a04b2a466bd320c65a72536f7577379" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.11.0-rc.0", + "const-oid 0.10.0-rc.0", + "crypto-common 0.2.0-rc.0", "subtle", ] @@ -660,86 +406,32 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" -[[package]] -name = "dsa" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" -dependencies = [ - "digest", - "num-bigint-dig", - "num-traits", - "pkcs8", - "rfc6979", - "sha2", - "signature", - "zeroize", -] - -[[package]] -name = "eax" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" -dependencies = [ - "aead", - "cipher", - "cmac", - "ctr", - "subtle", -] - [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.17.0-pre.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "fad051af2b2d2f356d716138c76775929be913deb5b4ea217cd2613535936bef" dependencies = [ "der", - "digest", + "digest 0.11.0-pre.9", "elliptic-curve", "rfc6979", "signature", "spki", ] -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2", - "subtle", - "zeroize", -] - [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.14.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "4ed8e96bb573517f42470775f8ef1b9cd7595de52ba7a8e19c48325a92c8fe4f" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.11.0-pre.9", "ff", - "generic-array", "group", - "hkdf", + "hybrid-array", "pem-rfc7468", "pkcs8", "rand_core", @@ -793,28 +485,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -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 = "futures" version = "0.3.30" @@ -918,7 +588,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -932,16 +601,6 @@ dependencies = [ "wasi", ] -[[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 = "gimli" version = "0.29.0" @@ -983,12 +642,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[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" @@ -1001,22 +654,13 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5491a308e0214554f07a81d8944abe45f552871c12e3c3c6e7e5d354039a6c4c" -[[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" +version = "0.13.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "e4b1fb14e4df79f9406b434b60acef9f45c26c50062cccf1346c6103b8c47d58" dependencies = [ - "digest", + "digest 0.11.0-pre.9", ] [[package]] @@ -1025,6 +669,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hybrid-array" +version = "0.2.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d306b679262030ad8813a82d4915fc04efff97776e4db7f8eb5137039d56400" +dependencies = [ + "typenum", + "zeroize", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1048,21 +702,6 @@ dependencies = [ "cc", ] -[[package]] -name = "idea" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" -dependencies = [ - "cipher", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "indexmap" version = "2.2.6" @@ -1075,11 +714,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.3" +version = "0.2.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "bbc33218cf9ce7b927426ee4ad3501bcc5d8c26bf5fb4a82849a083715aca427" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -1110,21 +749,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "iter-read" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a598c1abae8e3456ebda517868b254b6bc2a9bb6501ffd5b9d0875bf332e048b" - -[[package]] -name = "jobserver" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.69" @@ -1134,29 +758,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1172,17 +773,6 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -[[package]] -name = "libfuzzer-sys" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] - [[package]] name = "libm" version = "0.2.8" @@ -1195,16 +785,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1260,7 +840,6 @@ dependencies = [ "num-iter", "num-traits", "rand", - "serde", "smallvec", "zeroize", ] @@ -1305,27 +884,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_enum" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "object" version = "0.36.0" @@ -1335,30 +893,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "ocb3" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" -dependencies = [ - "aead", - "cipher", - "ctr", - "subtle", -] - [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openpgp-card" version = "0.5.0" @@ -1371,57 +911,46 @@ dependencies = [ "log", "nom", "secrecy", - "sha2", + "sha2 0.10.8", "thiserror", ] [[package]] name = "p256" -version = "0.13.2" +version = "0.14.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +checksum = "2c32c18a74d9dda1314d2f945fb3e274848822f63f264a9e4d3f783e29b3bc1f" dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.11.0-pre.4", ] [[package]] name = "p384" -version = "0.13.0" +version = "0.14.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +checksum = "99acc40dbfad9cc3dc102828f5678c8ca14f0cbf3a1f56f74c2875b5a84427af" dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.11.0-pre.4", ] [[package]] name = "p521" -version = "0.13.3" +version = "0.14.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +checksum = "9ec5d919bea930a34a522bb1c95a89f559925deab255db2c2ffa174fc48df664" dependencies = [ "base16ct", "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "rand_core", - "sha2", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core", - "subtle", + "sha2 0.11.0-pre.4", ] [[package]] @@ -1445,77 +974,13 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "b6c1cde4770761bf6bd336f947b9ac1fe700b0a4ec5867cf66cf08597fe89e8c" dependencies = [ "base64ct", ] -[[package]] -name = "pgp" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212202dc6341bc0efef0f70843c695ec45491d924c6310ccf1078c437d1a713d" -dependencies = [ - "aes", - "aes-gcm", - "argon2", - "base64", - "bitfield", - "block-padding", - "blowfish", - "bstr", - "buffer-redux", - "byteorder", - "camellia", - "cast5", - "cfb-mode", - "chrono", - "cipher", - "const-oid", - "crc24", - "curve25519-dalek", - "derive_builder", - "des", - "digest", - "dsa", - "eax", - "ecdsa", - "ed25519-dalek", - "elliptic-curve", - "flate2", - "generic-array", - "hex", - "hkdf", - "idea", - "iter-read", - "k256", - "log", - "md-5", - "nom", - "num-bigint-dig", - "num-traits", - "num_enum", - "ocb3", - "p256", - "p384", - "p521", - "rand", - "ripemd", - "rsa", - "sha1", - "sha1-checked", - "sha2", - "sha3", - "signature", - "smallvec", - "thiserror", - "twofish", - "x25519-dalek", - "zeroize", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1530,9 +995,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs1" -version = "0.7.5" +version = "0.8.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +checksum = "0d2f4c73d459a85331915baebd5082dce5ee8ef16fd9a1ca75559ac91e66a9ee" dependencies = [ "der", "pkcs8", @@ -1541,9 +1006,9 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.10.2" +version = "0.11.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "66180445f1dce533620a7743467ef85fe1c5e80cdaf7c7053609d7a2fbcdae20" dependencies = [ "der", "spki", @@ -1555,29 +1020,23 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[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 = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primefield" +version = "0.14.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3f2ce0fa9cccdaf216230d151ce51a15298aef50ad76081a830128ecbc6428a" + [[package]] name = "primeorder" -version = "0.13.6" +version = "0.14.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "9bed0c431186675ad845922b903d28c7faa2b634a6d130fb7b50bb289f5a4d52" dependencies = [ "elliptic-curve", ] @@ -1703,39 +1162,30 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.4.0" +version = "0.5.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "871ee76a3eee98b0f805e5d1caf26929f4565073c580c053a55f886fc15dea49" dependencies = [ "hmac", "subtle", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - [[package]] name = "rsa" -version = "0.9.6" +version = "0.10.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "57e864e43f5d003321ab452feea6450f9611d7be6726489b4ec051da34774c62" dependencies = [ - "const-oid", - "digest", + "const-oid 0.10.0-rc.0", + "digest 0.11.0-pre.9", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", "rand_core", - "sha1", - "sha2", + "sha1 0.11.0-pre.4", + "sha2 0.11.0-pre.4", "signature", "spki", "subtle", @@ -1789,13 +1239,13 @@ dependencies = [ [[package]] name = "sec1" -version = "0.7.3" +version = "0.8.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "32c98827dc6ed0ea1707286a3d14b4ad4e25e2643169cbf111568a46ff5b09f5" dependencies = [ "base16ct", "der", - "generic-array", + "hybrid-array", "pkcs8", "subtle", "zeroize", @@ -1816,26 +1266,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -[[package]] -name = "serde" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "service-binding" version = "3.0.0" @@ -1853,17 +1283,18 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] -name = "sha1-checked" -version = "0.10.0" +name = "sha1" +version = "0.11.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +checksum = "9540978cef7a8498211c1b1c14e5ce920fe5bd524ea84f4a3d72d4602515ae93" dependencies = [ - "digest", - "sha1", + "cfg-if", + "cpufeatures", + "digest 0.11.0-pre.9", ] [[package]] @@ -1874,26 +1305,27 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] -name = "sha3" -version = "0.10.8" +name = "sha2" +version = "0.11.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "540c0893cce56cdbcfebcec191ec8e0f470dd1889b6e7a0b503e310a94a168f5" dependencies = [ - "digest", - "keccak", + "cfg-if", + "cpufeatures", + "digest 0.11.0-pre.9", ] [[package]] name = "signature" -version = "2.2.0" +version = "2.3.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "054d71959c7051b9042c26af337f05cc930575ed2604d7d3ced3158383e59734" dependencies = [ - "digest", + "digest 0.11.0-pre.9", "rand_core", ] @@ -1930,9 +1362,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.7.3" +version = "0.8.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "ee3fb1c675852398475928637b3ebbdd7e1d0cc24d27b3bbc81788b4eb51e310" dependencies = [ "base64ct", "der", @@ -1955,14 +1387,13 @@ dependencies = [ "log", "openpgp-card", "p256", - "pgp", "rand", "retainer", "rsa", "rstest", "secrecy", "service-binding", - "sha1", + "sha1 0.10.6", "signature", "ssh-encoding", "ssh-key", @@ -1973,20 +1404,11 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "ssh-agent-lib-fuzz" -version = "0.0.0" -dependencies = [ - "libfuzzer-sys", - "ssh-agent-lib", - "ssh-encoding", -] - [[package]] name = "ssh-cipher" -version = "0.2.0" +version = "0.3.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +checksum = "4fb72d294fa54bbbce8c75185b5df6c91739a74b7db8a248a095aa00d93f19d0" dependencies = [ "cipher", "ssh-encoding", @@ -1994,22 +1416,21 @@ dependencies = [ [[package]] name = "ssh-encoding" -version = "0.2.0" +version = "0.3.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +checksum = "2b8db6c412940e90b3ba0900d6ea997483044cb534649541b681d3bcfb4a13e6" dependencies = [ "base64ct", "pem-rfc7468", - "sha2", + "sha2 0.11.0-pre.4", ] [[package]] name = "ssh-key" -version = "0.6.6" +version = "0.7.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9b366a80cf18bb6406f4cf4d10aebfb46140a8c0c33f666a144c5c76ecbafc" +checksum = "8b74bf76aa566fdddede93c19e6ad286d123151058a6239d865a0dd87d5a4ca0" dependencies = [ - "ed25519-dalek", "num-bigint-dig", "p256", "p384", @@ -2017,7 +1438,7 @@ dependencies = [ "rand_core", "rsa", "sec1", - "sha2", + "sha2 0.11.0-pre.4", "signature", "ssh-cipher", "ssh-encoding", @@ -2033,9 +1454,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2131,15 +1552,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "twofish" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" -dependencies = [ - "cipher", -] - [[package]] name = "typenum" version = "1.17.0" @@ -2152,16 +1564,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[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.9.0" @@ -2425,34 +1827,8 @@ dependencies = [ "memchr", ] -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index 0bc9150..52c4c7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ categories = ["authentication", "cryptography", "encoding", "network-programming exclude = [".github"] [workspace] -members = [".", "fuzz"] +members = ["."] [dependencies] byteorder = "1" @@ -26,11 +26,11 @@ log = { version = "0.4", optional = true } tokio = { version = "1", optional = true, features = ["rt", "net", "time"] } tokio-util = { version = "0.7", optional = true, features = ["codec"] } service-binding = { version = "^3" } -ssh-encoding = { version = "0.2" } -ssh-key = { version = "0.6", features = ["crypto", "alloc"] } +ssh-encoding = { version = "0.3.0-pre.0" } +ssh-key = { version = "0.7.0-pre.0", features = ["crypto", "alloc"] } thiserror = "1" subtle = { version = "2", default-features = false } -signature = { version = "2", features = ["alloc"] } +signature = { version = "2.3.0-pre.4", features = ["alloc"] } secrecy = "0.8" [features] @@ -41,13 +41,13 @@ agent = ["futures", "log", "tokio", "async-trait", "codec"] [dev-dependencies] env_logger = "0.11.3" rand = "0.8.5" -rsa = { version = "0.9.6", features = ["sha2", "sha1"] } +rsa = { version = "0.10.0-pre.2", features = ["sha2", "sha1"] } tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync"] } sha1 = { version = "0.10.6", default-features = false, features = ["oid"] } testresult = "0.4.0" hex-literal = "0.4.1" -ssh-key = { version = "0.6.6", features = ["p256", "rsa"] } -p256 = { version = "0.13.2" } +ssh-key = { version = "0.7.0-pre.0", features = ["p256", "rsa"] } +p256 = { version = "0.14.0-pre.1" } const-str = "0.5.7" rstest = "0.21.0" openpgp-card = "0.5.0" @@ -55,6 +55,5 @@ card-backend-pcsc = "0.5.0" clap = { version = "4.5.7", features = ["derive"] } secrecy = "0.8.0" retainer = "0.3.0" -pgp = "0.13.0" chrono = "0.4.38" interprocess = "2.2.0" diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 3a99cd6..0000000 --- a/examples/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Agent examples - -The examples in this directory show slightly more elaborate use-cases that can be implemented using this crate. - -## Agents - -### `key-storage` - -Implements a simple agent which remembers RSA private keys (added via `ssh-add`) and allows fetching their public keys and signing using three different signing mechanisms. - -This example additionally shows how to extract extensions from messages and works on all major OSes. - -It is used in integration tests that run as part of the CI. - -### `openpgp-card-agent` - -Allows using OpenPGP Card devices to sign SSH requests. -The PIN is stored in memory and can be time-constrained using SSH constraints. -For the sake of simplicity this agent supports only `ed25519` subkeys. - -This example additionally shows how to create custom protocol based on SSH extensions (in this case decrypt/derive feature). - -### `agent-socket-info` - -Shows how to extract information about the underlying connection. -For example under Unix systems this displays connecting process PID. -To keep the example brief the data is printed as part of a fake public key comment. - -## Clients - -### `pgp-wrapper` - -Wraps SSH keys in OpenPGP data thus allowing OpenPGP applications (such as GnuPG) to read and work with SSH keys. -This makes it possible to create OpenPGP signatures utilizing SSH keys. - -If the connecting agent supports derive/decrypt extension this example additionally creates a decryption subkey and can be used to decrypt OpenPGP data. - -### `proto-dumper` - -A simple forwarding example which works as an agent and client at the same time dumping all messages and forwarding them to the next agent. - -### `ssh-agent-client` - -Dumps identities stored by the agent. -Additionally invokes an extension and reads the result. - -### `ssh-agent-client-blocking` - -Dumps identities stored by the agent using blocking (synchronous) API. diff --git a/examples/agent-socket-info.rs b/examples/agent-socket-info.rs deleted file mode 100644 index 1dc075e..0000000 --- a/examples/agent-socket-info.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! This example shows how to access the underlying socket info. -//! The socket info can be used to implement fine-grained access controls based on UID/GID. -//! -//! Run the example with: `cargo run --example agent-socket-info -- -H unix:///tmp/sock` -//! Then inspect the socket info with: `SSH_AUTH_SOCK=/tmp/sock ssh-add -L` which should display -//! something like this: -//! -//! ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA unix: addr: (unnamed) cred: UCred { pid: Some(68463), uid: 1000, gid: 1000 } - -use clap::Parser; -use service_binding::Binding; -use ssh_agent_lib::{ - agent::{bind, Agent, Session}, - error::AgentError, - proto::Identity, -}; -use ssh_key::public::KeyData; -use testresult::TestResult; - -#[derive(Debug, Default)] -struct AgentSocketInfo { - comment: String, -} - -#[ssh_agent_lib::async_trait] -impl Session for AgentSocketInfo { - async fn request_identities(&mut self) -> Result, AgentError> { - Ok(vec![Identity { - // this is just a dummy key, the comment is important - pubkey: KeyData::Ed25519(ssh_key::public::Ed25519PublicKey([0; 32])).into(), - comment: self.comment.clone(), - }]) - } -} - -#[cfg(unix)] -impl Agent for AgentSocketInfo { - fn new_session(&mut self, socket: &tokio::net::UnixStream) -> impl Session { - Self { - comment: format!( - "unix: addr: {:?} cred: {:?}", - socket.peer_addr().unwrap(), - socket.peer_cred().unwrap() - ), - } - } -} - -impl Agent for AgentSocketInfo { - fn new_session(&mut self, _socket: &tokio::net::TcpStream) -> impl Session { - Self { - comment: "tcp".into(), - } - } -} - -#[cfg(windows)] -impl Agent for AgentSocketInfo { - fn new_session( - &mut self, - _socket: &tokio::net::windows::named_pipe::NamedPipeServer, - ) -> impl Session { - Self { - comment: "pipe".into(), - } - } -} - -#[derive(Debug, Parser)] -struct Args { - #[clap(short = 'H', long)] - host: Binding, -} - -#[tokio::main] -async fn main() -> TestResult { - env_logger::init(); - - let args = Args::parse(); - bind(args.host.try_into()?, AgentSocketInfo::default()).await?; - Ok(()) -} diff --git a/examples/extensions.rs b/examples/extensions.rs deleted file mode 100644 index 89965ac..0000000 --- a/examples/extensions.rs +++ /dev/null @@ -1,161 +0,0 @@ -use ssh_agent_lib::proto::{extension::MessageExtension, Identity, ProtoError}; -use ssh_encoding::{CheckedSum, Decode, Encode, Reader, Writer}; -use ssh_key::public::KeyData; - -pub struct RequestDecryptIdentities; - -const DECRYPT_DERIVE_IDS: &str = "decrypt-derive-ids@metacode.biz"; - -impl MessageExtension for RequestDecryptIdentities { - const NAME: &'static str = DECRYPT_DERIVE_IDS; -} - -impl Encode for RequestDecryptIdentities { - fn encoded_len(&self) -> Result { - Ok(0) - } - - fn encode(&self, _writer: &mut impl Writer) -> Result<(), ssh_encoding::Error> { - Ok(()) - } -} - -impl Decode for RequestDecryptIdentities { - type Error = ProtoError; - - fn decode(_reader: &mut impl Reader) -> core::result::Result { - Ok(Self) - } -} - -#[derive(Debug)] -pub struct DecryptIdentities { - pub identities: Vec, -} - -impl MessageExtension for DecryptIdentities { - const NAME: &'static str = DECRYPT_DERIVE_IDS; -} - -impl Decode for DecryptIdentities { - type Error = ProtoError; - - fn decode(reader: &mut impl Reader) -> Result { - let len = u32::decode(reader)?; - let mut identities = vec![]; - - for _ in 0..len { - identities.push(Identity::decode(reader)?); - } - - Ok(Self { identities }) - } -} - -impl Encode for DecryptIdentities { - fn encoded_len(&self) -> ssh_encoding::Result { - let ids = &self.identities; - let mut lengths = Vec::with_capacity(1 + ids.len()); - // Prefixed length - lengths.push(4); - - for id in ids { - lengths.push(id.encoded_len()?); - } - - lengths.checked_sum() - } - - fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> { - let ids = &self.identities; - (ids.len() as u32).encode(writer)?; - for id in ids { - id.encode(writer)?; - } - Ok(()) - } -} - -const DECRYPT_DERIVE: &str = "decrypt-derive@metacode.biz"; - -#[derive(Clone, PartialEq, Debug)] -pub struct DecryptDeriveRequest { - pub pubkey: KeyData, - - pub data: Vec, - - pub flags: u32, -} - -impl MessageExtension for DecryptDeriveRequest { - const NAME: &'static str = DECRYPT_DERIVE; -} - -impl Decode for DecryptDeriveRequest { - type Error = ProtoError; - - fn decode(reader: &mut impl Reader) -> Result { - let pubkey = reader.read_prefixed(KeyData::decode)?; - let data = Vec::decode(reader)?; - let flags = u32::decode(reader)?; - - Ok(Self { - pubkey, - data, - flags, - }) - } -} - -impl Encode for DecryptDeriveRequest { - fn encoded_len(&self) -> ssh_encoding::Result { - [ - self.pubkey.encoded_len_prefixed()?, - self.data.encoded_len()?, - self.flags.encoded_len()?, - ] - .checked_sum() - } - - fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> { - self.pubkey.encode_prefixed(writer)?; - self.data.encode(writer)?; - self.flags.encode(writer)?; - - Ok(()) - } -} - -#[derive(Debug)] -pub struct DecryptDeriveResponse { - pub data: Vec, -} - -impl MessageExtension for DecryptDeriveResponse { - const NAME: &'static str = DECRYPT_DERIVE; -} - -impl Encode for DecryptDeriveResponse { - fn encoded_len(&self) -> Result { - self.data.encoded_len() - } - - fn encode(&self, writer: &mut impl Writer) -> Result<(), ssh_encoding::Error> { - self.data.encode(writer) - } -} - -impl Decode for DecryptDeriveResponse { - type Error = ProtoError; - - fn decode(reader: &mut impl Reader) -> core::result::Result { - Ok(Self { - data: Vec::decode(reader)?, - }) - } -} - -#[allow(dead_code)] // rust will complain if main is missing in example crate -fn main() { - panic!("This is just a helper lib crate for extensions"); -} diff --git a/examples/key-storage.rs b/examples/key-storage.rs deleted file mode 100644 index fba18bf..0000000 --- a/examples/key-storage.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use async_trait::async_trait; -use log::info; -use rsa::pkcs1v15::SigningKey; -use rsa::sha2::{Sha256, Sha512}; -use rsa::signature::{RandomizedSigner, SignatureEncoding}; -use sha1::Sha1; -#[cfg(windows)] -use ssh_agent_lib::agent::NamedPipeListener as Listener; -use ssh_agent_lib::agent::{listen, Session}; -use ssh_agent_lib::error::AgentError; -use ssh_agent_lib::proto::extension::{QueryResponse, RestrictDestination, SessionBind}; -use ssh_agent_lib::proto::{ - message, signature, AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, Extension, - KeyConstraint, PrivateCredential, RemoveIdentity, SignRequest, SmartcardKey, -}; -use ssh_key::{ - private::{KeypairData, PrivateKey}, - public::PublicKey, - Algorithm, Signature, -}; -#[cfg(not(windows))] -use tokio::net::UnixListener as Listener; - -#[derive(Clone, PartialEq, Debug)] -struct Identity { - pubkey: PublicKey, - privkey: PrivateKey, - comment: String, -} - -#[derive(Default, Clone)] -struct KeyStorage { - identities: Arc>>, -} - -impl KeyStorage { - fn identity_index_from_pubkey(identities: &[Identity], pubkey: &PublicKey) -> Option { - for (index, identity) in identities.iter().enumerate() { - if &identity.pubkey == pubkey { - return Some(index); - } - } - None - } - - fn identity_from_pubkey(&self, pubkey: &PublicKey) -> Option { - let identities = self.identities.lock().unwrap(); - - let index = Self::identity_index_from_pubkey(&identities, pubkey)?; - Some(identities[index].clone()) - } - - fn identity_add(&self, identity: Identity) { - let mut identities = self.identities.lock().unwrap(); - if Self::identity_index_from_pubkey(&identities, &identity.pubkey).is_none() { - identities.push(identity); - } - } - - fn identity_remove(&self, pubkey: &PublicKey) -> Result<(), AgentError> { - let mut identities = self.identities.lock().unwrap(); - - if let Some(index) = Self::identity_index_from_pubkey(&identities, pubkey) { - identities.remove(index); - Ok(()) - } else { - Err(std::io::Error::other("Failed to remove identity: identity not found").into()) - } - } -} - -#[crate::async_trait] -impl Session for KeyStorage { - async fn sign(&mut self, sign_request: SignRequest) -> Result { - let pubkey: PublicKey = sign_request.pubkey.key_data().clone().into(); - - if let Some(identity) = self.identity_from_pubkey(&pubkey) { - match identity.privkey.key_data() { - KeypairData::Rsa(ref key) => { - let algorithm; - - let private_key: rsa::RsaPrivateKey = - key.try_into().map_err(AgentError::other)?; - let mut rng = rand::thread_rng(); - let data = &sign_request.data; - - let signature = if sign_request.flags & signature::RSA_SHA2_512 != 0 { - algorithm = "rsa-sha2-512"; - SigningKey::::new(private_key).sign_with_rng(&mut rng, data) - } else if sign_request.flags & signature::RSA_SHA2_256 != 0 { - algorithm = "rsa-sha2-256"; - SigningKey::::new(private_key).sign_with_rng(&mut rng, data) - } else { - algorithm = "ssh-rsa"; - SigningKey::::new(private_key).sign_with_rng(&mut rng, data) - }; - Ok(Signature::new( - Algorithm::new(algorithm).map_err(AgentError::other)?, - signature.to_bytes().to_vec(), - ) - .map_err(AgentError::other)?) - } - _ => Err(std::io::Error::other("Signature for key type not implemented").into()), - } - } else { - Err(std::io::Error::other("Failed to create signature: identity not found").into()) - } - } - - async fn request_identities(&mut self) -> Result, AgentError> { - let mut identities = vec![]; - for identity in self.identities.lock().unwrap().iter() { - identities.push(message::Identity { - pubkey: identity.pubkey.key_data().clone().into(), - comment: identity.comment.clone(), - }) - } - Ok(identities) - } - - async fn add_identity(&mut self, identity: AddIdentity) -> Result<(), AgentError> { - if let PrivateCredential::Key { privkey, comment } = identity.credential { - let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?; - self.identity_add(Identity { - pubkey: PublicKey::from(&privkey), - privkey, - comment, - }); - Ok(()) - } else { - info!("Unsupported key type: {:#?}", identity.credential); - Ok(()) - } - } - - async fn add_identity_constrained( - &mut self, - identity: AddIdentityConstrained, - ) -> Result<(), AgentError> { - let AddIdentityConstrained { - identity, - constraints, - } = identity; - info!("Would use these constraints: {constraints:#?}"); - for constraint in constraints { - if let KeyConstraint::Extension(extension) = constraint { - if let Some(destination) = - extension.parse_key_constraint::()? - { - info!("Destination constraint: {destination:?}"); - } - - if let PrivateCredential::Key { privkey, comment } = identity.credential.clone() { - let privkey = PrivateKey::try_from(privkey).map_err(AgentError::other)?; - self.identity_add(Identity { - pubkey: PublicKey::from(&privkey), - privkey, - comment, - }); - } - } - } - self.add_identity(identity).await - } - - async fn remove_identity(&mut self, identity: RemoveIdentity) -> Result<(), AgentError> { - let pubkey: PublicKey = identity.pubkey.into(); - self.identity_remove(&pubkey)?; - Ok(()) - } - - async fn add_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> { - info!("Adding smartcard key: {key:?}"); - - Ok(()) - } - - async fn add_smartcard_key_constrained( - &mut self, - key: AddSmartcardKeyConstrained, - ) -> Result<(), AgentError> { - info!("Adding smartcard key with constraints: {key:?}"); - Ok(()) - } - async fn lock(&mut self, pwd: String) -> Result<(), AgentError> { - info!("Locked with password: {pwd:?}"); - Ok(()) - } - - async fn unlock(&mut self, pwd: String) -> Result<(), AgentError> { - info!("Unlocked with password: {pwd:?}"); - Ok(()) - } - - async fn extension(&mut self, extension: Extension) -> Result, AgentError> { - info!("Extension: {extension:?}"); - - match extension.name.as_str() { - "query" => { - let response = Extension::new_message(QueryResponse { - extensions: vec!["query".into(), "session-bind@openssh.com".into()], - })?; - Ok(Some(response)) - } - "session-bind@openssh.com" => match extension.parse_message::()? { - Some(bind) => { - bind.verify_signature() - .map_err(|_| AgentError::ExtensionFailure)?; - - info!("Session binding: {bind:?}"); - Ok(None) - } - None => Err(AgentError::Failure), - }, - _ => Err(AgentError::Failure), - } - } -} - -#[tokio::main] -async fn main() -> Result<(), AgentError> { - env_logger::init(); - - #[cfg(not(windows))] - let socket = "ssh-agent.sock"; - #[cfg(windows)] - let socket = r"\\.\pipe\agent"; - - let _ = std::fs::remove_file(socket); // remove the socket if exists - - // This is only used for integration tests on Windows: - #[cfg(windows)] - std::fs::File::create("server-started")?; - - listen(Listener::bind(socket)?, KeyStorage::default()).await?; - Ok(()) -} diff --git a/examples/openpgp-card-agent.rs b/examples/openpgp-card-agent.rs deleted file mode 100644 index 5935105..0000000 --- a/examples/openpgp-card-agent.rs +++ /dev/null @@ -1,292 +0,0 @@ -//! OpenPGP Card SSH Agent -//! -//! Implements an SSH agent which forwards cryptographic operations to -//! an OpenPGP Card device (such as Yubikey, Nitrokey etc). -//! The PIN is stored in memory for the duration of the agent session. -//! This agent supports only ed25519 authentication subkeys. -//! To provision the token use [OpenPGP Card Tools](https://codeberg.org/openpgp-card/openpgp-card-tools/#generate-keys-on-the-card). -//! Due to the use of PC/SC the agent requires pcsclite on Linux but no other libs -//! on Windows and macOS as it will utilize built-in smartcard services. -//! -//! The typical session: -//! - starting the SSH agent: `cargo run --example openpgp-card-agent -- -H unix:///tmp/sock` -//! - listing available cards: `SSH_AUTH_SOCK=/tmp/sock ssh-add -L` (this will display the card ident used in the next step) -//! - storing PIN for one of the cards: `SSH_AUTH_SOCK=/tmp/sock ssh-add -s 0006:15422467` (the agent will validate the PIN before storing it) -//! - and that's it! You can use the agent to login to your SSH servers. - -use std::{sync::Arc, time::Duration}; - -use card_backend_pcsc::PcscBackend; -use clap::Parser; -use openpgp_card::{ - ocard::algorithm::AlgorithmAttributes, - ocard::crypto::{Cryptogram, EccType, PublicKeyMaterial}, - ocard::KeyType, - ocard::OpenPGP, -}; -use retainer::{Cache, CacheExpiration}; -use secrecy::{ExposeSecret, SecretString}; -use service_binding::Binding; -use ssh_agent_lib::{ - agent::{bind, Session}, - error::AgentError, - proto::{ - extension::MessageExtension, AddSmartcardKeyConstrained, Extension, Identity, - KeyConstraint, ProtoError, SignRequest, SmartcardKey, - }, -}; -use ssh_key::{ - public::{Ed25519PublicKey, KeyData}, - Algorithm, Signature, -}; -use testresult::TestResult; -mod extensions; -use extensions::{ - DecryptDeriveRequest, DecryptDeriveResponse, DecryptIdentities, RequestDecryptIdentities, -}; - -#[derive(Clone)] -struct CardSession { - pwds: Arc>, -} - -impl CardSession { - pub fn new() -> Self { - let pwds: Arc> = Arc::new(Default::default()); - let clone = Arc::clone(&pwds); - tokio::spawn(async move { clone.monitor(4, 0.25, Duration::from_secs(3)).await }); - Self { pwds } - } - - async fn handle_sign( - &self, - request: SignRequest, - ) -> Result> { - let cards = PcscBackend::cards(None).map_err(AgentError::other)?; - for card in cards { - let mut card = OpenPGP::new(card?)?; - let mut tx = card.transaction()?; - let ident = tx.application_identifier()?.ident(); - if let PublicKeyMaterial::E(e) = tx.public_key(KeyType::Authentication)? { - if let AlgorithmAttributes::Ecc(ecc) = e.algo() { - if ecc.ecc_type() == EccType::EdDSA { - let pubkey = KeyData::Ed25519(Ed25519PublicKey(e.data().try_into()?)); - if pubkey == *request.pubkey.key_data() { - let pin = self.pwds.get(&ident).await; - return if let Some(pin) = pin { - let str = pin.expose_secret().as_bytes().to_vec(); - tx.verify_pw1_user(str.into())?; - let signature = tx.internal_authenticate(request.data.clone())?; - - Ok(Signature::new(Algorithm::Ed25519, signature)?) - } else { - // no pin saved, use "ssh-add -s ..." - Err(std::io::Error::other("no pin saved").into()) - }; - } - } - } - } - } - Err(std::io::Error::other("no applicable card found").into()) - } - - async fn handle_add_smartcard_key( - &mut self, - key: SmartcardKey, - expiration: impl Into, - ) -> Result<(), AgentError> { - match PcscBackend::cards(None) { - Ok(cards) => { - let card_pin_matches = cards - .flat_map(|card| { - let mut card = OpenPGP::new(card?)?; - let mut tx = card.transaction()?; - let ident = tx.application_identifier()?.ident(); - if ident == key.id { - let str = key.pin.expose_secret().as_bytes().to_vec(); - tx.verify_pw1_user(str.into())?; - - Ok::<_, Box>(true) - } else { - Ok(false) - } - }) - .any(|x| x); - if card_pin_matches { - self.pwds.insert(key.id, key.pin, expiration).await; - Ok(()) - } else { - Err(AgentError::IO(std::io::Error::other( - "Card/PIN combination is not valid", - ))) - } - } - Err(error) => Err(AgentError::other(error)), - } - } - - async fn decrypt_derive( - &mut self, - req: DecryptDeriveRequest, - ) -> Result>, Box> { - if let Ok(cards) = PcscBackend::cards(None) { - for card in cards { - let mut card = OpenPGP::new(card?)?; - let mut tx = card.transaction()?; - if let PublicKeyMaterial::E(e) = tx.public_key(KeyType::Decryption)? { - if let AlgorithmAttributes::Ecc(ecc) = e.algo() { - if ecc.ecc_type() == EccType::ECDH { - let pubkey = KeyData::Ed25519(Ed25519PublicKey(e.data().try_into()?)); - if pubkey == req.pubkey { - let ident = tx.application_identifier()?.ident(); - let pin = self.pwds.get(&ident).await; - if let Some(pin) = pin { - let str = pin.expose_secret().as_bytes().to_vec(); - tx.verify_pw1_user(str.into())?; - - let data = tx.decipher(Cryptogram::ECDH(&req.data))?; - return Ok(Some(data)); - } - } - } - } - } - } - } - Ok(None) - } -} - -#[ssh_agent_lib::async_trait] -impl Session for CardSession { - async fn request_identities(&mut self) -> Result, AgentError> { - Ok(if let Ok(cards) = PcscBackend::cards(None) { - cards - .flat_map(|card| { - let mut card = OpenPGP::new(card?)?; - let mut tx = card.transaction()?; - let ident = tx.application_identifier()?.ident(); - if let PublicKeyMaterial::E(e) = tx.public_key(KeyType::Authentication)? { - if let AlgorithmAttributes::Ecc(ecc) = e.algo() { - if ecc.ecc_type() == EccType::EdDSA { - return Ok::<_, Box>(Some(Identity { - pubkey: KeyData::Ed25519(Ed25519PublicKey( - e.data().try_into()?, - )) - .into(), - comment: ident, - })); - } - } - } - Ok(None) - }) - .flatten() - .collect::>() - } else { - vec![] - }) - } - - async fn add_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> { - self.handle_add_smartcard_key(key, CacheExpiration::none()) - .await - } - - async fn add_smartcard_key_constrained( - &mut self, - key: AddSmartcardKeyConstrained, - ) -> Result<(), AgentError> { - if key.constraints.len() > 1 { - return Err(AgentError::other(std::io::Error::other( - "Only one lifetime constraint supported.", - ))); - } - let expiration_in_seconds = if let KeyConstraint::Lifetime(seconds) = key.constraints[0] { - Duration::from_secs(seconds as u64) - } else { - return Err(AgentError::other(std::io::Error::other( - "Only one lifetime constraint supported.", - ))); - }; - self.handle_add_smartcard_key(key.key, expiration_in_seconds) - .await - } - - async fn sign(&mut self, request: SignRequest) -> Result { - self.handle_sign(request).await.map_err(AgentError::Other) - } - - async fn extension(&mut self, extension: Extension) -> Result, AgentError> { - if extension.name == RequestDecryptIdentities::NAME { - let identities = if let Ok(cards) = PcscBackend::cards(None) { - cards - .flat_map(|card| { - let mut card = OpenPGP::new(card?)?; - let mut tx = card.transaction()?; - let ident = tx.application_identifier()?.ident(); - if let PublicKeyMaterial::E(e) = tx.public_key(KeyType::Decryption)? { - if let AlgorithmAttributes::Ecc(ecc) = e.algo() { - if ecc.ecc_type() == EccType::ECDH { - return Ok::<_, Box>(Some(Identity { - pubkey: KeyData::Ed25519(Ed25519PublicKey( - e.data().try_into()?, - )) - .into(), - comment: ident, - })); - } - } - } - Ok(None) - }) - .flatten() - .collect::>() - } else { - vec![] - }; - - Ok(Some( - Extension::new_message(DecryptIdentities { identities }) - .map_err(AgentError::other)?, - )) - } else if extension.name == DecryptDeriveRequest::NAME { - let req = extension - .parse_message::()? - .expect("message to be there"); - - let decrypted = self.decrypt_derive(req).await.map_err(AgentError::Other)?; - - if let Some(decrypted) = decrypted { - Ok(Some( - Extension::new_message(DecryptDeriveResponse { data: decrypted }) - .map_err(AgentError::other)?, - )) - } else { - Err(AgentError::from(ProtoError::UnsupportedCommand { - command: 27, - })) - } - } else { - Err(AgentError::from(ProtoError::UnsupportedCommand { - command: 27, - })) - } - } -} - -#[derive(Debug, Parser)] -struct Args { - #[clap(short = 'H', long)] - host: Binding, -} - -#[tokio::main] -async fn main() -> TestResult { - env_logger::init(); - - let args = Args::parse(); - bind(args.host.try_into()?, CardSession::new()).await?; - Ok(()) -} diff --git a/examples/pgp-wrapper.rs b/examples/pgp-wrapper.rs deleted file mode 100644 index 680ea75..0000000 --- a/examples/pgp-wrapper.rs +++ /dev/null @@ -1,490 +0,0 @@ -//! OpenPGP wrapper for SSH keys -//! -//! Creates an OpenPGP certificate based on the SSH key and allows signing files -//! emitting OpenPGP framed packets. -//! -//! Requires that the first key in SSH is ed25519 (see `ssh-add -L`). -//! -//! Generate a key with: -//! `cargo run --example pgp-wrapper generate "John Doe " > key.pgp` -//! -//! Sign data using: -//! `cargo run --example pgp-wrapper sign < Cargo.toml > Cargo.toml.sig` -//! -//! Import the certificate using GnuPG: -//! ```sh -//! $ gpg --import key.pgp -//! gpg: key A142E92C91BE3AD5: public key "John Doe " imported -//! gpg: Total number processed: 1 -//! gpg: imported: 1 -//! ``` -//! -//! Verify the signature using GnuPG: -//! ```sh -//! $ gpg --verify Cargo.toml.sig -//! gpg: assuming signed data in 'Cargo.toml' -//! gpg: Signature made Fri May 10 11:15:53 2024 CEST -//! gpg: using EDDSA key 4EB27E153DDC454364B36B59A142E92C91BE3AD5 -//! gpg: Good signature from "John Doe " [unknown] -//! gpg: WARNING: This key is not certified with a trusted signature! -//! gpg: There is no indication that the signature belongs to the owner. -//! Primary key fingerprint: 4EB2 7E15 3DDC 4543 64B3 6B59 A142 E92C 91BE 3AD5 -//! ``` -//! -//! Works perfectly in conjunction with `openpgp-card-agent.rs`! -//! -//! If the SSH agent implements `decrypt derive` extension this agent additionally -//! creates encryption capable subkey and supports the `decrypt` subcommand: -//! -//! ```sh -//! echo I like strawberries | gpg -er 4EB27E153DDC454364B36B59A142E92C91BE3AD5 > /tmp/encrypted.pgp -//! SSH_AUTH_SOCK=/tmp/ext-agent.sock cargo run --example pgp-wrapper -- decrypt < /tmp/encrypted.pgp -//! ... -//! I like strawberries -//! ``` - -use std::io::Write as _; - -use chrono::DateTime; -use clap::Parser; -use pgp::{ - crypto::{ecc_curve::ECCCurve, hash::HashAlgorithm, public_key::PublicKeyAlgorithm}, - packet::{ - KeyFlags, PacketTrait, PublicKey, SignatureConfig, SignatureType, SignatureVersion, - Subpacket, SubpacketData, UserId, - }, - ser::Serialize, - types::{ - CompressionAlgorithm, KeyTrait, KeyVersion, Mpi, PublicKeyTrait, PublicParams, - SecretKeyTrait, Version, - }, - Deserializable as _, Esk, KeyDetails, Message, PlainSessionKey, Signature, -}; -use service_binding::Binding; -use ssh_agent_lib::{ - agent::Session, - client::connect, - proto::{Extension, PublicCredential, SignRequest}, -}; -use ssh_key::public::KeyData; -use tokio::runtime::Runtime; -use tokio::sync::Mutex; -mod extensions; -use extensions::{ - DecryptDeriveRequest, DecryptDeriveResponse, DecryptIdentities, RequestDecryptIdentities, -}; - -struct WrappedKey { - public_key: PublicKey, - pubkey: KeyData, - client: Mutex>, -} - -#[derive(Clone, Copy, Debug)] -enum KeyRole { - Signing, - Decryption, -} - -impl From for PublicKeyAlgorithm { - fn from(value: KeyRole) -> Self { - match value { - KeyRole::Signing => PublicKeyAlgorithm::EdDSA, - KeyRole::Decryption => PublicKeyAlgorithm::ECDH, - } - } -} - -fn ssh_to_pgp(pubkey: KeyData, key_role: KeyRole) -> PublicKey { - let KeyData::Ed25519(key) = pubkey.clone() else { - panic!("The first key was not ed25519!"); - }; - - let mut key_bytes = key.0.to_vec(); - // Add prefix to mark that this MPI uses EdDSA point representation. - // See https://datatracker.ietf.org/doc/draft-koch-eddsa-for-openpgp/ - key_bytes.insert(0, 0x40); - - let public_params = match key_role { - KeyRole::Signing => PublicParams::EdDSA { - curve: ECCCurve::Ed25519, - q: key_bytes.into(), - }, - // most common values taken from - // https://gitlab.com/sequoia-pgp/sequoia/-/issues/838#note_909813463 - KeyRole::Decryption => PublicParams::ECDH { - curve: ECCCurve::Curve25519, - p: key_bytes.into(), - hash: HashAlgorithm::SHA2_256, - alg_sym: pgp::crypto::sym::SymmetricKeyAlgorithm::AES128, - }, - }; - - PublicKey::new( - Version::New, - KeyVersion::V4, - key_role.into(), - // use fixed date so that the fingerprint generation is deterministic - DateTime::parse_from_rfc3339("2016-09-06T17:00:00+02:00") - .expect("date to be valid") - .into(), - None, - public_params, - ) - .expect("key to be valid") -} - -impl WrappedKey { - fn new(pubkey: KeyData, client: Box, key_role: KeyRole) -> Self { - let public_key = ssh_to_pgp(pubkey.clone(), key_role); - Self { - pubkey, - client: Mutex::new(client), - public_key, - } - } - - fn decrypt( - &self, - mpis: &[Mpi], - ) -> Result<(Vec, pgp::crypto::sym::SymmetricKeyAlgorithm), pgp::errors::Error> { - if let PublicParams::ECDH { - curve, - alg_sym, - hash, - .. - } = self.public_key().public_params() - { - let ciphertext = mpis[0].as_bytes(); - - // encrypted and wrapped value derived from the session key - let encrypted_session_key = mpis[2].as_bytes(); - - let ciphertext = if *curve == ECCCurve::Curve25519 { - assert_eq!( - ciphertext[0], 0x40, - "Unexpected shape of Cv25519 encrypted data" - ); - - // Strip trailing 0x40 - &ciphertext[1..] - } else { - unimplemented!(); - }; - - let plaintext = Runtime::new() - .expect("creating runtime to succeed") - .handle() - .block_on(async { - let mut client = self.client.lock().await; - let result = client.extension( - Extension::new_message(DecryptDeriveRequest { - pubkey: self.pubkey.clone(), - data: ciphertext.to_vec(), - flags: 0, - }) - .expect("encoding to work"), - ); - result.await - }) - .expect("decryption to succeed") - .expect("result not to be empty"); - - let shared_secret = &plaintext - .parse_message::() - .expect("decoding to succeed") - .expect("not to be empty") - .data[..]; - - let encrypted_key_len: usize = mpis[1].first().copied().map(Into::into).unwrap_or(0); - - let decrypted_key: Vec = pgp::crypto::ecdh::derive_session_key( - shared_secret, - encrypted_session_key, - encrypted_key_len, - &(curve.clone(), *alg_sym, *hash), - &self.public_key.fingerprint(), - )?; - - // strip off the leading session key algorithm octet, and the two trailing checksum octets - let dec_len = decrypted_key.len(); - let (sessionkey, checksum) = ( - &decrypted_key[1..dec_len - 2], - &decrypted_key[dec_len - 2..], - ); - - // ... check the checksum, while we have it at hand - pgp::crypto::checksum::simple(checksum, sessionkey)?; - - let session_key_algorithm = decrypted_key[0].into(); - Ok((sessionkey.to_vec(), session_key_algorithm)) - } else { - unimplemented!(); - } - } -} - -impl std::fmt::Debug for WrappedKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "WrappedKey") - } -} - -impl KeyTrait for WrappedKey { - fn fingerprint(&self) -> Vec { - self.public_key.fingerprint() - } - - fn key_id(&self) -> pgp::types::KeyId { - self.public_key.key_id() - } - - fn algorithm(&self) -> pgp::crypto::public_key::PublicKeyAlgorithm { - self.public_key.algorithm() - } -} - -impl PublicKeyTrait for WrappedKey { - fn verify_signature( - &self, - hash: pgp::crypto::hash::HashAlgorithm, - data: &[u8], - sig: &[pgp::types::Mpi], - ) -> pgp::errors::Result<()> { - self.public_key.verify_signature(hash, data, sig) - } - - fn encrypt( - &self, - rng: &mut R, - plain: &[u8], - ) -> pgp::errors::Result> { - self.public_key.encrypt(rng, plain) - } - - fn to_writer_old(&self, writer: &mut impl std::io::Write) -> pgp::errors::Result<()> { - self.public_key.to_writer_old(writer) - } -} - -impl SecretKeyTrait for WrappedKey { - type PublicKey = PublicKey; - - type Unlocked = Self; - - fn unlock(&self, _pw: F, work: G) -> pgp::errors::Result - where - F: FnOnce() -> String, - G: FnOnce(&Self::Unlocked) -> pgp::errors::Result, - { - work(self) - } - - fn create_signature( - &self, - _key_pw: F, - _hash: pgp::crypto::hash::HashAlgorithm, - data: &[u8], - ) -> pgp::errors::Result> - where - F: FnOnce() -> String, - { - let signature = Runtime::new() - .expect("creating runtime to succeed") - .handle() - .block_on(async { - let mut client = self.client.lock().await; - let result = client.sign(SignRequest { - pubkey: self.pubkey.clone().into(), - data: data.to_vec(), - flags: 0, - }); - result.await - }) - .expect("signing to succeed"); - - let sig = &signature.as_bytes(); - - assert_eq!(sig.len(), 64); - - Ok(vec![ - Mpi::from_raw_slice(&sig[..32]), - Mpi::from_raw_slice(&sig[32..]), - ]) - } - - fn public_key(&self) -> Self::PublicKey { - self.public_key.clone() - } - - fn public_params(&self) -> &pgp::types::PublicParams { - self.public_key.public_params() - } -} - -#[derive(Debug, Parser)] -enum Args { - Generate { userid: String }, - Sign, - Decrypt, -} - -fn main() -> testresult::TestResult { - let args = Args::parse(); - - let rt = Runtime::new()?; - - let (client, identities, decrypt_ids) = rt.block_on(async move { - #[cfg(unix)] - let mut client = - connect(Binding::FilePath(std::env::var("SSH_AUTH_SOCK")?.into()).try_into()?)?; - - #[cfg(windows)] - let mut client = - connect(Binding::NamedPipe(std::env::var("SSH_AUTH_SOCK")?.into()).try_into()?)?; - - let identities = client.request_identities().await?; - - if identities.is_empty() { - panic!("We need at least one ed25519 identity!"); - } - - let decrypt_ids = if let Ok(Some(identities)) = client - .extension(Extension::new_message(RequestDecryptIdentities)?) - .await - { - identities - .parse_message::()? - .map(|d| d.identities) - .unwrap_or_default() - } else { - vec![] - }; - - Ok::<_, testresult::TestError>((client, identities, decrypt_ids)) - })?; - - let pubkey = &identities[0].pubkey; - - match args { - Args::Generate { userid } => { - let subkeys = if let Some(decryption_id) = decrypt_ids.first() { - let mut keyflags = KeyFlags::default(); - keyflags.set_encrypt_comms(true); - keyflags.set_encrypt_storage(true); - let PublicCredential::Key(pubkey) = &decryption_id.pubkey else { - panic!("Only pubkeys are supported."); - }; - let pk = ssh_to_pgp(pubkey.clone(), KeyRole::Decryption); - vec![pgp::PublicSubkey::new( - pgp::packet::PublicSubkey::new( - pk.packet_version(), - pk.version(), - pk.algorithm(), - *pk.created_at(), - pk.expiration(), - pk.public_params().clone(), - )?, - keyflags, - )] - } else { - vec![] - }; - - let PublicCredential::Key(pubkey) = pubkey else { - panic!("Only pubkeys are supported."); - }; - let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); - let mut keyflags = KeyFlags::default(); - keyflags.set_sign(true); - keyflags.set_certify(true); - - let composed_pk = pgp::PublicKey::new( - signer.public_key(), - KeyDetails::new( - UserId::from_str(Default::default(), &userid), - vec![], - vec![], - keyflags, - Default::default(), - Default::default(), - vec![CompressionAlgorithm::Uncompressed].into(), - None, - ), - subkeys, - ); - let signed_pk = composed_pk.sign(&signer, String::new)?; - signed_pk.to_writer(&mut std::io::stdout())?; - } - Args::Sign => { - let PublicCredential::Key(pubkey) = pubkey else { - panic!("Only pubkeys are supported."); - }; - let signer = WrappedKey::new(pubkey.clone(), client, KeyRole::Signing); - let signature = SignatureConfig::new_v4( - SignatureVersion::V4, - SignatureType::Binary, - signer.algorithm(), - HashAlgorithm::SHA2_256, - vec![ - Subpacket::regular(SubpacketData::SignatureCreationTime( - std::time::SystemTime::now().into(), - )), - Subpacket::regular(SubpacketData::Issuer(signer.key_id())), - Subpacket::regular(SubpacketData::IssuerFingerprint( - KeyVersion::V4, - signer.fingerprint().into(), - )), - ], - vec![], - ); - - let mut hasher = signature.hash_alg.new_hasher()?; - - signature.hash_data_to_sign(&mut *hasher, std::io::stdin())?; - let len = signature.hash_signature_data(&mut *hasher)?; - hasher.update(&signature.trailer(len)?); - - let hash = &hasher.finish()[..]; - - let signed_hash_value = [hash[0], hash[1]]; - let raw_sig = signer.create_signature(String::new, HashAlgorithm::SHA2_256, hash)?; - - let signature = Signature::from_config(signature, signed_hash_value, raw_sig); - pgp::packet::write_packet(&mut std::io::stdout(), &signature)?; - } - Args::Decrypt => { - let pubkey = decrypt_ids[0].pubkey.key_data(); - let decryptor = WrappedKey::new(pubkey.clone(), client, KeyRole::Decryption); - let message = Message::from_bytes(std::io::stdin())?; - - let Message::Encrypted { esk, edata } = message else { - panic!("not encrypted"); - }; - - let mpis = if let Esk::PublicKeyEncryptedSessionKey(ref k) = esk[0] { - k.mpis() - } else { - panic!("whoops") - }; - - let (session_key, session_key_algorithm) = - decryptor.unlock(String::new, |priv_key| priv_key.decrypt(mpis))?; - - let plain_session_key = PlainSessionKey::V4 { - key: session_key, - sym_alg: session_key_algorithm, - }; - - let decrypted = edata.decrypt(plain_session_key)?; - - if let Message::Literal(data) = decrypted { - std::io::stdout().write_all(data.data())?; - } else { - eprintln!("decrypted: {:?}", &decrypted); - } - } - } - - Ok(()) -} diff --git a/examples/proto-dumper.rs b/examples/proto-dumper.rs deleted file mode 100644 index 7583fda..0000000 --- a/examples/proto-dumper.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! This example illustrates a couple of features: First, it -//! implements a forwarder, exposing an SSH agent socket and -//! forwarding to a different one. Secondly it shows how to work with -//! low-level handling of messages instead of parsed high-level -//! structures. -//! -//! Run with -//! RUST_LOG=info cargo run --example proto-dumper -- --target unix://$SSH_AUTH_SOCK -H unix:///tmp/test.sock - -use clap::Parser; -use service_binding::Binding; -use ssh_agent_lib::{ - agent::bind, - agent::Agent, - agent::Session, - async_trait, - client::connect, - error::AgentError, - proto::{Request, Response}, -}; -use ssh_encoding::Encode; - -struct DumpAndForward { - target: Box, - session: u64, - id: u64, -} - -#[async_trait] -impl Session for DumpAndForward { - async fn handle(&mut self, message: Request) -> Result { - use std::io::Write; - - self.id += 1; - let req_file = format!("req-{}-{}.bin", self.session, self.id); - log::info!("Writing request {message:?} to {req_file}"); - - let mut req = std::fs::File::create(req_file)?; - let mut buf = vec![]; - message.encode(&mut buf).map_err(AgentError::other)?; - req.write_all(&buf)?; - drop(req); - - let response = self.target.handle(message).await?; - - let resp_file = format!("resp-{}-{}.bin", self.session, self.id); - log::info!("Writing response {response:?} to {resp_file}"); - let mut resp = std::fs::File::create(resp_file)?; - let mut buf = vec![]; - response.encode(&mut buf).map_err(AgentError::other)?; - resp.write_all(&buf)?; - drop(resp); - - Ok(response) - } -} - -struct Forwarder { - target: Binding, - id: u64, -} - -#[cfg(unix)] -impl Agent for Forwarder { - fn new_session(&mut self, _socket: &tokio::net::UnixStream) -> impl Session { - self.create_new_session() - } -} - -impl Agent for Forwarder { - fn new_session(&mut self, _socket: &tokio::net::TcpStream) -> impl Session { - self.create_new_session() - } -} - -#[cfg(windows)] -impl Agent for Forwarder { - fn new_session( - &mut self, - _socket: &tokio::net::windows::named_pipe::NamedPipeServer, - ) -> impl Session { - self.create_new_session() - } -} - -impl Forwarder { - fn create_new_session(&mut self) -> impl Session { - self.id += 1; - DumpAndForward { - target: connect(self.target.clone().try_into().unwrap()).unwrap(), - session: self.id, - id: 0, - } - } -} - -#[derive(Debug, Parser)] -struct Args { - /// Target SSH agent to which we will proxy all requests. - #[clap(long)] - target: Binding, - - /// Source that we will bind to. - #[clap(long, short = 'H')] - host: Binding, -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - env_logger::init(); - - let args = Args::parse(); - - bind( - args.host.try_into()?, - Forwarder { - target: args.target, - id: 0, - }, - ) - .await?; - - Ok(()) -} diff --git a/examples/ssh-agent-client-blocking.rs b/examples/ssh-agent-client-blocking.rs deleted file mode 100644 index 0dcd45e..0000000 --- a/examples/ssh-agent-client-blocking.rs +++ /dev/null @@ -1,35 +0,0 @@ -mod extensions; - -#[cfg(unix)] -use std::os::unix::net::UnixStream; - -use extensions::{DecryptIdentities, RequestDecryptIdentities}; -#[cfg(windows)] -use interprocess::os::windows::named_pipe::*; -use ssh_agent_lib::{blocking::Client, proto::Extension}; - -fn main() -> testresult::TestResult { - let socket = std::env::var("SSH_AUTH_SOCK")?; - #[cfg(unix)] - let mut client = Client::new(UnixStream::connect(socket)?); - #[cfg(windows)] - let mut client = Client::new(DuplexPipeStream::::connect_by_path( - socket, - )?); - - eprintln!( - "Identities that this agent knows of: {:#?}", - client.request_identities()? - ); - - if let Ok(Some(identities)) = - client.extension(Extension::new_message(RequestDecryptIdentities)?) - { - let identities = identities.parse_message::()?; - eprintln!("Decrypt identities that this agent knows of: {identities:#?}",); - } else { - eprintln!("No decryption identities found."); - } - - Ok(()) -} diff --git a/examples/ssh-agent-client.rs b/examples/ssh-agent-client.rs deleted file mode 100644 index 410d621..0000000 --- a/examples/ssh-agent-client.rs +++ /dev/null @@ -1,31 +0,0 @@ -use service_binding::Binding; -use ssh_agent_lib::{client::connect, proto::Extension}; -mod extensions; -use extensions::{DecryptIdentities, RequestDecryptIdentities}; -#[tokio::main] -async fn main() -> Result<(), Box> { - #[cfg(unix)] - let mut client = - connect(Binding::FilePath(std::env::var("SSH_AUTH_SOCK")?.into()).try_into()?)?; - - #[cfg(windows)] - let mut client = - connect(Binding::NamedPipe(std::env::var("SSH_AUTH_SOCK")?.into()).try_into()?)?; - - eprintln!( - "Identities that this agent knows of: {:#?}", - client.request_identities().await? - ); - - if let Ok(Some(identities)) = client - .extension(Extension::new_message(RequestDecryptIdentities)?) - .await - { - let identities = identities.parse_message::()?; - eprintln!("Decrypt identities that this agent knows of: {identities:#?}",); - } else { - eprintln!("No decryption identities found."); - } - - Ok(()) -} diff --git a/fuzz/.gitignore b/fuzz/.gitignore deleted file mode 100644 index 1a45eee..0000000 --- a/fuzz/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target -corpus -artifacts -coverage diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml deleted file mode 100644 index 5c80d88..0000000 --- a/fuzz/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "ssh-agent-lib-fuzz" -version = "0.0.0" -publish = false -edition = "2021" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = "0.4" -ssh-encoding = "0.2.0" - -[dependencies.ssh-agent-lib] -path = ".." - -[[bin]] -name = "request_decode" -path = "fuzz_targets/request_decode.rs" -test = false -doc = false -bench = false diff --git a/fuzz/README.md b/fuzz/README.md deleted file mode 100644 index 32d5590..0000000 --- a/fuzz/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Fuzzing - -This directory contains fuzzing targets for ssh-agent-lib. - -## Setup - -Install [`cargo-fuzz`](https://crates.io/crates/cargo-fuzz): - -```sh -cargo install --locked cargo-fuzz -``` - -## Running - -Select a target from the list printed by `cargo fuzz list` e.g. `message_decode`: - -```sh -cargo +nightly fuzz run message_decode -``` - -Options that can be added to the `fuzz run` command: - -- `--jobs N` - increase parallelism, -- `--sanitizer none` - disable sanitizer since ssh-agent-lib does not use any `unsafe` blocks, - -Note that due to a limitation of cargo-fuzz nightly version of the toolchain is required. - -For more details see [Fuzzing with cargo-fuzz](https://rust-fuzz.github.io/book/cargo-fuzz.html) or the [more detailed explanation of fuzzing output](https://github.com/rust-fuzz/cargo-fuzz/issues/72#issuecomment-284448618) in a `cargo-fuzz` comment. diff --git a/fuzz/fuzz_targets/request_decode.rs b/fuzz/fuzz_targets/request_decode.rs deleted file mode 100644 index 394cbba..0000000 --- a/fuzz/fuzz_targets/request_decode.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_main] - -use libfuzzer_sys::fuzz_target; -use ssh_agent_lib::proto::message::Request; -use ssh_encoding::Decode; - -fuzz_target!(|data: &[u8]| { - let _ = Request::decode(&mut &data[..]); -});