| 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. |
| 4 | module asn1 |
| 5 | |
| 6 | import math.big |
| 7 | |
| 8 | fn test_sequence_with_multi_items() ! { |
| 9 | mut seq := Sequence{} |
| 10 | |
| 11 | o1 := Boolean.new(true) // 3 |
| 12 | o2 := UtcTime.new('191215190210Z')! // 15 |
| 13 | o3 := GeneralizedTime.new('20100102030405Z')! // 17 |
| 14 | |
| 15 | // we are going to add with add_element to allow adding element with the same tag |
| 16 | seq.add_element(o1)! |
| 17 | seq.add_element(o2)! |
| 18 | seq.add_element(o3)! |
| 19 | |
| 20 | assert seq.payload()!.len == 3 + 15 + 17 // 35 |
| 21 | assert encoded_len(seq) == 2 + 35 |
| 22 | |
| 23 | out := encode(seq)! |
| 24 | exp := [u8(0x30), 35, u8(0x01), 0x01, 0xff, u8(0x17), 0x0D, 49, 57, 49, 50, 49, 53, 49, 57, |
| 25 | 48, 50, 49, 48, 90, u8(0x18), 0x0f, 50, 48, 49, 48, 48, 49, 48, 50, 48, 51, 48, 52, 48, |
| 26 | 53, 90] |
| 27 | |
| 28 | assert out == exp |
| 29 | } |
| 30 | |
| 31 | fn test_sequence_contains_other_seq() ! { |
| 32 | // lets create first sequence |
| 33 | mut seq1 := Sequence{} |
| 34 | // add two primitive elements to the sequence |
| 35 | seq1.add_element(Boolean.new(true))! |
| 36 | seq1.add_element(Null{})! |
| 37 | seq1.add_element(Boolean.new(false))! |
| 38 | |
| 39 | // lets create another sequences, where it contains primitive element and first sequence created above. |
| 40 | mut seq2 := Sequence{} |
| 41 | seq2.add_element(Boolean.new(false))! |
| 42 | seq2.add_element(seq1)! |
| 43 | // you should force add element to allow add second Boolean, by default its not allowed |
| 44 | seq2.add_element(Boolean.new(true))! |
| 45 | |
| 46 | // lets serialize it to bytes |
| 47 | |
| 48 | out := encode(seq2)! |
| 49 | |
| 50 | expected := [u8(0x30), 16, u8(0x01), 0x01, 0x00, u8(0x30), 8, 0x01, 0x01, 0xff, u8(0x05), 0x00, |
| 51 | u8(0x01), 0x01, 0x00, u8(0x01), 0x01, 0xff] |
| 52 | // assert for right value |
| 53 | assert seq2.payload()!.len == 16 |
| 54 | assert encoded_len(seq2) == 18 |
| 55 | assert out == expected |
| 56 | |
| 57 | seq2_back, _ := Sequence.decode(expected)! |
| 58 | assert seq2_back.fields()[1] is Sequence |
| 59 | } |
| 60 | |
| 61 | fn test_sequence_der_decode() ! { |
| 62 | data := [u8(0x30), 16, u8(0x01), 0x01, 0x00, u8(0x30), 8, u8(0x01), 0x01, 0xff, u8(0x05), 0x00, |
| 63 | u8(0x01), 0x01, 0x00, u8(0x01), 0x01, 0xff] |
| 64 | |
| 65 | seq, n := Sequence.decode(data)! |
| 66 | assert seq.tag().is_constructed() == true |
| 67 | assert seq.tag().tag_number() == int(TagType.sequence) |
| 68 | assert n == 18 |
| 69 | assert seq.fields().len == 3 |
| 70 | els := seq.fields() |
| 71 | |
| 72 | assert els[0].tag() == Tag.new(.universal, false, int(TagType.boolean))! |
| 73 | assert els[0].payload()! == [u8(0x00)] |
| 74 | |
| 75 | el1 := els[1] as Sequence |
| 76 | assert el1.fields().len == 3 // [true, null, false] |
| 77 | el10 := el1.fields()[0] as Boolean |
| 78 | assert el10.value() == true |
| 79 | el11 := el1.fields()[1] as Null |
| 80 | assert el11 == Null{} |
| 81 | el12 := el1.fields()[2] as Boolean |
| 82 | assert el12.value() == false |
| 83 | |
| 84 | el2 := els[2] as Boolean |
| 85 | assert el2.value() == true |
| 86 | } |
| 87 | |
| 88 | fn test_sequence_add_and_encode_boolean() { |
| 89 | o1 := Boolean.new(false) |
| 90 | o2 := Boolean.new(true) |
| 91 | o3 := Null{} |
| 92 | mut seq := Sequence{} |
| 93 | seq.add_element(o1)! |
| 94 | seq.add_element(o2)! |
| 95 | seq.add_element(o3)! |
| 96 | |
| 97 | length := seq.payload()!.len |
| 98 | assert length == 8 |
| 99 | |
| 100 | size := encoded_len(seq) |
| 101 | assert size == 10 |
| 102 | |
| 103 | out := encode(seq)! |
| 104 | |
| 105 | exp := [u8(0x30), 0x08, 0x01, 0x01, 0x00, 0x01, 0x01, 0xff, 0x05, 0x00] |
| 106 | |
| 107 | assert out == exp |
| 108 | assert exp.len == size |
| 109 | |
| 110 | back, n := Sequence.decode(out)! |
| 111 | assert n == exp.len |
| 112 | |
| 113 | assert back.fields().len == 3 |
| 114 | |
| 115 | assert back.tag().number == 0x10 |
| 116 | assert back.tag().constructed == true |
| 117 | assert back.tag().class == .universal |
| 118 | |
| 119 | assert back.fields()[0].tag().class == .universal |
| 120 | assert back.fields()[0].tag().constructed == false |
| 121 | assert back.fields()[0].tag().number == 0x01 |
| 122 | |
| 123 | assert back.fields()[1].tag().class == .universal |
| 124 | assert back.fields()[1].tag().constructed == false |
| 125 | assert back.fields()[1].tag().number == 0x01 |
| 126 | |
| 127 | assert back.fields()[2].tag().number == 0x05 |
| 128 | assert back.fields()[2].tag().constructed == false |
| 129 | } |
| 130 | |
| 131 | fn test_sequence_add_encode_oid() ! { |
| 132 | mut seq := Sequence{} |
| 133 | |
| 134 | o1 := ObjectIdentifier.new('1.2.3')! // size = 4 |
| 135 | o2 := ObjectIdentifier.new('1.2.4')! // size = 4 |
| 136 | o3 := Boolean.new(true) // size = 3 |
| 137 | |
| 138 | seq.add_element(o1)! |
| 139 | seq.add_element(o2)! |
| 140 | seq.add_element(o3)! |
| 141 | |
| 142 | assert seq.tag() == Tag.new(.universal, true, int(TagType.sequence))! |
| 143 | assert seq.payload()!.len == 11 |
| 144 | assert encoded_len(seq) == 13 |
| 145 | |
| 146 | mut out := encode(seq)! |
| 147 | exp := [u8(0x30), 0x0b, u8(0x06), 0x02, 0x2a, 0x03, u8(0x06), 0x02, 0x2a, 0x04, u8(0x01), 0x01, |
| 148 | 0xff] |
| 149 | |
| 150 | assert out == exp |
| 151 | |
| 152 | back, n := Sequence.decode(out)! |
| 153 | assert n == exp.len |
| 154 | //(back) |
| 155 | |
| 156 | assert back.fields().len == 3 |
| 157 | assert back.tag().constructed == true |
| 158 | // |
| 159 | out.clear() |
| 160 | out = encode(back.fields()[0])! |
| 161 | assert out == [u8(0x06), 0x02, 0x2a, 0x03] |
| 162 | // |
| 163 | out.clear() |
| 164 | out = encode(back.fields()[1])! |
| 165 | assert out == [u8(0x06), 0x02, 0x2a, 0x04] |
| 166 | // |
| 167 | out.clear() |
| 168 | out = encode(back.fields()[2])! |
| 169 | assert out == [u8(0x01), 0x01, 0xff] |
| 170 | } |
| 171 | |
| 172 | fn test_sequence_add_encode_integer() ! { |
| 173 | mut seq := Sequence.new()! |
| 174 | |
| 175 | o1 := Integer.from_i64(127) |
| 176 | o2 := Boolean.new(true) |
| 177 | o3 := Integer.from_i64(max_i64) |
| 178 | seq.add_element(o1)! |
| 179 | seq.add_element(o2)! |
| 180 | seq.add_element(o3)! |
| 181 | |
| 182 | assert seq.tag() == Tag.new(.universal, true, int(TagType.sequence))! |
| 183 | assert seq.payload()!.len == 16 |
| 184 | assert encoded_len(seq) == 18 |
| 185 | |
| 186 | mut out := encode(seq)! |
| 187 | // math.max_i64 serialize to 02087fffffffffffffff |
| 188 | exp := [u8(0x30), 0x10, u8(0x02), 0x01, 0x7f, u8(0x01), 0x01, 0xff, u8(0x02), 0x08, 0x7f, 0xff, |
| 189 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] |
| 190 | |
| 191 | assert out == exp |
| 192 | |
| 193 | back, n := Sequence.decode(out)! |
| 194 | assert n == exp.len |
| 195 | |
| 196 | assert back.fields().len == 3 |
| 197 | assert back.tag().number == 16 |
| 198 | assert back.tag().constructed == true |
| 199 | } |
| 200 | |
| 201 | fn test_sequence_integer_bigint() ! { |
| 202 | inp := |
| 203 | big.integer_from_string('84885164052257330097714121751630835360966663883732297726369399')! |
| 204 | mut seq := Sequence.new()! |
| 205 | |
| 206 | o1 := Integer.from_bigint(inp) |
| 207 | o2 := Boolean.new(true) |
| 208 | o3 := Null{} |
| 209 | seq.add_element(o1)! |
| 210 | seq.add_element(o2)! |
| 211 | seq.add_element(o3)! |
| 212 | |
| 213 | mut out := encode(seq)! |
| 214 | |
| 215 | assert seq.payload()!.len == 28 + 3 + 2 |
| 216 | assert encoded_len(seq) == 2 + 28 + 3 + 2 |
| 217 | exp := [u8(0x30), 33, u8(0x02), 26, 52, 210, 252, 160, 105, 66, 145, 88, 8, 53, 227, 150, 221, |
| 218 | 98, 149, 87, 146, 121, 109, 20, 162, 246, 230, 65, 30, 119, u8(0x01), 0x01, 0xff, u8(0x05), |
| 219 | 0x00] |
| 220 | |
| 221 | assert out == exp |
| 222 | |
| 223 | back, n := Sequence.decode(out)! // Sequence |
| 224 | assert n == exp.len |
| 225 | |
| 226 | // clear out |
| 227 | out.clear() |
| 228 | out = encode(back)! |
| 229 | assert out == exp |
| 230 | |
| 231 | assert back.fields().len == 3 |
| 232 | assert back.tag().number == 16 |
| 233 | assert back.tag().constructed == true |
| 234 | |
| 235 | // clear out |
| 236 | out.clear() |
| 237 | out = encode(back.fields()[1])! |
| 238 | assert out == [u8(0x01), 0x01, 0xff] |
| 239 | } |
| 240 | |
| 241 | fn test_sequence_of_string() ! { |
| 242 | str := 'iloveyou' // 8 |
| 243 | mut seq := Sequence.new()! |
| 244 | o1 := Null{} |
| 245 | o2 := Utf8String.new(str)! |
| 246 | o3 := IA5String.new(str)! |
| 247 | seq.add_element(o1)! |
| 248 | seq.add_element(o2)! |
| 249 | seq.add_element(o3)! |
| 250 | |
| 251 | assert seq.payload()!.len == 22 |
| 252 | assert seq.encoded_len() == 24 |
| 253 | |
| 254 | mut out := encode(seq)! |
| 255 | exp := [u8(0x30), 22, u8(0x05), 0x00, u8(12), 8, u8(105), 108, 111, 118, 101, 121, 111, 117, |
| 256 | u8(22), 8, u8(105), 108, 111, 118, 101, 121, 111, 117] |
| 257 | assert out == exp |
| 258 | |
| 259 | back, n := Sequence.decode(out)! |
| 260 | assert n == exp.len |
| 261 | // clears out |
| 262 | out.clear() |
| 263 | out = encode(back)! |
| 264 | assert out == exp |
| 265 | } |
| 266 | |
| 267 | fn test_sequnce_of_sequence() { |
| 268 | mut seq := Sequence.new()! |
| 269 | |
| 270 | seq.add_element(Null{})! |
| 271 | seq.add_element(Boolean.new(false))! |
| 272 | |
| 273 | mut out := encode(seq)! |
| 274 | assert out == [u8(0x30), 5, 5, 0, 1, 1, 0] |
| 275 | |
| 276 | mut seq2 := Sequence.new()! |
| 277 | seq2.add_element(Integer.from_i64(5))! |
| 278 | seq2.add_element(Integer.from_i64(i64(86424278346)))! |
| 279 | |
| 280 | // clear out |
| 281 | out.clear() |
| 282 | out = encode(seq2)! |
| 283 | assert out == [u8(0x30), 10, 2, 1, 5, 2, 5, 0x14, 0x1f, 0x49, 0xd5, 0x4a] |
| 284 | |
| 285 | seq.add_element(seq2)! |
| 286 | // clear out |
| 287 | out.clear() |
| 288 | out = encode(seq)! |
| 289 | assert out == [u8(0x30), 17, 5, 0, 1, 1, 0, u8(0x30), 10, 2, 1, 5, 2, 5, 0x14, 0x1f, 0x49, |
| 290 | 0xd5, 0x4a] |
| 291 | |
| 292 | back_seq := decode(out)! |
| 293 | assert back_seq.equal(seq) |
| 294 | |
| 295 | back := back_seq.into_object[Sequence]()! |
| 296 | assert back.fields().len == 3 |
| 297 | assert back.fields()[0] is Null |
| 298 | assert back.fields()[1] is Boolean |
| 299 | assert back.fields()[2] is Sequence |
| 300 | |
| 301 | two := back.fields()[2] |
| 302 | if two is Sequence { |
| 303 | assert two.fields()[0] is Integer |
| 304 | assert two.fields()[1] is Integer |
| 305 | assert two.fields()[1].payload()!.len == 5 |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | // Taken from https://letsencrypt.org/id/docs/a-warm-welcome-to-asn1-and-der/ |
| 310 | // |
| 311 | // As an example, RFC 5280 defines AlgorithmIdentifier as a SEQUENCE: |
| 312 | // |
| 313 | // AlgorithmIdentifier ::= SEQUENCE { |
| 314 | // algorithm OBJECT IDENTIFIER, |
| 315 | // parameters ANY DEFINED BY algorithm OPTIONAL |
| 316 | // } |
| 317 | // Here’s the encoding of the AlgorithmIdentifier containing 1.2.840.113549.1.1.11. |
| 318 | // RFC 8017 says “parameters” should have the type NULL for this algorithm. |
| 319 | // was serialized into: 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |
| 320 | struct AlgorithmIdentifier { |
| 321 | algorithm ObjectIdentifier |
| 322 | parameters AnyDefinedBy |
| 323 | } |
| 324 | |
| 325 | fn (a AlgorithmIdentifier) tag() Tag { |
| 326 | return default_sequence_tag |
| 327 | } |
| 328 | |
| 329 | fn (a AlgorithmIdentifier) payload() ![]u8 { |
| 330 | mut out := []u8{} |
| 331 | out << encode(a.algorithm)! |
| 332 | out << encode(a.parameters)! |
| 333 | |
| 334 | return out |
| 335 | } |
| 336 | |
| 337 | fn test_sequence_algorithm_identifier() ! { |
| 338 | expected := [u8(0x30), 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, |
| 339 | 0x05, 0x00] |
| 340 | algo := AlgorithmIdentifier{ |
| 341 | algorithm: ObjectIdentifier.new('1.2.840.113549.1.1.11')! |
| 342 | parameters: AnyDefinedBy.new(Null{}) |
| 343 | } |
| 344 | out := encode(algo)! |
| 345 | assert out == expected |
| 346 | |
| 347 | sback := decode(out)! |
| 348 | seq := sback as Sequence |
| 349 | s0 := seq.fields[0] as ObjectIdentifier |
| 350 | assert s0 == algo.algorithm |
| 351 | |
| 352 | s1 := seq.fields[1] as Null |
| 353 | prm := algo.parameters.params as Null |
| 354 | assert s1 == prm |
| 355 | } |
| 356 | |
| 357 | // Here is the encoding of a SEQUENCE OF INTEGER containing the numbers 7, 8, and 9: |
| 358 | // |
| 359 | // encoded into: 30 09 02 01 07 02 01 08 02 01 09 |
| 360 | fn test_sequence_of_integer() ! { |
| 361 | expected := [u8(0x30), 0x09, 0x02, 0x01, 0x07, 0x02, 0x01, 0x08, 0x02, 0x01, 0x09] |
| 362 | |
| 363 | mut els := []Integer{} |
| 364 | els << Integer.from_int(7) |
| 365 | els << Integer.from_int(8) |
| 366 | els << Integer.from_int(9) |
| 367 | |
| 368 | seqof := SequenceOf.from_list[Integer](els)! |
| 369 | out := encode(seqof)! |
| 370 | assert out == expected |
| 371 | } |
| 372 | |