// Copyright (c) 2022, 2024 blackshirt. All rights reserved. // Use of this source code is governed by a MIT License // that can be found in the LICENSE file. module asn1 // default_set_tag is the default tag of ASN.1 SET (SET OF) type. pub const default_set_tag = Tag{.universal, true, int(TagType.set)} const default_set_size = 64 const max_set_size = 255 // ASN.1 UNIVERSAL SET and SET OF TYPE. // // SET and SET OF contains an unordered series of fields of one or more types. // This differs from a SEQUENCE which contains an ordered list. // in DER encoding, SET types elements are sorted into tag order, and, // for SET OF types elements are sorted into ascending order of encoding. pub struct Set { mut: // maximal size of this set fields size int = default_set_size // fields is the elements of the set fields []Element } // creates a new Set with default size. pub fn Set.new() !Set { return Set.new_with_size(default_set_size)! } // from_list creates a new Set from arrays of element in els. pub fn Set.from_list(els []Element) !Set { if els.len > max_set_size { return error('Sequence size exceed limit') } return Set{ fields: els } } fn Set.new_with_size(size int) !Set { if size > max_set_size { return error('size is exceed limit') } if size < 0 { return error('Provides with correct size') } // if size is 0, use default_set_size limit := if size == 0 { default_set_size } else { size } return Set{ size: limit } } // tag returns the tag of Set element. pub fn (s Set) tag() Tag { return default_set_tag } // payload returns the payload of the Set element. // // Note: Required for DER encoding. // The encodings of the component values of a set value shall appear in an order determined by their tags. // The canonical order for tags is based on the outermost tag of each type and is defined as follows: // a) those elements or alternatives with universal class tags shall appear first, followed by those with // application class tags, followed by those with context-specific tags, followed by those with private class // tags; // b) within each class of tags, the elements or alternatives shall appear in ascending order of their tag // numbers. pub fn (s Set) payload() ![]u8 { // workaround by working with the copy of Set, changing it to 'mut s Set` would encounter some issues // ie, with messages `asn1.Set` incorrectly implements method `payload` of interface `asn1.Element`: // expected `asn1.Element` which is immutable, not `mut &asn1.Set` mut set := s return set.payload_with_rule(.der)! } fn (mut s Set) payload_with_rule(rule EncodingRule) ![]u8 { // first, we sort the set.fields and then serializing it. s.sort_set_fields() mut out := []u8{} for field in s.fields { item := unsafe { field } obj := encode_with_rule(item, rule)! out << obj } return out } // fields return the arrays of element's content in the Set.fields. pub fn (set Set) fields() []Element { return set.fields } fn Set.parse(mut p Parser) !Set { return error('not yet implemented') } fn Set.decode(bytes []u8) !(Set, int) { return Set.decode_with_rule(bytes, 0, .der)! } fn Set.decode_with_rule(bytes []u8, loc int, rule EncodingRule) !(Set, int) { tag, length_pos := Tag.decode_with_rule(bytes, loc, rule)! if !tag.equal(default_set_tag) { return error('Get unexpected non-set tag') } length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)! payload := if length == 0 { []u8{} } else { if content_pos + length > bytes.len { return error('Not enought bytes to read on') } unsafe { bytes[content_pos..content_pos + length] } } next := content_pos + length set := Set.from_bytes(payload)! return set, next } // bytes should seq.fields payload, not includes the tag fn Set.from_bytes(bytes []u8) !Set { mut set := Set{} if bytes.len == 0 { return set } mut i := 0 for i < bytes.len { el, pos := Element.decode_with_rule(bytes, i, .der)! i = pos set.add_element(el)! } if i > bytes.len { return error('i > bytes.len') } if i < bytes.len { return error('The src contains unprocessed bytes') } return set } fn (s Set) equal(o Set) bool { for i, item in s.fields { for j, obj in o.fields { if i == j { if !item.equal(obj) { return false } } else { continue } } } return true } // add_element adds an element el into Set. // By default it allowing adds element with the same tag pub fn (mut set Set) add_element(el Element) ! { set.relaxed_add_element(el, true)! } // add_element allows adding a new element into current Set fields. // Its does not allow adding element when is already the same tag in the fields. // but, some exception when you set relaxed to true fn (mut set Set) relaxed_add_element(el Element, relaxed bool) ! { if set.fields.len == 0 { // just adds it then return set.fields << el return } // remove this checks // for item in set.fields { // if item.equal(el) { // return error('has already in the fields') // } // } filtered_by_tag := set.fields.filter(it.tag().equal(el.tag())) if filtered_by_tag.len == 0 { set.fields << el return } else { if !relaxed { return error('You can not insert element without forcing') } set.fields << el return } } // `set_size` set internal maximal size of this set fields. pub fn (mut set Set) set_size(size int) ! { if size < 0 { return error('provides the correct size') } if size > max_set_size { return error('Provided limit was exceed current one') } set.size = size } // sort_set_fields sort the Set fields in places with sort_with_compare support fn (mut set Set) sort_set_fields() { // without &, its return an error: sort_with_compare callback function parameter // `x` with type `asn1.Element` should be `&asn1.Element` set.fields.sort_with_compare(fn (x &Element, y &Element) int { if x.tag().class != y.tag().class { s := if int(x.tag().class) < int(y.tag().class) { -1 } else { 1 } return s } if x.tag() == y.tag() { // compare by contents instead just return 0 xx := encode(x) or { panic(err) } yy := encode(y) or { panic(err) } return xx.bytestr().compare(yy.bytestr()) } q := if x.tag().number < y.tag().number { -1 } else { 1 } return q }) } // ASN.1 SET OF // pub struct SetOf[T] { mut: size int = default_set_size fields []T } // new creates an empty SetOf type T. pub fn SetOf.new[T]() !SetOf[T] { $if T !is Element { return error('Yur T is not Element') } return SetOf[T]{} } // from_list creates new SetOf type T from arrays of T. pub fn SetOf.from_list[T](els []T) !SetOf[T] { $if T !is Element { return error('Yur T is not Element') } if els.len > max_set_size { return error('[]T length is exceed limit') } return SetOf[T]{ fields: els } } // tag returns the tag of SetOf[T] element. pub fn (so SetOf[T]) tag() Tag { return default_set_tag } // fields returns underlying arrays of T from the SetOf[T]. pub fn (so SetOf[T]) fields() []T { return so.fields } // payload returns the payload of SetOf[T] element. pub fn (so SetOf[T]) payload() ![]u8 { mut sto := so return sto.payload_with_rule(.der)! } // issues: el cannot be used as interface object outside `unsafe` blocks // as it might be stored on stack. // Consider wrapping the `T` object in a `struct` declared as `@[heap]` fn (mut so SetOf[T]) payload_with_rule(rule EncodingRule) ![]u8 { $if T !is Element { return error('T is not an element') } // sort the fields and serialize so.sort_setof_fields() mut out := []u8{} for el in so.fields { // we encounter issues above at here // we can not directly pass el to encode routine elem := unsafe { el } obj := encode_with_rule(elem, rule)! out << obj } return out } fn (mut so SetOf[T]) sort_setof_fields() { so.fields.sort_with_compare(fn [T](x &T, y &T) int { xx := Element.from_object[T](x) or { panic(err) } yy := Element.from_object[T](y) or { panic(err) } aa := encode(xx) or { panic(err) } bb := encode(yy) or { panic(err) } return aa.bytestr().compare(bb.bytestr()) }) } // add_element adds an element el into SetOf[T] fields. pub fn (mut so SetOf[T]) add_element(el Element) ! { so.relaxed_add_element(el, true)! } // add_element allows adding a new element into current Set fields. // Its does not allow adding element when is already the same tag in the fields. // but, some exception when you set relaxed to true fn (mut so SetOf[T]) relaxed_add_element(el Element, relaxed bool) ! { the_t := el.into_object[T]()! if so.fields.len == 0 { // just adds it then return so.fields << the_t return } mut filtered_by_tag := []T{} for field in so.fields { item := Element.from_object(field)! if item.equal(el) { return error('has already in the fields') } if item.tag().equal(el.tag()) { // add this to filtered filtered_by_tag << field } } if filtered_by_tag.len == 0 { so.fields << the_t return } else { if !relaxed { return error('You can not insert element without forcing') } so.fields << the_t return } }