diff --git a/ssh-key/README.md b/ssh-key/README.md index 524c39a48..0d765ba5a 100644 --- a/ssh-key/README.md +++ b/ssh-key/README.md @@ -17,9 +17,9 @@ and `authorized_keys` files. ## Features -- [x] Constant-time Base64 decoding using the `base64ct` crate +- [x] Constant-time Base64 decoding/encoding using the `base64ct` crate - [x] `no_std` support including support for "heapless" (no-`alloc`) targets -- [x] Parsing OpenSSH-formatted public and private keys with the following algorithms: +- [x] Decoding/encoding OpenSSH-formatted public & private keys: - [x] DSA (`no_std` + `alloc`) - [x] ECDSA (`no_std` "heapless") - [x] Ed25519 (`no_std` "heapless") @@ -29,7 +29,6 @@ and `authorized_keys` files. #### TODO: -- [ ] Encoder support (currently decode-only) - [ ] Encrypted private key support - [ ] Legacy SSH key (pre-OpenSSH) format support - [ ] Integrations with other RustCrypto crates (e.g. `ecdsa`, `ed25519`, `rsa`) diff --git a/ssh-key/src/base64.rs b/ssh-key/src/base64.rs index fc6dea934..a35e047a3 100644 --- a/ssh-key/src/base64.rs +++ b/ssh-key/src/base64.rs @@ -178,6 +178,21 @@ pub(crate) trait DecoderExt { fn decode_string(&mut self) -> Result { String::from_utf8(self.decode_byte_vec()?).map_err(|_| Error::CharacterEncoding) } + + /// Drain the given number of bytes from the decoder, discarding them. + fn drain(&mut self, n_bytes: usize) -> Result<()> { + let mut byte = [0]; + for _ in 0..n_bytes { + self.decode_base64(&mut byte)?; + } + Ok(()) + } + + /// Decode a `u32` length prefix, and then drain the length of the body. + fn drain_prefixed(&mut self) -> Result<()> { + let n_bytes = self.decode_usize()?; + self.drain(n_bytes) + } } impl DecoderExt for Decoder<'_> { diff --git a/ssh-key/src/lib.rs b/ssh-key/src/lib.rs index 2783ae628..ef03a54d7 100644 --- a/ssh-key/src/lib.rs +++ b/ssh-key/src/lib.rs @@ -21,10 +21,9 @@ //! //! #### Example //! -//! ``` +#![cfg_attr(feature = "std", doc = "```")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # fn main() -> Result<(), Box> { -//! # #[cfg(feature = "std")] -//! # { //! use ssh_key::PublicKey; //! //! let encoded_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILM+rvN+ot98qgEN796jTiQfZfG1KaT0PtFDJ/XFSqti user@example.com"; @@ -32,10 +31,10 @@ //! //! // Key attributes //! assert_eq!(public_key.algorithm(), ssh_key::Algorithm::Ed25519); -//! assert_eq!(public_key.comment, "user@example.com"); +//! assert_eq!(public_key.comment(), "user@example.com"); //! //! // Key data: in this example an Ed25519 key -//! if let Some(ed25519_public_key) = public_key.key_data.ed25519() { +//! if let Some(ed25519_public_key) = public_key.key_data().ed25519() { //! assert_eq!( //! ed25519_public_key.as_ref(), //! [ @@ -45,7 +44,6 @@ //! ].as_ref() //! ); //! } -//! # } //! # Ok(()) //! # } //! ``` @@ -60,10 +58,9 @@ //! //! #### Example //! -//! ``` +#![cfg_attr(feature = "std", doc = " ```")] +#![cfg_attr(not(feature = "std"), doc = " ```ignore")] //! # fn main() -> Result<(), Box> { -//! # #[cfg(feature = "std")] -//! # { //! use ssh_key::PrivateKey; //! //! // WARNING: don't actually hardcode private keys in source code!!! @@ -81,10 +78,10 @@ //! //! // Key attributes //! assert_eq!(private_key.algorithm(), ssh_key::Algorithm::Ed25519); -//! assert_eq!(private_key.comment, "user@example.com"); +//! assert_eq!(private_key.comment(), "user@example.com"); //! //! // Key data: in this example an Ed25519 key -//! if let Some(ed25519_keypair) = private_key.key_data.ed25519() { +//! if let Some(ed25519_keypair) = private_key.key_data().ed25519() { //! assert_eq!( //! ed25519_keypair.public.as_ref(), //! [ @@ -103,7 +100,6 @@ //! ].as_ref() //! ) //! } -//! # } //! # Ok(()) //! # } //! ``` diff --git a/ssh-key/src/private.rs b/ssh-key/src/private.rs index b38d3149a..ee81b3f13 100644 --- a/ssh-key/src/private.rs +++ b/ssh-key/src/private.rs @@ -57,26 +57,37 @@ const UNIX_FILE_PERMISSIONS: u32 = 0o600; #[derive(Clone, Debug)] pub struct PrivateKey { /// Cipher algorithm (a.k.a. `ciphername`). - pub cipher_alg: CipherAlg, + cipher_alg: CipherAlg, /// KDF algorithm. - pub kdf_alg: KdfAlg, + kdf_alg: KdfAlg, /// KDF options. - pub kdf_options: KdfOptions, + kdf_options: KdfOptions, /// Key data. - pub key_data: KeypairData, + key_data: KeypairData, /// Comment on the key (e.g. email address). #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - pub comment: String, + comment: String, } impl PrivateKey { /// Magic string used to identify keys in this format. - pub const AUTH_MAGIC: &'static [u8] = b"openssh-key-v1\0"; + const AUTH_MAGIC: &'static [u8] = b"openssh-key-v1\0"; + + /// Create a new unencrypted private key with the given keypair data and comment. + /// + /// On `no_std` platforms, use `PrivateKey::from(key_data)` instead. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + pub fn new(key_data: KeypairData, comment: impl Into) -> Self { + let mut private_key = Self::from(key_data); + private_key.comment = comment.into(); + private_key + } /// Parse an OpenSSH-formatted PEM private key. /// @@ -128,13 +139,7 @@ impl PrivateKey { let key_data = KeypairData::decode(&mut pem_decoder)?; #[cfg(not(feature = "alloc"))] - { - let len = pem_decoder.decode_usize()?; - for _ in 0..len { - let mut byte = [0]; - pem_decoder.decode(&mut byte)?; - } - } + pem_decoder.drain_prefixed()?; #[cfg(feature = "alloc")] let comment = pem_decoder.decode_string()?; @@ -191,23 +196,15 @@ impl PrivateKey { pem_encoder.encode_usize(public_key_data.encoded_len()?)?; public_key_data.encode(&mut pem_encoder)?; - // Get private key comment - // TODO(tarcieri): comment accessor method with consistent behavior - #[cfg(not(feature = "alloc"))] - let comment = ""; - #[cfg(feature = "alloc")] - let comment = &self.comment; - // Encode private key let padding_len = self.padding_len()?; debug_assert!(padding_len <= 7, "padding too long: {}", padding_len); - pem_encoder.encode_usize(self.private_key_len()? + padding_len)?; let checkint = public_key_data.checkint(); pem_encoder.encode_u32(checkint)?; pem_encoder.encode_u32(checkint)?; self.key_data.encode(&mut pem_encoder)?; - pem_encoder.encode_str(comment)?; + pem_encoder.encode_str(self.comment())?; pem_encoder.encode_base64(&PADDING_BYTES[..padding_len])?; let encoded_len = pem_encoder.finish()?; @@ -260,6 +257,38 @@ impl PrivateKey { self.key_data.algorithm() } + /// Comment on the key (e.g. email address). + #[cfg(not(feature = "alloc"))] + pub fn comment(&self) -> &str { + "" + } + + /// Comment on the key (e.g. email address). + #[cfg(feature = "alloc")] + pub fn comment(&self) -> &str { + &self.comment + } + + /// Cipher algorithm (a.k.a. `ciphername`). + pub fn cipher_alg(&self) -> CipherAlg { + self.cipher_alg + } + + /// KDF algorithm. + pub fn kdf_alg(&self) -> KdfAlg { + self.kdf_alg + } + + /// KDF options. + pub fn kdf_options(&self) -> &KdfOptions { + &self.kdf_options + } + + /// Keypair data. + pub fn key_data(&self) -> &KeypairData { + &self.key_data + } + /// Get the [`PublicKey`] which corresponds to this private key. pub fn public_key(&self) -> PublicKey { PublicKey { @@ -295,16 +324,10 @@ impl PrivateKey { /// Get the length of the private key data in bytes (not including padding). fn private_key_len(&self) -> Result { - // TODO(tarcieri): comment accessor method with consistent behavior - #[cfg(not(feature = "alloc"))] - let comment_len = 0; - #[cfg(feature = "alloc")] - let comment_len = self.comment.len(); - Ok(8 // 2 * checkints - + self.key_data.encoded_len()? + + self.key_data().encoded_len()? + 4 // comment length prefix - + comment_len) + + self.comment().len()) } /// Get the number of padding bytes to add to this key (without padding). @@ -325,6 +348,19 @@ impl PrivateKey { } } +impl From for PrivateKey { + fn from(key_data: KeypairData) -> PrivateKey { + PrivateKey { + cipher_alg: CipherAlg::None, + kdf_alg: KdfAlg::None, + kdf_options: KdfOptions::default(), + key_data, + #[cfg(feature = "alloc")] + comment: String::new(), + } + } +} + impl From for PublicKey { fn from(private_key: PrivateKey) -> PublicKey { private_key.public_key() @@ -353,13 +389,14 @@ impl str::FromStr for PrivateKey { #[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] impl ConstantTimeEq for PrivateKey { fn ct_eq(&self, other: &Self) -> Choice { - // TODO(tarcieri): comment accessor method with consistent behavior - #[cfg(not(feature = "alloc"))] - let comment_eq = Choice::from(1); - #[cfg(feature = "alloc")] - let comment_eq = self.comment.as_bytes().ct_eq(other.comment.as_bytes()); - - comment_eq & self.key_data.ct_eq(&other.key_data) + // Constant-time with respect to key data and comment + self.key_data.ct_eq(&other.key_data) + & self.comment.as_bytes().ct_eq(other.comment.as_bytes()) + & Choice::from( + (self.cipher_alg == other.cipher_alg + && self.kdf_alg == other.kdf_alg + && self.kdf_options == other.kdf_options) as u8, + ) } } diff --git a/ssh-key/src/public.rs b/ssh-key/src/public.rs index ff8da45c4..b1118835c 100644 --- a/ssh-key/src/public.rs +++ b/ssh-key/src/public.rs @@ -33,15 +33,26 @@ use alloc::{ #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct PublicKey { /// Key data. - pub key_data: KeyData, + pub(crate) key_data: KeyData, /// Comment on the key (e.g. email address) #[cfg(feature = "alloc")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - pub comment: String, + pub(crate) comment: String, } impl PublicKey { + /// Create a new public key with the given comment. + /// + /// On `no_std` platforms, use `PublicKey::from(key_data)` instead. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + pub fn new(key_data: KeyData, comment: impl Into) -> Self { + Self { + key_data, + comment: comment.into(), + } + } + /// Parse an OpenSSH-formatted public key. /// /// OpenSSH-formatted public keys look like the following: @@ -72,12 +83,7 @@ impl PublicKey { /// Encode OpenSSH-formatted (PEM) public key. pub fn encode_openssh<'o>(&self, out: &'o mut [u8]) -> Result<&'o str> { - #[cfg(not(feature = "alloc"))] - let comment = ""; - #[cfg(feature = "alloc")] - let comment = &self.comment; - - openssh::Encapsulation::encode(out, self.algorithm().as_str(), comment, |encoder| { + openssh::Encapsulation::encode(out, self.algorithm().as_str(), self.comment(), |encoder| { self.key_data.encode(encoder) }) } @@ -85,6 +91,7 @@ impl PublicKey { /// Encode an OpenSSH-formatted public key, allocating a [`String`] for /// the result. #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn to_openssh(&self) -> Result { let alg_len = self.algorithm().as_str().len(); let key_data_len = base64::encoded_len(self.key_data.encoded_len()?); @@ -101,6 +108,33 @@ impl PublicKey { pub fn algorithm(&self) -> Algorithm { self.key_data.algorithm() } + + /// Comment on the key (e.g. email address). + #[cfg(not(feature = "alloc"))] + pub fn comment(&self) -> &str { + "" + } + + /// Comment on the key (e.g. email address). + #[cfg(feature = "alloc")] + pub fn comment(&self) -> &str { + &self.comment + } + + /// Private key data. + pub fn key_data(&self) -> &KeyData { + &self.key_data + } +} + +impl From for PublicKey { + fn from(key_data: KeyData) -> PublicKey { + PublicKey { + key_data, + #[cfg(feature = "alloc")] + comment: String::new(), + } + } } impl FromStr for PublicKey { diff --git a/ssh-key/tests/authorized_keys.rs b/ssh-key/tests/authorized_keys.rs index ce91a3eb5..4eed6830b 100644 --- a/ssh-key/tests/authorized_keys.rs +++ b/ssh-key/tests/authorized_keys.rs @@ -11,22 +11,22 @@ fn read_example_file() { let entry1 = authorized_keys.next().unwrap()?; assert_eq!(entry1.options.to_string(), ""); assert_eq!(entry1.public_key.to_string(), "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILM+rvN+ot98qgEN796jTiQfZfG1KaT0PtFDJ/XFSqti user1@example.com"); - assert_eq!(entry1.public_key.comment, "user1@example.com"); + assert_eq!(entry1.public_key.comment(), "user1@example.com"); let entry2 = authorized_keys.next().unwrap()?; assert_eq!(entry2.options.to_string(), "command=\"/usr/bin/date\""); assert_eq!(entry2.public_key.to_string(), "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHwf2HMM5TRXvo2SQJjsNkiDD5KqiiNjrGVv3UUh+mMT5RHxiRtOnlqvjhQtBq0VpmpCV/PwUdhOig4vkbqAcEc= user2@example.com"); - assert_eq!(entry2.public_key.comment, "user2@example.com"); + assert_eq!(entry2.public_key.comment(), "user2@example.com"); let entry3 = authorized_keys.next().unwrap()?; assert_eq!(entry3.options.to_string(), "environment=\"PATH=/bin:/usr/bin\""); assert_eq!(entry3.public_key.to_string(), "ssh-dss AAAAB3NzaC1kc3MAAACBANw9iSUO2UYhFMssjUgW46URqv8bBrDgHeF8HLBOWBvKuXF2Rx2J/XyhgX48SOLMuv0hcPaejlyLarabnF9F2V4dkpPpZSJ+7luHmxEjNxwhsdtg8UteXAWkeCzrQ6MvRJZHcDBjYh56KGvslbFnJsGLXlI4PQCyl6awNImwYGilAAAAFQCJGBU3hZf+QtP9Jh/nbfNlhFu7hwAAAIBHObOQioQVRm3HsVb7mOy3FVKhcLoLO3qoG9gTkd4KeuehtFAC3+rckiX7xSCnE/5BBKdL7VP9WRXac2Nlr9Pwl3e7zPut96wrCHt/TZX6vkfXKkbpUIj5zSqfvyNrWKaYJkfzwAQwrXNS1Hol676Ud/DDEn2oatdEhkS3beWHXAAAAIBgQqaz/YYTRMshzMzYcZ4lqgvgmA55y6v0h39e8HH2A5dwNS6sPUw2jyna+le0dceNRJifFld1J+WYM0vmquSr11DDavgEidOSaXwfMvPPPJqLmbzdtT16N+Gij9U9STQTHPQcQ3xnNNHgQAStzZJbhLOVbDDDo5BO7LMUALDfSA== user3@example.com"); - assert_eq!(entry3.public_key.comment, "user3@example.com"); + assert_eq!(entry3.public_key.comment(), "user3@example.com"); let entry4 = authorized_keys.next().unwrap()?; assert_eq!(entry4.options.to_string(), "from=\"10.0.0.?,*.example.com\",no-X11-forwarding"); assert_eq!(entry4.public_key.to_string(), "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC0WRHtxuxefSJhpIxGq4ibGFgwYnESPm8C3JFM88A1JJLoprenklrd7VJ+VH3Ov/bQwZwLyRU5dRmfR/SWTtIPWs7tToJVayKKDB+/qoXmM5ui/0CU2U4rCdQ6PdaCJdC7yFgpPL8WexjWN06+eSIKYz1AAXbx9rRv1iasslK/KUqtsqzVliagI6jl7FPO2GhRZMcso6LsZGgSxuYf/Lp0D/FcBU8GkeOo1Sx5xEt8H8bJcErtCe4Blb8JxcW6EXO3sReb4z+zcR07gumPgFITZ6hDA8sSNuvo/AlWg0IKTeZSwHHVknWdQqDJ0uczE837caBxyTZllDNIGkBjCIIOFzuTT76HfYc/7CTTGk07uaNkUFXKN79xDiFOX8JQ1ZZMZvGOTwWjuT9CqgdTvQRORbRWwOYv3MH8re9ykw3Ip6lrPifY7s6hOaAKry/nkGPMt40m1TdiW98MTIpooE7W+WXu96ax2l2OJvxX8QR7l+LFlKnkIEEJd/ItF1G22UmOjkVwNASTwza/hlY+8DoVvEmwum/nMgH2TwQT3bTQzF9s9DOJkH4d8p4Mw4gEDjNx0EgUFA91ysCAeUMQQyIvuR8HXXa+VcvhOOO5mmBcVhxJ3qUOJTyDBsT0932Zb4mNtkxdigoVxu+iiwk0vwtvKwGVDYdyMP5EAQeEIP1t0w== user4@example.com"); - assert_eq!(entry4.public_key.comment, "user4@example.com"); + assert_eq!(entry4.public_key.comment(), "user4@example.com"); assert_eq!(authorized_keys.next(), None); Ok(()) diff --git a/ssh-key/tests/private_key.rs b/ssh-key/tests/private_key.rs index 30cfed794..4d92f6a3e 100644 --- a/ssh-key/tests/private_key.rs +++ b/ssh-key/tests/private_key.rs @@ -46,9 +46,9 @@ const OSSH_RSA_4096_EXAMPLE: &str = include_str!("examples/id_rsa_4096"); #[test] fn decode_dsa_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_DSA_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Dsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Dsa, ossh_key.key_data().algorithm()); - let dsa_keypair = ossh_key.key_data.dsa().unwrap(); + let dsa_keypair = ossh_key.key_data().dsa().unwrap(); assert_eq!( &hex!( "00dc3d89250ed9462114cb2c8d4816e3a511aaff1b06b0e01de17c1cb04e581bcab97176471d89fd7ca1817 @@ -81,7 +81,7 @@ fn decode_dsa_openssh() { &hex!("0c377ac449e770d89a3557743cbd050396114b62"), dsa_keypair.private.as_bytes() ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -90,10 +90,10 @@ fn decode_ecdsa_p256_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_ECDSA_P256_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP256), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_keypair = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_keypair = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(EcdsaCurve::NistP256, ecdsa_keypair.curve()); assert_eq!( &hex!( @@ -108,7 +108,7 @@ fn decode_ecdsa_p256_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -117,10 +117,10 @@ fn decode_ecdsa_p384_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_ECDSA_P384_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP384), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_keypair = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_keypair = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(EcdsaCurve::NistP384, ecdsa_keypair.curve()); assert_eq!( &hex!( @@ -139,7 +139,7 @@ fn decode_ecdsa_p384_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -148,10 +148,10 @@ fn decode_ecdsa_p521_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_ECDSA_P521_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP521), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_keypair = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_keypair = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(EcdsaCurve::NistP521, ecdsa_keypair.curve()); assert_eq!( &hex!( @@ -171,15 +171,15 @@ fn decode_ecdsa_p521_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[test] fn decode_ed25519_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_ED25519_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Ed25519, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Ed25519, ossh_key.key_data().algorithm()); - let ed25519_keypair = ossh_key.key_data.ed25519().unwrap(); + let ed25519_keypair = ossh_key.key_data().ed25519().unwrap(); assert_eq!( &hex!("b33eaef37ea2df7caa010defdea34e241f65f1b529a4f43ed14327f5c54aab62"), ed25519_keypair.public.as_ref(), @@ -190,16 +190,16 @@ fn decode_ed25519_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!(ossh_key.comment, "user@example.com"); + assert_eq!(ossh_key.comment(), "user@example.com"); } #[cfg(feature = "alloc")] #[test] fn decode_rsa_3072_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_RSA_3072_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Rsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Rsa, ossh_key.key_data().algorithm()); - let rsa_keypair = ossh_key.key_data.rsa().unwrap(); + let rsa_keypair = ossh_key.key_data().rsa().unwrap(); assert_eq!(&hex!("010001"), rsa_keypair.public.e.as_bytes()); assert_eq!( &hex!( @@ -259,16 +259,16 @@ fn decode_rsa_3072_openssh() { ), rsa_keypair.private.q.as_bytes() ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "alloc")] #[test] fn decode_rsa_4096_openssh() { let ossh_key = PrivateKey::from_openssh(OSSH_RSA_4096_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Rsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Rsa, ossh_key.key_data().algorithm()); - let rsa_keypair = ossh_key.key_data.rsa().unwrap(); + let rsa_keypair = ossh_key.key_data().rsa().unwrap(); assert_eq!(&hex!("010001"), rsa_keypair.public.e.as_bytes()); assert_eq!( &hex!( @@ -337,7 +337,7 @@ fn decode_rsa_4096_openssh() { ), rsa_keypair.private.q.as_bytes() ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(all(feature = "alloc", feature = "subtle"))] diff --git a/ssh-key/tests/public_key.rs b/ssh-key/tests/public_key.rs index 12263db45..929e46698 100644 --- a/ssh-key/tests/public_key.rs +++ b/ssh-key/tests/public_key.rs @@ -37,9 +37,9 @@ const OSSH_RSA_4096_EXAMPLE: &str = include_str!("examples/id_rsa_4096.pub"); #[test] fn decode_dsa_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_DSA_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Dsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Dsa, ossh_key.key_data().algorithm()); - let dsa_key = ossh_key.key_data.dsa().unwrap(); + let dsa_key = ossh_key.key_data().dsa().unwrap(); assert_eq!( &hex!( "00dc3d89250ed9462114cb2c8d4816e3a511aaff1b06b0e01de17c1cb04e581bcab97176471d89fd7ca1817 @@ -69,7 +69,7 @@ fn decode_dsa_openssh() { dsa_key.y.as_bytes(), ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -78,10 +78,10 @@ fn decode_ecdsa_p256_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_ECDSA_P256_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP256), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_key = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_key = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(EcdsaCurve::NistP256, ecdsa_key.curve()); assert_eq!( &hex!( @@ -92,7 +92,7 @@ fn decode_ecdsa_p256_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -101,10 +101,10 @@ fn decode_ecdsa_p384_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_ECDSA_P384_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP384), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_key = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_key = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(EcdsaCurve::NistP384, ecdsa_key.curve()); assert_eq!( &hex!( @@ -116,7 +116,7 @@ fn decode_ecdsa_p384_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "ecdsa")] @@ -125,10 +125,10 @@ fn decode_ecdsa_p521_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_ECDSA_P521_EXAMPLE).unwrap(); assert_eq!( Algorithm::Ecdsa(EcdsaCurve::NistP521), - ossh_key.key_data.algorithm(), + ossh_key.key_data().algorithm(), ); - let ecdsa_key = ossh_key.key_data.ecdsa().unwrap(); + let ecdsa_key = ossh_key.key_data().ecdsa().unwrap(); assert_eq!(ecdsa_key.curve(), EcdsaCurve::NistP521); assert_eq!( &hex!( @@ -141,30 +141,30 @@ fn decode_ecdsa_p521_openssh() { ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[test] fn decode_ed25519_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_ED25519_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Ed25519, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Ed25519, ossh_key.key_data().algorithm()); assert_eq!( &hex!("b33eaef37ea2df7caa010defdea34e241f65f1b529a4f43ed14327f5c54aab62"), - ossh_key.key_data.ed25519().unwrap().as_ref(), + ossh_key.key_data().ed25519().unwrap().as_ref(), ); #[cfg(feature = "alloc")] - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "alloc")] #[test] fn decode_rsa_3072_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_RSA_3072_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Rsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Rsa, ossh_key.key_data().algorithm()); - let rsa_key = ossh_key.key_data.rsa().unwrap(); + let rsa_key = ossh_key.key_data().rsa().unwrap(); assert_eq!(&hex!("010001"), rsa_key.e.as_bytes()); assert_eq!( &hex!( @@ -181,16 +181,16 @@ fn decode_rsa_3072_openssh() { rsa_key.n.as_bytes(), ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "alloc")] #[test] fn decode_rsa_4096_openssh() { let ossh_key = PublicKey::from_openssh(OSSH_RSA_4096_EXAMPLE).unwrap(); - assert_eq!(Algorithm::Rsa, ossh_key.key_data.algorithm()); + assert_eq!(Algorithm::Rsa, ossh_key.key_data().algorithm()); - let rsa_key = ossh_key.key_data.rsa().unwrap(); + let rsa_key = ossh_key.key_data().rsa().unwrap(); assert_eq!(&hex!("010001"), rsa_key.e.as_bytes()); assert_eq!( &hex!( @@ -210,7 +210,7 @@ fn decode_rsa_4096_openssh() { rsa_key.n.as_bytes(), ); - assert_eq!("user@example.com", ossh_key.comment); + assert_eq!("user@example.com", ossh_key.comment()); } #[cfg(feature = "alloc")]