v2 / vlib / x / encoding / asn1 / common.v
153 lines · 142 sloc · 3.91 KB · 2f53e2d219cb0baac31887523366750bfd3c1942
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// common parsing routines
7//
8fn parse_element(tag Tag, content []u8) !Element {
9 match tag.class {
10 .universal {
11 return parse_universal(tag, content)!
12 }
13 .context_specific {
14 return parse_context_specific(tag, content)!
15 }
16 .application {
17 return parse_application(tag, content)!
18 }
19 .private {
20 return parse_private(tag, content)!
21 }
22 }
23}
24
25fn parse_universal(tag Tag, content []u8) !Element {
26 if tag.class != .universal {
27 return error('Non universal class')
28 }
29 if tag.constructed {
30 return parse_universal_constructed(tag, content)!
31 }
32 return parse_universal_primitive(tag, content)!
33}
34
35fn parse_universal_primitive(tag Tag, content []u8) !Element {
36 if tag.constructed {
37 return error('parse on constructed type')
38 }
39 match tag.tag_number() {
40 int(TagType.boolean) {
41 return Boolean.from_bytes(content)!
42 }
43 int(TagType.null) {
44 return Null.from_bytes(content)!
45 }
46 int(TagType.oid) {
47 return ObjectIdentifier.from_bytes(content)!
48 }
49 int(TagType.integer) {
50 return Integer.from_bytes(content)!
51 }
52 int(TagType.enumerated) {
53 return Enumerated.from_bytes(content)!
54 }
55 int(TagType.bitstring) {
56 return BitString.from_bytes(content)!
57 }
58 int(TagType.ia5string) {
59 return IA5String.from_bytes(content)!
60 }
61 int(TagType.utf8string) {
62 return Utf8String.from_bytes(content)!
63 }
64 int(TagType.numericstring) {
65 return NumericString.from_bytes(content)!
66 }
67 int(TagType.printablestring) {
68 return PrintableString.from_bytes(content)!
69 }
70 int(TagType.generalstring) {
71 return GeneralString.from_bytes(content)!
72 }
73 int(TagType.octetstring) {
74 return OctetString.from_bytes(content)!
75 }
76 int(TagType.visiblestring) {
77 return VisibleString.from_bytes(content)!
78 }
79 int(TagType.utctime) {
80 return UtcTime.from_bytes(content)!
81 }
82 int(TagType.generalizedtime) {
83 return GeneralizedTime.from_bytes(content)!
84 }
85 else {
86 // return the raw element
87 return RawElement.new(tag, content)!
88 }
89 }
90}
91
92fn parse_universal_constructed(tag Tag, content []u8) !Element {
93 if !tag.constructed {
94 return error('parse on non-constructed type')
95 }
96 match tag.tag_number() {
97 int(TagType.sequence) {
98 // todo: handle SequenceOf
99 return Sequence.from_bytes(content)!
100 }
101 int(TagType.set) {
102 return Set.from_bytes(content)!
103 }
104 else {
105 return RawElement.new(tag, content)!
106 }
107 }
108}
109
110fn parse_private(tag Tag, content []u8) !PrivateELement {
111 return PrivateELement.new(tag, content)!
112}
113
114fn parse_application(tag Tag, content []u8) !ApplicationElement {
115 return ApplicationElement.new(tag, content)!
116}
117
118// parse_context_specific_with_mode parses tag and content as ContextElement when mode is availables
119fn parse_context_specific_with_mode(tag Tag, content []u8, inner_tag Tag, mode TaggedMode) !ContextElement {
120 if tag.tag_class() != .context_specific {
121 return error('parse on non-context-specific class')
122 }
123 if mode == .implicit {
124 inner := parse_element(inner_tag, content)!
125 ctx := ContextElement.from_element(inner, tag.number, mode)!
126 return ctx
127 }
128 // explicit
129 // read an inner tag from content
130 mut p := Parser.new(content)
131 intag := p.peek_tag()!
132 if !intag.equal(inner_tag) {
133 return error('Get unexpected inner tag')
134 }
135 inner_el := p.read_tlv()!
136 // should finish
137 p.finish()!
138
139 ctx := ContextElement.from_element(inner_el, tag.number, .explicit)!
140
141 return ctx
142}
143
144// parse_context_specific parses tag and content as ContextElement.
145// The info of fields of ContextElement, ie, inner_tag and mode, is not availables here
146// You should provides this later with the correct value.
147fn parse_context_specific(tag Tag, content []u8) !ContextElement {
148 // mode and inner_tag is not set here without additional information,
149 // So its still none here, and you should set it with correct value
150 ctx := ContextElement.new(tag, content)!
151
152 return ctx
153}
154