v2 / vlib / x / encoding / asn1 / length.v
207 lines · 192 sloc · 6.93 KB · fdc49dc51a0d7e83abd5b383afaaab3f2793f2cf
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// max_definite_length_count is a limit tells how many bytes to represent this length.
7// We're going to limit this to 6 bytes following when the length is in long-definite form.
8const max_definite_length_count = 6
9const max_definite_length_value = max_int
10
11// ASN.1 length handling routines.
12//
13// The standard of X.690 ITU document defines two length types - definite and indefinite.
14// In DER encoding only uses the definite length. The length field must be encoded in the minimum number of octets.
15// There are two forms of definite length octets: short (for lengths value between 0 and 127),
16// and long definite (for lengths value between 0 and 2^1008 -1).
17// In short form contains one octet. Bit 8 has value "0" and bits 7-1 give the length (length value from 0 to 127)
18// 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
19// the number of additional length octets.
20// Second and following octets give the length, base 256, most significant digit first.
21//
22// This module only support definite length, in short or long form. Its required for DER encoding
23// the length octets should be in definite length.
24//
25// Length represent ASN.1 length value
26pub type Length = int
27
28// new creates Length from integer value. Passing negative value (<0) for length
29// is not make a sense, so just return error instead if it happen.
30pub fn Length.new(v int) !Length {
31 if v < 0 {
32 return error('Length: supply with positive int')
33 }
34 if v > max_definite_length_value {
35 return error('Length: value provided exceed limit')
36 }
37 return Length(v)
38}
39
40// Length.from_bytes tries to read length from bytes array and return the length
41// and the rest of remaining bytes on success, or error on fails.
42pub fn Length.from_bytes(bytes []u8) !(Length, []u8) {
43 length, next := Length.decode(bytes)!
44 if next < bytes.len {
45 rest := unsafe { bytes[next..] }
46 return length, rest
47 }
48 if next == bytes.len {
49 return length, []u8{}
50 }
51 return error('Length: too short data')
52}
53
54// encode serializes the length v into bytes array stored into buffer buf in .der rule.
55pub fn (v Length) encode(mut dst []u8) ! {
56 v.encode_with_rule(mut dst, .der)!
57}
58
59// encode_with_rule serializes Length v into bytes and append it into `dst`.
60// it would use rule of `Encodingrule` to drive how encode operation would be done.
61// By default the .der rule is only currently supported.
62fn (v Length) encode_with_rule(mut dst []u8, rule EncodingRule) ! {
63 // we currently only support .der and (stricter) .ber
64 if rule != .der && rule != .ber {
65 return error('Length: unsupported rule')
66 }
67 // TODO: add supports for undefinite form
68 // Long form
69 if v >= 128 {
70 // First, we count how many bytes occupied by this length value.
71 // if the count exceed the limit, we return error.
72 count := v.bytes_len()
73 if count > max_definite_length_count {
74 return error('something bad in your length')
75 }
76 // In definite long form, msb bit of first byte is set into 1, and the remaining bits
77 // of first byte tells exact count how many bytes following representing this length value.
78 dst << 0x80 | u8(count)
79 v.to_bytes(mut dst)
80 } else {
81 // short form, already tells the length value.
82 dst << u8(v)
83 }
84}
85
86// bytes_len tells how many bytes needed to represent this length
87fn (v Length) bytes_len() int {
88 mut i := v
89 mut num := 1
90 for i > 255 {
91 num++
92 i >>= 8
93 }
94 return num
95}
96
97// to_bytes packs Length v into bytes and apends it into `dst` bytes.
98fn (v Length) to_bytes(mut dst []u8) {
99 mut n := v.bytes_len()
100 for ; n > 0; n-- {
101 // pay attention to the brackets
102 dst << u8(v >> ((n - 1) * 8))
103 }
104}
105
106// length_size gets length of length v in .der rule
107fn (v Length) length_size() !int {
108 n := v.length_size_with_rule(.der)!
109 return n
110}
111
112// length_size_with_rule calculates the length of bytes needed to store the Length value `v`
113// includes one byte marker for long definite form of length value, for value >= 128
114fn (v Length) length_size_with_rule(rule EncodingRule) !int {
115 // we currently only support .der or (stricter) .ber
116 if rule != .der && rule != .ber {
117 return error('Length: unsupported rule')
118 }
119 n := if v < 128 { 1 } else { v.bytes_len() + 1 }
120 return n
121}
122
123// decode read length from bytes src with default context or return error on fails.
124fn Length.decode(src []u8) !(Length, int) {
125 ret, next := Length.decode_from_offset(src, 0)!
126 return ret, next
127}
128
129// decode_from_offset read length from src bytes start from offset pos or return error on fails.
130fn Length.decode_from_offset(src []u8, pos int) !(Length, int) {
131 ret, next := Length.decode_with_rule(src, pos, .der)!
132 return ret, next
133}
134
135// decode_with_rule tries to decode and deserializes buffer in src into Length form, start from offset loc in the buffer.
136// Its return Length and next offset in the buffer to process on, or return error on fails.
137fn Length.decode_with_rule(src []u8, loc int, rule EncodingRule) !(Length, int) {
138 if src.len < 1 {
139 return error('Length: truncated length')
140 }
141 // preliminary check
142 if rule != .der && rule != .ber {
143 return error('Length: unsupported rule')
144 }
145 // consider b := src[loc] would lead to panic
146 if loc >= src.len {
147 return error('Length: invalid pos')
148 }
149
150 mut pos := loc
151 mut b := src[pos]
152 pos += 1
153 mut length := 0
154 // check for the most bit is set or not
155 if b & 0x80 == 0 {
156 // for lengths between 0 and 127, the one-octet short form can be used.
157 // The bit 7 of the length octet is set to 0, and the length is encoded
158 // as an unsigned binary value in the octet's rightmost seven bits.
159 length = b & 0x7f
160 } else {
161 if pos > src.len {
162 return error('truncated tag or length')
163 }
164 // Otherwise, its a Long definite form or undefinite form
165 num_bytes := b & 0x7f
166 if num_bytes == 0 {
167 // TODO: add support for undefinite length
168 return error('Length: unsupported undefinite length')
169 }
170 if num_bytes == 0x7f {
171 return error('Length: 0x7f is for reserved use')
172 }
173 // we limit the bytes count for length definite form to `max_definite_length_count`
174 if num_bytes > max_definite_length_count {
175 return error('Length: count bytes exceed limit')
176 }
177 for i := 0; i < num_bytes; i++ {
178 if pos >= src.len {
179 return error('Length: truncated length')
180 }
181 b = src[pos]
182 pos += 1
183
184 // currently, we're only support limited length.
185 // The length is in int range
186 if length > max_definite_length_value {
187 return error('Length: length exceed limit value')
188 }
189 length <<= 8
190 length |= b
191 if length == 0 {
192 // TODO: leading zeros is allowed in Long form of BER encoding, but
193 // not allowed in DER encoding
194 if rule == .der {
195 return error('Length: leading zeros')
196 }
197 }
198 }
199 // do not allow values < 0x80 to be encoded in long form
200 if length < 0x80 {
201 // TODO: allow in BER
202 return error('Length: dont needed in long form')
203 }
204 }
205 ret := Length.new(length)!
206 return ret, pos
207}
208