Skip to content

Commit 6019d08

Browse files
committed
der: add IsConstructed trait, impl'ed on any FixedTag
der_derive: impl IsConstructed on derive(Choice) der: draft of test for IsConstructed vs Tagged edge case der: test: generic CHOICE inside [0] IMPLICIT CHOICE Revert "der: test: generic CHOICE inside [0] IMPLICIT CHOICE" This reverts commit dda1215. Revert "der: draft of test for IsConstructed vs Tagged edge case" This reverts commit 5daa9ba. der: add IsConstructed test docs der: format tests
1 parent 48040c8 commit 6019d08

5 files changed

Lines changed: 89 additions & 5 deletions

File tree

der/src/asn1/context_specific.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::{
44
Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header,
55
Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
6+
tag::IsConstructed,
67
};
78
use core::cmp::Ordering;
89

@@ -60,7 +61,7 @@ impl<T> ContextSpecific<T> {
6061
tag_number: TagNumber,
6162
) -> Result<Option<Self>, T::Error>
6263
where
63-
T: DecodeValue<'a> + Tagged,
64+
T: DecodeValue<'a> + IsConstructed,
6465
{
6566
Self::decode_with::<_, _, T::Error>(reader, tag_number, |reader| {
6667
// Decode IMPLICIT header
@@ -72,7 +73,7 @@ impl<T> ContextSpecific<T> {
7273
T::decode_value(reader, header)
7374
})?;
7475

75-
if header.tag.is_constructed() != value.tag().is_constructed() {
76+
if header.tag.is_constructed() != T::CONSTRUCTED {
7677
return Err(header.tag.non_canonical_error().into());
7778
}
7879

der/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ pub use crate::{
377377
length::{IndefiniteLength, Length},
378378
ord::{DerOrd, ValueOrd},
379379
reader::{Reader, slice::SliceReader},
380-
tag::{Class, FixedTag, Tag, TagMode, TagNumber, Tagged},
380+
tag::{Class, FixedTag, IsConstructed, Tag, TagMode, TagNumber, Tagged},
381381
writer::{Writer, slice::SliceWriter},
382382
};
383383

der/src/tag.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ impl<T: FixedTag + ?Sized> Tagged for T {
3232
}
3333
}
3434

35+
/// Types which have a constant ASN.1 constructed bit.
36+
pub trait IsConstructed {
37+
/// ASN.1 constructed bit
38+
const CONSTRUCTED: bool;
39+
}
40+
41+
/// Types which are [`FixedTag`] always known if they are constructed (or primitive).
42+
impl<T: FixedTag + ?Sized> IsConstructed for T {
43+
const CONSTRUCTED: bool = T::TAG.is_constructed();
44+
}
45+
3546
/// ASN.1 tags.
3647
///
3748
/// Tags are the leading identifier octet of the Tag-Length-Value encoding
@@ -229,7 +240,7 @@ impl Tag {
229240
}
230241

231242
/// Does this tag represent a constructed (as opposed to primitive) field?
232-
pub fn is_constructed(self) -> bool {
243+
pub const fn is_constructed(self) -> bool {
233244
match self {
234245
Tag::Sequence | Tag::Set => true,
235246
Tag::Application { constructed, .. }

der/tests/derive.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ mod choice {
112112
/// `Choice` with `IMPLICIT` tagging.
113113
mod implicit {
114114
use der::{
115-
Choice, Decode, Encode, SliceWriter,
115+
Choice, Decode, Encode, Sequence, SliceWriter,
116116
asn1::{BitStringRef, GeneralizedTime},
117117
};
118118
use hex_literal::hex;
@@ -179,6 +179,13 @@ mod choice {
179179
cs_time.encode(&mut encoder).unwrap();
180180
assert_eq!(TIME_DER, encoder.finish().unwrap());
181181
}
182+
183+
/// Test case for `CHOICE` inside `[0]` `EXPLICIT` tag in `SEQUENCE`.
184+
#[derive(Sequence, Debug, Eq, PartialEq)]
185+
pub struct ExplicitChoiceInsideSequence<'a> {
186+
#[asn1(tag_mode = "EXPLICIT", context_specific = "0")]
187+
choice_field: ImplicitChoice<'a>,
188+
}
182189
}
183190
}
184191

@@ -743,6 +750,67 @@ mod decode_value {
743750
}
744751
}
745752

753+
/// Custom derive test cases for the `DecodeValue` + `EncodeValue` macro combo.
754+
mod decode_encode_value {
755+
use der::{
756+
DecodeValue, EncodeValue, Header, IsConstructed, Length, SliceReader, SliceWriter, Tag,
757+
TagNumber,
758+
};
759+
760+
/// Example of a structure, that does not have a tag and is not a sequence
761+
#[derive(DecodeValue, EncodeValue, Default, Eq, PartialEq, Debug)]
762+
#[asn1(tag_mode = "IMPLICIT")]
763+
struct DecodeEncodeCheck<'a> {
764+
#[asn1(type = "OCTET STRING", context_specific = "5")]
765+
field: &'a [u8],
766+
}
767+
impl IsConstructed for DecodeEncodeCheck<'_> {
768+
const CONSTRUCTED: bool = true;
769+
}
770+
771+
// TODO(dishmaker): fix test after IMPLICIT/EXPLICIT trait split
772+
// #[derive(Sequence, Default, Eq, PartialEq, Debug)]
773+
// #[asn1(tag_mode = "IMPLICIT")]
774+
// struct ImplicitWrapper<'a> {
775+
// #[asn1(context_specific = "0")]
776+
// implicit_decode_encode: DecodeEncodeCheck<'a>,
777+
// }
778+
779+
#[test]
780+
fn sequence_decode_encode_custom_implicit() {
781+
// TODO(dishmaker): fix test after IMPLICIT/EXPLICIT trait split
782+
// let obj = ImplicitWrapper {
783+
// implicit_decode_encode: DecodeEncodeCheck {
784+
// field: &[0x33, 0x44],
785+
// },
786+
// };
787+
788+
// let der_encoded = obj.to_der().unwrap();
789+
790+
// assert_eq!(der_encoded, hex!("80 04 85 02 33 44"));
791+
// let obj_decoded = ImplicitWrapper::from_der(&der_encoded);
792+
// assert_eq!(obj, obj_decoded);
793+
794+
let header = Header {
795+
tag: Tag::ContextSpecific {
796+
constructed: true,
797+
number: TagNumber(0),
798+
},
799+
length: Length::new(6u16),
800+
};
801+
let obj = DecodeEncodeCheck {
802+
field: &[0x33, 0x44],
803+
};
804+
805+
let mut buf = [0u8; 100];
806+
let mut writer = SliceWriter::new(&mut buf);
807+
obj.encode_value(&mut writer).unwrap();
808+
809+
let mut reader = SliceReader::new(&buf).unwrap();
810+
let _ = DecodeEncodeCheck::decode_value(&mut reader, header);
811+
}
812+
}
813+
746814
/// Custom derive test cases for the `BitString` macro.
747815
#[cfg(feature = "std")]
748816
mod bitstring {

der_derive/src/choice.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ impl DeriveChoice {
9797
}
9898
}
9999

100+
impl #impl_generics ::der::IsConstructed for #ident #ty_generics #where_clause {
101+
const CONSTRUCTED: bool = true;
102+
}
103+
100104
impl #impl_generics ::der::Decode<#lifetime> for #ident #ty_generics #where_clause {
101105
type Error = #error;
102106

0 commit comments

Comments
 (0)