1
2
3
4
5 package cryptobyte
6
7 import (
8 "bytes"
9 encoding_asn1 "encoding/asn1"
10 "math/big"
11 "reflect"
12 "testing"
13 "time"
14
15 "golang.org/x/crypto/cryptobyte/asn1"
16 )
17
18 type readASN1Test struct {
19 name string
20 in []byte
21 tag asn1.Tag
22 ok bool
23 out interface{}
24 }
25
26 var readASN1TestData = []readASN1Test{
27 {"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}},
28 {"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil},
29 {"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil},
30 {"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil},
31 {"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil},
32 {"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil},
33 {"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff , false, nil},
34 {"2**31 - 1 length", []byte{0x30, 0x84, 0x7f, 0xff, 0xff, 0xff}, 0x30, false, nil},
35 {"2**32 - 1 length", []byte{0x30, 0x84, 0xff, 0xff, 0xff, 0xff}, 0x30, false, nil},
36 {"2**63 - 1 length", []byte{0x30, 0x88, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0x30, false, nil},
37 {"2**64 - 1 length", []byte{0x30, 0x88, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0x30, false, nil},
38 }
39
40 func TestReadASN1(t *testing.T) {
41 for _, test := range readASN1TestData {
42 t.Run(test.name, func(t *testing.T) {
43 var in, out String = test.in, nil
44 ok := in.ReadASN1(&out, test.tag)
45 if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) {
46 t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
47 }
48 })
49 }
50 }
51
52 func TestReadASN1Optional(t *testing.T) {
53 var empty String
54 var present bool
55 ok := empty.ReadOptionalASN1(nil, &present, 0xa0)
56 if !ok || present {
57 t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present)
58 }
59
60 var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil
61 ok = in.ReadOptionalASN1(&out, &present, 0xa0)
62 if !ok || present {
63 t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present)
64 }
65 ok = in.ReadOptionalASN1(&out, &present, 0xa1)
66 wantBytes := []byte{4, 1, 1}
67 if !ok || !present || !bytes.Equal(out, wantBytes) {
68 t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes)
69 }
70 }
71
72 var optionalOctetStringTestData = []struct {
73 readASN1Test
74 present bool
75 }{
76 {readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false},
77 {readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true},
78 {readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false},
79 {readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true},
80 }
81
82 func TestReadASN1OptionalOctetString(t *testing.T) {
83 for _, test := range optionalOctetStringTestData {
84 t.Run(test.name, func(t *testing.T) {
85 in := String(test.in)
86 var out []byte
87 var present bool
88 ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag)
89 if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) {
90 t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out)
91 }
92 })
93 }
94 }
95
96 const defaultInt = -1
97
98 var optionalIntTestData = []readASN1Test{
99 {"empty", []byte{}, 0xa0, true, defaultInt},
100 {"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0},
101 {"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt},
102 {"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42},
103 }
104
105 func TestReadASN1OptionalInteger(t *testing.T) {
106 for _, test := range optionalIntTestData {
107 t.Run(test.name, func(t *testing.T) {
108 in := String(test.in)
109 var out int
110 ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt)
111 if ok != test.ok || ok && out != test.out.(int) {
112 t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
113 }
114 })
115 }
116 }
117
118 const defaultBool = false
119
120 var optionalBoolTestData = []readASN1Test{
121 {"empty", []byte{}, 0xa0, true, false},
122 {"invalid", []byte{0xa1, 0x3, 0x1, 0x2, 0x7f}, 0xa1, false, defaultBool},
123 {"missing", []byte{0xa1, 0x3, 0x1, 0x1, 0x7f}, 0xa0, true, defaultBool},
124 {"present", []byte{0xa1, 0x3, 0x1, 0x1, 0xff}, 0xa1, true, true},
125 }
126
127 func TestReadASN1OptionalBoolean(t *testing.T) {
128 for _, test := range optionalBoolTestData {
129 t.Run(test.name, func(t *testing.T) {
130 in := String(test.in)
131 var out bool
132 ok := in.ReadOptionalASN1Boolean(&out, test.tag, defaultBool)
133 if ok != test.ok || ok && out != test.out.(bool) {
134 t.Errorf("in.ReadOptionalASN1Boolean() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
135 }
136 })
137 }
138 }
139
140 func TestReadASN1IntegerSigned(t *testing.T) {
141 testData64 := []struct {
142 in []byte
143 out int64
144 }{
145 {[]byte{2, 3, 128, 0, 0}, -0x800000},
146 {[]byte{2, 2, 255, 0}, -256},
147 {[]byte{2, 2, 255, 127}, -129},
148 {[]byte{2, 1, 128}, -128},
149 {[]byte{2, 1, 255}, -1},
150 {[]byte{2, 1, 0}, 0},
151 {[]byte{2, 1, 1}, 1},
152 {[]byte{2, 1, 2}, 2},
153 {[]byte{2, 1, 127}, 127},
154 {[]byte{2, 2, 0, 128}, 128},
155 {[]byte{2, 2, 1, 0}, 256},
156 {[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
157 }
158 for i, test := range testData64 {
159 in := String(test.in)
160 var out int64
161 ok := in.ReadASN1Integer(&out)
162 if !ok || out != test.out {
163 t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
164 }
165 }
166
167
168 t.Run("big.Int", func(t *testing.T) {
169 for i, test := range testData64 {
170 in := String(test.in)
171 var out big.Int
172 ok := in.ReadASN1Integer(&out)
173 if !ok || out.Int64() != test.out {
174 t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out)
175 }
176 }
177 })
178
179
180 t.Run("bytes", func(t *testing.T) {
181 for i, test := range testData64 {
182 in := String(test.in)
183 var out []byte
184 ok := in.ReadASN1Integer(&out)
185 if test.out < 0 {
186 if ok {
187 t.Errorf("#%d: in.ReadASN1Integer(%d) = %v, want false", i, test.out, ok)
188 }
189 continue
190 }
191 if !ok {
192 t.Errorf("#%d: in.ReadASN1Integer() = %v, want true", i, ok)
193 continue
194 }
195 n := new(big.Int).SetBytes(out).Int64()
196 if n != test.out {
197 t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %x, want %d", i, ok, out, test.out)
198 }
199 if out[0] == 0 && len(out) > 1 {
200 t.Errorf("#%d: in.ReadASN1Integer() = %v; out = %x, has leading zeroes", i, ok, out)
201 }
202 }
203 })
204
205
206 t.Run("WithTag", func(t *testing.T) {
207 for i, test := range testData64 {
208 tag := asn1.Tag((i * 3) % 32).ContextSpecific()
209
210 testData := make([]byte, len(test.in))
211 copy(testData, test.in)
212
213
214 testData[0] = uint8(tag)
215
216 in := String(testData)
217 var out int64
218 ok := in.ReadASN1Int64WithTag(&out, tag)
219 if !ok || out != test.out {
220 t.Errorf("#%d: in.ReadASN1Int64WithTag() = %v, want true; out = %d, want %d", i, ok, out, test.out)
221 }
222
223 var b Builder
224 b.AddASN1Int64WithTag(test.out, tag)
225 result, err := b.Bytes()
226
227 if err != nil {
228 t.Errorf("#%d: AddASN1Int64WithTag failed: %s", i, err)
229 continue
230 }
231
232 if !bytes.Equal(result, testData) {
233 t.Errorf("#%d: AddASN1Int64WithTag: got %x, want %x", i, result, testData)
234 }
235 }
236 })
237 }
238
239 func TestReadASN1IntegerUnsigned(t *testing.T) {
240 testData := []struct {
241 in []byte
242 out uint64
243 }{
244 {[]byte{2, 1, 0}, 0},
245 {[]byte{2, 1, 1}, 1},
246 {[]byte{2, 1, 2}, 2},
247 {[]byte{2, 1, 127}, 127},
248 {[]byte{2, 2, 0, 128}, 128},
249 {[]byte{2, 2, 1, 0}, 256},
250 {[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
251 {[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff},
252 {[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000},
253 {[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff},
254 }
255 for i, test := range testData {
256 in := String(test.in)
257 var out uint64
258 ok := in.ReadASN1Integer(&out)
259 if !ok || out != test.out {
260 t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
261 }
262 }
263 }
264
265 func TestReadASN1IntegerInvalid(t *testing.T) {
266 testData := []String{
267 []byte{3, 1, 0},
268
269 []byte{2, 1},
270 []byte{2, 2, 0},
271
272 []byte{2, 2, 0, 1},
273 []byte{2, 2, 0xff, 0xff},
274 }
275
276 for i, test := range testData {
277 var out int64
278 if test.ReadASN1Integer(&out) {
279 t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out)
280 }
281 }
282 }
283
284 func TestASN1ObjectIdentifier(t *testing.T) {
285 testData := []struct {
286 in []byte
287 ok bool
288 out []int
289 }{
290 {[]byte{}, false, []int{}},
291 {[]byte{6, 0}, false, []int{}},
292 {[]byte{5, 1, 85}, false, []int{2, 5}},
293 {[]byte{6, 1, 85}, true, []int{2, 5}},
294 {[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}},
295 {[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
296 {[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}},
297 {[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
298 {[]byte{6, 7, 85, 0x02, 0x85, 0xc7, 0xcc, 0xfb, 0x01}, true, []int{2, 5, 2, 1492336001}},
299 {[]byte{6, 7, 0x55, 0x02, 0x87, 0xff, 0xff, 0xff, 0x7f}, true, []int{2, 5, 2, 2147483647}},
300 {[]byte{6, 7, 0x55, 0x02, 0x88, 0x80, 0x80, 0x80, 0x00}, false, []int{}},
301 {[]byte{6, 3, 85, 0x80, 0x02}, false, []int{}},
302 }
303
304 for i, test := range testData {
305 in := String(test.in)
306 var out encoding_asn1.ObjectIdentifier
307 ok := in.ReadASN1ObjectIdentifier(&out)
308 if ok != test.ok || ok && !out.Equal(test.out) {
309 t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
310 continue
311 }
312
313 var b Builder
314 b.AddASN1ObjectIdentifier(out)
315 result, err := b.Bytes()
316 if builderOk := err == nil; test.ok != builderOk {
317 t.Errorf("#%d: error from Builder.Bytes: %s", i, err)
318 continue
319 }
320 if test.ok && !bytes.Equal(result, test.in) {
321 t.Errorf("#%d: reserialisation didn't match, got %x, want %x", i, result, test.in)
322 continue
323 }
324 }
325 }
326
327 func TestReadASN1GeneralizedTime(t *testing.T) {
328 testData := []struct {
329 in string
330 ok bool
331 out time.Time
332 }{
333 {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
334 {"20100102030405", false, time.Time{}},
335 {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
336 {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
337
339 {"00000100000000Z", false, time.Time{}},
340 {"20101302030405Z", false, time.Time{}},
341 {"20100002030405Z", false, time.Time{}},
342 {"20100100030405Z", false, time.Time{}},
343 {"20100132030405Z", false, time.Time{}},
344 {"20100231030405Z", false, time.Time{}},
345 {"20100102240405Z", false, time.Time{}},
346 {"20100102036005Z", false, time.Time{}},
347 {"20100102030460Z", false, time.Time{}},
348 {"-20100102030410Z", false, time.Time{}},
349 {"2010-0102030410Z", false, time.Time{}},
350 {"2010-0002030410Z", false, time.Time{}},
351 {"201001-02030410Z", false, time.Time{}},
352 {"20100102-030410Z", false, time.Time{}},
353 {"2010010203-0410Z", false, time.Time{}},
354 {"201001020304-10Z", false, time.Time{}},
355 }
356 for i, test := range testData {
357 in := String(append([]byte{byte(asn1.GeneralizedTime), byte(len(test.in))}, test.in...))
358 var out time.Time
359 ok := in.ReadASN1GeneralizedTime(&out)
360 if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
361 t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
362 }
363 }
364 }
365
366 func TestReadASN1UTCTime(t *testing.T) {
367 testData := []struct {
368 in string
369 ok bool
370 out time.Time
371 }{
372 {"000102030405Z", true, time.Date(2000, 01, 02, 03, 04, 05, 0, time.UTC)},
373 {"500102030405Z", true, time.Date(1950, 01, 02, 03, 04, 05, 0, time.UTC)},
374 {"490102030405Z", true, time.Date(2049, 01, 02, 03, 04, 05, 0, time.UTC)},
375 {"990102030405Z", true, time.Date(1999, 01, 02, 03, 04, 05, 0, time.UTC)},
376 {"250102030405Z", true, time.Date(2025, 01, 02, 03, 04, 05, 0, time.UTC)},
377 {"750102030405Z", true, time.Date(1975, 01, 02, 03, 04, 05, 0, time.UTC)},
378 {"000102030405+0905", true, time.Date(2000, 01, 02, 03, 04, 05, 0, time.FixedZone("", 9*60*60+5*60))},
379 {"000102030405-0905", true, time.Date(2000, 01, 02, 03, 04, 05, 0, time.FixedZone("", -9*60*60-5*60))},
380 {"0001020304Z", true, time.Date(2000, 01, 02, 03, 04, 0, 0, time.UTC)},
381 {"5001020304Z", true, time.Date(1950, 01, 02, 03, 04, 00, 0, time.UTC)},
382 {"0001020304+0905", true, time.Date(2000, 01, 02, 03, 04, 0, 0, time.FixedZone("", 9*60*60+5*60))},
383 {"0001020304-0905", true, time.Date(2000, 01, 02, 03, 04, 0, 0, time.FixedZone("", -9*60*60-5*60))},
384 {"000102030405Z0700", false, time.Time{}},
385 {"000102030405", false, time.Time{}},
386 }
387 for i, test := range testData {
388 in := String(append([]byte{byte(asn1.UTCTime), byte(len(test.in))}, test.in...))
389 var out time.Time
390 ok := in.ReadASN1UTCTime(&out)
391 if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
392 t.Errorf("#%d: in.ReadASN1UTCTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
393 }
394 }
395 }
396
397 func TestReadASN1BitString(t *testing.T) {
398 testData := []struct {
399 in []byte
400 ok bool
401 out encoding_asn1.BitString
402 }{
403 {[]byte{}, false, encoding_asn1.BitString{}},
404 {[]byte{0x00}, true, encoding_asn1.BitString{}},
405 {[]byte{0x07, 0x00}, true, encoding_asn1.BitString{Bytes: []byte{0}, BitLength: 1}},
406 {[]byte{0x07, 0x01}, false, encoding_asn1.BitString{}},
407 {[]byte{0x07, 0x40}, false, encoding_asn1.BitString{}},
408 {[]byte{0x08, 0x00}, false, encoding_asn1.BitString{}},
409 {[]byte{0xff}, false, encoding_asn1.BitString{}},
410 {[]byte{0xfe, 0x00}, false, encoding_asn1.BitString{}},
411 }
412 for i, test := range testData {
413 in := String(append([]byte{3, byte(len(test.in))}, test.in...))
414 var out encoding_asn1.BitString
415 ok := in.ReadASN1BitString(&out)
416 if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) {
417 t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
418 }
419 }
420 }
421
422 func TestAddASN1BigInt(t *testing.T) {
423 x := big.NewInt(-1)
424 var b Builder
425 b.AddASN1BigInt(x)
426 got, err := b.Bytes()
427 if err != nil {
428 t.Fatalf("unexpected error adding -1: %v", err)
429 }
430 s := String(got)
431 var y big.Int
432 ok := s.ReadASN1Integer(&y)
433 if !ok || x.Cmp(&y) != 0 {
434 t.Errorf("unexpected bytes %v, want %v", &y, x)
435 }
436 }
437
438 func TestReadASN1Boolean(t *testing.T) {
439 testData := []struct {
440 in []byte
441 ok bool
442 out bool
443 }{
444 {[]byte{}, false, false},
445 {[]byte{0x01, 0x01, 0x00}, true, false},
446 {[]byte{0x01, 0x01, 0xff}, true, true},
447 {[]byte{0x01, 0x01, 0x01}, false, false},
448 }
449 for i, test := range testData {
450 in := String(test.in)
451 var out bool
452 ok := in.ReadASN1Boolean(&out)
453 if ok != test.ok || ok && (out != test.out) {
454 t.Errorf("#%d: in.ReadASN1Boolean() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
455 }
456 }
457 }
458
View as plain text