@@ -176,7 +176,7 @@ const DEFAULT_RSA_KEY_SIZE: usize = 4096;
176
176
const MAX_BLOCK_SIZE : usize = 16 ;
177
177
178
178
/// 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 ] ;
180
180
181
181
/// Unix file permissions for SSH private keys.
182
182
#[ cfg( all( unix, feature = "std" ) ) ]
@@ -358,6 +358,7 @@ impl PrivateKey {
358
358
& mut & * * buffer,
359
359
self . public_key . key_data . clone ( ) ,
360
360
self . cipher . block_size ( ) ,
361
+ self . cipher . block_size ( ) - 1 ,
361
362
)
362
363
}
363
364
@@ -548,8 +549,10 @@ impl PrivateKey {
548
549
reader : & mut impl Reader ,
549
550
public_key : public:: KeyData ,
550
551
block_size : usize ,
552
+ max_padding_size : usize ,
551
553
) -> Result < Self > {
552
554
debug_assert ! ( block_size <= MAX_BLOCK_SIZE ) ;
555
+ debug_assert ! ( max_padding_size <= MAX_BLOCK_SIZE ) ;
553
556
554
557
// Ensure input data is padding-aligned
555
558
if reader. remaining_len ( ) . checked_rem ( block_size) != Some ( 0 ) {
@@ -575,7 +578,7 @@ impl PrivateKey {
575
578
576
579
let padding_len = reader. remaining_len ( ) ;
577
580
578
- if padding_len >= block_size {
581
+ if padding_len > max_padding_size {
579
582
return Err ( encoding:: Error :: Length . into ( ) ) ;
580
583
}
581
584
@@ -733,7 +736,25 @@ impl Decode for PrivateKey {
733
736
}
734
737
735
738
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
+ )
737
758
} )
738
759
}
739
760
}
0 commit comments