v2 / vlib / x / encoding / asn1 / oid.v
206 lines · 181 sloc · 4.98 KB · 58fc4dead559901cad648fb695f31d0f6de9945a
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// TODO: doing check for limiting oid array length.
7const max_oid_length = 128
8
9// default_oid_tag is the default tag of ASN.1 OBJECTIDENTIFIER type.
10pub const default_oid_tag = Tag{.universal, false, int(TagType.oid)}
11
12// ASN.1 ObjectIdentifier type.
13//
14// The ASN. 1 OBJECT IDENTIFIER type is used when you need to provide a unique identifier.
15pub struct ObjectIdentifier {
16mut:
17 value []int
18}
19
20// value returns underlying ObjectIdentifier values as arrays of int.
21pub fn (o ObjectIdentifier) value() []int {
22 return o.value
23}
24
25// tag returns the tag of ObjectIdentifier type.
26pub fn (oid ObjectIdentifier) tag() Tag {
27 return default_oid_tag
28}
29
30// payload the payload of ObjectIdentifier type.
31pub fn (oid ObjectIdentifier) payload() ![]u8 {
32 return oid.pack_into_bytes()!
33}
34
35// new creates a new ObjectIdentifier type from dots (`.`) separated string.
36pub fn ObjectIdentifier.new(s string) !ObjectIdentifier {
37 if s.len < 2 {
38 return error('ObjectIdentifier: bad string oid length')
39 }
40 mut result := []int{}
41 src := s.split('.')
42 for n in src {
43 v := n.parse_int(10, 32)!
44 result << int(v)
45 }
46 oid := ObjectIdentifier{
47 value: result
48 }
49 if !oid.validate() {
50 return error('ObjectIdentifier: bad oid string')
51 }
52 return oid
53}
54
55// from_ints creates a new ObjectIdentifier type from arrays of int.
56pub fn ObjectIdentifier.from_ints(src []int) !ObjectIdentifier {
57 // allowed value of first int was 0, 1 or 2,
58 // and when first=2, second int was not limited.
59 // contrary, when first < 2, second <= 39
60 if src.len < 2 || src[0] > 2 || (src[0] < 2 && src[1] >= 40) {
61 return error('ObjectIdentifier: bad oid int array')
62 }
63 // doing check for overflow
64 for k in src {
65 if k > max_i32 {
66 return error('ObjectIdentifier: overflow parse_int result')
67 }
68 }
69 oid := ObjectIdentifier{
70 value: src
71 }
72 if !oid.validate() {
73 return error('ObjectIdentifier: bad oid int array')
74 }
75 return oid
76}
77
78fn ObjectIdentifier.from_bytes(src []u8) !ObjectIdentifier {
79 // maybe two integer fits in 1 bytes
80 if src.len == 0 {
81 return error('ObjectIdentifier: bad string oid length')
82 }
83 mut s := []int{len: src.len + 1}
84
85 mut val, mut pos := decode_base128_int(src, 0)!
86
87 if val < 80 {
88 s[0] = val / 40
89 s[1] = val % 40
90 } else {
91 s[0] = 2
92 s[1] = val - 80
93 }
94 mut i := 2
95 for ; pos < src.len; i++ {
96 val, pos = decode_base128_int(src, pos)!
97 s[i] = val
98 }
99 s = unsafe { s[0..i] }
100
101 oid := ObjectIdentifier{
102 value: s
103 }
104 if !oid.validate() {
105 return error('ObjectIdentifier: failed to validate')
106 }
107 return oid
108}
109
110fn (oid ObjectIdentifier) pack_into_bytes() ![]u8 {
111 if !oid.validate() {
112 return error('ObjectIdentifier: failed to validate')
113 }
114 mut dst := []u8{}
115 // the first two components (a.b) of ObjectIdentifier are encoded as 40*a+b
116 encode_base128_int(mut dst, i64(oid.value[0] * 40 + oid.value[1]))
117 for i := 2; i < oid.value.len; i++ {
118 encode_base128_int(mut dst, i64(oid.value[i]))
119 }
120 return dst
121}
122
123fn ObjectIdentifier.parse(mut p Parser) !ObjectIdentifier {
124 tag := p.read_tag()!
125 if !tag.equal(default_oid_tag) {
126 return error('Bad ObjectIdentifier tag')
127 }
128 length := p.read_length()!
129 bytes := p.read_bytes(length)!
130
131 res := ObjectIdentifier.from_bytes(bytes)!
132
133 return res
134}
135
136fn ObjectIdentifier.decode(src []u8) !(ObjectIdentifier, int) {
137 return ObjectIdentifier.decode_with_rule(src, .der)!
138}
139
140fn ObjectIdentifier.decode_with_rule(bytes []u8, rule EncodingRule) !(ObjectIdentifier, int) {
141 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
142 if !tag.equal(default_oid_tag) {
143 return error('Unexpected non-oid tag')
144 }
145 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
146 content := if length == 0 {
147 []u8{}
148 } else {
149 if content_pos >= bytes.len || content_pos + length > bytes.len {
150 return error('ObjectIdentifier: truncated payload bytes')
151 }
152 unsafe { bytes[content_pos..content_pos + length] }
153 }
154
155 oid := ObjectIdentifier.from_bytes(content)!
156 next := content_pos + length
157
158 return oid, next
159}
160
161// equal checks whether two ObjectIdentifier was equal.
162pub fn (oid ObjectIdentifier) equal(oth ObjectIdentifier) bool {
163 if !oid.tag().equal(oth.tag()) {
164 return false
165 }
166 if oid.value.len != oth.value.len {
167 return false
168 }
169 for i := 0; i < oid.value.len; i++ {
170 if oid.value[i] != oth.value[i] {
171 return false
172 }
173 }
174 return true
175}
176
177fn (oid ObjectIdentifier) str() string {
178 if oid.value.len == 0 {
179 return 'OID <nil>'
180 }
181 mut s := []string{}
182 for i in oid.value {
183 s << i.str()
184 }
185 res := s.join('.')
186
187 return '${res}'
188}
189
190fn (oid ObjectIdentifier) validate() bool {
191 if oid.value.len > max_oid_length {
192 return false
193 }
194 if oid.value.len < 2 || oid.value[0] > 2 || (oid.value[0] < 2 && oid.value[1] >= 40) {
195 return false
196 }
197 return true
198}
199
200fn (oid ObjectIdentifier) oid_length() int {
201 mut n := base128_int_length(i64(oid.value[0] * 40 + oid.value[1]))
202 for i := 2; i < oid.value.len; i++ {
203 n += base128_int_length(i64(oid.value[i]))
204 }
205 return n
206}
207