Skip to content

Commit 65b5d4c

Browse files
authored
der: remove EOC bytes from decoded indefinite lengths (#1885)
The bytes `00 00` are used as a marker that we've reached the end of an indefinite length field, and are not of interest to someone who wants the actual value contained in the field.
1 parent 1d596fc commit 65b5d4c

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

der/src/length.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Length calculations for encoded ASN.1 DER values
22
33
use crate::{
4-
Decode, DerOrd, Encode, EncodingRules, Error, ErrorKind, Reader, Result, SliceWriter, Tag,
5-
Writer,
4+
Decode, DerOrd, Encode, EncodingRules, Error, ErrorKind, Header, Reader, Result, SliceWriter,
5+
Tag, Writer,
66
};
77
use core::{
88
cmp::Ordering,
@@ -347,6 +347,8 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
347347
let start_pos = reader.position();
348348

349349
loop {
350+
let current_pos = reader.position();
351+
350352
// Look for the end-of-contents marker
351353
if reader.peek_byte() == Some(EOC_TAG) {
352354
// Drain the end-of-contents tag
@@ -355,15 +357,14 @@ fn decode_indefinite_length<'a, R: Reader<'a>>(reader: &mut R) -> Result<Length>
355357
// Read the length byte and ensure it's zero (i.e. the full EOC is `00 00`)
356358
let length_byte = reader.read_byte()?;
357359
if length_byte == 0 {
358-
return reader.position() - start_pos;
360+
return current_pos - start_pos;
359361
} else {
360362
return Err(reader.error(ErrorKind::IndefiniteLength));
361363
}
362364
}
363365

364-
let _tag = Tag::decode(reader)?;
365-
let inner_length = Length::decode(reader)?;
366-
reader.drain(inner_length)?;
366+
let header = Header::decode(reader)?;
367+
reader.drain(header.length)?;
367368
}
368369
}
369370

@@ -470,6 +471,9 @@ mod tests {
470471
/// Length of example in octets.
471472
const EXAMPLE_LEN: usize = 68;
472473

474+
/// Length of end-of-content octets (i.e. `00 00`).
475+
const EOC_LEN: usize = 2;
476+
473477
/// Test vector from: <https://github.com/RustCrypto/formats/issues/779#issuecomment-2902948789>
474478
///
475479
/// Notably this example contains nested indefinite lengths to ensure the decoder handles
@@ -496,7 +500,30 @@ mod tests {
496500
let pos = usize::try_from(reader.position()).unwrap();
497501
assert_eq!(pos, 2);
498502

499-
// The first two bytes are the header and the rest is the length of the message
500-
assert_eq!(usize::try_from(length).unwrap(), EXAMPLE_LEN - pos);
503+
// The first two bytes are the header and the rest is the length of the message.
504+
// The last four are two end-of-content markers (2 * 2 bytes).
505+
assert_eq!(
506+
usize::try_from(length).unwrap(),
507+
EXAMPLE_LEN - pos - (EOC_LEN * 2)
508+
);
509+
510+
// Read OID
511+
reader.tlv_bytes().unwrap();
512+
// Read SEQUENCE
513+
reader.tlv_bytes().unwrap();
514+
515+
// We're now at the next indefinite length record
516+
let tag = Tag::decode(&mut reader).unwrap();
517+
assert_eq!(
518+
tag,
519+
Tag::ContextSpecific {
520+
constructed: true,
521+
number: 0u32.into()
522+
}
523+
);
524+
525+
// Parse the inner indefinite length
526+
let length = Length::decode(&mut reader).unwrap();
527+
assert_eq!(usize::try_from(length).unwrap(), 18);
501528
}
502529
}

der/src/tag/number.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ impl TagNumber {
6262
}
6363
}
6464

65+
impl From<u32> for TagNumber {
66+
fn from(value: u32) -> TagNumber {
67+
TagNumber(value)
68+
}
69+
}
70+
71+
impl From<TagNumber> for u32 {
72+
fn from(number: TagNumber) -> u32 {
73+
number.0
74+
}
75+
}
76+
6577
impl fmt::Display for TagNumber {
6678
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6779
write!(f, "{}", self.0)

0 commit comments

Comments
 (0)