v2 / vlib / x / encoding / asn1 / integer_test.v
268 lines · 234 sloc · 10.04 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
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
6import math.big
7
8struct TwoFormTest {
9 value string
10 expected string
11}
12
13const string_data = [
14 TwoFormTest{'0', '\x00'},
15 TwoFormTest{'25', '\x19'},
16 TwoFormTest{'100', '\x64'},
17 TwoFormTest{'-1042342234234123423435647768234', '\xF2\xD8\x02\xB6R\x7F\x99\xEE\x98#\x99\xA9V'},
18 TwoFormTest{'-12095473475870063', '\xD5\a;\x20\x14\xA2\x91'},
19 TwoFormTest{'12095473475870063', '*\xF8\xC4\xDF\xEB]o'},
20 TwoFormTest{'12438789579431234124191998', '\nJ\x04"^\x91\x04\x8a\xb1\x18\xfe'},
21 TwoFormTest{'-112233441191', '\xe5\xde]\x98Y'},
22 TwoFormTest{'64206', '\x00\xfa\xce'},
23 TwoFormTest{'-100', '\x9C'},
24 TwoFormTest{'100', '\x64'},
25 TwoFormTest{'255', '\x00\xFF'},
26 TwoFormTest{'0', '\x00'},
27 TwoFormTest{'-2', '\xfe'},
28 TwoFormTest{'-1', '\xff'},
29 TwoFormTest{'-16', '\xf0'},
30 TwoFormTest{'-256', '\xff\x00'},
31 TwoFormTest{'-255', '\xff\x01'},
32 TwoFormTest{'-32768', '\x80\x00'},
33 TwoFormTest{'-128', '\x80'},
34 TwoFormTest{'-129', '\xff\x7f'},
35 TwoFormTest{'-127', '\x81'},
36]
37
38fn test_integer_pack_n_unpack_from_n_into_2form() ! {
39 for i, c in string_data {
40 v := Integer.from_string(c.value)!
41 out, _ := v.pack_into_twoscomplement_form()!
42
43 assert out == c.expected.bytes()
44
45 // unpack back
46 b := Integer.unpack_from_twoscomplement_bytes(c.expected.bytes())!
47 assert b.value.str() == c.value
48 }
49}
50
51struct UnpackTest {
52 val i64
53 out []u8
54}
55
56// from python asn1tools
57//
58const unpack_data = [
59 UnpackTest{32768, [u8(0x02), 0x03, 0x00, 0x80, 0x00]},
60 UnpackTest{32767, [u8(0x02), 0x02, 0x7f, 0xff]},
61 UnpackTest{256, [u8(0x02), 0x02, 0x01, 0x00]},
62 UnpackTest{255, [u8(0x02), 0x02, 0x00, 0xff]},
63 UnpackTest{128, [u8(0x02), 0x02, 0x00, 0x80]},
64 UnpackTest{127, [u8(0x02), 0x01, 0x7f]},
65 UnpackTest{1, [u8(0x02), 0x01, 0x01]},
66 UnpackTest{0, [u8(0x02), 0x01, 0x00]},
67 UnpackTest{-1, [u8(0x02), 0x01, 0xff]},
68 UnpackTest{-128, [u8(0x02), 0x01, 0x80]},
69 UnpackTest{-129, [u8(0x02), 0x02, 0xff, 0x7f]},
70 UnpackTest{-256, [u8(0x02), 0x02, 0xff, 0x00]},
71 UnpackTest{-32768, [u8(0x02), 0x02, 0x80, 0x00]},
72 UnpackTest{-32769, [u8(0x02), 0x03, 0xff, 0x7f, 0xff]},
73]
74
75fn test_asn1_integer_unencode() ! {
76 for i, c in unpack_data {
77 n := Integer.from_i64(c.val)
78 to := encode(n)!
79 assert to == c.out
80 }
81}
82
83struct ASNIntegerTest {
84 bytes []u8
85 err IError
86 expected Integer
87}
88
89const integer_test_data = [
90 ASNIntegerTest{[u8(0x00)], none, Integer.from_int(0)},
91 ASNIntegerTest{[u8(0x7f)], none, Integer.from_int(127)},
92 ASNIntegerTest{[u8(0x00), 0x80], none, Integer.from_int(128)},
93 ASNIntegerTest{[u8(0x01), 0x00], none, Integer.from_int(256)},
94 ASNIntegerTest{[u8(0x80)], none, Integer.from_int(-128)},
95 ASNIntegerTest{[u8(0xff), 0x7f], none, Integer.from_int(-129)},
96 ASNIntegerTest{[u8(0xff)], none, Integer.from_int(-1)},
97 ASNIntegerTest{[u8(0x80), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], none, Integer{
98 value: big.integer_from_string('-9223372036854775808') or { panic(err) }
99 }},
100 ASNIntegerTest{[u8(0x80), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], none, Integer{
101 value: big.integer_from_string('-2361183241434822606848') or { panic(err) }
102 }},
103 ASNIntegerTest{[], error('Integer: check return false'), Integer.from_i64(0)},
104 ASNIntegerTest{[u8(0x00), 0x7f], error('Integer: check return false'), Integer.from_int(127)}, // non-minimal form
105 ASNIntegerTest{[u8(0xff), 0xf0], error('Integer: check return false'), Integer.from_int(-16)}, // non-minimal form
106 ASNIntegerTest{[], error('Integer: check return false'), Integer.from_i64(0)}, // empty integer
107 ASNIntegerTest{[u8(0x00)], none, Integer.from_i64(0)},
108 ASNIntegerTest{[u8(0x7f)], none, Integer.from_int(127)},
109 ASNIntegerTest{[u8(0x00), 0x80], none, Integer.from_int(128)},
110 ASNIntegerTest{[u8(0x01), 0x00], none, Integer.from_int(256)},
111 ASNIntegerTest{[u8(0x80)], none, Integer.from_int(-128)},
112 ASNIntegerTest{[u8(0xff), 0x7f], none, Integer.from_int(-129)},
113 ASNIntegerTest{[u8(0x80), 0x00, 0x00, 0x00], none, Integer.from_string('-2147483648') or {
114 panic(err)
115 }},
116 ASNIntegerTest{[u8(0x80), 0x00, 0x00, 0x00, 0x00], none, Integer.from_i64(-549755813888)},
117 ASNIntegerTest{[u8(0x00), 0x7f], error('Integer: check return false'), Integer.from_i64(0)},
118 ASNIntegerTest{[u8(0xff), 0xf0], error('Integer: check return false'), Integer.from_i64(0)}, // not minimally
119]
120
121// from golang encoding/asn1 test
122fn test_asn1_unpack_and_validate() {
123 for i, v in integer_test_data {
124 ret := Integer.unpack_and_validate(v.bytes) or {
125 assert err == v.err
126 continue
127 }
128 // compared directly, with ret == v.expected, failed with -cstrict option
129 // assert ret == v.expected
130 // > assert ret == v.expected
131 // Left value (len: 28): `Integer -9223372036854775808`
132 // Right value (len: 28):`Integer -9223372036854775808`
133 assert ret.equal(v.expected)
134 }
135}
136
137fn test_asn1_integer_simple_long_integer_pack_unpack() ! {
138 num := Integer.from_hex('0102030405060708090a0b0c0d0e0f')!
139 dst := encode(num)!
140
141 expected := '\x02\x0f\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'.bytes()
142 assert dst == expected
143
144 // unpack back
145 val, pos := Integer.decode(expected)!
146 assert val == num
147 assert pos == 17
148
149 // test with negative value
150 negnum := Integer.from_hex('-0102030405060708090a0b0c0d0e0f')!
151 out := encode(negnum)!
152 expneg := '\x02\x0f\xfe\xfd\xfc\xfb\xfa\xf9\xf8\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf1'.bytes()
153 assert out == expneg
154
155 // unpack back a negative number
156 val2, pos2 := Integer.decode(expneg)!
157 assert val2 == negnum
158 assert pos2 == 17
159}
160
161// from asn-one test cases
162// FIXME: Its still need a fix, remove additional 0x00 before 0x8f in unpack operation
163fn test_integer_large_int() ! {
164 bytes := [u8(0x02), 0x81, 0x81, 0x00, 0x8f, 0xe2, 0x41, 0x2a, 0x08, 0xe8, 0x51, 0xa8, 0x8c,
165 0xb3, 0xe8, 0x53, 0xe7, 0xd5, 0x49, 0x50, 0xb3, 0x27, 0x8a, 0x2b, 0xcb, 0xea, 0xb5, 0x42,
166 0x73, 0xea, 0x02, 0x57, 0xcc, 0x65, 0x33, 0xee, 0x88, 0x20, 0x61, 0xa1, 0x17, 0x56, 0xc1,
167 0x24, 0x18, 0xe3, 0xa8, 0x08, 0xd3, 0xbe, 0xd9, 0x31, 0xf3, 0x37, 0x0b, 0x94, 0xb8, 0xcc,
168 0x43, 0x08, 0x0b, 0x70, 0x24, 0xf7, 0x9c, 0xb1, 0x8d, 0x5d, 0xd6, 0x6d, 0x82, 0xd0, 0x54,
169 0x09, 0x84, 0xf8, 0x9f, 0x97, 0x01, 0x75, 0x05, 0x9c, 0x89, 0xd4, 0xd5, 0xc9, 0x1e, 0xc9,
170 0x13, 0xd7, 0x2a, 0x6b, 0x30, 0x91, 0x19, 0xd6, 0xd4, 0x42, 0xe0, 0xc4, 0x9d, 0x7c, 0x92,
171 0x71, 0xe1, 0xb2, 0x2f, 0x5c, 0x8d, 0xee, 0xf0, 0xf1, 0x17, 0x1e, 0xd2, 0x5f, 0x31, 0x5b,
172 0xb1, 0x9c, 0xbc, 0x20, 0x55, 0xbf, 0x3a, 0x37, 0x42, 0x45, 0x75, 0xdc, 0x90, 0x65]
173 expected_integer :=
174 Integer.from_string('101038645214968213029489864879507742420925199145132483818978980455132582258676381289000109319204510275496178360219909358646064503513889573494768497419381751359787623037449375660247011308028102339473875820259375735204357343091558075960601364303443174344509161224592926325506446708043127306053676664799729848421')!
175 out, pos := Integer.decode(bytes)!
176
177 assert pos == bytes.len
178
179 assert out.tag() == expected_integer.tag() // success
180 outbytes := out.bytes()
181 expbytes := expected_integer.bytes()
182 assert outbytes == expbytes // success
183
184 // this direct assert fails
185 // BUG?: there are some issues when compared out == expected directly, even internally its a same,
186 // but it fails to assert, so we provide and use equality check
187 // assert out == expected_integer
188 // dump(out)
189 // dump(expected_integer)
190 assert out.equal(expected_integer)
191
192 // pack back
193 dst := encode(expected_integer)!
194 assert dst == bytes
195
196 dst2 := encode(out)!
197 assert dst2 == bytes
198}
199
200// This test taken from: https://learn.microsoft.com/id-id/windows/win32/seccertenroll/about-integer
201// 02 81 81 ; INTEGER (81 Bytes)
202// | 00
203// | 8f e2 41 2a 08 e8 51 a8 8c b3 e8 53 e7 d5 49 50
204// | b3 27 8a 2b cb ea b5 42 73 ea 02 57 cc 65 33 ee
205// | 88 20 61 a1 17 56 c1 24 18 e3 a8 08 d3 be d9 31
206// | f3 37 0b 94 b8 cc 43 08 0b 70 24 f7 9c b1 8d 5d
207// | d6 6d 82 d0 54 09 84 f8 9f 97 01 75 05 9c 89 d4
208// | d5 c9 1e c9 13 d7 2a 6b 30 91 19 d6 d4 42 e0 c4
209// | 9d 7c 92 71 e1 b2 2f 5c 8d ee f0 f1 17 1e d2 5f
210// | 31 5b b1 9c bc 20 55 bf 3a 37 42 45 75 dc 90 65
211fn test_integer_decode_encode_with_real_data() ! {
212 data := [u8(0x02), 0x81, 0x81, 0x00, 0x8f, 0xe2, 0x41, 0x2a, 0x08, 0xe8, 0x51, 0xa8, 0x8c,
213 0xb3, 0xe8, 0x53, 0xe7, 0xd5, 0x49, 0x50, 0xb3, 0x27, 0x8a, 0x2b, 0xcb, 0xea, 0xb5, 0x42,
214 0x73, 0xea, 0x02, 0x57, 0xcc, 0x65, 0x33, 0xee, 0x88, 0x20, 0x61, 0xa1, 0x17, 0x56, 0xc1,
215 0x24, 0x18, 0xe3, 0xa8, 0x08, 0xd3, 0xbe, 0xd9, 0x31, 0xf3, 0x37, 0x0b, 0x94, 0xb8, 0xcc,
216 0x43, 0x08, 0x0b, 0x70, 0x24, 0xf7, 0x9c, 0xb1, 0x8d, 0x5d, 0xd6, 0x6d, 0x82, 0xd0, 0x54,
217 0x09, 0x84, 0xf8, 0x9f, 0x97, 0x01, 0x75, 0x05, 0x9c, 0x89, 0xd4, 0xd5, 0xc9, 0x1e, 0xc9,
218 0x13, 0xd7, 0x2a, 0x6b, 0x30, 0x91, 0x19, 0xd6, 0xd4, 0x42, 0xe0, 0xc4, 0x9d, 0x7c, 0x92,
219 0x71, 0xe1, 0xb2, 0x2f, 0x5c, 0x8d, 0xee, 0xf0, 0xf1, 0x17, 0x1e, 0xd2, 0x5f, 0x31, 0x5b,
220 0xb1, 0x9c, 0xbc, 0x20, 0x55, 0xbf, 0x3a, 0x37, 0x42, 0x45, 0x75, 0xdc, 0x90, 0x65]
221
222 // try to decode
223 val, pos := Integer.decode(data)!
224 value := val.as_bigint()! // big.Integer
225 assert pos == data.len
226
227 // serialized back
228 int_element := Integer.from_bigint(value)
229 serialized_int := encode(int_element)!
230 assert serialized_int == data
231
232 // with decode
233 el := decode(data)!
234 assert el.equal(val)
235}
236
237// This is taken from https://letsencrypt.org/id/docs/a-warm-welcome-to-asn1-and-der/
238// for integer encoding
239fn test_integer_encoding() ! {
240 data := [u8(0x02), 0x09, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
241 // try to decode
242 val, pos := Integer.decode(data)!
243 value := val.as_bigint()! // big.Integer
244 assert pos == data.len
245
246 // serialized back
247 int_element := Integer.from_bigint(value)
248 serialized_int := encode(int_element)!
249 assert serialized_int == data
250
251 // with decode
252 el := decode(data)!
253 assert el.equal(val)
254}
255
256// taken from https://github.com/PeculiarVentures/ASN1.js test.
257fn test_negative_number() ! {
258 value := Integer.from_string('-9150748177064392952')!
259
260 out := encode(value)!
261 assert out.hex() == '02088102030405060708'
262
263 back := decode(out)!
264 back_value := back.into_object[Integer]()!
265 assert back_value.value.str() == '-9150748177064392952'
266
267 assert back_value.value == value.value
268}
269