@@ -176,7 +176,7 @@ const DEFAULT_RSA_KEY_SIZE: usize = 4096;
176176const MAX_BLOCK_SIZE : usize = 16 ;
177177
178178/// Padding bytes to use.
179- const PADDING_BYTES : [ u8 ; MAX_BLOCK_SIZE - 1 ] = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ] ;
179+ const PADDING_BYTES : [ u8 ; MAX_BLOCK_SIZE ] = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 ] ;
180180
181181/// Unix file permissions for SSH private keys.
182182#[ cfg( all( unix, feature = "std" ) ) ]
@@ -358,6 +358,7 @@ impl PrivateKey {
358358 & mut & * * buffer,
359359 self . public_key . key_data . clone ( ) ,
360360 self . cipher . block_size ( ) ,
361+ self . cipher . block_size ( ) - 1 ,
361362 )
362363 }
363364
@@ -548,8 +549,10 @@ impl PrivateKey {
548549 reader : & mut impl Reader ,
549550 public_key : public:: KeyData ,
550551 block_size : usize ,
552+ max_padding_size : usize ,
551553 ) -> Result < Self > {
552554 debug_assert ! ( block_size <= MAX_BLOCK_SIZE ) ;
555+ debug_assert ! ( max_padding_size <= MAX_BLOCK_SIZE ) ;
553556
554557 // Ensure input data is padding-aligned
555558 if reader. remaining_len ( ) . checked_rem ( block_size) != Some ( 0 ) {
@@ -575,7 +578,7 @@ impl PrivateKey {
575578
576579 let padding_len = reader. remaining_len ( ) ;
577580
578- if padding_len >= block_size {
581+ if padding_len > max_padding_size {
579582 return Err ( encoding:: Error :: Length . into ( ) ) ;
580583 }
581584
@@ -733,7 +736,25 @@ impl Decode for PrivateKey {
733736 }
734737
735738 reader. read_prefixed ( |reader| {
736- Self :: decode_privatekey_comment_pair ( reader, public_key, cipher. block_size ( ) )
739+ // PuTTYgen uses a non-standard block size of 16
740+ // and _always_ adds a padding even if data length
741+ // is divisible by 16 - for unencrypted keys
742+ // in the OpenSSH format.
743+ // We're only relaxing the exact length check, but will
744+ // still validate that the contents of the padding area.
745+ // In all other cases there can be up to (but not including)
746+ // `block_size` padding bytes as per `PROTOCOL.key`.
747+ let max_padding_size = match cipher {
748+ Cipher :: None => 16 ,
749+ #[ allow( clippy:: arithmetic_side_effects) ] // block sizes are constants
750+ _ => cipher. block_size ( ) - 1 ,
751+ } ;
752+ Self :: decode_privatekey_comment_pair (
753+ reader,
754+ public_key,
755+ cipher. block_size ( ) ,
756+ max_padding_size,
757+ )
737758 } )
738759 }
739760}
0 commit comments