From afbe00ec10069c9e32b76a6939dd70fc93e3466a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 28 Jul 2024 14:33:58 -0600 Subject: [PATCH] ssh-encoding: PEM line width detection (#252) Uses the line width detection support added to `pem-rfc7468` in RustCrypto/formats#1464 to automatically detect the input line width and parse PEM documents accordingly, which allows support for a wider range of SSH keys which don't use the default 70 chars of line wrapping. Fixes #195 --- Cargo.lock | 4 ++-- ssh-encoding/Cargo.toml | 2 +- ssh-encoding/src/pem/reader.rs | 7 ++----- ssh-key/tests/examples/id_ed25519.64cols | 8 ++++++++ ssh-key/tests/private_key.rs | 11 +++++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 ssh-key/tests/examples/id_ed25519.64cols diff --git a/Cargo.lock b/Cargo.lock index d944a18..93ac802 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "1.0.0-rc.0" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b24c1c4a3b352d47de5ec824193e68317dc0ce041f6279a4771eb550ab7f8c" +checksum = "b6c1cde4770761bf6bd336f947b9ac1fe700b0a4ec5867cf66cf08597fe89e8c" dependencies = [ "base64ct", ] diff --git a/ssh-encoding/Cargo.toml b/ssh-encoding/Cargo.toml index 3c62a1a..2c6f779 100644 --- a/ssh-encoding/Cargo.toml +++ b/ssh-encoding/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.60" [dependencies] base64ct = { version = "1.4", optional = true } bytes = { version = "1", optional = true, default-features = false } -pem-rfc7468 = { version = "1.0.0-rc.0", optional = true } +pem-rfc7468 = { version = "1.0.0-rc.1", optional = true } sha2 = { version = "=0.11.0-pre.4", optional = true, default-features = false } [dev-dependencies] diff --git a/ssh-encoding/src/pem/reader.rs b/ssh-encoding/src/pem/reader.rs index 88cf95e..6323c9d 100644 --- a/ssh-encoding/src/pem/reader.rs +++ b/ssh-encoding/src/pem/reader.rs @@ -1,4 +1,3 @@ -use super::LINE_WIDTH; use crate::{Decode, Error, Reader, Result}; /// Inner PEM decoder. @@ -14,11 +13,9 @@ pub struct PemReader<'i> { } impl<'i> PemReader<'i> { - /// Create a new PEM reader. - /// - /// Uses [`LINE_WIDTH`] as the default line width (i.e. 70 chars). + /// Create a new PEM reader which autodetects the line width of the input. pub fn new(pem: &'i [u8]) -> Result { - let inner = Inner::new_wrapped(pem, LINE_WIDTH)?; + let inner = Inner::new_detect_wrap(pem)?; let remaining_len = inner.remaining_len(); Ok(Self { diff --git a/ssh-key/tests/examples/id_ed25519.64cols b/ssh-key/tests/examples/id_ed25519.64cols new file mode 100644 index 0000000..d81d248 --- /dev/null +++ b/ssh-key/tests/examples/id_ed25519.64cols @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz +c2gtZWQyNTUxOQAAACCzPq7zfqLffKoBDe/eo04kH2XxtSmk9D7RQyf1xUqrYgAA +AJgAIAxdACAMXQAAAAtzc2gtZWQyNTUxOQAAACCzPq7zfqLffKoBDe/eo04kH2Xx +tSmk9D7RQyf1xUqrYgAAAEC2BsIi0QwW2uFscKTUUXNHLsYX4FxlaSDSblbAj7WR +7bM+rvN+ot98qgEN796jTiQfZfG1KaT0PtFDJ/XFSqtiAAAAEHVzZXJAZXhhbXBs +ZS5jb20BAgMEBQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/ssh-key/tests/private_key.rs b/ssh-key/tests/private_key.rs index 9ad4ec2..0bb4c6d 100644 --- a/ssh-key/tests/private_key.rs +++ b/ssh-key/tests/private_key.rs @@ -34,6 +34,9 @@ const OPENSSH_ECDSA_P521_EXAMPLE: &str = include_str!("examples/id_ecdsa_p521"); /// Ed25519 OpenSSH-formatted private key const OPENSSH_ED25519_EXAMPLE: &str = include_str!("examples/id_ed25519"); +/// Ed25519 OpenSSH-formatted private key with 64-column line wrapping +const OPENSSH_ED25519_64COLS_EXAMPLE: &str = include_str!("examples/id_ed25519.64cols"); + /// RSA (3072-bit) OpenSSH-formatted public key #[cfg(feature = "alloc")] const OPENSSH_RSA_3072_EXAMPLE: &str = include_str!("examples/id_rsa_3072"); @@ -247,6 +250,14 @@ fn decode_ed25519_openssh() { assert_eq!(key.comment(), "user@example.com"); } +/// Test alternative PEM line wrappings (64 columns). +#[test] +fn decode_ed25519_openssh_64cols() { + let key = PrivateKey::from_openssh(OPENSSH_ED25519_64COLS_EXAMPLE).unwrap(); + let other_key = PrivateKey::from_openssh(OPENSSH_ED25519_EXAMPLE).unwrap(); + assert_eq!(key, other_key); +} + #[cfg(feature = "alloc")] #[test] fn decode_rsa_3072_openssh() {