Skip to content

Commit 41fa980

Browse files
committed
der: add tests for Application and Private tags
1 parent a126b9f commit 41fa980

File tree

3 files changed

+102
-46
lines changed

3 files changed

+102
-46
lines changed

der/src/asn1/custom_class.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ where
216216
let value = T::decode_value(
217217
&mut reader,
218218
Header {
219-
tag: tag,
219+
tag,
220220
length: content.len().try_into()?,
221221
},
222222
)?;

der/src/lib.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
//! - [`Utf8StringRef`]: ASN.1 `UTF8String`.
6464
//!
6565
//! Context specific fields can be modeled using these generic types:
66-
//! - [`ContextSpecific`]: decoder/encoder for owned context-specific fields
67-
//! - [`ContextSpecificRef`]: encode-only type for references to context-specific fields
66+
//! - [`ContextSpecificExplicit`]: decoder/encoder for owned context-specific fields
67+
//! - [`ContextSpecificExplicitRef`]: encode-only type for references to context-specific fields
6868
//!
6969
//! ## Example
7070
//! The following example implements X.509's `AlgorithmIdentifier` message type
@@ -309,8 +309,10 @@
309309
//!
310310
//! [`Any`]: asn1::Any
311311
//! [`AnyRef`]: asn1::AnyRef
312-
//! [`ContextSpecific`]: asn1::ContextSpecific
313-
//! [`ContextSpecificRef`]: asn1::ContextSpecificRef
312+
//! [`ContextSpecificExplicit`]: asn1::ContextSpecificExplicit
313+
//! [`ContextSpecificExplicitRef`]: asn1::ContextSpecificExplicitRef
314+
//! [`ContextSpecificImplicit`]: asn1::ContextSpecificImplicit
315+
//! [`ContextSpecificImplicitRef`]: asn1::ContextSpecificImplicitRef
314316
//! [`BitString`]: asn1::BitString
315317
//! [`BitStringRef`]: asn1::BitStringRef
316318
//! [`GeneralizedTime`]: asn1::GeneralizedTime

der/src/tag.rs

+95-41
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,12 @@ fn parse_parts<'a, R: Reader<'a>>(first_byte: u8, reader: &mut R) -> Result<(boo
359359
return Ok((constructed, TagNumber::new(first_number_part.into())));
360360
}
361361

362-
let mut multi_byte_tag_number = 0;
362+
let mut multi_byte_tag_number: u16 = 0;
363363

364-
for _ in 0..Tag::MAX_SIZE - 2 {
365-
multi_byte_tag_number <<= 7;
364+
for _ in 0..Tag::MAX_SIZE - 1 {
365+
multi_byte_tag_number = multi_byte_tag_number
366+
.checked_mul(0x80)
367+
.ok_or_else(|| Error::new(ErrorKind::TagNumberInvalid, reader.position()))?;
366368

367369
let byte = reader.read_byte()?;
368370
multi_byte_tag_number |= u16::from(byte & 0x7F);
@@ -372,54 +374,59 @@ fn parse_parts<'a, R: Reader<'a>>(first_byte: u8, reader: &mut R) -> Result<(boo
372374
}
373375
}
374376

375-
let byte = reader.read_byte()?;
376-
if multi_byte_tag_number > u16::MAX >> 7 || byte & 0x80 != 0 {
377-
return Err(ErrorKind::TagNumberInvalid.into());
377+
Err(Error::new(ErrorKind::TagNumberInvalid, reader.position()))
378+
}
379+
380+
fn tag_length(tag_number: u16) -> Length {
381+
if tag_number <= 30 {
382+
Length::ONE
383+
} else if tag_number < 0x80 {
384+
Length::new(2)
385+
} else if tag_number < 0x80 * 0x80 {
386+
Length::new(3)
387+
} else {
388+
Length::new(4)
378389
}
379-
multi_byte_tag_number |= u16::from(byte & 0x7F);
390+
}
380391

381-
Ok((constructed, TagNumber::new(multi_byte_tag_number)))
392+
#[allow(clippy::cast_possible_truncation)]
393+
fn tag_number_bytes(first_byte: u8, num: u16, buf: &mut [u8; Tag::MAX_SIZE]) -> &[u8] {
394+
if num <= 30 {
395+
buf[0] = first_byte | num as u8;
396+
&buf[..1]
397+
} else if num < 0x80 {
398+
buf[0] = first_byte | 0x1F;
399+
buf[1] = num as u8;
400+
&buf[..2]
401+
} else if num < 0x80 * 0x80 {
402+
buf[0] = first_byte | 0x1F;
403+
buf[1] = 0x80 | (num >> 7) as u8;
404+
buf[2] = (num & 0x7F) as u8;
405+
&buf[..3]
406+
} else {
407+
buf[0] = first_byte | 0x1F;
408+
buf[1] = 0x80 | (num >> 14) as u8;
409+
buf[2] = 0x80 | (num >> 7) as u8;
410+
buf[3] = (num & 0x7F) as u8;
411+
&buf[..4]
412+
}
382413
}
383414

384415
impl Encode for Tag {
385416
fn encoded_len(&self) -> Result<Length> {
386-
let number = self.number().value();
387-
388-
let length = if number <= 30 {
389-
Length::ONE
390-
} else {
391-
Length::new(number.ilog2() as u16 / 7 + 2)
392-
};
393-
394-
Ok(length)
417+
Ok(tag_length(self.number().value()))
395418
}
396419

397420
fn encode(&self, writer: &mut impl Writer) -> Result<()> {
398-
let mut first_byte = self.class() as u8 | u8::from(self.is_constructed()) << 5;
399-
400-
let number = self.number().value();
401-
402-
if number <= 30 {
403-
first_byte |= number as u8;
404-
writer.write_byte(first_byte)?;
405-
} else {
406-
first_byte |= 0x1F;
407-
writer.write_byte(first_byte)?;
408-
409-
let extra_bytes = number.ilog2() as u16 / 7 + 1;
410-
411-
for shift in (0..extra_bytes).rev() {
412-
let mut byte = (number >> (shift * 7)) as u8 & 0x7f;
413-
414-
if shift != 0 {
415-
byte |= 0x80;
416-
}
417-
418-
writer.write_byte(byte)?;
419-
}
421+
let mut first_byte = self.class() as u8;
422+
if self.is_constructed() {
423+
first_byte |= CONSTRUCTED_FLAG;
420424
}
425+
let num = self.number().value();
421426

422-
Ok(())
427+
let mut buf = [0u8; Tag::MAX_SIZE];
428+
let tag_bytes = tag_number_bytes(first_byte, num, &mut buf);
429+
writer.write(tag_bytes)
423430
}
424431
}
425432

@@ -499,7 +506,7 @@ impl fmt::Debug for Tag {
499506
#[cfg(test)]
500507
mod tests {
501508
use super::{Class, Tag, TagNumber};
502-
use crate::{Length, Reader, SliceReader};
509+
use crate::{Decode, Encode, Length, Reader, SliceReader};
503510

504511
#[test]
505512
fn tag_class() {
@@ -564,4 +571,51 @@ mod tests {
564571
assert_eq!(Tag::peek(&reader).unwrap(), Tag::Integer);
565572
assert_eq!(reader.position(), Length::ZERO); // Position unchanged
566573
}
574+
575+
#[test]
576+
fn decode_application() {
577+
const TAG_APPLICATION: [u8; 2] = [0x7F, 0x21];
578+
let mut reader = SliceReader::new(&TAG_APPLICATION).unwrap();
579+
let tag = Tag::decode(&mut reader).unwrap();
580+
581+
assert_eq!(
582+
tag,
583+
Tag::Application {
584+
constructed: true,
585+
number: TagNumber(33)
586+
}
587+
);
588+
589+
let mut buf = [0u8; 8];
590+
let encoded = tag.encode_to_slice(&mut buf).unwrap();
591+
592+
assert_eq!(TAG_APPLICATION, encoded);
593+
}
594+
595+
#[test]
596+
fn decode_private_out_of_range() {
597+
const TAG_PRIVATE: [u8; 4] = [0xFF, 0xFF, 0xFF, 0x7f];
598+
let mut reader = SliceReader::new(&TAG_PRIVATE).unwrap();
599+
let result = Tag::decode(&mut reader);
600+
assert!(result.is_err());
601+
}
602+
#[test]
603+
fn decode_private() {
604+
const TAG_PRIVATE: [u8; 4] = [0xFF, 0x83, 0xFF, 0x70];
605+
let mut reader = SliceReader::new(&TAG_PRIVATE).unwrap();
606+
let tag = Tag::decode(&mut reader).unwrap();
607+
608+
assert_eq!(
609+
tag,
610+
Tag::Private {
611+
constructed: true,
612+
number: TagNumber(0xfff0)
613+
}
614+
);
615+
616+
let mut buf = [0u8; 8];
617+
let encoded = tag.encode_to_slice(&mut buf).unwrap();
618+
619+
assert_eq!(TAG_PRIVATE, encoded);
620+
}
567621
}

0 commit comments

Comments
 (0)