Skip to content

Commit bf080c9

Browse files
authored
ssh-key: support for undersized ECDSA/P-521 keys (#351)
Fixes #350
1 parent 342903c commit bf080c9

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

ssh-key/src/private/ecdsa.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ impl<const SIZE: usize> Decode for EcdsaPrivateKey<SIZE> {
3939

4040
fn decode(reader: &mut impl Reader) -> Result<Self> {
4141
reader.read_prefixed(|reader| {
42-
if reader.remaining_len() == SIZE.checked_add(1).ok_or(encoding::Error::Length)? {
42+
let len = reader.remaining_len();
43+
if len == SIZE.checked_add(1).ok_or(encoding::Error::Length)? {
4344
// Strip leading zero
4445
// TODO(tarcieri): make sure leading zero was necessary
4546
if u8::decode(reader)? != 0 {
@@ -48,7 +49,17 @@ impl<const SIZE: usize> Decode for EcdsaPrivateKey<SIZE> {
4849
}
4950

5051
let mut bytes = [0u8; SIZE];
51-
reader.read(&mut bytes)?;
52+
if SIZE == 66 {
53+
// https://stackoverflow.com/questions/50002149/why-p-521-public-key-x-y-some-time-is-65-bytes-some-time-is-66-bytes
54+
// although lower keys than 64 are vanishingly possible, but lets stop here
55+
if len > 63 {
56+
reader.read(&mut bytes[..core::cmp::min(len, SIZE)])?;
57+
} else {
58+
return Err(encoding::Error::Length.into());
59+
}
60+
} else {
61+
reader.read(&mut bytes)?;
62+
}
5263
Ok(Self { bytes })
5364
})
5465
}

ssh-key/tests/private_key.rs

+28
Original file line numberDiff line numberDiff line change
@@ -713,3 +713,31 @@ fn encoding_integration_test(private_key: PrivateKey) {
713713
// Ensure ssh-keygen successfully parsed our public key
714714
assert_eq!(&public_key, private_key.public_key());
715715
}
716+
717+
#[cfg(all(feature = "alloc", feature = "p521"))]
718+
#[test]
719+
fn paramiko_ecdsa_key() {
720+
let key_data = r#"-----BEGIN OPENSSH PRIVATE KEY-----
721+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
722+
1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBf1mOQFzzGhb+5d4dEzPRbrHrrV+G
723+
ODWR5lOkdlhXpljXb/aPfFGD1RcsrD+WMo510xKHUN4MblVCa//W24EAwbAApVKdO2tte1
724+
72+L2JfNuaJWTU+7QfSWnCDqNFg+XIQSL3UN8nbgOl8Uqd+vF/Z6NqIhyVACLmsm5h3Z3c
725+
blUsh0gAAAEQpYZBIaWGQSEAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
726+
AAAIUEAX9ZjkBc8xoW/uXeHRMz0W6x661fhjg1keZTpHZYV6ZY12/2j3xRg9UXLKw/ljKO
727+
ddMSh1DeDG5VQmv/1tuBAMGwAKVSnTtrbXte9vi9iXzbmiVk1Pu0H0lpwg6jRYPlyEEi91
728+
DfJ24DpfFKnfrxf2ejaiIclQAi5rJuYd2d3G5VLIdIAAAAQQ9lo6iDFKZNqcdQtVY5teUy
729+
2uAhY8gEm4tacIWp4k+PLPuz7l7fLe+V9JgZ6D32zoaVskogcJOXKw5fdF0D7VDUAAAAE3
730+
phY3prb3dzQGwtemFjemtvd3M=
731+
-----END OPENSSH PRIVATE KEY-----"#;
732+
733+
let key = PrivateKey::from_openssh(key_data);
734+
assert!(key.is_ok());
735+
let key = key.unwrap();
736+
assert!(!key.is_encrypted());
737+
assert_eq!(
738+
key.algorithm(),
739+
Algorithm::Ecdsa {
740+
curve: ssh_key::EcdsaCurve::NistP521
741+
}
742+
);
743+
}

0 commit comments

Comments
 (0)