Home | History | Annotate | Download | only in asn1
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package asn1
      6 
      7 import (
      8 	"bytes"
      9 	"encoding/hex"
     10 	"math/big"
     11 	"strings"
     12 	"testing"
     13 	"time"
     14 )
     15 
     16 type intStruct struct {
     17 	A int
     18 }
     19 
     20 type twoIntStruct struct {
     21 	A int
     22 	B int
     23 }
     24 
     25 type bigIntStruct struct {
     26 	A *big.Int
     27 }
     28 
     29 type nestedStruct struct {
     30 	A intStruct
     31 }
     32 
     33 type rawContentsStruct struct {
     34 	Raw RawContent
     35 	A   int
     36 }
     37 
     38 type implicitTagTest struct {
     39 	A int `asn1:"implicit,tag:5"`
     40 }
     41 
     42 type explicitTagTest struct {
     43 	A int `asn1:"explicit,tag:5"`
     44 }
     45 
     46 type flagTest struct {
     47 	A Flag `asn1:"tag:0,optional"`
     48 }
     49 
     50 type generalizedTimeTest struct {
     51 	A time.Time `asn1:"generalized"`
     52 }
     53 
     54 type ia5StringTest struct {
     55 	A string `asn1:"ia5"`
     56 }
     57 
     58 type printableStringTest struct {
     59 	A string `asn1:"printable"`
     60 }
     61 
     62 type optionalRawValueTest struct {
     63 	A RawValue `asn1:"optional"`
     64 }
     65 
     66 type omitEmptyTest struct {
     67 	A []string `asn1:"omitempty"`
     68 }
     69 
     70 type defaultTest struct {
     71 	A int `asn1:"optional,default:1"`
     72 }
     73 
     74 type testSET []int
     75 
     76 var PST = time.FixedZone("PST", -8*60*60)
     77 
     78 type marshalTest struct {
     79 	in  interface{}
     80 	out string // hex encoded
     81 }
     82 
     83 func farFuture() time.Time {
     84 	t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
     85 	if err != nil {
     86 		panic(err)
     87 	}
     88 	return t
     89 }
     90 
     91 var marshalTests = []marshalTest{
     92 	{10, "02010a"},
     93 	{127, "02017f"},
     94 	{128, "02020080"},
     95 	{-128, "020180"},
     96 	{-129, "0202ff7f"},
     97 	{intStruct{64}, "3003020140"},
     98 	{bigIntStruct{big.NewInt(0x123456)}, "30050203123456"},
     99 	{twoIntStruct{64, 65}, "3006020140020141"},
    100 	{nestedStruct{intStruct{127}}, "3005300302017f"},
    101 	{[]byte{1, 2, 3}, "0403010203"},
    102 	{implicitTagTest{64}, "3003850140"},
    103 	{explicitTagTest{64}, "3005a503020140"},
    104 	{flagTest{true}, "30028000"},
    105 	{flagTest{false}, "3000"},
    106 	{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
    107 	{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
    108 	{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
    109 	{farFuture(), "180f32313030303430353132303130315a"},
    110 	{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
    111 	{BitString{[]byte{0x80}, 1}, "03020780"},
    112 	{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
    113 	{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
    114 	{ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
    115 	{ObjectIdentifier([]int{2, 100, 3}), "0603813403"},
    116 	{"test", "130474657374"},
    117 	{
    118 		"" +
    119 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    120 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    121 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    122 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 127 times 'x'
    123 		"137f" +
    124 			"7878787878787878787878787878787878787878787878787878787878787878" +
    125 			"7878787878787878787878787878787878787878787878787878787878787878" +
    126 			"7878787878787878787878787878787878787878787878787878787878787878" +
    127 			"78787878787878787878787878787878787878787878787878787878787878",
    128 	},
    129 	{
    130 		"" +
    131 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    132 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    133 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
    134 			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 128 times 'x'
    135 		"138180" +
    136 			"7878787878787878787878787878787878787878787878787878787878787878" +
    137 			"7878787878787878787878787878787878787878787878787878787878787878" +
    138 			"7878787878787878787878787878787878787878787878787878787878787878" +
    139 			"7878787878787878787878787878787878787878787878787878787878787878",
    140 	},
    141 	{ia5StringTest{"test"}, "3006160474657374"},
    142 	{optionalRawValueTest{}, "3000"},
    143 	{printableStringTest{"test"}, "3006130474657374"},
    144 	{printableStringTest{"test*"}, "30071305746573742a"},
    145 	{rawContentsStruct{nil, 64}, "3003020140"},
    146 	{rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
    147 	{RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
    148 	{testSET([]int{10}), "310302010a"},
    149 	{omitEmptyTest{[]string{}}, "3000"},
    150 	{omitEmptyTest{[]string{"1"}}, "30053003130131"},
    151 	{"", "0c02cea3"},
    152 	{defaultTest{0}, "3003020100"},
    153 	{defaultTest{1}, "3000"},
    154 	{defaultTest{2}, "3003020102"},
    155 }
    156 
    157 func TestMarshal(t *testing.T) {
    158 	for i, test := range marshalTests {
    159 		data, err := Marshal(test.in)
    160 		if err != nil {
    161 			t.Errorf("#%d failed: %s", i, err)
    162 		}
    163 		out, _ := hex.DecodeString(test.out)
    164 		if !bytes.Equal(out, data) {
    165 			t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
    166 
    167 		}
    168 	}
    169 }
    170 
    171 type marshalErrTest struct {
    172 	in  interface{}
    173 	err string
    174 }
    175 
    176 var marshalErrTests = []marshalErrTest{
    177 	{bigIntStruct{nil}, "empty integer"},
    178 }
    179 
    180 func TestMarshalError(t *testing.T) {
    181 	for i, test := range marshalErrTests {
    182 		_, err := Marshal(test.in)
    183 		if err == nil {
    184 			t.Errorf("#%d should fail, but success", i)
    185 			continue
    186 		}
    187 
    188 		if !strings.Contains(err.Error(), test.err) {
    189 			t.Errorf("#%d got: %v want %v", i, err, test.err)
    190 		}
    191 	}
    192 }
    193 
    194 func TestInvalidUTF8(t *testing.T) {
    195 	_, err := Marshal(string([]byte{0xff, 0xff}))
    196 	if err == nil {
    197 		t.Errorf("invalid UTF8 string was accepted")
    198 	}
    199 }
    200 
    201 func BenchmarkMarshal(b *testing.B) {
    202 	b.ReportAllocs()
    203 
    204 	for i := 0; i < b.N; i++ {
    205 		for _, test := range marshalTests {
    206 			Marshal(test.in)
    207 		}
    208 	}
    209 }
    210