From 414a90b9167c996fbfa159d2bce5c545f7c88d90 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 20 Oct 2023 13:19:52 -0600 Subject: [PATCH] ssh-key: handle leading zeroes in `Mpint::from_positive_bytes` (#171) Changes the method to allow leading zeroes, stripping them and readding a leading one if need be. Closes #170 --- ssh-key/src/mpint.rs | 27 +++++++++++++++++++++++---- ssh-key/src/signature.rs | 7 +++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/ssh-key/src/mpint.rs b/ssh-key/src/mpint.rs index 6c4bcd6..c6d8426 100644 --- a/ssh-key/src/mpint.rs +++ b/ssh-key/src/mpint.rs @@ -57,12 +57,16 @@ impl Mpint { /// Create a new multiple precision integer from the given big endian /// encoded byte slice representing a positive integer. /// - /// The integer should not start with any leading zeroes. - pub fn from_positive_bytes(bytes: &[u8]) -> Result { + /// The input may begin with leading zeros, which will be stripped when + /// converted to [`Mpint`] encoding. + pub fn from_positive_bytes(mut bytes: &[u8]) -> Result { let mut inner = Vec::with_capacity(bytes.len()); - match bytes.first().cloned() { - Some(0) => return Err(Error::FormatEncoding), + while bytes.first().copied() == Some(0) { + bytes = &bytes[1..]; + } + + match bytes.first().copied() { Some(n) if n >= 0x80 => inner.push(0), _ => (), } @@ -261,6 +265,21 @@ mod tests { // Leading zero stripped assert_eq!(&hex!("80"), n.as_positive_bytes().unwrap()) } + #[test] + fn from_positive_bytes_strips_leading_zeroes() { + assert_eq!( + Mpint::from_positive_bytes(&hex!("00")).unwrap().as_ref(), + b"" + ); + assert_eq!( + Mpint::from_positive_bytes(&hex!("00 00")).unwrap().as_ref(), + b"" + ); + assert_eq!( + Mpint::from_positive_bytes(&hex!("00 01")).unwrap().as_ref(), + b"\x01" + ); + } // TODO(tarcieri): drop support for negative numbers? #[test] diff --git a/ssh-key/src/signature.rs b/ssh-key/src/signature.rs index 6081255..76de351 100644 --- a/ssh-key/src/signature.rs +++ b/ssh-key/src/signature.rs @@ -684,6 +684,13 @@ mod tests { #[cfg(feature = "ed25519")] const EXAMPLE_MSG: &[u8] = b"Hello, world!"; + #[cfg(feature = "p256")] + #[test] + fn convert_ecdsa_sha2_p256() { + let p256_signature = p256::ecdsa::Signature::try_from(hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001").as_ref()).unwrap(); + let _ssh_signature = Signature::try_from(p256_signature).unwrap(); + } + #[test] fn decode_dsa() { let signature = Signature::try_from(DSA_SIGNATURE).unwrap();