diff --git a/CHANGELOG.md b/CHANGELOG.md index b55b1eb..b801bf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Replace the `guard` crate with (now stabilized) `let else` expressions supported directly by the compiler. Fixes compatibility with Rust 1.70.0. +- Upgraded dependencies. ## 0.2.1 (2023-02-09) diff --git a/Cargo.toml b/Cargo.toml index eafcc88..5c5d3c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,39 +27,37 @@ path = "tests/keys/main.rs" aes = "0.8" aes-gcm = "0.10" base64 = "0.21" -bcrypt-pbkdf = "0.9" +bcrypt-pbkdf = "0.10" bytes = "1.1" cbc = "0.1" chacha20 = "0.9" ctr = "0.9" derivative = "2.2" -ecdsa = {version = "0.15", features = ["signing", "verifying"]} -ed25519 = {version = "1.5", features = ["pkcs8"]} -ed25519-dalek = "1.0" +ecdsa = {version = "0.16", features = ["signing", "verifying", "digest"]} +ed25519-dalek = {version = "^2.0.0-rc", features = ["pkcs8"]} futures-core = "0.3" -hex-literal = "0.3" +hex-literal = "0.4" hmac = "0.12" log = "0.4" num-bigint-dig = {version = "0.8", features = ["rand"]} -p256 = "0.12" -p384 = "0.12" +p256 = "0.13" +p384 = "0.13" parking_lot = "0.12" -pem = "1.0" +pem = "2.0" pin-project = "1.0" -pkcs8 = {version = "0.9", features = ["encryption"]} +pkcs8 = {version = "0.10", features = ["encryption"]} poly1305 = "0.8" rand = {version = "0.8", features = ["getrandom"]} -rand_0_7 = {version = "0.7", package = "rand"} # because of x25519-dalek rand_chacha = "0.3" regex = {version = "1.6", features = ["std"], default-features = false} -regex-syntax = {version = "0.6", features = [], default-features = false} -rsa = {version = "0.8"} +regex-syntax = {version = "0.7", features = [], default-features = false} +rsa = {version = "0.9"} sha-1 = {version = "0.10", features = ["oid"]} sha2 = {version = "0.10", features = ["oid"]} thiserror = "1.0" tokio = {version = "1", features = ["sync"]} tokio-util = {version = "0.7", features = []} -x25519-dalek = "1.1" # due to issue #89 +x25519-dalek = "^2.0.0-rc" [dev-dependencies] anyhow = "1" @@ -70,7 +68,7 @@ enclose = "1.1" env_logger = "0.10" futures = "0.3" home = "0.5" -rustix = {version = "0.36", features = ["termios"]} +rustix = {version = "0.37", features = ["termios"]} tokio = {version = "1", features = ["full"]} [features] diff --git a/examples/client.rs b/examples/client.rs index 880befc..e8632df 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -5,7 +5,6 @@ use enclose::enclose; use futures::ready; use futures::future::{FutureExt as _, FusedFuture as _, Fuse}; use futures::stream::{StreamExt as _, TryStreamExt as _, FuturesUnordered}; -use guard::guard; use regex::Regex; use rustix::termios; use std::collections::{HashMap, HashSet}; @@ -189,7 +188,7 @@ struct HostFile { fn read_host_file(path: Option) -> Result> { let default_path = home::home_dir().map(|dir| dir.join(".ssh/known_hosts")); - guard!{let Some(path) = path.or(default_path) else { return Ok(None) }}; + let Some(path) = path.or(default_path) else { return Ok(None) }; let file_data = fs::read(&path) .context(format!("could not read known_hosts file {}", path.display()))?; @@ -304,7 +303,7 @@ async fn run_events( }, Some(makiko::ClientEvent::Tunnel(accept)) => { let connect_addr = remote_tunnel_addrs.get(&accept.connected_addr); - guard!{let Some(connect_addr) = connect_addr else { continue }}; + let Some(connect_addr) = connect_addr else { continue }; tunnel_tasks.push(TaskHandle(tokio::task::spawn( run_remote_tunnel(accept, connect_addr.clone()) ))); diff --git a/src/host_file.rs b/src/host_file.rs index d498945..28b775d 100644 --- a/src/host_file.rs +++ b/src/host_file.rs @@ -773,7 +773,7 @@ mod tests { let pubkey_b64 = "AAAAC3NzaC1lZDI1NTE5AAAAIPJUmxF+H42aRAqDYOHqs9Wh2JDecL51WgYygy1hxswl"; let pubkey_bytes = hex!("f2549b117e1f8d9a440a8360e1eab3d5a1d890de70be755a0632832d61c6cc25"); - let pubkey = ed25519_dalek::PublicKey::from_bytes(&pubkey_bytes).unwrap(); + let pubkey = ed25519_dalek::VerifyingKey::from_bytes(&pubkey_bytes).unwrap(); let pubkey = Pubkey::Ed25519(pubkey.into()); check_entry(format!("example.com ssh-ed25519 {} edward", pubkey_b64), Entry { diff --git a/src/kex/curve25519.rs b/src/kex/curve25519.rs index 257b551..e9a7213 100644 --- a/src/kex/curve25519.rs +++ b/src/kex/curve25519.rs @@ -42,7 +42,7 @@ struct EcdhReply { fn init_kex(_rng: &mut dyn CryptoRngCore) -> Result { // x25519-dalek depends on rand 0.7 and also requires an owned rng, so there is no way that we // could pass `&mut dyn CryptoRngCore` to `EphemeralSecret::new()` - let our_eph_privkey = x25519_dalek::EphemeralSecret::new(rand_0_7::rngs::OsRng); + let our_eph_privkey = x25519_dalek::EphemeralSecret::random_from_rng(rand::rngs::OsRng); let our_eph_pubkey = x25519_dalek::PublicKey::from(&our_eph_privkey); log::debug!("initialized curve25519 kex"); Ok(Curve25519Kex { diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 34d81ce..bbc1c5f 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -22,10 +22,10 @@ mod pkcs8; fn decode_pem(pem_data: &[u8], expected_tag: &'static str) -> Result> { let pem = pem::parse(pem_data).map_err(Error::Pem)?; - if pem.tag != expected_tag { - return Err(Error::BadPemTag(pem.tag, expected_tag.into())) + if pem.tag() != expected_tag { + return Err(Error::BadPemTag(pem.tag().into(), expected_tag.into())) } - Ok(pem.contents) + Ok(pem.into_contents()) } /// Decode a private key from any supported PEM format. @@ -43,13 +43,13 @@ fn decode_pem(pem_data: &[u8], expected_tag: &'static str) -> Result> { /// empty passphrase if the key is not encrypted. pub fn decode_pem_privkey(pem_data: &[u8], passphrase: &[u8]) -> Result { let pem = pem::parse(pem_data).map_err(Error::Pem)?; - match pem.tag.as_str() { - "OPENSSH PRIVATE KEY" => decode_openssh_binary_keypair(pem.contents.into(), passphrase) + match pem.tag() { + "OPENSSH PRIVATE KEY" => decode_openssh_binary_keypair(pem.into_contents().into(), passphrase) .map(|keypair| keypair.privkey), - "RSA PRIVATE KEY" => decode_pkcs1_der_privkey(&pem.contents).map(Privkey::Rsa), - "PRIVATE KEY" => decode_pkcs8_der_privkey(&pem.contents), - "ENCRYPTED PRIVATE KEY" => decode_pkcs8_encrypted_der_privkey(&pem.contents, passphrase), - _ => Err(Error::UnknownPemTag(pem.tag)), + "RSA PRIVATE KEY" => decode_pkcs1_der_privkey(pem.contents()).map(Privkey::Rsa), + "PRIVATE KEY" => decode_pkcs8_der_privkey(pem.contents()), + "ENCRYPTED PRIVATE KEY" => decode_pkcs8_encrypted_der_privkey(pem.contents(), passphrase), + _ => Err(Error::UnknownPemTag(pem.tag().into())), } } @@ -99,20 +99,20 @@ impl DecodedPrivkeyNopass { /// [`DecodedPrivkeyNopass::Encrypted`]. pub fn decode_pem_privkey_nopass(pem_data: &[u8]) -> Result { let pem = pem::parse(pem_data).map_err(Error::Pem)?; - match pem.tag.as_str() { + match pem.tag() { "OPENSSH PRIVATE KEY" => - decode_openssh_binary_keypair_nopass(pem.contents.into()).map(|keypair| { + decode_openssh_binary_keypair_nopass(pem.into_contents().into()).map(|keypair| { match keypair.privkey { Some(privkey) => DecodedPrivkeyNopass::Privkey(privkey), None => DecodedPrivkeyNopass::Pubkey(keypair.pubkey), } }), - "RSA PRIVATE KEY" => decode_pkcs1_der_privkey(&pem.contents) + "RSA PRIVATE KEY" => decode_pkcs1_der_privkey(pem.contents()) .map(|privkey| DecodedPrivkeyNopass::Privkey(Privkey::Rsa(privkey))), - "PRIVATE KEY" => decode_pkcs8_der_privkey(&pem.contents) + "PRIVATE KEY" => decode_pkcs8_der_privkey(pem.contents()) .map(DecodedPrivkeyNopass::Privkey), "ENCRYPTED PRIVATE KEY" => Ok(DecodedPrivkeyNopass::Encrypted), - _ => Err(Error::UnknownPemTag(pem.tag)), + _ => Err(Error::UnknownPemTag(pem.tag().into())), } } @@ -125,9 +125,9 @@ pub fn decode_pem_privkey_nopass(pem_data: &[u8]) -> Result Result { let pem = pem::parse(pem_data).map_err(Error::Pem)?; - match pem.tag.as_str() { - "RSA PUBLIC KEY" => decode_pkcs1_der_pubkey(&pem.contents).map(Pubkey::Rsa), - "PUBLIC KEY" => decode_pkcs8_der_pubkey(&pem.contents), - _ => Err(Error::UnknownPemTag(pem.tag)), + match pem.tag() { + "RSA PUBLIC KEY" => decode_pkcs1_der_pubkey(pem.contents()).map(Pubkey::Rsa), + "PUBLIC KEY" => decode_pkcs8_der_pubkey(pem.contents()), + _ => Err(Error::UnknownPemTag(pem.tag().into())), } } diff --git a/src/keys/pkcs8.rs b/src/keys/pkcs8.rs index 3aa8c6b..ed63a9e 100644 --- a/src/keys/pkcs8.rs +++ b/src/keys/pkcs8.rs @@ -1,5 +1,4 @@ use ecdsa::elliptic_curve; -use ed25519_dalek::ed25519; use pkcs8::AssociatedOid as _; use crate::error::{Result, Error}; use crate::pubkey::{Privkey, Pubkey}; @@ -14,12 +13,12 @@ use crate::pubkey::{Privkey, Pubkey}; /// empty passphrase if the key is not encrypted. pub fn decode_pkcs8_pem_privkey(pem_data: &[u8], passphrase: &[u8]) -> Result { let pem = pem::parse(pem_data).map_err(Error::Pem)?; - if pem.tag == "PRIVATE KEY" { - decode_pkcs8_der_privkey(&pem.contents) - } else if pem.tag == "ENCRYPTED PRIVATE KEY" { - decode_pkcs8_encrypted_der_privkey(&pem.contents, passphrase) + if pem.tag() == "PRIVATE KEY" { + decode_pkcs8_der_privkey(pem.contents()) + } else if pem.tag() == "ENCRYPTED PRIVATE KEY" { + decode_pkcs8_encrypted_der_privkey(pem.contents(), passphrase) } else { - Err(Error::BadPemTag(pem.tag, "PRIVATE KEY".into())) + Err(Error::BadPemTag(pem.tag().into(), "PRIVATE KEY".into())) } } @@ -32,9 +31,7 @@ pub fn decode_pkcs8_der_privkey(der_data: &[u8]) -> Result { let info = pkcs8::PrivateKeyInfo::try_from(der_data).map_err(Error::Pkcs8)?; let algo_oid = info.algorithm.oid; if algo_oid == RSA_OID { - // unfortunately, `rsa` uses an older version of `pkcs8`, so we must re-parse the DER - let info = rsa::pkcs8::PrivateKeyInfo::try_from(der_data).map_err(Error::Pkcs8Rsa)?; - let privkey = rsa::RsaPrivateKey::try_from(info).map_err(Error::Pkcs8Rsa)?; + let privkey = rsa::RsaPrivateKey::try_from(info).map_err(Error::Pkcs8)?; Ok(Privkey::Rsa(privkey.into())) } else if algo_oid == EC_OID { let curve_oid = info.algorithm.parameters_oid().map_err(Error::Pkcs8Spki)?; @@ -48,14 +45,8 @@ pub fn decode_pkcs8_der_privkey(der_data: &[u8]) -> Result { Err(Error::Pkcs8BadCurveOid(curve_oid.to_string())) } } else if algo_oid == ED25519_OID { - let keypair_bytes = ed25519::pkcs8::KeypairBytes::try_from(info).map_err(Error::Pkcs8)?; - let secret = ed25519_dalek::SecretKey::from_bytes(&keypair_bytes.secret_key) - .map_err(Error::Pkcs8Ed25519)?; - let public = match keypair_bytes.public_key { - Some(bytes) => ed25519_dalek::PublicKey::from_bytes(&bytes).map_err(Error::Pkcs8Ed25519)?, - None => ed25519_dalek::PublicKey::from(&secret), - }; - Ok(Privkey::Ed25519(ed25519_dalek::Keypair { secret, public }.into())) + let signing = ed25519_dalek::SigningKey::try_from(info).map_err(Error::Pkcs8)?; + Ok(Privkey::Ed25519(signing.into())) } else { Err(Error::Pkcs8BadAlgorithmOid(algo_oid.to_string())) } @@ -81,9 +72,7 @@ pub fn decode_pkcs8_der_pubkey(der_data: &[u8]) -> Result { let info = pkcs8::SubjectPublicKeyInfo::try_from(der_data).map_err(Error::Pkcs8Spki)?; let algo_oid = info.algorithm.oid; if algo_oid == RSA_OID { - // unfortunately, `rsa` uses an older version of `pkcs8`, so we must re-parse the DER - let info = rsa::pkcs8::SubjectPublicKeyInfo::try_from(der_data).map_err(Error::Pkcs8RsaSpki)?; - let pubkey = rsa::RsaPublicKey::try_from(info).map_err(Error::Pkcs8RsaSpki)?; + let pubkey = rsa::RsaPublicKey::try_from(info).map_err(Error::Pkcs8Spki)?; Ok(Pubkey::Rsa(pubkey.into())) } else if algo_oid == EC_OID { let curve_oid = info.algorithm.parameters_oid().map_err(Error::Pkcs8Spki)?; @@ -99,10 +88,8 @@ pub fn decode_pkcs8_der_pubkey(der_data: &[u8]) -> Result { Err(Error::Pkcs8BadCurveOid(curve_oid.to_string())) } } else if algo_oid == ED25519_OID { - let public_bytes = ed25519::pkcs8::PublicKeyBytes::try_from(info).map_err(Error::Pkcs8Spki)?; - let pubkey = ed25519_dalek::PublicKey::from_bytes(&public_bytes.to_bytes()) - .map_err(Error::Pkcs8Ed25519)?; - Ok(Pubkey::Ed25519(pubkey.into())) + let verifying = ed25519_dalek::VerifyingKey::try_from(info).map_err(Error::Pkcs8Spki)?; + Ok(Pubkey::Ed25519(verifying.into())) } else { Err(Error::Pkcs8BadAlgorithmOid(algo_oid.to_string())) } diff --git a/src/pubkey/ecdsa.rs b/src/pubkey/ecdsa.rs index d85e900..05d08a0 100644 --- a/src/pubkey/ecdsa.rs +++ b/src/pubkey/ecdsa.rs @@ -39,8 +39,9 @@ pub static ECDSA_SHA2_NISTP384: PubkeyAlgo = PubkeyAlgo { /// You can convert it to and from [`ecdsa::VerifyingKey`] and [`elliptic_curve::PublicKey`] /// using `from()`/`into()`. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct EcdsaPubkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, +pub struct EcdsaPubkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, + ecdsa::SignatureSize: generic_array::ArrayLength, { verifying: ecdsa::VerifyingKey, } @@ -54,9 +55,8 @@ pub struct EcdsaPubkey /// using `from()`/`into()`. #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "debug_less_secure", derive(Debug))] -pub struct EcdsaPrivkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, +pub struct EcdsaPrivkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, { signing: ecdsa::SigningKey, @@ -78,11 +78,10 @@ impl EcdsaPrivkey { fn verify(pubkey: &Pubkey, message: &[u8], signature: Bytes) -> Result - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, elliptic_curve::AffinePoint: ecdsa::hazmat::VerifyPrimitive, - C::Digest: digest::FixedOutput>, + C::Digest: digest::FixedOutput>, { let verifying = C::extract_verifying(pubkey)?; @@ -94,7 +93,7 @@ fn verify(pubkey: &Pubkey, message: &[u8], signature: Bytes) -> Result let to_field_bytes = |scalar: BigUint| -> Result> { use typenum::Unsigned as _; let scalar = scalar.to_bytes_be(); - if scalar.len() <= elliptic_curve::FieldSize::::to_usize() { + if scalar.len() <= elliptic_curve::FieldBytesSize::::to_usize() { let mut scalar_bytes = elliptic_curve::FieldBytes::::default(); let copy_idx = scalar_bytes.len() - scalar.len(); scalar_bytes[copy_idx..].copy_from_slice(&scalar); @@ -121,12 +120,10 @@ fn verify(pubkey: &Pubkey, message: &[u8], signature: Bytes) -> Result } fn sign(privkey: &Privkey, message: &[u8]) -> Result - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, - C::UInt: for<'a> From<&'a elliptic_curve::Scalar>, C::Digest: crypto_common::BlockSizeUser, - C::Digest: digest::FixedOutput>, + C::Digest: digest::FixedOutput>, C::Digest: digest::FixedOutputReset, { let signing = C::extract_signing(privkey)?; @@ -139,7 +136,7 @@ fn sign(privkey: &Privkey, message: &[u8]) -> Result let digest = C::Digest::new_with_prefix(message); use signature::DigestSigner as _; - let ecdsa_signature = signing.sign_digest(digest); + let ecdsa_signature: ecdsa::Signature = signing.sign_digest(digest); let (r, s) = ecdsa_signature.split_bytes(); let r = from_field_bytes(r); let s = from_field_bytes(s); @@ -155,10 +152,9 @@ fn sign(privkey: &Privkey, message: &[u8]) -> Result } pub(super) fn decode_pubkey(blob: &mut PacketDecode) -> Result> - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, - elliptic_curve::FieldSize: elliptic_curve::sec1::ModulusSize, + elliptic_curve::FieldBytesSize: elliptic_curve::sec1::ModulusSize, elliptic_curve::AffinePoint: elliptic_curve::sec1::ToEncodedPoint, elliptic_curve::AffinePoint: elliptic_curve::sec1::FromEncodedPoint, { @@ -179,10 +175,9 @@ pub(super) fn decode_pubkey(blob: &mut PacketDecode) -> Result(blob: &mut PacketEncode, pubkey: &EcdsaPubkey) - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, - elliptic_curve::FieldSize: elliptic_curve::sec1::ModulusSize, + elliptic_curve::FieldBytesSize: elliptic_curve::sec1::ModulusSize, elliptic_curve::AffinePoint: elliptic_curve::sec1::ToEncodedPoint, elliptic_curve::AffinePoint: elliptic_curve::sec1::FromEncodedPoint, { @@ -196,10 +191,9 @@ pub(super) fn encode_pubkey(blob: &mut PacketEncode, pubkey: &EcdsaPub } pub(super) fn decode_privkey(blob: &mut PacketDecode) -> Result> - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, - elliptic_curve::FieldSize: elliptic_curve::sec1::ModulusSize, + elliptic_curve::FieldBytesSize: elliptic_curve::sec1::ModulusSize, elliptic_curve::AffinePoint: elliptic_curve::sec1::ToEncodedPoint, elliptic_curve::AffinePoint: elliptic_curve::sec1::FromEncodedPoint, { @@ -216,9 +210,10 @@ pub(super) fn decode_privkey(blob: &mut PacketDecode) -> Result::from_be_bytes(&secret_scalar) + use typenum::Unsigned as _; + let secret_scalar = blob.get_scalar(elliptic_curve::FieldBytesSize::::to_usize())?; + let secret_scalar = generic_array::GenericArray::from_slice(&secret_scalar); + let secret_key = elliptic_curve::SecretKey::::from_bytes(&secret_scalar) .map_err(|_| Error::Decode("ecdsa private key is invalid (bad bytes of private scalar)"))?; if secret_key.public_key() != public_key { @@ -230,14 +225,12 @@ pub(super) fn decode_privkey(blob: &mut PacketDecode) -> Result::Scalar: ecdsa::hazmat::SignPrimitive, +pub trait Curve: ecdsa::PrimeCurve + elliptic_curve::CurveArithmetic + ecdsa::hazmat::DigestPrimitive + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, { const ALGO_NAME: &'static str; const CURVE_NAME: &'static str; - type Digest: digest::Digest; fn extract_verifying(pubkey: &Pubkey) -> Result<&ecdsa::VerifyingKey>; fn extract_signing(privkey: &Privkey) -> Result<&ecdsa::SigningKey>; @@ -246,7 +239,6 @@ pub(super) trait Curve impl Curve for p256::NistP256 { const ALGO_NAME: &'static str = "ecdsa-sha2-nistp256"; const CURVE_NAME: &'static str = "nistp256"; - type Digest = sha2::Sha256; fn extract_verifying(pubkey: &Pubkey) -> Result<&ecdsa::VerifyingKey> { match pubkey { @@ -266,7 +258,6 @@ impl Curve for p256::NistP256 { impl Curve for p384::NistP384 { const ALGO_NAME: &'static str = "ecdsa-sha2-nistp384"; const CURVE_NAME: &'static str = "nistp384"; - type Digest = sha2::Sha384; fn extract_verifying(pubkey: &Pubkey) -> Result<&ecdsa::VerifyingKey> { match pubkey { @@ -284,49 +275,50 @@ impl Curve for p384::NistP384 { } -impl From> for EcdsaPubkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, +impl From> for EcdsaPubkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, + ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(verifying: ecdsa::VerifyingKey) -> Self { Self { verifying } } } -impl From> for EcdsaPubkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, +impl From> for EcdsaPubkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, + ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(public: elliptic_curve::PublicKey) -> Self { Self { verifying: public.into() } } } -impl From> for ecdsa::VerifyingKey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, +impl From> for ecdsa::VerifyingKey + where ::Scalar: ecdsa::hazmat::SignPrimitive, + ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(pubkey: EcdsaPubkey) -> Self { pubkey.verifying } } -impl From> for elliptic_curve::PublicKey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, +impl From> for elliptic_curve::PublicKey + where ::Scalar: ecdsa::hazmat::SignPrimitive, + ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(pubkey: EcdsaPubkey) -> Self { pubkey.verifying.into() } } -impl From> for EcdsaPrivkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, +impl From> for EcdsaPrivkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(signing: ecdsa::SigningKey) -> Self { Self { signing } } } -impl From> for EcdsaPrivkey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, +impl From> for EcdsaPrivkey + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(secret: elliptic_curve::SecretKey) -> Self { Self { signing: secret.into() } } } -impl From> for ecdsa::SigningKey - where C: ecdsa::PrimeCurve + elliptic_curve::ProjectiveArithmetic, - ::Scalar: ecdsa::hazmat::SignPrimitive, +impl From> for ecdsa::SigningKey + where ::Scalar: ecdsa::hazmat::SignPrimitive, ecdsa::SignatureSize: generic_array::ArrayLength, { fn from(privkey: EcdsaPrivkey) -> Self { privkey.signing } diff --git a/src/pubkey/ed25519.rs b/src/pubkey/ed25519.rs index 34dc872..bc3d691 100644 --- a/src/pubkey/ed25519.rs +++ b/src/pubkey/ed25519.rs @@ -16,25 +16,25 @@ pub static SSH_ED25519: PubkeyAlgo = PubkeyAlgo { /// Ed25519 public key from RFC 8032. /// /// This key is compatible with [`SSH_ED25519`]. You can convert it to and from -/// [`ed25519_dalek::PublicKey`] using `from()`/`into()`. +/// [`ed25519_dalek::VerifyingKey`] using `from()`/`into()`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Ed25519Pubkey { - pub(crate) pubkey: ed25519_dalek::PublicKey, + pub(crate) verifying: ed25519_dalek::VerifyingKey, } /// Ed25519 keypair from RFC 8032. /// /// This key is compatible with [`SSH_ED25519`]. You can convert it to and from -/// [`ed25519_dalek::Keypair`] using `from()`/`into()`. +/// [`ed25519_dalek::SigningKey`] using `from()`/`into()`. #[cfg_attr(feature = "debug_less_secure", derive(Debug))] pub struct Ed25519Privkey { - pub(crate) keypair: ed25519_dalek::Keypair, + pub(crate) signing: ed25519_dalek::SigningKey, } impl Ed25519Privkey { /// Get the public associated with this private key. pub fn pubkey(&self) -> Ed25519Pubkey { - Ed25519Pubkey { pubkey: self.keypair.public } + Ed25519Pubkey { verifying: self.signing.verifying_key() } } } @@ -49,7 +49,7 @@ fn verify(pubkey: &Pubkey, message: &[u8], signature: Bytes) -> Result()?; let ed_signature = ed25519_dalek::Signature::from(signature_data); - match pubkey.pubkey.verify_strict(message, &ed_signature) { + match pubkey.verifying.verify_strict(message, &ed_signature) { Ok(_) => Ok(SignatureVerified::assertion()), Err(_) => Err(Error::Signature), } @@ -59,7 +59,7 @@ fn sign(privkey: &Privkey, message: &[u8]) -> Result { let Privkey::Ed25519(privkey) = privkey else { return Err(Error::PrivkeyFormat) }; use ed25519_dalek::Signer as _; - let ed_signature = privkey.keypair.try_sign(message) + let ed_signature = privkey.signing.try_sign(message) .map_err(|_| Error::Crypto("could not sign with ed25519"))?; let mut signature = PacketEncode::new(); @@ -70,14 +70,14 @@ fn sign(privkey: &Privkey, message: &[u8]) -> Result { pub(super) fn encode_pubkey(blob: &mut PacketEncode, pubkey: &Ed25519Pubkey) { blob.put_str("ssh-ed25519"); - blob.put_bytes(pubkey.pubkey.as_bytes()); + blob.put_bytes(pubkey.verifying.as_bytes()); } pub(super) fn decode_pubkey(blob: &mut PacketDecode) -> Result { - let pubkey = blob.get_bytes()?; - let pubkey = ed25519_dalek::PublicKey::from_bytes(&pubkey) + let pubkey = blob.get_byte_array::<32>()?; + let verifying = ed25519_dalek::VerifyingKey::from_bytes(&pubkey) .map_err(|_| Error::Crypto("ed25519 public key is not valid"))?; - Ok(Ed25519Pubkey { pubkey }) + Ok(Ed25519Pubkey { verifying }) } pub(super) fn decode_privkey(blob: &mut PacketDecode) -> Result { @@ -87,44 +87,43 @@ pub(super) fn decode_privkey(blob: &mut PacketDecode) -> Result return Err(Error::Decode("ed25519 privkey is not valid (public keys do not match)")); } - let keypair = ed25519_dalek::Keypair::from_bytes(&keypair_bytes) - .map_err(|_| Error::Crypto("ed25519 keypair is not valid"))?; - Ok(Ed25519Privkey { keypair }) + let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes) + .map_err(|_| Error::Crypto("ed25519 privkey is not valid"))?; + Ok(Ed25519Privkey { signing }) } -impl From for Ed25519Pubkey { - fn from(pubkey: ed25519_dalek::PublicKey) -> Self { Self { pubkey } } +impl From for Ed25519Pubkey { + fn from(verifying: ed25519_dalek::VerifyingKey) -> Self { Self { verifying } } } -impl From for ed25519_dalek::PublicKey { - fn from(pubkey: Ed25519Pubkey) -> Self { pubkey.pubkey } +impl From for ed25519_dalek::VerifyingKey { + fn from(pubkey: Ed25519Pubkey) -> Self { pubkey.verifying } } -impl From for Ed25519Privkey { - fn from(keypair: ed25519_dalek::Keypair) -> Self { Self { keypair } } +impl From for Ed25519Privkey { + fn from(signing: ed25519_dalek::SigningKey) -> Self { Self { signing } } } -impl From for ed25519_dalek::Keypair { - fn from(privkey: Ed25519Privkey) -> Self { privkey.keypair } +impl From for ed25519_dalek::SigningKey { + fn from(privkey: Ed25519Privkey) -> Self { privkey.signing } } impl fmt::Display for Ed25519Pubkey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ed25519 {:x}", Bytes::copy_from_slice(self.pubkey.as_bytes())) + write!(f, "ed25519 {:x}", Bytes::copy_from_slice(self.verifying.as_bytes())) } } impl PartialEq for Ed25519Privkey { fn eq(&self, other: &Self) -> bool { - self.keypair.public == other.keypair.public && - self.keypair.secret.as_bytes() == other.keypair.secret.as_bytes() + self.signing.to_keypair_bytes() == other.signing.to_keypair_bytes() } } impl Eq for Ed25519Privkey {} impl Clone for Ed25519Privkey { fn clone(&self) -> Self { - Self { keypair: ed25519_dalek::Keypair::from_bytes(&self.keypair.to_bytes()).unwrap() } + Self { signing: ed25519_dalek::SigningKey::from_keypair_bytes(&self.signing.to_keypair_bytes()).unwrap() } } } diff --git a/src/pubkey/rsa.rs b/src/pubkey/rsa.rs index 38741cd..40ec92e 100644 --- a/src/pubkey/rsa.rs +++ b/src/pubkey/rsa.rs @@ -1,5 +1,5 @@ use bytes::Bytes; -use rsa::{PublicKey as _, PublicKeyParts as _, pkcs8}; +use rsa::pkcs8; use sha1::digest; use std::fmt; use crate::codec::{PacketDecode, PacketEncode}; @@ -99,6 +99,7 @@ fn sign(privkey: &Privkey, message: &[u8]) -> Result { } pub(super) fn encode_pubkey(blob: &mut PacketEncode, pubkey: &RsaPubkey) { + use rsa::traits::PublicKeyParts as _; blob.put_str("ssh-rsa"); blob.put_biguint(pubkey.pubkey.e()); blob.put_biguint(pubkey.pubkey.n()); @@ -161,6 +162,7 @@ impl From for rsa::RsaPrivateKey { impl fmt::Display for RsaPubkey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use rsa::traits::PublicKeyParts as _; write!(f, "rsa n {:x}, e {}", self.pubkey.n(), self.pubkey.e()) } } diff --git a/tests/keys/keys.rs b/tests/keys/keys.rs index 1c0d0ad..10d25a2 100644 --- a/tests/keys/keys.rs +++ b/tests/keys/keys.rs @@ -4,12 +4,12 @@ use hex_literal::hex; use makiko::elliptic_curve; pub fn alice_ed25519() -> makiko::Privkey { - let private_bytes = hex!("e264980178ad0b28ef8b9a7cad8278f4f9001c52e1f2fc61165d7baa36b53175"); - let public_bytes = hex!("09255d6093be46c9db2f486fd0a946f21f5729127603811e20c2fddbf58592b3"); - makiko::Privkey::Ed25519(ed25519_dalek::Keypair { - secret: ed25519_dalek::SecretKey::from_bytes(&private_bytes).unwrap(), - public: ed25519_dalek::PublicKey::from_bytes(&public_bytes).unwrap(), - }.into()) + let keypair_bytes = hex!( + "e264980178ad0b28ef8b9a7cad8278f4f9001c52e1f2fc61165d7baa36b53175" + "09255d6093be46c9db2f486fd0a946f21f5729127603811e20c2fddbf58592b3" + ); + let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes).unwrap(); + makiko::Privkey::Ed25519(signing.into()) } pub static ALICE_ED25519_PRIVKEY_FILE: &'static str = concat!( "-----BEGIN OPENSSH PRIVATE KEY-----\n", @@ -26,12 +26,12 @@ pub static ALICE_ED25519_PUBKEY_FILE: &'static str = concat!( ); pub fn edward_ed25519() -> makiko::Privkey { - let private_bytes = hex!("3972dfb17dcf6a949e08d8979ef0722b021379e72c66b549af2a98d3eeae905c"); - let public_bytes = hex!("f2549b117e1f8d9a440a8360e1eab3d5a1d890de70be755a0632832d61c6cc25"); - makiko::Privkey::Ed25519(ed25519_dalek::Keypair { - secret: ed25519_dalek::SecretKey::from_bytes(&private_bytes).unwrap(), - public: ed25519_dalek::PublicKey::from_bytes(&public_bytes).unwrap(), - }.into()) + let keypair_bytes = hex!( + "3972dfb17dcf6a949e08d8979ef0722b021379e72c66b549af2a98d3eeae905c" + "f2549b117e1f8d9a440a8360e1eab3d5a1d890de70be755a0632832d61c6cc25" + ); + let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes).unwrap(); + makiko::Privkey::Ed25519(signing.into()) } pub static EDWARD_ED25519_PRIVKEY_FILE: &'static str = concat!( "-----BEGIN OPENSSH PRIVATE KEY-----\n", @@ -296,10 +296,10 @@ pub static RUTH_RSA_4096_PUBKEY_FILE: &'static str = concat!( ); pub fn eda_ecdsa_p256() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "d8fd4505ee0da7db5269de892c3d1a577a1a46188df892478ee7550c359abb1a" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP256(privkey) } pub static EDA_ECDSA_P256_PRIVKEY_FILE: &'static str = concat!( @@ -319,10 +319,10 @@ pub static EDA_ECDSA_P256_PUBKEY_FILE: &'static str = concat!( ); pub fn eda_ecdsa_p384() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "48881a10e3140e41e6c4da6c7dfe4cfa3db82d10526f5707dee2722e29e5545d6840d14e54efd37e6eae9c20490729c1" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP384(privkey) } pub static EDA_ECDSA_P384_PRIVKEY_FILE: &'static str = concat!( @@ -445,12 +445,12 @@ pub static RSA_ENCRYPTED_PUBKEY_FILE: &'static str = concat!( ); pub fn ed25519_encrypted() -> makiko::Privkey { - let private_bytes = hex!("658ffa60f316e34424206cb7423a9083034e92cbbb9c4558767dfbcd9ae0ca7e"); - let public_bytes = hex!("b745e4c87adfbd3945c243969a127b9767132eb232279d3b16607fa70940b027"); - makiko::Privkey::Ed25519(ed25519_dalek::Keypair { - secret: ed25519_dalek::SecretKey::from_bytes(&private_bytes).unwrap(), - public: ed25519_dalek::PublicKey::from_bytes(&public_bytes).unwrap(), - }.into()) + let keypair_bytes = hex!( + "658ffa60f316e34424206cb7423a9083034e92cbbb9c4558767dfbcd9ae0ca7e" + "b745e4c87adfbd3945c243969a127b9767132eb232279d3b16607fa70940b027" + ); + let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes).unwrap(); + makiko::Privkey::Ed25519(signing.into()) } pub static ED25519_ENCRYPTED_PRIVKEY_FILE: &'static str = concat!( "-----BEGIN OPENSSH PRIVATE KEY-----\n", @@ -468,10 +468,10 @@ pub static ED25519_ENCRYPTED_PUBKEY_FILE: &'static str = concat!( ); pub fn ecdsa_p256_encrypted() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "ad18e77b6941aaba4496a348ec21a863b6fbac8d456c508ce1cd90da7d00968d" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP256(privkey) } pub static ECDSA_P256_ENCRYPTED_PRIVKEY_FILE: &'static str = concat!( @@ -492,10 +492,10 @@ pub static ECDSA_P256_ENCRYPTED_PUBKEY_FILE: &'static str = concat!( ); pub fn ecdsa_p384_encrypted() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "d5e1163bd7efb7b0e2c7554e8dca5cf66eaedd345d54f8734832070997baf782575a660cf57fc71b98deded3a29f22a1" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP384(privkey) } pub static ECDSA_P384_ENCRYPTED_PRIVKEY_FILE: &'static str = concat!( @@ -912,10 +912,10 @@ pub static PKCS8_RSA_PUBKEY_FILE: &'static str = concat!( ); pub fn pkcs8_ecdsa_p256() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "d5e07955f86df89a1abb70d494a40a6e7698ff1ef8b940fece2bda7da5d08ce7" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP256(privkey) } pub static PKCS8_ECDSA_P256_PRIVKEY_FILE: &'static str = concat!( @@ -933,10 +933,10 @@ pub static PKCS8_ECDSA_P256_PUBKEY_FILE: &'static str = concat!( ); pub fn pkcs8_ecdsa_p384() -> makiko::Privkey { - let private_key = elliptic_curve::SecretKey::::from_be_bytes(&hex!( + let secret_key = elliptic_curve::SecretKey::::from_slice(&hex!( "3b9564ce53defb1405a8061e85014f8363ebfe1de8a58052784fbc634fac38faca2547df6e00eb74c1a60df24a3953c6" )).unwrap(); - let privkey = makiko::pubkey::EcdsaPrivkey::::from(private_key); + let privkey = makiko::pubkey::EcdsaPrivkey::::from(secret_key); makiko::Privkey::EcdsaP384(privkey) } pub static PKCS8_ECDSA_P384_PRIVKEY_FILE: &'static str = concat!( @@ -956,12 +956,12 @@ pub static PKCS8_ECDSA_P384_PUBKEY_FILE: &'static str = concat!( ); pub fn pkcs8_ed25519() -> makiko::Privkey { - let private_bytes = hex!("913b3c130b79f9949f91a227ea91a388906e778d19358e2fdf67fb1b26aec1fc"); - let public_bytes = hex!("5652ceff9784c400f92e20c891fda383efb48b27e163086c05ebf8c214adca28"); - makiko::Privkey::Ed25519(ed25519_dalek::Keypair { - secret: ed25519_dalek::SecretKey::from_bytes(&private_bytes).unwrap(), - public: ed25519_dalek::PublicKey::from_bytes(&public_bytes).unwrap(), - }.into()) + let keypair_bytes = hex!( + "913b3c130b79f9949f91a227ea91a388906e778d19358e2fdf67fb1b26aec1fc" + "5652ceff9784c400f92e20c891fda383efb48b27e163086c05ebf8c214adca28" + ); + let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes).unwrap(); + makiko::Privkey::Ed25519(signing.into()) } pub static PKCS8_ED25519_PRIVKEY_FILE: &'static str = concat!( "-----BEGIN PRIVATE KEY-----\n", diff --git a/tests/keys/print_keys.py b/tests/keys/print_keys.py index 0366834..8dd6b93 100644 --- a/tests/keys/print_keys.py +++ b/tests/keys/print_keys.py @@ -17,12 +17,12 @@ def print_privkey(private_key, public_key): serialization.PublicFormat.Raw, ) - print(f" let private_bytes = hex!(\"{raw_private.hex()}\");") - print(f" let public_bytes = hex!(\"{raw_public.hex()}\");") - print( " makiko::Privkey::Ed25519(ed25519_dalek::Keypair {") - print( " secret: ed25519_dalek::SecretKey::from_bytes(&private_bytes).unwrap(),") - print( " public: ed25519_dalek::PublicKey::from_bytes(&public_bytes).unwrap(),") - print( " }.into())") + print( " let keypair_bytes = hex!(") + print(f" \"{raw_private.hex()}\"") + print(f" \"{raw_public.hex()}\"") + print( " );") + print( " let signing = ed25519_dalek::SigningKey::from_keypair_bytes(&keypair_bytes).unwrap();") + print( " makiko::Privkey::Ed25519(signing.into())") elif isinstance(private_key, RSAPrivateKey): def print_num(name, x): x = to_be_bytes(x) @@ -57,10 +57,10 @@ def print_num(name, x): private_numbers = private_key.private_numbers() private_bytes = to_be_bytes(private_numbers.private_value) - print(f" let private_key = elliptic_curve::SecretKey::<{curve}>::from_be_bytes(&hex!(") + print(f" let secret_key = elliptic_curve::SecretKey::<{curve}>::from_slice(&hex!(") print(f" \"{private_bytes.hex()}\"") print( " )).unwrap();") - print(f" let privkey = makiko::pubkey::EcdsaPrivkey::<{curve}>::from(private_key);") + print(f" let privkey = makiko::pubkey::EcdsaPrivkey::<{curve}>::from(secret_key);") print(f" makiko::Privkey::{variant}(privkey)") else: raise NotImplementedError()