1 package x509
2
3 import (
4 "bytes"
5 "errors"
6 )
7
8 var encodeIndent = 0
9
10 type asn1Object interface {
11 EncodeTo(writer *bytes.Buffer) error
12 }
13
14 type asn1Structured struct {
15 tagBytes []byte
16 content []asn1Object
17 }
18
19 func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
20
21 encodeIndent++
22 inner := new(bytes.Buffer)
23 for _, obj := range s.content {
24 err := obj.EncodeTo(inner)
25 if err != nil {
26 return err
27 }
28 }
29 encodeIndent--
30 out.Write(s.tagBytes)
31 encodeLength(out, inner.Len())
32 out.Write(inner.Bytes())
33 return nil
34 }
35
36 type asn1Primitive struct {
37 tagBytes []byte
38 length int
39 content []byte
40 }
41
42 func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error {
43 _, err := out.Write(p.tagBytes)
44 if err != nil {
45 return err
46 }
47 if err = encodeLength(out, p.length); err != nil {
48 return err
49 }
50
51
52 out.Write(p.content)
53
54 return nil
55 }
56
57 func ber2der(ber []byte) ([]byte, error) {
58 if len(ber) == 0 {
59 return nil, errors.New("ber2der: input ber is empty")
60 }
61
62 out := new(bytes.Buffer)
63
64 obj, _, err := readObject(ber, 0)
65 if err != nil {
66 return nil, err
67 }
68 obj.EncodeTo(out)
69
70
71
72
73
74 return out.Bytes(), nil
75 }
76
77
78 func marshalLongLength(out *bytes.Buffer, i int) (err error) {
79 n := lengthLength(i)
80
81 for ; n > 0; n-- {
82 err = out.WriteByte(byte(i >> uint((n-1)*8)))
83 if err != nil {
84 return
85 }
86 }
87
88 return nil
89 }
90
91
92 func lengthLength(i int) (numBytes int) {
93 numBytes = 1
94 for i > 255 {
95 numBytes++
96 i >>= 8
97 }
98 return
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 func encodeLength(out *bytes.Buffer, length int) (err error) {
116 if length >= 128 {
117 l := lengthLength(length)
118 err = out.WriteByte(0x80 | byte(l))
119 if err != nil {
120 return
121 }
122 err = marshalLongLength(out, length)
123 if err != nil {
124 return
125 }
126 } else {
127 err = out.WriteByte(byte(length))
128 if err != nil {
129 return
130 }
131 }
132 return
133 }
134
135 func readObject(ber []byte, offset int) (asn1Object, int, error) {
136
137 tagStart := offset
138 b := ber[offset]
139 offset++
140 tag := b & 0x1F
141 if tag == 0x1F {
142 tag = 0
143 for ber[offset] >= 0x80 {
144 tag = tag*128 + ber[offset] - 0x80
145 offset++
146 }
147 tag = tag*128 + ber[offset] - 0x80
148 offset++
149 }
150 tagEnd := offset
151
152 kind := b & 0x20
153
160
161 var length int
162 l := ber[offset]
163 offset++
164 indefinite := false
165 if l > 0x80 {
166 numberOfBytes := (int)(l & 0x7F)
167 if numberOfBytes > 4 {
168 return nil, 0, errors.New("ber2der: BER tag length too long")
169 }
170 if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
171 return nil, 0, errors.New("ber2der: BER tag length is negative")
172 }
173 if 0x0 == (int)(ber[offset]) {
174 return nil, 0, errors.New("ber2der: BER tag length has leading zero")
175 }
176
177
178 for i := 0; i < numberOfBytes; i++ {
179 length = length*256 + (int)(ber[offset])
180 offset++
181 }
182 } else if l == 0x80 {
183 indefinite = true
184 } else {
185 length = (int)(l)
186 }
187
188
189 contentEnd := offset + length
190 if contentEnd > len(ber) {
191 return nil, 0, errors.New("ber2der: BER tag length is more than available data")
192 }
193
194
195
196 var obj asn1Object
197 if indefinite && kind == 0 {
198 return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
199 }
200 if kind == 0 {
201 obj = asn1Primitive{
202 tagBytes: ber[tagStart:tagEnd],
203 length: length,
204 content: ber[offset:contentEnd],
205 }
206 } else {
207 var subObjects []asn1Object
208 for (offset < contentEnd) || indefinite {
209 var subObj asn1Object
210 var err error
211 subObj, offset, err = readObject(ber, offset)
212 if err != nil {
213 return nil, 0, err
214 }
215 subObjects = append(subObjects, subObj)
216
217 if indefinite {
218 terminated, err := isIndefiniteTermination(ber, offset)
219 if err != nil {
220 return nil, 0, err
221 }
222
223 if terminated {
224 break
225 }
226 }
227 }
228 obj = asn1Structured{
229 tagBytes: ber[tagStart:tagEnd],
230 content: subObjects,
231 }
232 }
233
234
235 if indefinite {
236 contentEnd = offset + 2
237 }
238
239 return obj, contentEnd, nil
240 }
241
242 func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
243 if len(ber)-offset < 2 {
244 return false, errors.New("ber2der: Invalid BER format")
245 }
246
247 return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
248 }
249
View as plain text