From d41520debe7651276b4e4b639453b092015523f7 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Tue, 14 Nov 2023 04:27:09 +0200 Subject: [PATCH] Fix PER ObjectIdentifier, Alignment for Choice index encoding --- macros/src/enum.rs | 16 ++++++++++++++++ src/aper.rs | 33 +++++++++++++++++++++++++++++++++ src/ber/enc.rs | 1 + src/enc.rs | 1 + src/jer/enc.rs | 1 + src/per/de.rs | 3 ++- src/per/enc.rs | 34 ++++++++++++++++++++++------------ src/uper.rs | 30 ++++++++++++++++++++++++++++++ 8 files changed, 106 insertions(+), 13 deletions(-) diff --git a/macros/src/enum.rs b/macros/src/enum.rs index 4bb2b756..1829f909 100644 --- a/macros/src/enum.rs +++ b/macros/src/enum.rs @@ -324,6 +324,19 @@ impl Enum { syn::Fields::Unit => quote!(#name::#ident => #identifier), } }); + let tags = self.variants.iter().enumerate().map(|(i, v)| { + let ident = &v.ident; + let name = &self.name; + let variant_config = VariantConfig::new(v, generics, &self.config); + let variant_tag = variant_config.tag(i); + let tag_tokens = variant_tag.to_tokens(crate_root); + + match &v.fields { + syn::Fields::Named(_) => quote!(#name::#ident { .. } => #tag_tokens), + syn::Fields::Unnamed(_) => quote!(#name::#ident (_) => #tag_tokens), + syn::Fields::Unit => quote!(#name::#ident => #tag_tokens), + } + }); let variants = self.variants.iter().enumerate().map(|(i, v)| { let ident = &v.ident; @@ -397,6 +410,9 @@ impl Enum { let encode_variants = quote! { encoder.encode_choice::( Self::CONSTRAINTS, + match self { + #(#tags),* + }, match self { #(#identifiers),* }, diff --git a/src/aper.rs b/src/aper.rs index b6873290..65f8ebd1 100644 --- a/src/aper.rs +++ b/src/aper.rs @@ -288,6 +288,7 @@ mod tests { &[0x90, 0x27, 0x10, 0x80] ); } + #[test] fn visible_string() { // B ::= VisibleString (SIZE (5)) @@ -433,6 +434,7 @@ mod tests { &[0x01] ); } + #[test] fn issue_192() { // https://github.com/XAMPPRocky/rasn/issues/192 @@ -459,4 +461,35 @@ mod tests { round_trip!(aper, Message, msg, &[0, 1, 1]); } + + #[test] + fn issue_201() { + use crate as rasn; + use crate::prelude::*; + + const T124_IDENTIFIER_KEY: &Oid = Oid::const_new(&[0, 0, 20, 124, 0, 1]); + #[derive(Debug, AsnType, Encode, rasn::Decode)] + #[rasn(choice, automatic_tags)] + enum Key { + #[rasn(tag(explicit(5)))] + Object(ObjectIdentifier), + H221NonStandard(OctetString), + } + + #[derive(Debug, AsnType, rasn::Encode, rasn::Decode)] + #[rasn(automatic_tags)] + struct ConnectData { + t124_identifier_key: Key, + connect_pdu: OctetString, + } + + let connect_pdu: OctetString = vec![0u8, 1u8, 2u8, 3u8].into(); + let connect_data = ConnectData { + t124_identifier_key: Key::Object(T124_IDENTIFIER_KEY.into()), + connect_pdu, + }; + + let encoded = rasn::aper::encode(&connect_data).expect("failed to encode"); + let _: ConnectData = rasn::aper::decode(&encoded).expect("failed to decode"); + } } diff --git a/src/ber/enc.rs b/src/ber/enc.rs index 2efd5f8c..860062a7 100644 --- a/src/ber/enc.rs +++ b/src/ber/enc.rs @@ -357,6 +357,7 @@ impl crate::Encoder for Encoder { fn encode_choice( &mut self, _: Constraints, + _t: Tag, _i: &str, encode_fn: impl FnOnce(&mut Self) -> Result, ) -> Result { diff --git a/src/enc.rs b/src/enc.rs index 6730739e..261a07c1 100644 --- a/src/enc.rs +++ b/src/enc.rs @@ -322,6 +322,7 @@ pub trait Encoder { fn encode_choice( &mut self, constraints: Constraints, + tag: Tag, identifier: &'static str, encode_fn: impl FnOnce(&mut Self) -> Result, ) -> Result; diff --git a/src/jer/enc.rs b/src/jer/enc.rs index e789427c..42870250 100644 --- a/src/jer/enc.rs +++ b/src/jer/enc.rs @@ -365,6 +365,7 @@ impl crate::Encoder for Encoder { fn encode_choice( &mut self, _c: crate::types::Constraints, + _t: crate::types::Tag, identifier: &'static str, encode_fn: impl FnOnce(&mut Self) -> Result, ) -> Result { diff --git a/src/per/de.rs b/src/per/de.rs index 9999fe2a..1b9190f0 100644 --- a/src/per/de.rs +++ b/src/per/de.rs @@ -678,7 +678,8 @@ impl<'input> crate::Decoder for Decoder<'input> { fn decode_object_identifier(&mut self, _: Tag) -> Result { let octets = self.decode_octets()?.into_vec(); - crate::ber::decode(&octets) + let decoder = crate::ber::de::Decoder::new(&octets, crate::ber::de::DecoderOptions::ber()); + decoder.decode_object_identifier_from_bytes(&octets) } fn decode_bit_string(&mut self, _: Tag, constraints: Constraints) -> Result { diff --git a/src/per/enc.rs b/src/per/enc.rs index 5a0da3e4..70fcd8f2 100644 --- a/src/per/enc.rs +++ b/src/per/enc.rs @@ -835,7 +835,8 @@ impl crate::Encoder for Encoder { fn encode_object_identifier(&mut self, tag: Tag, oid: &[u32]) -> Result { self.set_bit(tag, true)?; - let der = crate::der::encode_scope(|encoder| encoder.encode_object_identifier(tag, oid))?; + let mut encoder = crate::der::enc::Encoder::new(crate::der::enc::EncoderOptions::der()); + let der = encoder.object_identifier_as_bytes(oid)?; self.encode_octet_string(tag, <_>::default(), &der) } @@ -1073,19 +1074,13 @@ impl crate::Encoder for Encoder { fn encode_choice( &mut self, constraints: Constraints, + tag: Tag, _: &str, encode_fn: impl FnOnce(&mut Self) -> Result, ) -> Result { let mut buffer = BitString::new(); - let mut choice_encoder = Self::new(self.options.without_set_encoding()); - // Extensibility must be noted for byte alignment - if E::EXTENDED_VARIANTS.is_some() && self.options.aligned { - choice_encoder.parent_output_length = Some(1); - } - let tag = (encode_fn)(&mut choice_encoder)?; let is_root_extension = crate::TagTree::tag_contains(&tag, E::VARIANTS); - self.encode_extensible_bit(&constraints, &mut buffer, || is_root_extension); let variants = crate::types::variants::Variants::from_static(if is_root_extension { E::VARIANTS @@ -1102,15 +1097,30 @@ impl crate::Encoder for Encoder { let bounds = if is_root_extension { let variance = variants.len(); debug_assert!(variance > 0); - - if variance != 1 { - Some(Some(variance)) - } else { + if variance == 1 { None + } else { + Some(Some(variance)) } } else { Some(None) }; + + let mut choice_encoder = Self::new(self.options.without_set_encoding()); + // Extensibility and index encoding size must be noted for byte alignment + let mut choice_bits_len = 0; + if E::EXTENDED_VARIANTS.is_some() && self.options.aligned { + choice_bits_len += 1; + } + choice_bits_len += if let Some(Some(variance)) = bounds { + crate::num::log2(variance as i128) as usize + } else { + 0 + }; + + choice_encoder.parent_output_length = Some(choice_bits_len); + let _tag = (encode_fn)(&mut choice_encoder)?; + match (index, bounds) { (index, Some(Some(variance))) => { // https://github.com/XAMPPRocky/rasn/issues/168 diff --git a/src/uper.rs b/src/uper.rs index b5933224..c101754c 100644 --- a/src/uper.rs +++ b/src/uper.rs @@ -977,4 +977,34 @@ mod tests { &[96, 8, 5, 52] ); } + #[test] + fn test_object_identifier() { + round_trip!( + uper, + ObjectIdentifier, + ObjectIdentifier::new(vec![1, 2]).unwrap(), + &[0x01u8, 0x2a] + ); + round_trip!( + uper, + ObjectIdentifier, + ObjectIdentifier::new(vec![1, 2, 3321]).unwrap(), + &[0x03u8, 0x2a, 0x99, 0x79] + ); + #[derive(AsnType, Debug, Decode, Encode, PartialEq)] + #[rasn(crate_root = "crate")] + struct B { + a: bool, + b: ObjectIdentifier, + } + round_trip!( + uper, + B, + B { + a: true, + b: ObjectIdentifier::new(vec![1, 2]).unwrap() + }, + &[0x80, 0x95, 0x00] + ); + } }