mirror of
https://github.com/vlang/v.git
synced 2025-09-08 06:41:58 -04:00
283 lines
7.6 KiB
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
|
|
}
|