v/vlib/x/encoding/asn1/sequence.v

283 lines
7.6 KiB
V

// 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_sequence_tag is the default tag of ASN.1 SEQUENCE (SEQUENCE OF) type.
pub const default_sequence_tag = Tag{.universal, true, int(TagType.sequence)}
// constant for sequence(of) and set(of) internal value
// vfmt off
const max_sequence_size = 256 // max of seq size
const max_sequence_bytes_length = (1 << 23 - 1) //
const default_sequence_size = 64 // default size
// vfmt on
// ASN.1 UNIVERSAL CLASS OF SEQUENCE and SEQUENCE OF TYPE.
//
// https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der
// These are two very different types.
// A SEQUENCE is equivalent to “struct” in most programming languages.
// It holds a fixed number of fields of different types.
// A SEQUENCE OF, holds an arbitrary number of fields of a single type.
// This is analogous to an array or a list in a programming language.
// Sequence structure can represents both SEQUENCE and SEQUENCE OF type.
// The encoding of a sequence value shall be constructed.
// in DER encoded of SEQUENCE or SET, never encode a default value.
pub struct Sequence {
mut:
// maximal size of this sequence fields
size int = default_sequence_size
// fields is the elements of the sequence
fields []Element
}
// new creates new Sequence with default size.
pub fn Sequence.new() !Sequence {
return Sequence.new_with_size(default_sequence_size)!
}
// from_list creates new Sequence from list of elements.
pub fn Sequence.from_list(els []Element) !Sequence {
if els.len > max_sequence_size {
return error('Sequence size exceed limit')
}
return Sequence{
fields: els
}
}
fn Sequence.new_with_size(size int) !Sequence {
if size > max_sequence_size {
return error('size is exceed limit')
}
if size < 0 {
return error('Provides with correct size')
}
// if size is 0, use default_sequence_size
limit := if size == 0 { default_sequence_size } else { size }
return Sequence{
size: limit
}
}
// tag returns the tag of Sequence element.
pub fn (seq Sequence) tag() Tag {
return default_sequence_tag
}
// payload returns the payload of Sequence element.
pub fn (seq Sequence) payload() ![]u8 {
return seq.payload_with_rule(.der)!
}
fn (seq Sequence) payload_with_rule(rule EncodingRule) ![]u8 {
mut out := []u8{}
for el in seq.fields {
obj := encode_with_rule(el, rule)!
out << obj
}
return out
}
// encoded_len tells the length of serialized Sequence element in bytes.
pub fn (seq Sequence) encoded_len() int {
mut n := 0
n += seq.tag().tag_size()
fields := ElementList(seq.fields)
len := fields.encoded_len()
length := Length.new(len) or { panic(err) }
n += length.length_size() or { panic(err) }
n += len
return n
}
// fields returns the Sequences fields.
pub fn (seq Sequence) fields() []Element {
return seq.fields
}
// parse tries to parse into Sequence from ongoing Parser p.
// Uts return a parsed Sequence or error on fails.
fn Sequence.parse(mut p Parser) !Sequence {
tag := p.read_tag()!
if !tag.equal(default_sequence_tag) {
return error('Get non Sequence tag')
}
length := p.read_length()!
content := p.read_bytes(length)!
seq := Sequence.from_bytes(content)!
return seq
}
// decode tries to decode bytes into Sequence.
// Its return a decoded Sequence and next offset to read on
// if possible, or return error on fails.
fn Sequence.decode(bytes []u8) !(Sequence, int) {
return Sequence.decode_with_rule(bytes, 0, .der)!
}
fn Sequence.decode_with_rule(bytes []u8, loc int, rule EncodingRule) !(Sequence, int) {
tag, length_pos := Tag.decode_with_rule(bytes, loc, rule)!
if !tag.equal(default_sequence_tag) {
return error('Get unexpected non-sequence 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
seq := Sequence.from_bytes(payload)!
return seq, next
}
// bytes should seq.fields payload, not includes the tag
fn Sequence.from_bytes(bytes []u8) !Sequence {
mut seq := Sequence{}
if bytes.len == 0 {
return seq
}
mut i := 0
for i < bytes.len {
el, pos := Element.decode_with_rule(bytes, i, .der)!
i = pos
seq.add_element(el)!
}
if i > bytes.len {
return error('i > bytes.len')
}
if i < bytes.len {
return error('The src contains unprocessed bytes')
}
return seq
}
// set_size sets maximal size of this sequence fields.
pub fn (mut seq Sequence) set_size(size int) ! {
if size <= 0 {
return error('provides with correct limit')
}
if size > max_sequence_size {
return error('Provided limit was exceed current one')
}
seq.size = size
}
// add_element adds an element el into Sequence fields.
// By default its allows adding element with the same tag.
pub fn (mut seq Sequence) add_element(el Element) ! {
seq.relaxed_add_element(el, true)!
}
// add_element allows adding a new element into current sequence 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 seq Sequence) relaxed_add_element(el Element, relaxed bool) ! {
// todo: check against size
if seq.fields.len == 0 {
// just adds it then return
seq.fields << el
return
}
// for item in seq.fields {
// if item.equal_with(el) {
// return error('has already in the fields')
// }
// }
filtered_by_tag := seq.fields.filter(it.tag().equal(el.tag()))
if filtered_by_tag.len == 0 {
seq.fields << el
return
} else {
if !relaxed {
return error('You can not insert element without forcing')
}
seq.fields << el
return
}
}
// is_sequence_of[T] checks whether this sequence is SequenceOf[T] type.
pub fn (seq Sequence) is_sequence_of[T]() bool {
return seq.fields.all(it is T)
}
// into_sequence_of[T] turns this sequence into SequenceOf[T] element.
pub fn (seq Sequence) into_sequence_of[T]() !SequenceOf[T] {
if seq.is_sequence_of[T]() {
return error('This sequence is not SequenceOf[T]')
}
mut sqof := SequenceOf[T]{}
for el in seq.fields {
obj := el.into_object[T]()!
sqof.fields << obj
}
return sqof
}
// ASN.1 SEQUENCE OF TYPE.
// SequenceOf[T] is an arrays of generic T, so the generic T should fullfill Element interface.
// We dont use generic aliases because generic type aliases are not yet implemented.
pub struct SequenceOf[T] {
mut:
size int = default_sequence_size
fields []T
}
// SequenceOf.new creates a new SequenceOf[T]
pub fn SequenceOf.new[T]() SequenceOf[T] {
return SequenceOf[T]{}
}
// SequenceOf.from_list creates a new SequenceOf[T] from arrays of T type.
pub fn SequenceOf.from_list[T](els []T) !SequenceOf[T] {
if els.len > max_sequence_size {
return error('SequenceOf size exceed limit')
}
$if T !is Element {
return error('T not hold element')
}
return SequenceOf[T]{
fields: els
}
}
// The tag of SequenceOf element.
pub fn (so SequenceOf[T]) tag() Tag {
return default_sequence_tag
}
// The payload of SequenceOf element.
pub fn (so SequenceOf[T]) payload() ![]u8 {
return so.payload_with_rule(.der)!
}
fn (so SequenceOf[T]) payload_with_rule(rule EncodingRule) ![]u8 {
$if T !is Element {
return error('T is not an element')
}
mut out := []u8{}
for el in so.fields {
// placing el directly bring into error: `el` cannot be used as interface object
// outside `unsafe` blocks as it might be stored on stack.
curr := unsafe { el }
obj := encode_with_rule(curr, rule)!
out << obj
}
return out
}
// fields returns underlying arrays of T from the SequenceOf[T].
pub fn (so SequenceOf[T]) fields() []T {
return so.fields
}