Skip to content

Commit f0b55c8

Browse files
authored
ssh-key: simplified ECDSA private key decoding logic (#356)
Followup to #351 Also includes a fix and test to ensure that short keys zero-pad MSB rather than LSB, since they're encoded as big endian.
1 parent 26d482b commit f0b55c8

File tree

2 files changed

+26
-14
lines changed

2 files changed

+26
-14
lines changed

ssh-key/src/private/ecdsa.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,31 @@ impl<const SIZE: usize> Decode for EcdsaPrivateKey<SIZE> {
3939

4040
fn decode(reader: &mut impl Reader) -> Result<Self> {
4141
reader.read_prefixed(|reader| {
42-
let len = reader.remaining_len();
42+
let mut len = reader.remaining_len();
43+
44+
// Strip leading zero if necessary:
45+
// `mpint` is signed and may need a leading zero for unsigned integers
4346
if len == SIZE.checked_add(1).ok_or(encoding::Error::Length)? {
44-
// Strip leading zero
4547
// TODO(tarcieri): make sure leading zero was necessary
4648
if u8::decode(reader)? != 0 {
4749
return Err(Error::FormatEncoding);
4850
}
51+
52+
len = SIZE;
4953
}
5054

51-
let mut bytes = [0u8; SIZE];
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)?;
55+
// Minimum allowed key size: may be smaller than modulus size
56+
const MIN_SIZE: usize = 32;
57+
if len < MIN_SIZE || len > SIZE {
58+
return Err(encoding::Error::Length.into());
6259
}
60+
61+
// Add leading zeros if the encoded key is smaller than `SIZE`.
62+
// The resulting value is big endian and needs leading zero padding.
63+
let leading_zeros = SIZE.checked_sub(len).ok_or(encoding::Error::Length)?;
64+
65+
let mut bytes = [0u8; SIZE];
66+
reader.read(&mut bytes[leading_zeros..])?;
6367
Ok(Self { bytes })
6468
})
6569
}

ssh-key/tests/private_key.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,15 @@ phY3prb3dzQGwtemFjemtvd3M=
737737
assert_eq!(
738738
key.algorithm(),
739739
Algorithm::Ecdsa {
740-
curve: ssh_key::EcdsaCurve::NistP521
740+
curve: EcdsaCurve::NistP521
741741
}
742742
);
743+
744+
let keypair_data = key.key_data().ecdsa().unwrap();
745+
assert_eq!(
746+
keypair_data.private_key_bytes(),
747+
hex!(
748+
"000f65a3a88314a64da9c750b55639b5e532dae02163c8049b8b5a7085a9e24f8f2cfbb3ee5edf2def95f49819e83df6ce8695b24a207093972b0e5f745d03ed50d4"
749+
)
750+
);
743751
}

0 commit comments

Comments
 (0)