@@ -8,6 +8,7 @@ use crate::Error;
88use crate :: buffer:: { Buf , TmpBuf } ;
99use crate :: crypto:: { Aad , Nonce } ;
1010use crate :: dtls12:: message:: { ContentType , DTLSRecord , Dtls12CipherSuite , Handshake , Sequence } ;
11+ use crate :: window:: ReplayWindow ;
1112
1213/// Holds both the UDP packet and the parsed result of that packet.
1314pub struct Incoming {
@@ -67,12 +68,14 @@ pub struct Records {
6768}
6869
6970impl Records {
70- pub fn parse (
71+ fn parse (
7172 mut packet : & [ u8 ] ,
7273 decrypt : & mut dyn RecordHandler ,
7374 cs : Option < Dtls12CipherSuite > ,
7475 ) -> Result < Records , Error > {
7576 let mut parsed_records: ArrayVec < Record , 8 > = ArrayVec :: new ( ) ;
77+ let mut replay_updates: ArrayVec < Sequence , 8 > = ArrayVec :: new ( ) ;
78+ let mut pending_replay = ReplayWindow :: new ( ) ;
7679
7780 // Find record boundaries and copy each record ONCE from the packet
7881 while !packet. is_empty ( ) {
@@ -91,21 +94,43 @@ impl Records {
9194 // This is the ONLY copy: packet -> record buffer
9295 let record_slice = & packet[ ..record_end] ;
9396 match Record :: parse ( record_slice, decrypt, cs) {
94- Ok ( record) => {
95- if let Some ( record) = record {
97+ Ok ( parsed) => {
98+ if let Some ( sequence) = parsed. replay_sequence {
99+ if !pending_replay. check ( sequence. sequence_number ) {
100+ trace ! ( "Discarding duplicate rec in same datagram" ) ;
101+ packet = & packet[ record_end..] ;
102+ continue ;
103+ }
104+ }
105+
106+ if let Some ( record) = parsed. record {
96107 if parsed_records. try_push ( record) . is_err ( ) {
97108 return Err ( Error :: TooManyRecords ) ;
98109 }
99- } else {
110+ } else if parsed . replay_sequence . is_none ( ) {
100111 trace ! ( "Discarding replayed rec" ) ;
101112 }
113+
114+ if let Some ( sequence) = parsed. replay_sequence {
115+ pending_replay. update ( sequence. sequence_number ) ;
116+ if replay_updates. try_push ( sequence) . is_err ( ) {
117+ return Err ( Error :: TooManyRecords ) ;
118+ }
119+ }
102120 }
103121 Err ( e) => return Err ( e) ,
104122 }
105123
106124 packet = & packet[ record_end..] ;
107125 }
108126
127+ // Commit replay state only after the whole UDP datagram has parsed
128+ // successfully. A malformed trailing record must not consume
129+ // replay state for an earlier authenticated record in the same datagram.
130+ for sequence in replay_updates {
131+ decrypt. replay_update ( sequence) ;
132+ }
133+
109134 let mut records = ArrayVec :: new ( ) ;
110135 for record in parsed_records {
111136 if let Some ( record) = decrypt. classify_record ( record) ? {
@@ -134,14 +159,19 @@ pub struct Record {
134159 parsed : Box < ParsedRecord > ,
135160}
136161
162+ struct RecordParse {
163+ record : Option < Record > ,
164+ replay_sequence : Option < Sequence > ,
165+ }
166+
137167impl Record {
138168 /// The first parse pass only parses the DTLSRecord header which is unencrypted.
139169 /// Copies record data from UDP packet ONCE into a pooled buffer.
140- pub fn parse (
170+ fn parse (
141171 record_slice : & [ u8 ] ,
142172 decrypt : & mut dyn RecordHandler ,
143173 cs : Option < Dtls12CipherSuite > ,
144- ) -> Result < Option < Record > , Error > {
174+ ) -> Result < RecordParse , Error > {
145175 // ONLY COPY: UDP packet slice -> pooled buffer
146176 let mut buffer = Buf :: new ( ) ;
147177 buffer. extend_from_slice ( record_slice) ;
@@ -151,7 +181,10 @@ impl Record {
151181 // RFC 6347 §4.1.2.7: Invalid records SHOULD be silently discarded.
152182 // This includes epoch 0 records with invalid ContentType.
153183 trace ! ( "Discarding record: parse failed: {}" , e) ;
154- return Ok ( None ) ;
184+ return Ok ( RecordParse {
185+ record : None ,
186+ replay_sequence : None ,
187+ } ) ;
155188 }
156189 } ;
157190 let parsed = Box :: new ( parsed) ;
@@ -162,7 +195,10 @@ impl Record {
162195 // packet loss, we can end up seeing epoch 1 records before we can decrypt them.
163196 let is_epoch_0 = record. record ( ) . sequence . epoch == 0 ;
164197 if is_epoch_0 || !decrypt. is_peer_encryption_enabled ( ) {
165- return Ok ( Some ( record) ) ;
198+ return Ok ( RecordParse {
199+ record : Some ( record) ,
200+ replay_sequence : None ,
201+ } ) ;
166202 }
167203
168204 // We need to decrypt the record and redo the parsing.
@@ -171,12 +207,18 @@ impl Record {
171207
172208 // Anti-replay check (read-only, does not update window)
173209 if !decrypt. replay_check ( sequence) {
174- return Ok ( None ) ;
210+ return Ok ( RecordParse {
211+ record : None ,
212+ replay_sequence : None ,
213+ } ) ;
175214 }
176215
177216 let explicit_nonce_len = decrypt. explicit_nonce_len ( ) ;
178217 if ( dtls. length as usize ) < decrypt. min_protected_fragment_len ( ) {
179- return Ok ( None ) ;
218+ return Ok ( RecordParse {
219+ record : None ,
220+ replay_sequence : None ,
221+ } ) ;
180222 }
181223
182224 // Get a reference to the buffer
@@ -203,25 +245,35 @@ impl Record {
203245 }
204246
205247 trace ! ( "Discarding record: decrypt failed: {}" , e) ;
206- return Ok ( None ) ;
248+ return Ok ( RecordParse {
249+ record : None ,
250+ replay_sequence : None ,
251+ } ) ;
207252 }
208253
209254 buffer. len ( )
210255 } ;
211256
212- // Decryption succeeded — now commit the replay window update.
213- // RFC 6347 §4.1.2.6: "The receive window is updated only if the
214- // MAC verification succeeds."
215- decrypt. replay_update ( sequence) ;
216-
217257 // Update the length of the record.
218258 buffer[ 11 ] = ( new_len >> 8 ) as u8 ;
219259 buffer[ 12 ] = new_len as u8 ;
220260
221- let parsed = ParsedRecord :: parse ( & buffer, cs, explicit_nonce_len) ?;
261+ let parsed = match ParsedRecord :: parse ( & buffer, cs, explicit_nonce_len) {
262+ Ok ( parsed) => parsed,
263+ Err ( e) => {
264+ trace ! ( "Discarding authenticated record: parse failed: {}" , e) ;
265+ return Ok ( RecordParse {
266+ record : None ,
267+ replay_sequence : Some ( sequence) ,
268+ } ) ;
269+ }
270+ } ;
222271 let parsed = Box :: new ( parsed) ;
223272
224- Ok ( Some ( Record { buffer, parsed } ) )
273+ Ok ( RecordParse {
274+ record : Some ( Record { buffer, parsed } ) ,
275+ replay_sequence : Some ( sequence) ,
276+ } )
225277 }
226278
227279 pub fn record ( & self ) -> & DTLSRecord {
0 commit comments