Skip to content

Commit 9c32817

Browse files
authored
der: fix BER IMPLICIT constructed octet string (#1922)
1 parent f228c6c commit 9c32817

File tree

9 files changed

+104
-28
lines changed

9 files changed

+104
-28
lines changed

der/src/asn1/application.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Application class field.
22
33
use crate::{
4-
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header,
5-
Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
4+
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, EncodingRules,
5+
Error, Header, Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
66
tag::IsConstructed,
77
};
88
use core::cmp::Ordering;

der/src/asn1/context_specific.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Context-specific field.
22
33
use crate::{
4-
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header,
5-
Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
4+
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, EncodingRules,
5+
Error, Header, Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
66
tag::IsConstructed,
77
};
88
use core::cmp::Ordering;

der/src/asn1/integer/int.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ mod allocating {
231231
type Error = Error;
232232

233233
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
234-
let bytes = BytesOwned::decode_value(reader, header)?;
234+
let bytes = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
235235
validate_canonical(bytes.as_slice())?;
236236

237237
let result = Self::new(bytes.as_slice())?;

der/src/asn1/integer/uint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ mod allocating {
217217
type Error = Error;
218218

219219
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
220-
let bytes = BytesOwned::decode_value(reader, header)?;
220+
let bytes = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
221221
let result = Self::new(decode_to_slice(bytes.as_slice())?)?;
222222

223223
// Ensure we compute the same encoded length as the original any value.

der/src/asn1/internal_macros.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ macro_rules! impl_custom_class {
147147
let header = Header::decode(reader)?;
148148

149149
// the encoding shall be constructed if the base encoding is constructed
150-
if header.tag.is_constructed() != T::CONSTRUCTED {
150+
if header.tag.is_constructed() != T::CONSTRUCTED
151+
&& reader.encoding_rules() == EncodingRules::Der {
151152
return Err(reader.error(header.tag.non_canonical_error()).into());
152153
}
153154

der/src/asn1/octet_string.rs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ mod allocating {
218218
type Error = Error;
219219

220220
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
221-
let inner = BytesOwned::decode_value(reader, header)?;
221+
let inner = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
222222
Ok(Self { inner })
223223
}
224224
}
@@ -363,6 +363,16 @@ mod bytes {
363363
mod tests {
364364
use crate::asn1::{OctetStringRef, PrintableStringRef};
365365

366+
#[test]
367+
fn octet_string_decode_into() {
368+
// PrintableString "hi"
369+
let der = b"\x13\x02\x68\x69";
370+
let oct = OctetStringRef::new(der).unwrap();
371+
372+
let res = oct.decode_into::<PrintableStringRef<'_>>().unwrap();
373+
assert_eq!(AsRef::<str>::as_ref(&res), "hi");
374+
}
375+
366376
#[test]
367377
#[cfg(feature = "alloc")]
368378
fn decode_ber() {
@@ -372,7 +382,7 @@ mod tests {
372382
const EXAMPLE_BER: &[u8] = &hex!(
373383
"2480" // Constructed indefinite length OCTET STRING
374384
"040648656c6c6f2c" // Segment containing "Hello,"
375-
"040620776f726c64" // Segment containing world
385+
"040620776f726c64" // Segment containing "world"
376386
"0000" // End-of-contents marker
377387
);
378388

@@ -381,12 +391,62 @@ mod tests {
381391
}
382392

383393
#[test]
384-
fn octet_string_decode_into() {
385-
// PrintableString "hi"
386-
let der = b"\x13\x02\x68\x69";
387-
let oct = OctetStringRef::new(der).unwrap();
394+
#[cfg(feature = "alloc")]
395+
fn decode_context_specific_ber_explicit() {
396+
use crate::{
397+
EncodingRules, SliceReader, TagNumber,
398+
asn1::{ContextSpecific, OctetString},
399+
};
400+
use hex_literal::hex;
388401

389-
let res = oct.decode_into::<PrintableStringRef<'_>>().unwrap();
390-
assert_eq!(AsRef::<str>::as_ref(&res), "hi");
402+
let tag_number = TagNumber(0);
403+
404+
const EXAMPLE_BER: &[u8] = &hex!(
405+
"A080" // indefinite length explicit tag
406+
"2480" // Constructed indefinite length OCTET STRING
407+
"040648656c6c6f2c" // Segment containing "Hello,"
408+
"040620776f726c64" // Segment containing "world"
409+
"0000" // End-of-contents marker
410+
"0000" // End-of-contents marker
411+
);
412+
413+
let mut reader =
414+
SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
415+
416+
let decoded = ContextSpecific::<OctetString>::decode_explicit(&mut reader, tag_number)
417+
.unwrap()
418+
.unwrap()
419+
.value;
420+
421+
assert_eq!(decoded.as_bytes(), b"Hello, world");
422+
}
423+
424+
#[test]
425+
#[cfg(feature = "alloc")]
426+
fn decode_context_specific_ber_implicit() {
427+
use crate::{
428+
EncodingRules, SliceReader, TagNumber,
429+
asn1::{ContextSpecific, OctetString},
430+
};
431+
use hex_literal::hex;
432+
433+
let tag_number = TagNumber(0);
434+
435+
const EXAMPLE_BER: &[u8] = &hex!(
436+
"A080" // implicit tag, constructed indefinite length OCTET STRING
437+
"040648656c6c6f2c" // Segment containing "Hello,"
438+
"040620776f726c64" // Segment containing "world"
439+
"0000" // End-of-contents marker
440+
);
441+
442+
let mut reader =
443+
SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
444+
445+
let decoded = ContextSpecific::<OctetString>::decode_implicit(&mut reader, tag_number)
446+
.unwrap()
447+
.unwrap()
448+
.value;
449+
450+
assert_eq!(decoded.as_bytes(), b"Hello, world");
391451
}
392452
}

der/src/asn1/private.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Private class field.
22
33
use crate::{
4-
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header,
5-
Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
4+
Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, EncodingRules,
5+
Error, Header, Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
66
tag::IsConstructed,
77
};
88
use core::cmp::Ordering;

der/src/bytes.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ impl<'a> arbitrary::Arbitrary<'a> for &'a BytesRef {
118118
pub(crate) mod allocating {
119119
use super::BytesRef;
120120
use crate::{
121-
DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, Writer,
122-
length::indefinite::read_constructed_vec,
121+
DecodeValue, DerOrd, EncodeValue, EncodingRules, Error, Header, Length, Reader, Result,
122+
Tag, Writer, length::indefinite::read_constructed_vec,
123123
};
124124
use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
125125
use core::{borrow::Borrow, cmp::Ordering, ops::Deref};
@@ -145,6 +145,22 @@ pub(crate) mod allocating {
145145
inner,
146146
})
147147
}
148+
/// Decodes [`BytesOwned`] as DER, or from parts, when using a BER reader.
149+
pub fn decode_value_parts<'a, R: Reader<'a>>(
150+
reader: &mut R,
151+
header: Header,
152+
inner_tag: Tag,
153+
) -> Result<Self> {
154+
// Reassemble indefinite length string types
155+
if reader.encoding_rules() == EncodingRules::Ber
156+
&& header.length.is_indefinite()
157+
&& !inner_tag.is_constructed()
158+
{
159+
return Self::new(read_constructed_vec(reader, header.length, inner_tag)?);
160+
}
161+
162+
Self::decode_value(reader, header)
163+
}
148164
}
149165

150166
impl AsRef<[u8]> for BytesOwned {
@@ -183,11 +199,6 @@ pub(crate) mod allocating {
183199
type Error = Error;
184200

185201
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
186-
// Reassemble indefinite length string types
187-
if header.length.is_indefinite() && !header.tag.is_constructed() {
188-
return Self::new(read_constructed_vec(reader, header)?);
189-
}
190-
191202
reader.read_vec(header.length).and_then(Self::new)
192203
}
193204
}

der/src/length/indefinite.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
2222
use crate::{Decode, ErrorKind, Header, Length, Reader};
2323

24+
#[cfg(feature = "alloc")]
25+
use crate::Tag;
26+
2427
#[cfg(feature = "alloc")]
2528
use alloc::vec::Vec;
2629

@@ -80,18 +83,19 @@ pub(crate) fn read_eoc<'a>(reader: &mut impl Reader<'a>) -> crate::Result<()> {
8083
#[cfg(feature = "alloc")]
8184
pub(crate) fn read_constructed_vec<'r, R: Reader<'r>>(
8285
reader: &mut R,
83-
header: Header,
86+
length: Length,
87+
inner_tag: Tag,
8488
) -> crate::Result<Vec<u8>> {
85-
if !header.length.is_indefinite() {
89+
if !length.is_indefinite() {
8690
return Err(reader.error(ErrorKind::IndefiniteLength));
8791
}
8892

89-
let mut bytes = Vec::with_capacity(header.length.try_into()?);
93+
let mut bytes = Vec::with_capacity(length.try_into()?);
9094
let mut offset = 0;
9195

9296
while !reader.is_finished() {
9397
let h = Header::decode(reader)?;
94-
h.tag.assert_eq(header.tag)?;
98+
h.tag.assert_eq(inner_tag)?;
9599

96100
// Indefinite length headers can't be indefinite
97101
if h.length.is_indefinite() {

0 commit comments

Comments
 (0)