@@ -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,25 @@ 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+ // Indefinite lengths should always have EOC markers
107+ debug_assert ! ( self . inner >= 2 ) ;
108+ Self {
109+ inner : self . inner . saturating_sub ( 2 ) ,
110+ indefinite : true ,
111+ }
112+ } else {
113+ self
114+ }
115+ }
116+
95117 /// Get initial octet of the encoded length (if one is required).
96118 ///
97119 /// From X.690 Section 8.1.3.5:
@@ -379,22 +401,12 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
379401 let start_pos = reader. position ( ) ;
380402
381403 loop {
382- let current_pos = reader. position ( ) ;
383-
384404 // Look for the end-of-contents marker
385405 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- }
406+ read_eoc ( reader) ?;
395407
396408 // Compute how much we read and flag the decoded length as indefinite
397- let mut ret = ( current_pos - start_pos) ?;
409+ let mut ret = ( reader . position ( ) - start_pos) ?;
398410 ret. indefinite = true ;
399411 return Ok ( ret) ;
400412 }
@@ -404,6 +416,21 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
404416 }
405417}
406418
419+ /// Read an expected end-of-contents (EOC) marker: `00 00`.
420+ ///
421+ /// # Errors
422+ ///
423+ /// - Returns `ErrorKind::IndefiniteLength` if the EOC marker isn't present as expected.
424+ pub ( crate ) fn read_eoc < ' a > ( reader : & mut impl Reader < ' a > ) -> Result < ( ) > {
425+ for _ in 0 ..=1 {
426+ if reader. read_byte ( ) ? != 0 {
427+ return Err ( reader. error ( ErrorKind :: IndefiniteLength ) ) ;
428+ }
429+ }
430+
431+ Ok ( ( ) )
432+ }
433+
407434#[ cfg( test) ]
408435#[ allow( clippy:: unwrap_used) ]
409436mod tests {
@@ -507,9 +534,6 @@ mod tests {
507534 /// Length of example in octets.
508535 const EXAMPLE_LEN : usize = 68 ;
509536
510- /// Length of end-of-content octets (i.e. `00 00`).
511- const EOC_LEN : usize = 2 ;
512-
513537 /// Test vector from: <https://github.com/RustCrypto/formats/issues/779#issuecomment-2902948789>
514538 ///
515539 /// Notably this example contains nested indefinite lengths to ensure the decoder handles
@@ -534,18 +558,15 @@ mod tests {
534558
535559 // Decode indefinite length
536560 let length = Length :: decode ( & mut reader) . unwrap ( ) ;
537- assert ! ( length. indefinite ) ;
561+ assert ! ( length. is_indefinite ( ) ) ;
538562
539563 // Decoding the length should leave the position at the end of the indefinite length octet
540564 let pos = usize:: try_from ( reader. position ( ) ) . unwrap ( ) ;
541565 assert_eq ! ( pos, 2 ) ;
542566
543567 // The first two bytes are the header and the rest is the length of the message.
544568 // 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- ) ;
569+ assert_eq ! ( usize :: try_from( length) . unwrap( ) , EXAMPLE_LEN - pos) ;
549570
550571 // Read OID
551572 reader. tlv_bytes ( ) . unwrap ( ) ;
@@ -564,7 +585,7 @@ mod tests {
564585
565586 // Parse the inner indefinite length
566587 let length = Length :: decode ( & mut reader) . unwrap ( ) ;
567- assert ! ( length. indefinite ) ;
568- assert_eq ! ( usize :: try_from( length) . unwrap( ) , 18 ) ;
588+ assert ! ( length. is_indefinite ( ) ) ;
589+ assert_eq ! ( usize :: try_from( length) . unwrap( ) , 20 ) ;
569590 }
570591}
0 commit comments