@@ -12,6 +12,7 @@ use std::{
12
12
} ;
13
13
14
14
use bytes:: { Buf , BufMut } ;
15
+ use rand:: { Rng , RngCore } ;
15
16
use thiserror:: Error ;
16
17
17
18
use crate :: {
@@ -300,9 +301,7 @@ impl TransportParameters {
300
301
}
301
302
apply_params ! ( write_params) ;
302
303
303
- // Add a reserved parameter to keep people on their toes
304
- w. write_var ( 31 * 5 + 27 ) ;
305
- w. write_var ( 0 ) ;
304
+ write_random_grease_reserved_parameter ( w, & mut rand:: thread_rng ( ) ) ;
306
305
307
306
if let Some ( ref x) = self . stateless_reset_token {
308
307
w. write_var ( 0x02 ) ;
@@ -476,6 +475,34 @@ fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) ->
476
475
Ok ( ( ) )
477
476
}
478
477
478
+ // Write transport parameter with up to 16 bytes of random payload and ID from reserved values.
479
+ fn write_random_grease_reserved_parameter < W : BufMut , R : RngCore > ( w : & mut W , rng : & mut R ) {
480
+ // See: https://datatracker.ietf.org/doc/html/rfc9000#section-22.3
481
+ // Inspired by quic-go & quiche implementation:
482
+ // [1] https://github.com/quic-go/quic-go/blob/3e0a67b2476e1819752f04d75968de042b197b56/internal/wire/transport_parameters.go#L338-L344
483
+ // [2] https://github.com/google/quiche/blob/cb1090b20c40e2f0815107857324e99acf6ec567/quiche/quic/core/crypto/transport_parameters.cc#L843-L860
484
+
485
+ let id = {
486
+ let rand = rng. next_u64 ( ) ;
487
+ let n = ( rand % ( ( 1 << 62 ) - 27 ) ) / 31 ;
488
+ 31 * n + 27
489
+ } ;
490
+ debug_assert ! ( id < ( 1 << 62 ) ) ;
491
+ debug_assert ! ( id % 31 == 27 ) ;
492
+
493
+ let len = rng. gen_range ( 0 ..16 ) ;
494
+
495
+ let payload = {
496
+ let mut slice = [ 0u8 ; 16 ] ;
497
+ rng. fill_bytes ( & mut slice[ ..len] ) ;
498
+ slice
499
+ } ;
500
+
501
+ w. write_var ( id) ;
502
+ w. write_var ( len as u64 ) ;
503
+ w. put_slice ( & payload[ ..len] ) ;
504
+ }
505
+
479
506
#[ cfg( test) ]
480
507
mod test {
481
508
use super :: * ;
@@ -507,6 +534,43 @@ mod test {
507
534
) ;
508
535
}
509
536
537
+ #[ test]
538
+ fn write_random_reserved_transport_parameter ( ) {
539
+ use rand:: rngs:: mock:: StepRng ;
540
+ let mut rngs = [
541
+ StepRng :: new ( 0 , 1 ) ,
542
+ StepRng :: new ( 1 , 1 ) ,
543
+ StepRng :: new ( 27 , 1 ) ,
544
+ StepRng :: new ( 31 , 1 ) ,
545
+ StepRng :: new ( u32:: MAX as u64 , 1 ) ,
546
+ StepRng :: new ( u32:: MAX as u64 - 1 , 1 ) ,
547
+ StepRng :: new ( u32:: MAX as u64 + 1 , 1 ) ,
548
+ StepRng :: new ( u32:: MAX as u64 - 27 , 1 ) ,
549
+ StepRng :: new ( u32:: MAX as u64 + 27 , 1 ) ,
550
+ StepRng :: new ( u32:: MAX as u64 - 31 , 1 ) ,
551
+ StepRng :: new ( u32:: MAX as u64 + 31 , 1 ) ,
552
+ StepRng :: new ( u64:: MAX as u64 , 1 ) ,
553
+ StepRng :: new ( u64:: MAX as u64 - 1 , 1 ) ,
554
+ StepRng :: new ( u64:: MAX as u64 - 27 , 1 ) ,
555
+ StepRng :: new ( u64:: MAX as u64 - 31 , 1 ) ,
556
+ StepRng :: new ( 1 << 62 , 1 ) ,
557
+ StepRng :: new ( ( 1 << 62 ) - 1 , 1 ) ,
558
+ StepRng :: new ( ( 1 << 62 ) + 1 , 1 ) ,
559
+ StepRng :: new ( ( 1 << 62 ) - 27 , 1 ) ,
560
+ StepRng :: new ( ( 1 << 62 ) + 27 , 1 ) ,
561
+ StepRng :: new ( ( 1 << 62 ) - 31 , 1 ) ,
562
+ StepRng :: new ( ( 1 << 62 ) + 31 , 1 ) ,
563
+ ] ;
564
+ for rng in & mut rngs {
565
+ let mut buf = Vec :: new ( ) ;
566
+ write_random_grease_reserved_parameter ( & mut buf, rng) ;
567
+ assert_eq ! (
568
+ TransportParameters :: read( Side :: Client , & mut buf. as_slice( ) ) . unwrap( ) ,
569
+ TransportParameters :: default ( ) ,
570
+ ) ;
571
+ }
572
+ }
573
+
510
574
#[ test]
511
575
fn read_semantic_validation ( ) {
512
576
#[ allow( clippy:: type_complexity) ]
0 commit comments