mirror of
https://github.com/vlang/v.git
synced 2025-09-15 15:32:27 +03:00
207 lines
6.9 KiB
V
207 lines
6.9 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
|
|
|
|
// max_definite_length_count is a limit tells how many bytes to represent this length.
|
|
// We're going to limit this to 6 bytes following when the length is in long-definite form.
|
|
const max_definite_length_count = 6
|
|
const max_definite_length_value = max_int
|
|
|
|
// ASN.1 length handling routines.
|
|
//
|
|
// The standard of X.690 ITU document defines two length types - definite and indefinite.
|
|
// In DER encoding only uses the definite length. The length field must be encoded in the minimum number of octets.
|
|
// There are two forms of definite length octets: short (for lengths value between 0 and 127),
|
|
// and long definite (for lengths value between 0 and 2^1008 -1).
|
|
// In short form contains one octet. Bit 8 has value "0" and bits 7-1 give the length (length value from 0 to 127)
|
|
// In long form, its required two or more octets, limited to 127 octets. Bit 8 of first octet has value "1" and bits 7-1 gives
|
|
// the number of additional length octets.
|
|
// Second and following octets give the length, base 256, most significant digit first.
|
|
//
|
|
// This module only support definite length, in short or long form. Its required for DER encoding
|
|
// the length octets should be in definite length.
|
|
//
|
|
// Length represent ASN.1 length value
|
|
pub type Length = int
|
|
|
|
// new creates Length from integer value. Passing negative value (<0) for length
|
|
// is not make a sense, so just return error instead if it happen.
|
|
pub fn Length.new(v int) !Length {
|
|
if v < 0 {
|
|
return error('Length: supply with positive int')
|
|
}
|
|
if v > max_definite_length_value {
|
|
return error('Length: value provided exceed limit')
|
|
}
|
|
return Length(v)
|
|
}
|
|
|
|
// Length.from_bytes tries to read length from bytes array and return the length
|
|
// and the rest of remaining bytes on success, or error on fails.
|
|
pub fn Length.from_bytes(bytes []u8) !(Length, []u8) {
|
|
length, next := Length.decode(bytes)!
|
|
if next < bytes.len {
|
|
rest := unsafe { bytes[next..] }
|
|
return length, rest
|
|
}
|
|
if next == bytes.len {
|
|
return length, []u8{}
|
|
}
|
|
return error('Length: too short data')
|
|
}
|
|
|
|
// encode serializes the length v into bytes array stored into buffer buf in .der rule.
|
|
pub fn (v Length) encode(mut dst []u8) ! {
|
|
v.encode_with_rule(mut dst, .der)!
|
|
}
|
|
|
|
// encode_with_rule serializes Length v into bytes and append it into `dst`.
|
|
// it would use rule of `Encodingrule` to drive how encode operation would be done.
|
|
// By default the .der rule is only currently supported.
|
|
fn (v Length) encode_with_rule(mut dst []u8, rule EncodingRule) ! {
|
|
// we currently only support .der and (stricter) .ber
|
|
if rule != .der && rule != .ber {
|
|
return error('Length: unsupported rule')
|
|
}
|
|
// TODO: add supports for undefinite form
|
|
// Long form
|
|
if v >= 128 {
|
|
// First, we count how many bytes occupied by this length value.
|
|
// if the count exceed the limit, we return error.
|
|
count := v.bytes_len()
|
|
if count > max_definite_length_count {
|
|
return error('something bad in your length')
|
|
}
|
|
// In definite long form, msb bit of first byte is set into 1, and the remaining bits
|
|
// of first byte tells exact count how many bytes following representing this length value.
|
|
dst << 0x80 | u8(count)
|
|
v.to_bytes(mut dst)
|
|
} else {
|
|
// short form, already tells the length value.
|
|
dst << u8(v)
|
|
}
|
|
}
|
|
|
|
// bytes_len tells how many bytes needed to represent this length
|
|
fn (v Length) bytes_len() int {
|
|
mut i := v
|
|
mut num := 1
|
|
for i > 255 {
|
|
num++
|
|
i >>= 8
|
|
}
|
|
return num
|
|
}
|
|
|
|
// to_bytes packs Length v into bytes and apends it into `dst` bytes.
|
|
fn (v Length) to_bytes(mut dst []u8) {
|
|
mut n := v.bytes_len()
|
|
for ; n > 0; n-- {
|
|
// pay attention to the brackets
|
|
dst << u8(v >> ((n - 1) * 8))
|
|
}
|
|
}
|
|
|
|
// length_size gets length of length v in .der rule
|
|
fn (v Length) length_size() !int {
|
|
n := v.length_size_with_rule(.der)!
|
|
return n
|
|
}
|
|
|
|
// length_size_with_rule calculates the length of bytes needed to store the Length value `v`
|
|
// includes one byte marker for long definite form of length value, for value >= 128
|
|
fn (v Length) length_size_with_rule(rule EncodingRule) !int {
|
|
// we currently only support .der or (stricter) .ber
|
|
if rule != .der && rule != .ber {
|
|
return error('Length: unsupported rule')
|
|
}
|
|
n := if v < 128 { 1 } else { v.bytes_len() + 1 }
|
|
return n
|
|
}
|
|
|
|
// decode read length from bytes src with default context or return error on fails.
|
|
fn Length.decode(src []u8) !(Length, int) {
|
|
ret, next := Length.decode_from_offset(src, 0)!
|
|
return ret, next
|
|
}
|
|
|
|
// decode_from_offset read length from src bytes start from offset pos or return error on fails.
|
|
fn Length.decode_from_offset(src []u8, pos int) !(Length, int) {
|
|
ret, next := Length.decode_with_rule(src, pos, .der)!
|
|
return ret, next
|
|
}
|
|
|
|
// decode_with_rule tries to decode and deserializes buffer in src into Length form, start from offset loc in the buffer.
|
|
// Its return Length and next offset in the buffer to process on, or return error on fails.
|
|
fn Length.decode_with_rule(src []u8, loc int, rule EncodingRule) !(Length, int) {
|
|
if src.len < 1 {
|
|
return error('Length: truncated length')
|
|
}
|
|
// preliminary check
|
|
if rule != .der && rule != .ber {
|
|
return error('Length: unsupported rule')
|
|
}
|
|
// consider b := src[loc] would lead to panic
|
|
if loc >= src.len {
|
|
return error('Length: invalid pos')
|
|
}
|
|
|
|
mut pos := loc
|
|
mut b := src[pos]
|
|
pos += 1
|
|
mut length := 0
|
|
// check for the most bit is set or not
|
|
if b & 0x80 == 0 {
|
|
// for lengths between 0 and 127, the one-octet short form can be used.
|
|
// The bit 7 of the length octet is set to 0, and the length is encoded
|
|
// as an unsigned binary value in the octet's rightmost seven bits.
|
|
length = b & 0x7f
|
|
} else {
|
|
if pos > src.len {
|
|
return error('truncated tag or length')
|
|
}
|
|
// Otherwise, its a Long definite form or undefinite form
|
|
num_bytes := b & 0x7f
|
|
if num_bytes == 0 {
|
|
// TODO: add support for undefinite length
|
|
return error('Length: unsupported undefinite length')
|
|
}
|
|
if num_bytes == 0x7f {
|
|
return error('Length: 0x7f is for reserved use')
|
|
}
|
|
// we limit the bytes count for length definite form to `max_definite_length_count`
|
|
if num_bytes > max_definite_length_count {
|
|
return error('Length: count bytes exceed limit')
|
|
}
|
|
for i := 0; i < num_bytes; i++ {
|
|
if pos >= src.len {
|
|
return error('Length: truncated length')
|
|
}
|
|
b = src[pos]
|
|
pos += 1
|
|
|
|
// currently, we're only support limited length.
|
|
// The length is in int range
|
|
if length > max_definite_length_value {
|
|
return error('Length: length exceed limit value')
|
|
}
|
|
length <<= 8
|
|
length |= b
|
|
if length == 0 {
|
|
// TODO: leading zeros is allowed in Long form of BER encoding, but
|
|
// not allowed in DER encoding
|
|
if rule == .der {
|
|
return error('Length: leading zeros')
|
|
}
|
|
}
|
|
}
|
|
// do not allow values < 0x80 to be encoded in long form
|
|
if length < 0x80 {
|
|
// TODO: allow in BER
|
|
return error('Length: dont needed in long form')
|
|
}
|
|
}
|
|
ret := Length.new(length)!
|
|
return ret, pos
|
|
}
|