From 1deb6142acfce8fbb38326847493bd56c91a964d Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Sun, 17 May 2026 18:41:47 +0800 Subject: [PATCH] fix(sign): use ssh-keygen for SSH commit signing Replace in-process ssh-key signing with `ssh-keygen -Y sign`, matching Git's gpg.format=ssh behavior (agent support, encrypted keys, RSA-4096). Fixes #2825 Co-authored-by: Cursor --- Cargo.lock | 634 -------------------------------------- asyncgit/Cargo.toml | 1 - asyncgit/src/sync/sign.rs | 210 ++++++++----- deny.toml | 3 - 4 files changed, 137 insertions(+), 711 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1534622d6a..918bca2e2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,41 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[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" @@ -168,7 +133,6 @@ dependencies = [ "scopetime", "serde", "serial_test", - "ssh-key", "tempfile", "thiserror 2.0.18", "unicode-truncate", @@ -205,35 +169,12 @@ dependencies = [ "windows-link", ] -[[package]] -name = "base16ct" -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 = "bcrypt-pbkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" -dependencies = [ - "blowfish", - "pbkdf2", - "sha2", -] - [[package]] name = "bincode" version = "1.3.3" @@ -297,25 +238,6 @@ dependencies = [ "generic-array", ] -[[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.12.0" @@ -380,15 +302,6 @@ dependencies = [ "rustversion", ] -[[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.7" @@ -412,17 +325,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[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.44" @@ -434,16 +336,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "4.5.57" @@ -510,12 +402,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "convert_case" version = "0.10.0" @@ -628,18 +514,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -660,41 +534,6 @@ dependencies = [ "phf", ] -[[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", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "darling" version = "0.20.10" @@ -750,16 +589,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "deranged" version = "0.5.8" @@ -804,9 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", - "subtle", ] [[package]] @@ -862,66 +689,12 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23f40539c229fc2e4674bdecdf24bfcc2cb83631ca911c78a035fa9f2381c32b" -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "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", - "sha2", - "subtle", -] - [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "encode_unicode" version = "1.0.0" @@ -1028,22 +801,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - [[package]] name = "filedescriptor" version = "0.8.3" @@ -1186,7 +943,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -1235,16 +991,6 @@ dependencies = [ "regex", ] -[[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.32.3" @@ -2120,17 +1866,6 @@ dependencies = [ "gix-validate", ] -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - [[package]] name = "hash32" version = "0.3.1" @@ -2188,15 +1923,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "iana-time-zone" version = "0.1.61" @@ -2418,16 +2144,6 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "insta" version = "1.44.3" @@ -2588,9 +2304,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "leb128fmt" @@ -2618,12 +2331,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libm" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - [[package]] name = "libredox" version = "0.1.3" @@ -2864,23 +2571,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.2.0" @@ -2898,26 +2588,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2925,7 +2595,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2980,12 +2649,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl-probe" version = "0.1.5" @@ -3029,44 +2692,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p521" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" -dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core", - "sha2", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -3090,24 +2715,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -3221,27 +2828,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.31" @@ -3261,29 +2847,6 @@ dependencies = [ "time", ] -[[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 = "portable-atomic" version = "1.10.0" @@ -3305,15 +2868,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - [[package]] name = "pretty_assertions" version = "1.4.1" @@ -3334,15 +2888,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - [[package]] name = "proc-macro2" version = "1.0.94" @@ -3397,17 +2942,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", "rand_core", ] @@ -3416,9 +2950,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] [[package]] name = "ratatui" @@ -3591,16 +3122,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "ron" version = "0.12.0" @@ -3615,27 +3136,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "rsa" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "sha2", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3726,20 +3226,6 @@ version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "1.0.24" @@ -3903,16 +3389,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - [[package]] name = "similar" version = "2.7.0" @@ -3950,73 +3426,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "ssh-cipher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" -dependencies = [ - "aes", - "aes-gcm", - "cbc", - "chacha20", - "cipher", - "ctr", - "poly1305", - "ssh-encoding", - "subtle", -] - -[[package]] -name = "ssh-encoding" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" -dependencies = [ - "base64ct", - "pem-rfc7468", - "sha2", -] - -[[package]] -name = "ssh-key" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" -dependencies = [ - "bcrypt-pbkdf", - "ed25519-dalek", - "num-bigint-dig", - "p256", - "p384", - "p521", - "rand_core", - "rsa", - "sec1", - "sha2", - "signature", - "ssh-cipher", - "ssh-encoding", - "subtle", - "zeroize", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -4076,12 +3485,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "syn" version = "1.0.109" @@ -4440,16 +3843,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[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 = "url" version = "2.5.4" @@ -5126,27 +4519,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "zerofrom" version = "0.1.5" @@ -5168,12 +4540,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - [[package]] name = "zerovec" version = "0.10.4" diff --git a/asyncgit/Cargo.toml b/asyncgit/Cargo.toml index 5e77498ae3..f8d345464c 100644 --- a/asyncgit/Cargo.toml +++ b/asyncgit/Cargo.toml @@ -34,7 +34,6 @@ rayon = "1.11" rayon-core = "1.13" scopetime = { path = "../scopetime", version = "0.1" } serde = { version = "1.0", features = ["derive"] } -ssh-key = { version = "0.6.7", features = ["crypto", "encryption"] } thiserror = "2.0" unicode-truncate = "2.0" url = "2.5" diff --git a/asyncgit/src/sync/sign.rs b/asyncgit/src/sync/sign.rs index da5079f72c..a6f2a50c3f 100644 --- a/asyncgit/src/sync/sign.rs +++ b/asyncgit/src/sync/sign.rs @@ -1,6 +1,5 @@ //! Sign commit data. -use ssh_key::{HashAlg, LineEnding, PrivateKey}; use std::path::PathBuf; /// Error type for [`SignBuilder`], used to create [`Sign`]'s @@ -156,37 +155,48 @@ impl SignBuilder { String::from("x509"), )), "ssh" => { - let ssh_signer = config + let program = config + .get_string("gpg.ssh.program") + .unwrap_or_else(|_| "ssh-keygen".to_string()); + + let signing_key = config .get_string("user.signingKey") - .ok() - .and_then(|key_path| { - key_path.strip_prefix('~').map_or_else( - || Some(PathBuf::from(&key_path)), - |ssh_key_path| { - dirs::home_dir().map(|home| { - home.join( - ssh_key_path - .strip_prefix('/') - .unwrap_or(ssh_key_path), - ) - }) - }, + .map_err(|err| { + SignBuilderError::SSHSigningKey( + err.to_string(), ) - }) - .ok_or_else(|| { - SignBuilderError::SSHSigningKey(String::from( - "ssh key setting absent", - )) - }) - .and_then(SSHSign::new)?; - let signer: Box = Box::new(ssh_signer); - Ok(signer) + })?; + + let signing_key_path = + expand_signing_key_path(&signing_key).map_err(|err| { + SignBuilderError::SSHSigningKey(err) + })?; + + Ok(Box::new(SSHSign { + program, + signing_key_path, + })) } _ => Err(SignBuilderError::InvalidFormat(format)), } } } +fn expand_signing_key_path(signing_key: &str) -> Result { + let path = if let Some(rest) = signing_key.strip_prefix('~') { + let home = dirs::home_dir().ok_or_else(|| { + String::from( + "could not resolve home directory for ~ in signing key path", + ) + })?; + home.join(rest.strip_prefix('/').unwrap_or(rest)) + } else { + PathBuf::from(signing_key) + }; + + Ok(path.to_string_lossy().into_owned()) +} + /// Sign commit data using `OpenPGP` pub struct GPGSign { program: String, @@ -271,45 +281,10 @@ impl Sign for GPGSign { } } -/// Sign commit data using `SSHDiskKeySign` +/// Sign commit data using `ssh-keygen`, matching Git's `gpg.format = ssh` behavior. pub struct SSHSign { - #[cfg(test)] program: String, - #[cfg(test)] - key_path: String, - secret_key: PrivateKey, -} - -impl SSHSign { - /// Create new `SSHDiskKeySign` for sign. - pub fn new(mut key: PathBuf) -> Result { - key.set_extension(""); - if key.is_file() { - #[cfg(test)] - let key_path = format!("{}", &key.display()); - std::fs::read(key) - .ok() - .and_then(|bytes| { - PrivateKey::from_openssh(bytes).ok() - }) - .map(|secret_key| Self { - #[cfg(test)] - program: "ssh".to_string(), - #[cfg(test)] - key_path, - secret_key, - }) - .ok_or_else(|| { - SignBuilderError::SSHSigningKey(String::from( - "Fail to read the private key for sign.", - )) - }) - } else { - Err(SignBuilderError::SSHSigningKey( - String::from("Currently, we only support a pair of ssh key in disk."), - )) - } - } + signing_key_path: String, } impl Sign for SSHSign { @@ -317,13 +292,54 @@ impl Sign for SSHSign { &self, commit: &[u8], ) -> Result<(String, Option), SignError> { - let sig = self - .secret_key - .sign("git", HashAlg::Sha256, commit) - .map_err(|err| SignError::Spawn(err.to_string()))? - .to_pem(LineEnding::LF) - .map_err(|err| SignError::Spawn(err.to_string()))?; - Ok((sig, None)) + use std::io::Write; + use std::process::{Command, Stdio}; + + let mut cmd = Command::new(&self.program); + cmd.stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("-Y") + .arg("sign") + .arg("-n") + .arg("git") + .arg("-f") + .arg(&self.signing_key_path); + + if self.program == "ssh-keygen" { + cmd.arg("-U"); + } + + log::trace!("signing command: {cmd:?}"); + + let mut child = cmd + .spawn() + .map_err(|e| SignError::Spawn(e.to_string()))?; + + let mut stdin = child.stdin.take().ok_or(SignError::Stdin)?; + + stdin + .write_all(commit) + .map_err(|e| SignError::WriteBuffer(e.to_string()))?; + drop(stdin); + + let output = child + .wait_with_output() + .map_err(|e| SignError::Output(e.to_string()))?; + + if !output.status.success() { + let error_msg = std::str::from_utf8(&output.stderr) + .unwrap_or("[error could not be read from stderr]"); + return Err(SignError::Shellout(format!( + "failed to sign data, program '{}' exited non-zero: {}", + &self.program, error_msg + ))); + } + + let signed_commit = std::str::from_utf8(&output.stdout) + .map_err(|e| SignError::Shellout(e.to_string()))?; + + Ok((signed_commit.to_string(), None)) } #[cfg(test)] @@ -333,7 +349,7 @@ impl Sign for SSHSign { #[cfg(test)] fn signing_key(&self) -> &String { - &self.key_path + &self.signing_key_path } } @@ -424,19 +440,67 @@ mod tests { #[test] fn test_ssh_program_configs() -> Result<()> { let (_tmp_dir, repo) = repo_init_empty()?; + let temp_file = tempfile::NamedTempFile::new() + .expect("failed to create temp file"); { let mut config = repo.config()?; - config.set_str("gpg.program", "ssh")?; - config.set_str("user.signingKey", "/tmp/key.pub")?; + config.set_str("gpg.format", "ssh")?; + config.set_str( + "user.signingKey", + temp_file.path().to_str().unwrap(), + )?; } let sign = SignBuilder::from_gitconfig(&repo, &repo.config()?)?; - assert_eq!("ssh", sign.program()); - assert_eq!("/tmp/key.pub", sign.signing_key()); + assert_eq!("ssh-keygen", sign.program()); + assert_eq!( + temp_file.path().to_str().unwrap(), + sign.signing_key() + ); Ok(()) } + + #[test] + fn test_ssh_custom_program_config() -> Result<()> { + let (_tmp_dir, repo) = repo_init_empty()?; + let temp_file = tempfile::NamedTempFile::new() + .expect("failed to create temp file"); + + { + let mut config = repo.config()?; + config.set_str("gpg.format", "ssh")?; + config.set_str("gpg.ssh.program", "/opt/ssh/signer")?; + config.set_str( + "user.signingKey", + temp_file.path().to_str().unwrap(), + )?; + } + + let sign = + SignBuilder::from_gitconfig(&repo, &repo.config()?)?; + + assert_eq!("/opt/ssh/signer", sign.program()); + assert_eq!( + temp_file.path().to_str().unwrap(), + sign.signing_key() + ); + + Ok(()) + } + + #[test] + fn test_expand_signing_key_path_tilde() { + let home = dirs::home_dir().expect("home dir"); + let expanded = + expand_signing_key_path("~/.ssh/id_ed25519.pub").unwrap(); + assert_eq!( + expanded, + home.join(".ssh/id_ed25519.pub") + .to_string_lossy() + ); + } } diff --git a/deny.toml b/deny.toml index 92c14f0d89..1c5b04e85e 100644 --- a/deny.toml +++ b/deny.toml @@ -14,9 +14,6 @@ allow = [ [advisories] version = 2 ignore = [ - # No fix for RSA, and this is a dependency from ssh_key crate to handle rsa ssh key. - # https://rustsec.org/advisories/RUSTSEC-2023-0071 - "RUSTSEC-2023-0071", # See https://github.com/trishume/syntect/issues/606 { id = "RUSTSEC-2025-0141", reason = "Only brought in via syntect" }, ]