@@ -40,6 +40,9 @@ impl Length {
4040 /// Maximum length (`u32::MAX`).
4141 pub const MAX : Self = Self :: new ( u32:: MAX ) ;
4242
43+ /// Length of end-of-content octets (i.e. `00 00`).
44+ pub ( crate ) const EOC_LEN : Self = Self :: new ( 2 ) ;
45+
4346 /// Maximum number of octets in a DER encoding of a [`Length`] using the
4447 /// rules implemented by this crate.
4548 pub ( crate ) const MAX_SIZE : usize = 5 ;
@@ -92,6 +95,26 @@ impl Length {
9295 Self :: new ( self . inner . saturating_sub ( rhs. inner ) )
9396 }
9497
98+ /// If the length is indefinite, compute a length with the EOC marker removed
99+ /// (i.e. the final two bytes `00 00`).
100+ ///
101+ /// Otherwise (as should always be the case with DER), the length is unchanged.
102+ ///
103+ /// This method notably preserves the `indefinite` flag when performing arithmetic.
104+ pub ( crate ) fn sans_eoc ( self ) -> Self {
105+ if self . indefinite {
106+ // We expect EOC to be present when this is called.
107+ debug_assert ! ( self >= Self :: EOC_LEN ) ;
108+
109+ Self {
110+ inner : self . saturating_sub ( Self :: EOC_LEN ) . inner ,
111+ indefinite : true ,
112+ }
113+ } else {
114+ self
115+ }
116+ }
117+
95118 /// Get initial octet of the encoded length (if one is required).
96119 ///
97120 /// From X.690 Section 8.1.3.5:
@@ -379,22 +402,12 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
379402 let start_pos = reader. position ( ) ;
380403
381404 loop {
382- let current_pos = reader. position ( ) ;
383-
384405 // Look for the end-of-contents marker
385406 if reader. peek_byte ( ) == Some ( EOC_TAG ) {
386- // Drain the end-of-contents tag
387- reader. drain ( Length :: ONE ) ?;
388-
389- // Read the length byte and ensure it's zero (i.e. the full EOC is `00 00`)
390- let length_byte = reader. read_byte ( ) ?;
391-
392- if length_byte != 0 {
393- return Err ( reader. error ( ErrorKind :: IndefiniteLength ) ) ;
394- }
407+ read_eoc ( reader) ?;
395408
396409 // Compute how much we read and flag the decoded length as indefinite
397- let mut ret = ( current_pos - start_pos) ?;
410+ let mut ret = ( reader . position ( ) - start_pos) ?;
398411 ret. indefinite = true ;
399412 return Ok ( ret) ;
400413 }
@@ -404,6 +417,21 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
404417 }
405418}
406419
420+ /// Read an expected end-of-contents (EOC) marker: `00 00`.
421+ ///
422+ /// # Errors
423+ ///
424+ /// - Returns `ErrorKind::IndefiniteLength` if the EOC marker isn't present as expected.
425+ pub ( crate ) fn read_eoc < ' a > ( reader : & mut impl Reader < ' a > ) -> Result < ( ) > {
426+ for _ in 0 ..Length :: EOC_LEN . inner as usize {
427+ if reader. read_byte ( ) ? != 0 {
428+ return Err ( reader. error ( ErrorKind :: IndefiniteLength ) ) ;
429+ }
430+ }
431+
432+ Ok ( ( ) )
433+ }
434+
407435#[ cfg( test) ]
408436#[ allow( clippy:: unwrap_used) ]
409437mod tests {
@@ -507,9 +535,6 @@ mod tests {
507535 /// Length of example in octets.
508536 const EXAMPLE_LEN : usize = 68 ;
509537
510- /// Length of end-of-content octets (i.e. `00 00`).
511- const EOC_LEN : usize = 2 ;
512-
513538 /// Test vector from: <https://github.com/RustCrypto/formats/issues/779#issuecomment-2902948789>
514539 ///
515540 /// Notably this example contains nested indefinite lengths to ensure the decoder handles
@@ -534,18 +559,15 @@ mod tests {
534559
535560 // Decode indefinite length
536561 let length = Length :: decode ( & mut reader) . unwrap ( ) ;
537- assert ! ( length. indefinite ) ;
562+ assert ! ( length. is_indefinite ( ) ) ;
538563
539564 // Decoding the length should leave the position at the end of the indefinite length octet
540565 let pos = usize:: try_from ( reader. position ( ) ) . unwrap ( ) ;
541566 assert_eq ! ( pos, 2 ) ;
542567
543568 // The first two bytes are the header and the rest is the length of the message.
544569 // The last four are two end-of-content markers (2 * 2 bytes).
545- assert_eq ! (
546- usize :: try_from( length) . unwrap( ) ,
547- EXAMPLE_LEN - pos - ( EOC_LEN * 2 )
548- ) ;
570+ assert_eq ! ( usize :: try_from( length) . unwrap( ) , EXAMPLE_LEN - pos) ;
549571
550572 // Read OID
551573 reader. tlv_bytes ( ) . unwrap ( ) ;
@@ -564,7 +586,7 @@ mod tests {
564586
565587 // Parse the inner indefinite length
566588 let length = Length :: decode ( & mut reader) . unwrap ( ) ;
567- assert ! ( length. indefinite ) ;
568- assert_eq ! ( usize :: try_from( length) . unwrap( ) , 18 ) ;
589+ assert ! ( length. is_indefinite ( ) ) ;
590+ assert_eq ! ( usize :: try_from( length) . unwrap( ) , 20 ) ;
569591 }
570592}
0 commit comments