1 package ber
2
3 import (
4 "bytes"
5 "io"
6 "math"
7 "testing"
8 )
9
10 func TestReadIdentifier(t *testing.T) {
11 testCases := map[string]struct {
12 Data []byte
13
14 ExpectedIdentifier Identifier
15 ExpectedBytesRead int
16 ExpectedError string
17 }{
18 "empty": {
19 Data: []byte{},
20 ExpectedBytesRead: 0,
21 ExpectedError: io.EOF.Error(),
22 },
23
24 "universal primitive eoc": {
25 Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
26 ExpectedIdentifier: Identifier{
27 ClassType: ClassUniversal,
28 TagType: TypePrimitive,
29 Tag: TagEOC,
30 },
31 ExpectedBytesRead: 1,
32 },
33 "universal primitive character string": {
34 Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
35 ExpectedIdentifier: Identifier{
36 ClassType: ClassUniversal,
37 TagType: TypePrimitive,
38 Tag: TagCharacterString,
39 },
40 ExpectedBytesRead: 1,
41 },
42
43 "universal constructed bit string": {
44 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
45 ExpectedIdentifier: Identifier{
46 ClassType: ClassUniversal,
47 TagType: TypeConstructed,
48 Tag: TagBitString,
49 },
50 ExpectedBytesRead: 1,
51 },
52 "universal constructed character string": {
53 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
54 ExpectedIdentifier: Identifier{
55 ClassType: ClassUniversal,
56 TagType: TypeConstructed,
57 Tag: TagCharacterString,
58 },
59 ExpectedBytesRead: 1,
60 },
61
62 "application constructed object descriptor": {
63 Data: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
64 ExpectedIdentifier: Identifier{
65 ClassType: ClassApplication,
66 TagType: TypeConstructed,
67 Tag: TagObjectDescriptor,
68 },
69 ExpectedBytesRead: 1,
70 },
71 "context constructed object descriptor": {
72 Data: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
73 ExpectedIdentifier: Identifier{
74 ClassType: ClassContext,
75 TagType: TypeConstructed,
76 Tag: TagObjectDescriptor,
77 },
78 ExpectedBytesRead: 1,
79 },
80 "private constructed object descriptor": {
81 Data: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
82 ExpectedIdentifier: Identifier{
83 ClassType: ClassPrivate,
84 TagType: TypeConstructed,
85 Tag: TagObjectDescriptor,
86 },
87 ExpectedBytesRead: 1,
88 },
89
90 "high-tag-number tag missing bytes": {
91 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag)},
92 ExpectedError: io.ErrUnexpectedEOF.Error(),
93 ExpectedBytesRead: 1,
94 },
95 "high-tag-number tag invalid first byte": {
96 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), 0x0},
97 ExpectedError: "invalid first high-tag-number tag byte",
98 ExpectedBytesRead: 2,
99 },
100 "high-tag-number tag invalid first byte with continue bit": {
101 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask)},
102 ExpectedError: "invalid first high-tag-number tag byte",
103 ExpectedBytesRead: 2,
104 },
105 "high-tag-number tag continuation missing bytes": {
106 Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x1)},
107 ExpectedError: io.ErrUnexpectedEOF.Error(),
108 ExpectedBytesRead: 2,
109 },
110 "high-tag-number tag overflow": {
111 Data: []byte{
112 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
113 byte(HighTagContinueBitmask | 0x1),
114 byte(HighTagContinueBitmask | 0x1),
115 byte(HighTagContinueBitmask | 0x1),
116 byte(HighTagContinueBitmask | 0x1),
117 byte(HighTagContinueBitmask | 0x1),
118 byte(HighTagContinueBitmask | 0x1),
119 byte(HighTagContinueBitmask | 0x1),
120 byte(HighTagContinueBitmask | 0x1),
121 byte(HighTagContinueBitmask | 0x1),
122 byte(0x1),
123 },
124 ExpectedError: "high-tag-number tag overflow",
125 ExpectedBytesRead: 11,
126 },
127 "max high-tag-number tag": {
128 Data: []byte{
129 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
130 byte(HighTagContinueBitmask | 0x7f),
131 byte(HighTagContinueBitmask | 0x7f),
132 byte(HighTagContinueBitmask | 0x7f),
133 byte(HighTagContinueBitmask | 0x7f),
134 byte(HighTagContinueBitmask | 0x7f),
135 byte(HighTagContinueBitmask | 0x7f),
136 byte(HighTagContinueBitmask | 0x7f),
137 byte(HighTagContinueBitmask | 0x7f),
138 byte(0x7f),
139 },
140 ExpectedIdentifier: Identifier{
141 ClassType: ClassUniversal,
142 TagType: TypeConstructed,
143 Tag: Tag(0x7FFFFFFFFFFFFFFF),
144 },
145 ExpectedBytesRead: 10,
146 },
147 "high-tag-number encoding of low-tag value": {
148 Data: []byte{
149 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
150 byte(TagObjectDescriptor),
151 },
152 ExpectedIdentifier: Identifier{
153 ClassType: ClassUniversal,
154 TagType: TypeConstructed,
155 Tag: TagObjectDescriptor,
156 },
157 ExpectedBytesRead: 2,
158 },
159 "max high-tag-number tag ignores extra data": {
160 Data: []byte{
161 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
162 byte(HighTagContinueBitmask | 0x7f),
163 byte(HighTagContinueBitmask | 0x7f),
164 byte(HighTagContinueBitmask | 0x7f),
165 byte(HighTagContinueBitmask | 0x7f),
166 byte(HighTagContinueBitmask | 0x7f),
167 byte(HighTagContinueBitmask | 0x7f),
168 byte(HighTagContinueBitmask | 0x7f),
169 byte(HighTagContinueBitmask | 0x7f),
170 byte(0x7f),
171 byte(0x01),
172 byte(0x02),
173 byte(0x03),
174 },
175 ExpectedIdentifier: Identifier{
176 ClassType: ClassUniversal,
177 TagType: TypeConstructed,
178 Tag: Tag(0x7FFFFFFFFFFFFFFF),
179 },
180 ExpectedBytesRead: 10,
181 },
182 }
183
184 for k, tc := range testCases {
185 reader := bytes.NewBuffer(tc.Data)
186 identifier, read, err := readIdentifier(reader)
187
188 if err != nil {
189 if tc.ExpectedError == "" {
190 t.Errorf("%s: unexpected error: %v", k, err)
191 } else if err.Error() != tc.ExpectedError {
192 t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
193 }
194 } else if tc.ExpectedError != "" {
195 t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
196 continue
197 }
198
199 if read != tc.ExpectedBytesRead {
200 t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
201 }
202
203 if identifier.ClassType != tc.ExpectedIdentifier.ClassType {
204 t.Errorf("%s: expected class type %d (%s), got %d (%s)", k,
205 tc.ExpectedIdentifier.ClassType,
206 ClassMap[tc.ExpectedIdentifier.ClassType],
207 identifier.ClassType,
208 ClassMap[identifier.ClassType],
209 )
210 }
211 if identifier.TagType != tc.ExpectedIdentifier.TagType {
212 t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k,
213 tc.ExpectedIdentifier.TagType,
214 TypeMap[tc.ExpectedIdentifier.TagType],
215 identifier.TagType,
216 TypeMap[identifier.TagType],
217 )
218 }
219 if identifier.Tag != tc.ExpectedIdentifier.Tag {
220 t.Errorf("%s: expected tag %d (%s), got %d (%s)", k,
221 tc.ExpectedIdentifier.Tag,
222 tagMap[tc.ExpectedIdentifier.Tag],
223 identifier.Tag,
224 tagMap[identifier.Tag],
225 )
226 }
227 }
228 }
229
230 func TestEncodeIdentifier(t *testing.T) {
231 testCases := map[string]struct {
232 Identifier Identifier
233 ExpectedBytes []byte
234 }{
235 "universal primitive eoc": {
236 Identifier: Identifier{
237 ClassType: ClassUniversal,
238 TagType: TypePrimitive,
239 Tag: TagEOC,
240 },
241 ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
242 },
243 "universal primitive character string": {
244 Identifier: Identifier{
245 ClassType: ClassUniversal,
246 TagType: TypePrimitive,
247 Tag: TagCharacterString,
248 },
249 ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
250 },
251
252 "universal constructed bit string": {
253 Identifier: Identifier{
254 ClassType: ClassUniversal,
255 TagType: TypeConstructed,
256 Tag: TagBitString,
257 },
258 ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
259 },
260 "universal constructed character string": {
261 Identifier: Identifier{
262 ClassType: ClassUniversal,
263 TagType: TypeConstructed,
264 Tag: TagCharacterString,
265 },
266 ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
267 },
268
269 "application constructed object descriptor": {
270 Identifier: Identifier{
271 ClassType: ClassApplication,
272 TagType: TypeConstructed,
273 Tag: TagObjectDescriptor,
274 },
275 ExpectedBytes: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
276 },
277 "context constructed object descriptor": {
278 Identifier: Identifier{
279 ClassType: ClassContext,
280 TagType: TypeConstructed,
281 Tag: TagObjectDescriptor,
282 },
283 ExpectedBytes: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
284 },
285 "private constructed object descriptor": {
286 Identifier: Identifier{
287 ClassType: ClassPrivate,
288 TagType: TypeConstructed,
289 Tag: TagObjectDescriptor,
290 },
291 ExpectedBytes: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
292 },
293
294 "max low-tag-number tag": {
295 Identifier: Identifier{
296 ClassType: ClassUniversal,
297 TagType: TypeConstructed,
298 Tag: TagBMPString,
299 },
300 ExpectedBytes: []byte{
301 byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBMPString),
302 },
303 },
304
305 "min high-tag-number tag": {
306 Identifier: Identifier{
307 ClassType: ClassUniversal,
308 TagType: TypeConstructed,
309 Tag: TagBMPString + 1,
310 },
311 ExpectedBytes: []byte{
312 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
313 byte(TagBMPString + 1),
314 },
315 },
316
317 "max high-tag-number tag": {
318 Identifier: Identifier{
319 ClassType: ClassUniversal,
320 TagType: TypeConstructed,
321 Tag: Tag(math.MaxInt64),
322 },
323 ExpectedBytes: []byte{
324 byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
325 byte(HighTagContinueBitmask | 0x7f),
326 byte(HighTagContinueBitmask | 0x7f),
327 byte(HighTagContinueBitmask | 0x7f),
328 byte(HighTagContinueBitmask | 0x7f),
329 byte(HighTagContinueBitmask | 0x7f),
330 byte(HighTagContinueBitmask | 0x7f),
331 byte(HighTagContinueBitmask | 0x7f),
332 byte(HighTagContinueBitmask | 0x7f),
333 byte(0x7f),
334 },
335 },
336 }
337
338 for k, tc := range testCases {
339 b := encodeIdentifier(tc.Identifier)
340 if !bytes.Equal(tc.ExpectedBytes, b) {
341 t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b)
342 }
343 }
344 }
345
346 func TestEncodeHighTag(t *testing.T) {
347 cases := []struct {
348 tag Tag
349 want []byte
350 }{
351 {134, []byte{0x80 + 0x01, 0x06}},
352 {123456, []byte{0x80 + 0x07, 0x80 + 0x44, 0x40}},
353 {0xFF, []byte{0x81, 0x7F}},
354 }
355
356 for _, c := range cases {
357 got := encodeHighTag(c.tag)
358
359 if !bytes.Equal(c.want, got) {
360 t.Errorf("tag: %d want: %#v got: %#v", c.tag, c.want, got)
361 }
362 }
363 }
364
View as plain text