diff --git a/Cargo.toml b/Cargo.toml index c146d9e6f857d7b19de635b264a075dd44ca7e99..52c2110ec20e49a2c0f9050c11d38406ab411b9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,9 +53,9 @@ subtle = { version = "2.4", default-features = false } # fork allows hashing by parts (sign/verify from sshwire), and zeroize # salty = { version = "0.2", git = "https://github.com/mkj/salty", branch = "sunset" } salty = { version = "0.2", path = "/home/matt/3rd/rs/salty" } -ed25519-dalek = { version = "1", default-features = false } -x25519-dalek = { version = "1", default-features = false } -curve25519-dalek = { version = "3", default-features = false, features = [ "u32_backend"]} +ed25519-dalek = { version = "2.0.0-rc.2", default-features = false, features = ["zeroize", "rand_core", "hazmat"] } +x25519-dalek = { version = "2.0.0-rc.2", default-features = false, features = ["zeroize"] } +curve25519-dalek = { version = "4.0.0-rc.2", default-features = false, features = ["zeroize"] } rsa = { version = "0.8", default-features = false, optional = true, features = ["sha2"] } # TODO: getrandom feature is a workaround for missing ssh-key dependency with rsa. fixed in pending 0.6 @@ -90,3 +90,5 @@ simplelog = { version = "0.12", features = ["test"] } [patch.crates-io] curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" } +x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" } +ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" } diff --git a/embassy/demos/common/Cargo.toml b/embassy/demos/common/Cargo.toml index 01e3aa5a8825231799ad53c32998b80b1ec8d2bf..dab227be7ca589355a8f0a6f2cbcde1bd50cf88f 100644 --- a/embassy/demos/common/Cargo.toml +++ b/embassy/demos/common/Cargo.toml @@ -24,8 +24,8 @@ heapless = "0.7.15" embedded-io = { version = "0.4", features = ["async"] } sha2 = { version = "0.10", default-features = false } hmac = { version = "0.12", default-features = false } -# TODO: has zeroize bcrypt = { version = "0.14", default-features = false } +ed25519-dalek = { version = "2.0.0-rc.2", default-features = false } defmt = { version = "0.3", optional = true } log = "0.4" @@ -39,3 +39,4 @@ log = ["embassy-net/log"] embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" } embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" } embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" } +ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" } diff --git a/embassy/demos/common/src/config.rs b/embassy/demos/common/src/config.rs index 034febcad47b157a7ab1a8e4748fbca8d332e482..0406fa58dea56cc504a6da56167cdd26fc1d7927 100644 --- a/embassy/demos/common/src/config.rs +++ b/embassy/demos/common/src/config.rs @@ -29,7 +29,7 @@ pub const KEY_SLOTS: usize = 3; // Be sure to bump CURRENT_VERSION // if this struct changes (or encode/decode impls). // BUF_SIZE will probably also need updating. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct SSHConfig { pub hostkey: SignKey, @@ -112,7 +112,7 @@ impl SSHConfig { fn enc_signkey(k: &SignKey, s: &mut dyn SSHSink) -> WireResult<()> { // need to add a variant field if we support more key types. match k { - SignKey::Ed25519(seed) => seed.enc(s), + SignKey::Ed25519(k) => k.to_bytes().enc(s), _ => Err(WireError::UnknownVariant), } } @@ -121,7 +121,9 @@ fn dec_signkey<'de, S>(s: &mut S) -> WireResult<SignKey> where S: SSHSource<'de>, { - Ok(SignKey::Ed25519(SSHDecode::dec(s)?)) + let k: ed25519_dalek::SecretKey = SSHDecode::dec(s)?; + let k = ed25519_dalek::SigningKey::from_bytes(&k); + Ok(SignKey::Ed25519(k)) } // encode Option<T> as a bool then maybe a value diff --git a/embassy/demos/picow/Cargo.lock b/embassy/demos/picow/Cargo.lock index 42b03678b7c779b89efabc78dc420c53e0d3859f..ddd28618d2ccca1708188977dccd69b896fc0819 100644 --- a/embassy/demos/picow/Cargo.lock +++ b/embassy/demos/picow/Cargo.lock @@ -348,6 +348,19 @@ dependencies = [ "cipher", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.2" +dependencies = [ + "cfg-if", + "digest", + "fiat-crypto", + "platforms", + "rustc_version 0.4.0", + "subtle", + "zeroize", +] + [[package]] name = "cyw43" version = "0.1.0" @@ -511,6 +524,26 @@ dependencies = [ "signature 1.6.4", ] +[[package]] +name = "ed25519" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "signature 2.0.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0-rc.2" +dependencies = [ + "curve25519-dalek", + "ed25519 2.2.1", + "rand_core", + "sha2", + "zeroize", +] + [[package]] name = "either" version = "1.8.1" @@ -840,6 +873,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "fixed" version = "1.23.1" @@ -1355,6 +1394,12 @@ dependencies = [ "syn", ] +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "poly1305" version = "0.8.0" @@ -1553,7 +1598,7 @@ name = "salty" version = "0.2.0" dependencies = [ "defmt", - "ed25519", + "ed25519 1.5.3", "subtle", "zeroize", ] @@ -1730,8 +1775,10 @@ dependencies = [ "chacha20", "cipher", "ctr", + "curve25519-dalek", "defmt", "digest", + "ed25519-dalek", "embedded-io", "futures", "getrandom", @@ -1747,6 +1794,7 @@ dependencies = [ "snafu", "subtle", "sunset-sshwire-derive", + "x25519-dalek", "zeroize", ] @@ -1756,6 +1804,7 @@ version = "0.1.0" dependencies = [ "bcrypt", "defmt", + "ed25519-dalek", "embassy-futures", "embassy-net", "embassy-net-driver", @@ -2185,6 +2234,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "x25519-dalek" +version = "2.0.0-rc.2" +dependencies = [ + "curve25519-dalek", + "rand_core", + "zeroize", +] + [[package]] name = "zeroize" version = "1.5.7" diff --git a/embassy/demos/picow/Cargo.toml b/embassy/demos/picow/Cargo.toml index 694ecab24516be4858a69083f5ffadc02926e7b9..b9777052dbdcd75ea0962000e1eec116af4e6921 100644 --- a/embassy/demos/picow/Cargo.toml +++ b/embassy/demos/picow/Cargo.toml @@ -94,6 +94,10 @@ embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d3 bcrypt = { version = "0.14", git = "https://github.com/mkj/rust-bcrypt", branch = "noalloc" } #bcrypt = { path = "/home/matt/3rd/rs/bcrypt" } +curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" } +x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" } +ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" } + [profile.dev] debug = 2 debug-assertions = true diff --git a/embassy/demos/picow/build.rs b/embassy/demos/picow/build.rs index 7ba8277d34842bb68b96edbfb143c12242153d3e..7b19e112bcf15b4da9d3c3fe5ebc98363b5473a6 100644 --- a/embassy/demos/picow/build.rs +++ b/embassy/demos/picow/build.rs @@ -49,5 +49,5 @@ fn git() { .unwrap_or("(unknown)".to_string()); println!("cargo:rustc-env=GIT_REV={git_rev}"); - println!("cargo:rerun-if-changed=.git/HEAD"); + println!("cargo:rerun-if-changed=../../../.git/HEAD"); } diff --git a/embassy/demos/std/Cargo.lock b/embassy/demos/std/Cargo.lock index 76e991d5c1e8951e55d2fb8518e6df8fc3326e48..771263c954358fe19767ac9a4870fc10c991b7b1 100644 --- a/embassy/demos/std/Cargo.lock +++ b/embassy/demos/std/Cargo.lock @@ -151,15 +151,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array 0.14.6", -] - [[package]] name = "block-buffer" version = "0.10.3" @@ -273,13 +264,13 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +version = "4.0.0-rc.2" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", "subtle", "zeroize", ] @@ -351,22 +342,13 @@ dependencies = [ "thiserror", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.6", -] - [[package]] name = "digest" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer", "crypto-common", "subtle", ] @@ -387,14 +369,22 @@ dependencies = [ ] [[package]] -name = "ed25519-dalek" -version = "1.0.1" +name = "ed25519" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "signature 2.0.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0-rc.2" dependencies = [ "curve25519-dalek", - "ed25519", - "sha2 0.9.9", + "ed25519 2.2.1", + "rand_core", + "sha2", "zeroize", ] @@ -587,6 +577,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "fnv" version = "1.0.7" @@ -763,7 +759,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest", ] [[package]] @@ -893,6 +889,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "polling" version = "2.5.2" @@ -972,15 +974,9 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - [[package]] name = "rand_core" version = "0.6.4" @@ -1021,7 +1017,7 @@ name = "salty" version = "0.2.0" dependencies = [ "defmt", - "ed25519", + "ed25519 1.5.3", "subtle", "zeroize", ] @@ -1038,19 +1034,6 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.6" @@ -1059,7 +1042,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest", ] [[package]] @@ -1174,7 +1157,7 @@ dependencies = [ "cipher", "ctr", "curve25519-dalek", - "digest 0.10.6", + "digest", "ed25519-dalek", "embedded-io", "futures", @@ -1184,9 +1167,9 @@ dependencies = [ "log", "poly1305", "pretty-hex", - "rand_core 0.6.4", + "rand_core", "salty", - "sha2 0.10.6", + "sha2", "signature 2.0.0", "snafu", "subtle", @@ -1200,6 +1183,7 @@ name = "sunset-demo-embassy-common" version = "0.1.0" dependencies = [ "bcrypt", + "ed25519-dalek", "embassy-futures", "embassy-net", "embassy-net-driver", @@ -1210,7 +1194,7 @@ dependencies = [ "hmac", "log", "pretty-hex", - "sha2 0.10.6", + "sha2", "sunset", "sunset-embassy", "sunset-sshwire-derive", @@ -1235,7 +1219,7 @@ dependencies = [ "libc", "log", "rand", - "sha2 0.10.6", + "sha2", "static_cell", "sunset", "sunset-demo-embassy-common", @@ -1471,12 +1455,10 @@ checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "x25519-dalek" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +version = "2.0.0-rc.2" dependencies = [ "curve25519-dalek", - "rand_core 0.5.1", + "rand_core", "zeroize", ] diff --git a/embassy/demos/std/Cargo.toml b/embassy/demos/std/Cargo.toml index 0af5512475a6b9ce586d04e191296309b8db22db..9b2e2dc0cb91b113834b08f3a1b0202a4bf060bf 100644 --- a/embassy/demos/std/Cargo.toml +++ b/embassy/demos/std/Cargo.toml @@ -44,6 +44,10 @@ embassy-net = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa1 # for tuntap embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "1d34078fa11839f88dd2e47a9355c6b35755128f" } +curve25519-dalek = { path = "/home/matt/3rd/rs/crypto/curve25519-dalek" } +x25519-dalek = { path = "/home/matt/3rd/rs/crypto/x25519-dalek" } +ed25519-dalek = { path = "/home/matt/3rd/rs/crypto/ed25519-dalek" } + [profile.dev] debug = 2 debug-assertions = true diff --git a/src/kex.rs b/src/kex.rs index 9c49906e5ffe364d518992cda1c31217c6ab7ef7..2becba96e3a5164af96d460c91b69ecc79fb34ab 100644 --- a/src/kex.rs +++ b/src/kex.rs @@ -694,7 +694,7 @@ impl KexCurve25519 { random::fill_random(s.as_mut_slice())?; // TODO: check that pure random bytes are OK let ours = x25519_dalek::EphemeralSecret::new(OsRng); - let pubkey = x25519_dalek::PublicKey::from(ours); + let pubkey = x25519_dalek::PublicKey::from(&ours); let pubkey = pubkey.to_bytes(); Ok(KexCurve25519 { ours: Some(ours), pubkey }) } diff --git a/src/sign.rs b/src/sign.rs index f2c1ba33bfb9ffe4f5c8ea1112a85243212c9121..6bbdf537f277c098fbf5dd88db1bdb8738b727cc 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -1,4 +1,3 @@ - #[allow(unused_imports)] use { crate::error::*, @@ -7,14 +6,15 @@ use { use core::ops::Deref; -use signature::Verifier; +use ed25519_dalek as dalek; +use ed25519_dalek::{Signer, Verifier}; use zeroize::ZeroizeOnDrop; use crate::*; use packets::ParseContext; +use packets::{Ed25519PubKey, PubKey, Signature}; use sshnames::*; -use packets::{PubKey, Signature, Ed25519PubKey}; -use sshwire::{BinString, SSHEncode, Blob}; +use sshwire::{BinString, Blob, SSHEncode}; use pretty_hex::PrettyHex; @@ -22,10 +22,10 @@ use core::mem::discriminant; use digest::Digest; -#[cfg(feature = "rsa")] -use rsa::signature::{DigestVerifier, DigestSigner}; #[cfg(feature = "rsa")] use packets::RSAPubKey; +#[cfg(feature = "rsa")] +use rsa::signature::{DigestSigner, DigestVerifier}; // #[cfg(feature = "rsa")] // use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme}; @@ -62,8 +62,12 @@ impl SigType { /// Returns `Ok(())` on success pub fn verify( - &self, pubkey: &PubKey, msg: &dyn SSHEncode, sig: &Signature, parse_ctx: Option<&ParseContext>) -> Result<()> { - + &self, + pubkey: &PubKey, + msg: &dyn SSHEncode, + sig: &Signature, + parse_ctx: Option<&ParseContext>, + ) -> Result<()> { // Check that the signature type is known let sig_type = sig.sig_type().map_err(|_| Error::BadSig)?; @@ -71,44 +75,50 @@ impl SigType { // This would also get caught by SignatureMismatch below // but that error message is intended for mismatch key vs sig. if discriminant(&sig_type) != discriminant(self) { - warn!("Received {:?} signature, expecting {}", - sig.algorithm_name(), self.algorithm_name()); - return Err(Error::BadSig) + warn!( + "Received {:?} signature, expecting {}", + sig.algorithm_name(), + self.algorithm_name() + ); + return Err(Error::BadSig); } match (self, pubkey, sig) { - (SigType::Ed25519, PubKey::Ed25519(k), Signature::Ed25519(s)) => { let k: &[u8; 32] = &k.key.0; let k: salty::PublicKey = k.try_into().map_err(|_| Error::BadKey)?; let s: &[u8; 64] = s.sig.0.try_into().map_err(|_| Error::BadSig)?; let s: salty::Signature = s.into(); k.verify_parts(&s, |h| { - sshwire::hash_ser(h, msg, parse_ctx).map_err(|_| salty::Error::ContextTooLong) + sshwire::hash_ser(h, msg, parse_ctx) + .map_err(|_| salty::Error::ContextTooLong) }) .map_err(|_| Error::BadSig) } #[cfg(feature = "rsa")] (SigType::RSA, PubKey::RSA(k), Signature::RSA(s)) => { - let verifying_key = rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new_with_prefix(k.key.clone()); + let verifying_key = + rsa::pkcs1v15::VerifyingKey::<sha2::Sha256>::new_with_prefix( + k.key.clone(), + ); let s: Box<[u8]> = s.sig.0.into(); let signature = s.into(); let mut h = sha2::Sha256::new(); sshwire::hash_ser(&mut h, msg, parse_ctx)?; - verifying_key.verify_digest(h, &signature) - .map_err(|e| { + verifying_key.verify_digest(h, &signature).map_err(|e| { trace!("RSA signature failed: {e}"); Error::BadSig }) } _ => { - warn!("Signature \"{:?}\" doesn't match key type \"{:?}\"", + warn!( + "Signature \"{:?}\" doesn't match key type \"{:?}\"", sig.algorithm_name(), pubkey.algorithm_name(), - ); + ); Err(Error::BadSig) } } @@ -116,8 +126,7 @@ impl SigType { } pub enum OwnedSig { - // salty::Signature doesn't let us borrow the inner bytes, - // so we just store raw bytes here. + // just store raw bytes here. Ed25519([u8; 64]), #[cfg(feature = "rsa")] RSA(rsa::pkcs1v15::Signature), @@ -151,7 +160,7 @@ impl TryFrom<Signature<'_>> for OwnedSig { } Signature::Unknown(u) => { debug!("Unknown {u} signature"); - Err(Error::UnknownMethod {kind: "signature" }) + Err(Error::UnknownMethod { kind: "signature" }) } } } @@ -168,13 +177,16 @@ pub enum KeyType { /// /// This may hold the private key part locally /// or potentially send the signing requests to an SSH agent or other entity. -#[derive(ZeroizeOnDrop, Clone, PartialEq)] +// #[derive(ZeroizeOnDrop, Clone, PartialEq)] +#[derive(ZeroizeOnDrop, Clone)] pub enum SignKey { - // 32 byte seed value is the private key - Ed25519([u8; 32]), + // TODO: we could just have the 32 byte seed here to save memory, but + // computing the public part may be slow. + #[zeroize(skip)] + Ed25519(dalek::SigningKey), #[zeroize(skip)] - AgentEd25519(salty::PublicKey), + AgentEd25519(dalek::VerifyingKey), #[cfg(feature = "rsa")] // TODO zeroize doesn't seem supported? though BigUint has Zeroize @@ -193,42 +205,41 @@ impl SignKey { if bits.unwrap_or(256) != 256 { return Err(Error::msg("Bad key size")); } - let mut seed = [0u8; 32]; - random::fill_random(&mut seed)?; - Ok(Self::Ed25519(seed)) - }, + let k = dalek::SigningKey::generate(&mut rand_core::OsRng); + Ok(Self::Ed25519(k)) + } #[cfg(feature = "rsa")] KeyType::RSA => { let bits = bits.unwrap_or(config::RSA_DEFAULT_KEYSIZE); if bits < config::RSA_MIN_KEYSIZE || bits > rsa::RsaPublicKey::MAX_SIZE - || (bits % 8 != 0) { + || (bits % 8 != 0) + { return Err(Error::msg("Bad key size")); } let k = rsa::RsaPrivateKey::new(&mut rand_core::OsRng, bits) - .map_err(|e| { - debug!("RSA key generation error {e}"); - // RNG shouldn't fail, keysize has been checked - Error::bug() - })?; + .map_err(|e| { + debug!("RSA key generation error {e}"); + // RNG shouldn't fail, keysize has been checked + Error::bug() + })?; Ok(Self::RSA(k)) - }, + } } } pub fn pubkey(&self) -> PubKey { match self { - SignKey::Ed25519(seed) => { - let k = salty::Keypair::from(seed); - PubKey::Ed25519(Ed25519PubKey - { key: Blob(k.public.as_bytes().clone()) } ) - }, - - SignKey::AgentEd25519(pk) => PubKey::Ed25519(Ed25519PubKey - { key: Blob(pk.as_bytes().clone()) } ), + SignKey::Ed25519(k) => { + let pubk = k.verifying_key().to_bytes(); + PubKey::Ed25519(Ed25519PubKey { key: Blob(pubk) }) + } + SignKey::AgentEd25519(pk) => { + PubKey::Ed25519(Ed25519PubKey { key: Blob(pk.to_bytes()) }) + } #[cfg(feature = "rsa")] SignKey::RSA(k) => PubKey::RSA(RSAPubKey { key: k.deref().clone() }), @@ -241,9 +252,7 @@ impl SignKey { #[cfg(feature = "openssh-key")] pub fn from_openssh(k: impl AsRef<[u8]>) -> Result<Self> { let k = ssh_key::PrivateKey::from_openssh(k) - .map_err(|_| { - Error::msg("Unsupported OpenSSH key") - })?; + .map_err(|_| Error::msg("Unsupported OpenSSH key"))?; k.try_into() } @@ -251,47 +260,60 @@ impl SignKey { pub fn from_agent_pubkey(pk: &PubKey) -> Result<Self> { match pk { PubKey::Ed25519(k) => { - let k: salty::PublicKey = k.try_into().map_err(|_| Error::BadKey)?; + let k: dalek::VerifyingKey = + k.key.0.as_slice().try_into().map_err(|_| Error::BadKey)?; Ok(Self::AgentEd25519(k)) - }, + } - #[cfg (feature = "rsa")] + #[cfg(feature = "rsa")] PubKey::RSA(k) => Ok(Self::AgentRSA(k.key.clone())), - PubKey::Unknown(_) => { - Err(Error::msg("Unsupported agent key")) - } + PubKey::Unknown(_) => Err(Error::msg("Unsupported agent key")), } } /// Returns whether this `SignKey` can create a given signature type pub(crate) fn can_sign(&self, sig_type: SigType) -> bool { match self { - | SignKey::Ed25519(_) - | SignKey::AgentEd25519(_) - => matches!(sig_type, SigType::Ed25519), + SignKey::Ed25519(_) | SignKey::AgentEd25519(_) => { + matches!(sig_type, SigType::Ed25519) + } #[cfg(feature = "rsa")] - | SignKey::RSA(_) - | SignKey::AgentRSA(_) - => matches!(sig_type, SigType::RSA), + SignKey::RSA(_) | SignKey::AgentRSA(_) => { + matches!(sig_type, SigType::RSA) + } } } - pub(crate) fn sign(&self, msg: &impl SSHEncode, parse_ctx: Option<&ParseContext>) -> Result<OwnedSig> { + pub(crate) fn sign( + &self, + msg: &impl SSHEncode, + parse_ctx: Option<&ParseContext>, + ) -> Result<OwnedSig> { let sig: OwnedSig = match self { - SignKey::Ed25519(seed) => { - let k = salty::Keypair::from(seed); - let sig = k.sign_parts(|h| { - sshwire::hash_ser(h, msg, parse_ctx).map_err(|_| salty::Error::ContextTooLong) - }) + SignKey::Ed25519(k) => { + let exk = dalek::hazmat::ExpandedSecretKey::from_bytes( + &k.to_keypair_bytes(), + ); + let sig = dalek::hazmat::raw_sign_byupdate::<sha2::Sha512, _>( + &exk, + |h| { + sshwire::hash_ser(h, msg, parse_ctx) + .map_err(|_| dalek::SignatureError::new()) + }, + &k.verifying_key(), + ) .trap()?; - sig.into() + OwnedSig::Ed25519(sig.to_bytes()) } #[cfg(feature = "rsa")] SignKey::RSA(k) => { - let signing_key = rsa::pkcs1v15::SigningKey::<sha2::Sha256>::new_with_prefix(k.clone()); + let signing_key = + rsa::pkcs1v15::SigningKey::<sha2::Sha256>::new_with_prefix( + k.clone(), + ); let mut h = sha2::Sha256::new(); sshwire::hash_ser(&mut h, msg, parse_ctx)?; let sig = signing_key.try_sign_digest(h).map_err(|e| { @@ -302,10 +324,9 @@ impl SignKey { } // callers should check for agent keys first - | SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"), + SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"), #[cfg(feature = "rsa")] - | SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"), - + SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"), }; // { @@ -367,10 +388,11 @@ impl TryFrom<ssh_key::PrivateKey> for SignKey { (&k.public.e).try_into().map_err(|_| Error::BadKey)?, (&k.private.d).try_into().map_err(|_| Error::BadKey)?, primes, - ).map_err(|_| Error::BadKey)?; + ) + .map_err(|_| Error::BadKey)?; Ok(SignKey::RSA(key)) } - _ => Err(Error::NotAvailable { what: k.algorithm().as_str() }) + _ => Err(Error::NotAvailable { what: k.algorithm().as_str() }), } } } @@ -379,9 +401,9 @@ impl TryFrom<ssh_key::PrivateKey> for SignKey { pub(crate) mod tests { use crate::*; - use sshnames::SSH_NAME_ED25519; use packets; use sign::*; + use sshnames::SSH_NAME_ED25519; use sunsetlog::init_test_log; // TODO: tests for sign()/verify() and invalid signatures