@@ -76,6 +76,8 @@ pub enum ASN1Object {
7676 Date ( ASN1Date ) ,
7777 #[ rasn( tag( universal, 3 ) ) ]
7878 BitString ( ASN1RawBitString ) ,
79+ #[ rasn( tag( universal, 16 ) ) ]
80+ Struct ( ASN1Struct ) ,
7981 #[ rasn( tag( context, 0 ) ) ]
8082 Context ( ASN1Context ) ,
8183}
@@ -164,6 +166,23 @@ pub struct ASN1BitString {
164166 pub unused_bits : Option < u8 > ,
165167}
166168
169+ /// ASN1 Struct represented as a sequence of ASN1Data values.
170+ #[ derive( AsnType , Decode , Encode , Clone , Eq , PartialEq , Debug ) ]
171+ #[ rasn( delegate) ]
172+ pub struct ASN1Struct ( pub Vec < ASN1Data > ) ;
173+
174+ /// Shim to surface ASN1Struct in generated TypeScript declarations only.
175+ #[ napi( object, js_name = "ASN1Struct" ) ]
176+ #[ allow( dead_code) ]
177+ pub struct ASN1StructShim {
178+ #[ napi( ts_type = "'struct'" ) ]
179+ pub r#type : & ' static str ,
180+ #[ napi( js_name = "fieldNames" ) ]
181+ pub field_names : Option < Vec < String > > ,
182+ #[ napi( ts_type = "Record<string, ASN1AnyJS>" ) ]
183+ pub contains : JsUnknown ,
184+ }
185+
167186/// Get an oid as u32 words from a canonically named identifier.
168187fn get_oid_from_name < T : AsRef < str > > ( name : T ) -> Result < & ' static [ u32 ] > {
169188 if let Some ( oid) = NAME_TO_OID_MAP . get ( name. as_ref ( ) ) {
@@ -200,6 +219,7 @@ fn get_name_from_oid_string<T: AsRef<str>>(oid: T) -> Result<&'static str> {
200219pub trait TypedObject < ' a > {
201220 const TYPE : & ' a str ;
202221
222+ #[ allow( dead_code) ]
203223 fn get_type ( ) -> & ' a str {
204224 Self :: TYPE
205225 }
@@ -306,6 +326,7 @@ type_object!(ASN1Set, "set");
306326type_object ! ( ASN1String , "string" ) ;
307327type_object ! ( ASN1Date , "date" ) ;
308328type_object ! ( ASN1ContextTag , "context" ) ;
329+ type_object ! ( ASN1Struct , "struct" ) ;
309330
310331impl Encode for ASN1RawBitString {
311332 fn encode_with_tag < E : Encoder > ( & self , encoder : & mut E , tag : Tag ) -> Result < ( ) , E :: Error > {
@@ -563,6 +584,7 @@ impl Encode for ASN1Data {
563584 ASN1Object :: Date ( date) => date. encode ( encoder) ,
564585 ASN1Object :: BitString ( bs) => bs. encode ( encoder) ,
565586 ASN1Object :: Context ( context) => context. encode ( encoder) ,
587+ ASN1Object :: Struct ( struct_value) => struct_value. encode ( encoder) ,
566588 } ,
567589 ASN1Data :: Utf8String ( string) => string. encode_with_tag ( encoder, Tag :: UTF8_STRING ) ,
568590 ASN1Data :: UtcTime ( date) => date. encode ( encoder) ,
@@ -638,6 +660,73 @@ impl TryFrom<JsObject> for ASN1RawBitString {
638660 }
639661}
640662
663+ impl TryFrom < JsObject > for ASN1Struct {
664+ type Error = Error ;
665+
666+ fn try_from ( object : JsObject ) -> Result < Self , Self :: Error > {
667+ if !object. has_named_property ( ASN1_OBJECT_CONTAINS_KEY ) ? {
668+ bail ! ( ASN1NAPIError :: UnknownObject ) ;
669+ }
670+
671+ let contains = object. get_named_property :: < JsObject > ( ASN1_OBJECT_CONTAINS_KEY ) ?;
672+ let mut ordered_names = Vec :: new ( ) ;
673+
674+ if object. has_named_property ( ASN1_OBJECT_FIELD_NAMES_KEY ) ? {
675+ let js_field_names =
676+ object. get_named_property :: < JsObject > ( ASN1_OBJECT_FIELD_NAMES_KEY ) ?;
677+ let len = js_field_names. get_array_length ( ) ?;
678+ for index in 0 ..len {
679+ ordered_names. push (
680+ js_field_names
681+ . get_element :: < JsString > ( index) ?
682+ . into_utf8 ( ) ?
683+ . as_str ( ) ?
684+ . to_string ( ) ,
685+ ) ;
686+ }
687+ }
688+
689+ let property_names = contains. get_property_names ( ) ?;
690+ let len = property_names. get_array_length ( ) ?;
691+ let mut discovered = Vec :: with_capacity ( len as usize ) ;
692+ for index in 0 ..len {
693+ discovered. push (
694+ property_names
695+ . get_element :: < JsString > ( index) ?
696+ . into_utf8 ( ) ?
697+ . as_str ( ) ?
698+ . to_string ( ) ,
699+ ) ;
700+ }
701+
702+ if ordered_names. is_empty ( ) {
703+ ordered_names = discovered. clone ( ) ;
704+ } else {
705+ for name in discovered {
706+ if !ordered_names. iter ( ) . any ( |existing| existing == & name) {
707+ ordered_names. push ( name) ;
708+ }
709+ }
710+ }
711+
712+ let mut values = Vec :: new ( ) ;
713+ for field_name in ordered_names {
714+ if !contains. has_named_property ( & field_name) ? {
715+ continue ;
716+ }
717+
718+ let field_value = contains. get_named_property :: < JsUnknown > ( & field_name) ?;
719+ if field_value. get_type ( ) ? == ValueType :: Undefined {
720+ continue ;
721+ }
722+
723+ values. push ( ASN1Data :: try_from ( field_value) ?) ;
724+ }
725+
726+ Ok ( ASN1Struct ( values) )
727+ }
728+ }
729+
641730impl TryFrom < ASN1OID > for ObjectIdentifier {
642731 type Error = Error ;
643732
@@ -876,6 +965,7 @@ impl TryFrom<JsObject> for ASN1Object {
876965 ASN1Date :: TYPE => ASN1Object :: Date ( ASN1Date :: try_from ( obj) ?) ,
877966 ASN1BitString :: TYPE => ASN1Object :: BitString ( ASN1RawBitString :: try_from ( obj) ?) ,
878967 ASN1ContextTag :: TYPE => ASN1Object :: Context ( ASN1Context :: try_from ( obj) ?) ,
968+ ASN1Struct :: TYPE => ASN1Object :: Struct ( ASN1Struct :: try_from ( obj) ?) ,
879969 _ => bail ! ( ASN1NAPIError :: UnknownFieldProperty ) ,
880970 } )
881971 } else {
0 commit comments