v2 / vlib / x / encoding / asn1 / sequence.v
282 lines · 251 sloc · 7.63 KB · 94905820e6da47fbb60eb4f30a3c553ba6d73a95
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_sequence_tag is the default tag of ASN.1 SEQUENCE (SEQUENCE OF) type.
7pub const default_sequence_tag = Tag{.universal, true, int(TagType.sequence)}
8
9// constant for sequence(of) and set(of) internal value
10// vfmt off
11const max_sequence_size = 256 // max of seq size
12const max_sequence_bytes_length = (1 << 23 - 1) //
13const default_sequence_size = 64 // default size
14// vfmt on
15
16// ASN.1 UNIVERSAL CLASS OF SEQUENCE and SEQUENCE OF TYPE.
17//
18// https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der
19// These are two very different types.
20// A SEQUENCE is equivalent to “struct” in most programming languages.
21// It holds a fixed number of fields of different types.
22// A SEQUENCE OF, holds an arbitrary number of fields of a single type.
23// This is analogous to an array or a list in a programming language.
24// Sequence structure can represents both SEQUENCE and SEQUENCE OF type.
25// The encoding of a sequence value shall be constructed.
26// in DER encoded of SEQUENCE or SET, never encode a default value.
27pub struct Sequence {
28mut:
29 // maximal size of this sequence fields
30 size int = default_sequence_size
31 // fields is the elements of the sequence
32 fields []Element
33}
34
35// new creates new Sequence with default size.
36pub fn Sequence.new() !Sequence {
37 return Sequence.new_with_size(default_sequence_size)!
38}
39
40// from_list creates new Sequence from list of elements.
41pub fn Sequence.from_list(els []Element) !Sequence {
42 if els.len > max_sequence_size {
43 return error('Sequence size exceed limit')
44 }
45 return Sequence{
46 fields: els
47 }
48}
49
50fn Sequence.new_with_size(size int) !Sequence {
51 if size > max_sequence_size {
52 return error('size is exceed limit')
53 }
54 if size < 0 {
55 return error('Provides with correct size')
56 }
57
58 // if size is 0, use default_sequence_size
59 limit := if size == 0 { default_sequence_size } else { size }
60 return Sequence{
61 size: limit
62 }
63}
64
65// tag returns the tag of Sequence element.
66pub fn (seq Sequence) tag() Tag {
67 return default_sequence_tag
68}
69
70// payload returns the payload of Sequence element.
71pub fn (seq Sequence) payload() ![]u8 {
72 return seq.payload_with_rule(.der)!
73}
74
75fn (seq Sequence) payload_with_rule(rule EncodingRule) ![]u8 {
76 mut out := []u8{}
77 for el in seq.fields {
78 obj := encode_with_rule(el, rule)!
79 out << obj
80 }
81 return out
82}
83
84// encoded_len tells the length of serialized Sequence element in bytes.
85pub fn (seq Sequence) encoded_len() int {
86 mut n := 0
87 n += seq.tag().tag_size()
88 fields := ElementList(seq.fields)
89 len := fields.encoded_len()
90 length := Length.new(len) or { panic(err) }
91 n += length.length_size() or { panic(err) }
92 n += len
93 return n
94}
95
96// fields returns the Sequences fields.
97pub fn (seq Sequence) fields() []Element {
98 return seq.fields
99}
100
101// parse tries to parse into Sequence from ongoing Parser p.
102// Uts return a parsed Sequence or error on fails.
103fn Sequence.parse(mut p Parser) !Sequence {
104 tag := p.read_tag()!
105 if !tag.equal(default_sequence_tag) {
106 return error('Get non Sequence tag')
107 }
108 length := p.read_length()!
109 content := p.read_bytes(length)!
110
111 seq := Sequence.from_bytes(content)!
112 return seq
113}
114
115// decode tries to decode bytes into Sequence.
116// Its return a decoded Sequence and next offset to read on
117// if possible, or return error on fails.
118fn Sequence.decode(bytes []u8) !(Sequence, int) {
119 return Sequence.decode_with_rule(bytes, 0, .der)!
120}
121
122fn Sequence.decode_with_rule(bytes []u8, loc int, rule EncodingRule) !(Sequence, int) {
123 tag, length_pos := Tag.decode_with_rule(bytes, loc, rule)!
124 if !tag.equal(default_sequence_tag) {
125 return error('Get unexpected non-sequence tag')
126 }
127 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
128 payload := if length == 0 {
129 []u8{}
130 } else {
131 if content_pos + length > bytes.len {
132 return error('Not enought bytes to read on')
133 }
134 unsafe { bytes[content_pos..content_pos + length] }
135 }
136 next := content_pos + length
137 seq := Sequence.from_bytes(payload)!
138 return seq, next
139}
140
141// bytes should seq.fields payload, not includes the tag
142fn Sequence.from_bytes(bytes []u8) !Sequence {
143 mut seq := Sequence{}
144 if bytes.len == 0 {
145 return seq
146 }
147 mut i := 0
148 for i < bytes.len {
149 el, pos := Element.decode_with_rule(bytes, i, .der)!
150 i = pos
151 seq.add_element(el)!
152 }
153
154 if i > bytes.len {
155 return error('i > bytes.len')
156 }
157 if i < bytes.len {
158 return error('The src contains unprocessed bytes')
159 }
160 return seq
161}
162
163// set_size sets maximal size of this sequence fields.
164pub fn (mut seq Sequence) set_size(size int) ! {
165 if size <= 0 {
166 return error('provides with correct limit')
167 }
168 if size > max_sequence_size {
169 return error('Provided limit was exceed current one')
170 }
171 seq.size = size
172}
173
174// add_element adds an element el into Sequence fields.
175// By default its allows adding element with the same tag.
176pub fn (mut seq Sequence) add_element(el Element) ! {
177 seq.relaxed_add_element(el, true)!
178}
179
180// add_element allows adding a new element into current sequence fields.
181// Its does not allow adding element when is already the same tag in the fields.
182// but, some exception when you set relaxed to true
183fn (mut seq Sequence) relaxed_add_element(el Element, relaxed bool) ! {
184 // todo: check against size
185 if seq.fields.len == 0 {
186 // just adds it then return
187 seq.fields << el
188 return
189 }
190
191 // for item in seq.fields {
192 // if item.equal_with(el) {
193 // return error('has already in the fields')
194 // }
195 // }
196 filtered_by_tag := seq.fields.filter(it.tag().equal(el.tag()))
197 if filtered_by_tag.len == 0 {
198 seq.fields << el
199 return
200 } else {
201 if !relaxed {
202 return error('You can not insert element without forcing')
203 }
204 seq.fields << el
205 return
206 }
207}
208
209// is_sequence_of[T] checks whether this sequence is SequenceOf[T] type.
210pub fn (seq Sequence) is_sequence_of[T]() bool {
211 return seq.fields.all(it is T)
212}
213
214// into_sequence_of[T] turns this sequence into SequenceOf[T] element.
215pub fn (seq Sequence) into_sequence_of[T]() !SequenceOf[T] {
216 if seq.is_sequence_of[T]() {
217 return error('This sequence is not SequenceOf[T]')
218 }
219 mut sqof := SequenceOf[T]{}
220 for el in seq.fields {
221 obj := el.into_object[T]()!
222 sqof.fields << obj
223 }
224 return sqof
225}
226
227// ASN.1 SEQUENCE OF TYPE.
228// SequenceOf[T] is an arrays of generic T, so the generic T should fullfill Element interface.
229// We dont use generic aliases because generic type aliases are not yet implemented.
230pub struct SequenceOf[T] {
231mut:
232 size int = default_sequence_size
233 fields []T
234}
235
236// SequenceOf.new creates a new SequenceOf[T]
237pub fn SequenceOf.new[T]() SequenceOf[T] {
238 return SequenceOf[T]{}
239}
240
241// SequenceOf.from_list creates a new SequenceOf[T] from arrays of T type.
242pub fn SequenceOf.from_list[T](els []T) !SequenceOf[T] {
243 if els.len > max_sequence_size {
244 return error('SequenceOf size exceed limit')
245 }
246 $if T !is Element {
247 return error('T not hold element')
248 }
249 return SequenceOf[T]{
250 fields: els
251 }
252}
253
254// The tag of SequenceOf element.
255pub fn (so SequenceOf[T]) tag() Tag {
256 return default_sequence_tag
257}
258
259// The payload of SequenceOf element.
260pub fn (so SequenceOf[T]) payload() ![]u8 {
261 return so.payload_with_rule(.der)!
262}
263
264fn (so SequenceOf[T]) payload_with_rule(rule EncodingRule) ![]u8 {
265 $if T !is Element {
266 return error('T is not an element')
267 }
268 mut out := []u8{}
269 for el in so.fields {
270 // placing el directly bring into error: `el` cannot be used as interface object
271 // outside `unsafe` blocks as it might be stored on stack.
272 curr := unsafe { el }
273 obj := encode_with_rule(curr, rule)!
274 out << obj
275 }
276 return out
277}
278
279// fields returns underlying arrays of T from the SequenceOf[T].
280pub fn (so SequenceOf[T]) fields() []T {
281 return so.fields
282}
283