v2 / vlib / x / encoding / asn1 / set.v
340 lines · 305 sloc · 8.86 KB · 3d60410b605d001e54f280070d5f952da9de1112
Raw
1// Copyright (c) 2022, 2024 blackshirt. All rights reserved.
2// Use of this source code is governed by a MIT License
3// that can be found in the LICENSE file.
4module asn1
5
6// default_set_tag is the default tag of ASN.1 SET (SET OF) type.
7pub const default_set_tag = Tag{.universal, true, int(TagType.set)}
8
9const default_set_size = 64
10const max_set_size = 255
11
12// ASN.1 UNIVERSAL SET and SET OF TYPE.
13//
14// SET and SET OF contains an unordered series of fields of one or more types.
15// This differs from a SEQUENCE which contains an ordered list.
16// in DER encoding, SET types elements are sorted into tag order, and,
17// for SET OF types elements are sorted into ascending order of encoding.
18pub struct Set {
19mut:
20 // maximal size of this set fields
21 size int = default_set_size
22 // fields is the elements of the set
23 fields []Element
24}
25
26// creates a new Set with default size.
27pub fn Set.new() !Set {
28 return Set.new_with_size(default_set_size)!
29}
30
31// from_list creates a new Set from arrays of element in els.
32pub fn Set.from_list(els []Element) !Set {
33 if els.len > max_set_size {
34 return error('Sequence size exceed limit')
35 }
36 return Set{
37 fields: els
38 }
39}
40
41fn Set.new_with_size(size int) !Set {
42 if size > max_set_size {
43 return error('size is exceed limit')
44 }
45 if size < 0 {
46 return error('Provides with correct size')
47 }
48
49 // if size is 0, use default_set_size
50 limit := if size == 0 { default_set_size } else { size }
51 return Set{
52 size: limit
53 }
54}
55
56// tag returns the tag of Set element.
57pub fn (s Set) tag() Tag {
58 return default_set_tag
59}
60
61// payload returns the payload of the Set element.
62//
63// Note: Required for DER encoding.
64// The encodings of the component values of a set value shall appear in an order determined by their tags.
65// The canonical order for tags is based on the outermost tag of each type and is defined as follows:
66// a) those elements or alternatives with universal class tags shall appear first, followed by those with
67// application class tags, followed by those with context-specific tags, followed by those with private class
68// tags;
69// b) within each class of tags, the elements or alternatives shall appear in ascending order of their tag
70// numbers.
71pub fn (s Set) payload() ![]u8 {
72 // workaround by working with the copy of Set, changing it to 'mut s Set` would encounter some issues
73 // ie, with messages `asn1.Set` incorrectly implements method `payload` of interface `asn1.Element`:
74 // expected `asn1.Element` which is immutable, not `mut &asn1.Set`
75 mut set := s
76 return set.payload_with_rule(.der)!
77}
78
79fn (mut s Set) payload_with_rule(rule EncodingRule) ![]u8 {
80 // first, we sort the set.fields and then serializing it.
81 s.sort_set_fields()
82
83 mut out := []u8{}
84 for field in s.fields {
85 item := unsafe { field }
86 obj := encode_with_rule(item, rule)!
87 out << obj
88 }
89 return out
90}
91
92// fields return the arrays of element's content in the Set.fields.
93pub fn (set Set) fields() []Element {
94 return set.fields
95}
96
97fn Set.parse(mut _p Parser) !Set {
98 return error('not yet implemented')
99}
100
101fn Set.decode(bytes []u8) !(Set, int) {
102 return Set.decode_with_rule(bytes, 0, .der)!
103}
104
105fn Set.decode_with_rule(bytes []u8, loc int, rule EncodingRule) !(Set, int) {
106 tag, length_pos := Tag.decode_with_rule(bytes, loc, rule)!
107 if !tag.equal(default_set_tag) {
108 return error('Get unexpected non-set tag')
109 }
110 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
111 payload := if length == 0 {
112 []u8{}
113 } else {
114 if content_pos + length > bytes.len {
115 return error('Not enought bytes to read on')
116 }
117 unsafe { bytes[content_pos..content_pos + length] }
118 }
119 next := content_pos + length
120 set := Set.from_bytes(payload)!
121 return set, next
122}
123
124// bytes should seq.fields payload, not includes the tag
125fn Set.from_bytes(bytes []u8) !Set {
126 mut set := Set{}
127 if bytes.len == 0 {
128 return set
129 }
130 mut i := 0
131 for i < bytes.len {
132 el, pos := Element.decode_with_rule(bytes, i, .der)!
133 i = pos
134 set.add_element(el)!
135 }
136
137 if i > bytes.len {
138 return error('i > bytes.len')
139 }
140 if i < bytes.len {
141 return error('The src contains unprocessed bytes')
142 }
143 return set
144}
145
146fn (s Set) equal(o Set) bool {
147 for i, item in s.fields {
148 for j, obj in o.fields {
149 if i == j {
150 if !item.equal(obj) {
151 return false
152 }
153 } else {
154 continue
155 }
156 }
157 }
158 return true
159}
160
161// add_element adds an element el into Set.
162// By default it allowing adds element with the same tag
163pub fn (mut set Set) add_element(el Element) ! {
164 set.relaxed_add_element(el, true)!
165}
166
167// add_element allows adding a new element into current Set fields.
168// Its does not allow adding element when is already the same tag in the fields.
169// but, some exception when you set relaxed to true
170fn (mut set Set) relaxed_add_element(el Element, relaxed bool) ! {
171 if set.fields.len == 0 {
172 // just adds it then return
173 set.fields << el
174 return
175 }
176
177 // remove this checks
178 // for item in set.fields {
179 // if item.equal(el) {
180 // return error('has already in the fields')
181 // }
182 // }
183 filtered_by_tag := set.fields.filter(it.tag().equal(el.tag()))
184 if filtered_by_tag.len == 0 {
185 set.fields << el
186 return
187 } else {
188 if !relaxed {
189 return error('You can not insert element without forcing')
190 }
191 set.fields << el
192 return
193 }
194}
195
196// `set_size` set internal maximal size of this set fields.
197pub fn (mut set Set) set_size(size int) ! {
198 if size < 0 {
199 return error('provides the correct size')
200 }
201 if size > max_set_size {
202 return error('Provided limit was exceed current one')
203 }
204 set.size = size
205}
206
207// sort_set_fields sort the Set fields in places with sort_with_compare support
208fn (mut set Set) sort_set_fields() {
209 // without &, its return an error: sort_with_compare callback function parameter
210 // `x` with type `asn1.Element` should be `&asn1.Element`
211 set.fields.sort_with_compare(fn (x &Element, y &Element) int {
212 if x.tag().class != y.tag().class {
213 s := if int(x.tag().class) < int(y.tag().class) { -1 } else { 1 }
214 return s
215 }
216 if x.tag() == y.tag() {
217 // compare by contents instead just return 0
218 xx := encode(x) or { panic(err) }
219 yy := encode(y) or { panic(err) }
220 return xx.bytestr().compare(yy.bytestr())
221 }
222 q := if x.tag().number < y.tag().number { -1 } else { 1 }
223 return q
224 })
225}
226
227// ASN.1 SET OF
228//
229pub struct SetOf[T] {
230mut:
231 size int = default_set_size
232 fields []T
233}
234
235// new creates an empty SetOf type T.
236pub fn SetOf.new[T]() !SetOf[T] {
237 $if T !is Element {
238 return error('Yur T is not Element')
239 }
240 return SetOf[T]{}
241}
242
243// from_list creates new SetOf type T from arrays of T.
244pub fn SetOf.from_list[T](els []T) !SetOf[T] {
245 $if T !is Element {
246 return error('Yur T is not Element')
247 }
248 if els.len > max_set_size {
249 return error('[]T length is exceed limit')
250 }
251 return SetOf[T]{
252 fields: els
253 }
254}
255
256// tag returns the tag of SetOf[T] element.
257pub fn (so SetOf[T]) tag() Tag {
258 return default_set_tag
259}
260
261// fields returns underlying arrays of T from the SetOf[T].
262pub fn (so SetOf[T]) fields() []T {
263 return so.fields
264}
265
266// payload returns the payload of SetOf[T] element.
267pub fn (so SetOf[T]) payload() ![]u8 {
268 mut sto := so
269 return sto.payload_with_rule(.der)!
270}
271
272// issues: el cannot be used as interface object outside `unsafe` blocks
273// as it might be stored on stack.
274// Consider wrapping the `T` object in a `struct` declared as `@[heap]`
275fn (mut so SetOf[T]) payload_with_rule(rule EncodingRule) ![]u8 {
276 $if T !is Element {
277 return error('T is not an element')
278 }
279 // sort the fields and serialize
280 so.sort_setof_fields()
281
282 mut out := []u8{}
283 for el in so.fields {
284 // we encounter issues above at here
285 // we can not directly pass el to encode routine
286 elem := unsafe { el }
287 obj := encode_with_rule(elem, rule)!
288 out << obj
289 }
290 return out
291}
292
293fn (mut so SetOf[T]) sort_setof_fields() {
294 so.fields.sort_with_compare(fn [T](x &T, y &T) int {
295 xx := Element.from_object[T](x) or { panic(err) }
296 yy := Element.from_object[T](y) or { panic(err) }
297 aa := encode(xx) or { panic(err) }
298 bb := encode(yy) or { panic(err) }
299 return aa.bytestr().compare(bb.bytestr())
300 })
301}
302
303// add_element adds an element el into SetOf[T] fields.
304pub fn (mut so SetOf[T]) add_element(el Element) ! {
305 so.relaxed_add_element(el, true)!
306}
307
308// add_element allows adding a new element into current Set fields.
309// Its does not allow adding element when is already the same tag in the fields.
310// but, some exception when you set relaxed to true
311fn (mut so SetOf[T]) relaxed_add_element(el Element, relaxed bool) ! {
312 the_t := el.into_object[T]()!
313 if so.fields.len == 0 {
314 // just adds it then return
315 so.fields << the_t
316 return
317 }
318 mut filtered_by_tag := []T{}
319 for field in so.fields {
320 item := Element.from_object(field)!
321 if item.equal(el) {
322 return error('has already in the fields')
323 }
324 if item.tag().equal(el.tag()) {
325 // add this to filtered
326 filtered_by_tag << field
327 }
328 }
329
330 if filtered_by_tag.len == 0 {
331 so.fields << the_t
332 return
333 } else {
334 if !relaxed {
335 return error('You can not insert element without forcing')
336 }
337 so.fields << the_t
338 return
339 }
340}
341