1
2
3
4
5 package asn1
6
7 import (
8 "big"
9 "bytes"
10 "fmt"
11 "io"
12 "os"
13 "reflect"
14 "time"
15 )
16
17
18
19
20
21
22 type forkableWriter struct {
23 *bytes.Buffer
24 pre, post *forkableWriter
25 }
26
27 func newForkableWriter() *forkableWriter {
28 return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
29 }
30
31 func (f *forkableWriter) fork() (pre, post *forkableWriter) {
32 if f.pre != nil || f.post != nil {
33 panic("have already forked")
34 }
35 f.pre = newForkableWriter()
36 f.post = newForkableWriter()
37 return f.pre, f.post
38 }
39
40 func (f *forkableWriter) Len() (l int) {
41 l += f.Buffer.Len()
42 if f.pre != nil {
43 l += f.pre.Len()
44 }
45 if f.post != nil {
46 l += f.post.Len()
47 }
48 return
49 }
50
51 func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
52 n, err = out.Write(f.Bytes())
53 if err != nil {
54 return
55 }
56
57 var nn int
58
59 if f.pre != nil {
60 nn, err = f.pre.writeTo(out)
61 n += nn
62 if err != nil {
63 return
64 }
65 }
66
67 if f.post != nil {
68 nn, err = f.post.writeTo(out)
69 n += nn
70 }
71 return
72 }
73
74 func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
75 if n == 0 {
76 err = out.WriteByte(0)
77 return
78 }
79
80 l := 0
81 for i := n; i > 0; i >>= 7 {
82 l++
83 }
84
85 for i := l - 1; i >= 0; i-- {
86 o := byte(n >> uint(i*7))
87 o &= 0x7f
88 if i != 0 {
89 o |= 0x80
90 }
91 err = out.WriteByte(o)
92 if err != nil {
93 return
94 }
95 }
96
97 return nil
98 }
99
100 func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
101 n := int64Length(i)
102
103 for ; n > 0; n-- {
104 err = out.WriteByte(byte(i >> uint((n-1)*8)))
105 if err != nil {
106 return
107 }
108 }
109
110 return nil
111 }
112
113 func int64Length(i int64) (numBytes int) {
114 numBytes = 1
115
116 for i > 127 {
117 numBytes++
118 i >>= 8
119 }
120
121 for i < -128 {
122 numBytes++
123 i >>= 8
124 }
125
126 return
127 }
128
129 func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) {
130 if n.Sign() < 0 {
131
132
133
134
135 nMinus1 := new(big.Int).Neg(n)
136 nMinus1.Sub(nMinus1, bigOne)
137 bytes := nMinus1.Bytes()
138 for i := range bytes {
139 bytes[i] ^= 0xff
140 }
141 if len(bytes) == 0 || bytes[0]&0x80 == 0 {
142 err = out.WriteByte(0xff)
143 if err != nil {
144 return
145 }
146 }
147 _, err = out.Write(bytes)
148 } else if n.Sign() == 0 {
149
150 err = out.WriteByte(0x00)
151 } else {
152 bytes := n.Bytes()
153 if len(bytes) > 0 && bytes[0]&0x80 != 0 {
154
155
156 err = out.WriteByte(0)
157 if err != nil {
158 return
159 }
160 }
161 _, err = out.Write(bytes)
162 }
163 return
164 }
165
166 func marshalLength(out *forkableWriter, i int) (err os.Error) {
167 n := lengthLength(i)
168
169 for ; n > 0; n-- {
170 err = out.WriteByte(byte(i >> uint((n-1)*8)))
171 if err != nil {
172 return
173 }
174 }
175
176 return nil
177 }
178
179 func lengthLength(i int) (numBytes int) {
180 numBytes = 1
181 for i > 255 {
182 numBytes++
183 i >>= 8
184 }
185 return
186 }
187
188 func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
189 b := uint8(t.class) << 6
190 if t.isCompound {
191 b |= 0x20
192 }
193 if t.tag >= 31 {
194 b |= 0x1f
195 err = out.WriteByte(b)
196 if err != nil {
197 return
198 }
199 err = marshalBase128Int(out, int64(t.tag))
200 if err != nil {
201 return
202 }
203 } else {
204 b |= uint8(t.tag)
205 err = out.WriteByte(b)
206 if err != nil {
207 return
208 }
209 }
210
211 if t.length >= 128 {
212 l := lengthLength(t.length)
213 err = out.WriteByte(0x80 | byte(l))
214 if err != nil {
215 return
216 }
217 err = marshalLength(out, t.length)
218 if err != nil {
219 return
220 }
221 } else {
222 err = out.WriteByte(byte(t.length))
223 if err != nil {
224 return
225 }
226 }
227
228 return nil
229 }
230
231 func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
232 paddingBits := byte((8 - b.BitLength%8) % 8)
233 err = out.WriteByte(paddingBits)
234 if err != nil {
235 return
236 }
237 _, err = out.Write(b.Bytes)
238 return
239 }
240
241 func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
242 if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
243 return StructuralError{"invalid object identifier"}
244 }
245
246 err = out.WriteByte(byte(oid[0]*40 + oid[1]))
247 if err != nil {
248 return
249 }
250 for i := 2; i < len(oid); i++ {
251 err = marshalBase128Int(out, int64(oid[i]))
252 if err != nil {
253 return
254 }
255 }
256
257 return
258 }
259
260 func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
261 b := []byte(s)
262 for _, c := range b {
263 if !isPrintable(c) {
264 return StructuralError{"PrintableString contains invalid character"}
265 }
266 }
267
268 _, err = out.Write(b)
269 return
270 }
271
272 func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
273 b := []byte(s)
274 for _, c := range b {
275 if c > 127 {
276 return StructuralError{"IA5String contains invalid character"}
277 }
278 }
279
280 _, err = out.Write(b)
281 return
282 }
283
284 func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
285 err = out.WriteByte(byte('0' + (v/10)%10))
286 if err != nil {
287 return
288 }
289 return out.WriteByte(byte('0' + v%10))
290 }
291
292 func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
293 switch {
294 case 1950 <= t.Year && t.Year < 2000:
295 err = marshalTwoDigits(out, int(t.Year-1900))
296 case 2000 <= t.Year && t.Year < 2050:
297 err = marshalTwoDigits(out, int(t.Year-2000))
298 default:
299 return StructuralError{"Cannot represent time as UTCTime"}
300 }
301
302 if err != nil {
303 return
304 }
305
306 err = marshalTwoDigits(out, t.Month)
307 if err != nil {
308 return
309 }
310
311 err = marshalTwoDigits(out, t.Day)
312 if err != nil {
313 return
314 }
315
316 err = marshalTwoDigits(out, t.Hour)
317 if err != nil {
318 return
319 }
320
321 err = marshalTwoDigits(out, t.Minute)
322 if err != nil {
323 return
324 }
325
326 err = marshalTwoDigits(out, t.Second)
327 if err != nil {
328 return
329 }
330
331 switch {
332 case t.ZoneOffset/60 == 0:
333 err = out.WriteByte('Z')
334 return
335 case t.ZoneOffset > 0:
336 err = out.WriteByte('+')
337 case t.ZoneOffset < 0:
338 err = out.WriteByte('-')
339 }
340
341 if err != nil {
342 return
343 }
344
345 offsetMinutes := t.ZoneOffset / 60
346 if offsetMinutes < 0 {
347 offsetMinutes = -offsetMinutes
348 }
349
350 err = marshalTwoDigits(out, offsetMinutes/60)
351 if err != nil {
352 return
353 }
354
355 err = marshalTwoDigits(out, offsetMinutes%60)
356 return
357 }
358
359 func stripTagAndLength(in []byte) []byte {
360 _, offset, err := parseTagAndLength(in, 0)
361 if err != nil {
362 return in
363 }
364 return in[offset:]
365 }
366
367 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
368 switch value.Type() {
369 case timeType:
370 return marshalUTCTime(out, value.Interface().(*time.Time))
371 case bitStringType:
372 return marshalBitString(out, value.Interface().(BitString))
373 case objectIdentifierType:
374 return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
375 case bigIntType:
376 return marshalBigInt(out, value.Interface().(*big.Int))
377 }
378
379 switch v := value; v.Kind() {
380 case reflect.Bool:
381 if v.Bool() {
382 return out.WriteByte(255)
383 } else {
384 return out.WriteByte(0)
385 }
386 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
387 return marshalInt64(out, int64(v.Int()))
388 case reflect.Struct:
389 t := v.Type()
390
391 startingField := 0
392
393
394
395 if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
396 s := v.Field(0)
397 if s.Len() > 0 {
398 bytes := make([]byte, s.Len())
399 for i := 0; i < s.Len(); i++ {
400 bytes[i] = uint8(s.Index(i).Uint())
401 }
402 403 404 405
406 _, err = out.Write(stripTagAndLength(bytes))
407 return
408 } else {
409 startingField = 1
410 }
411 }
412
413 for i := startingField; i < t.NumField(); i++ {
414 var pre *forkableWriter
415 pre, out = out.fork()
416 err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
417 if err != nil {
418 return
419 }
420 }
421 return
422 case reflect.Slice:
423 sliceType := v.Type()
424 if sliceType.Elem().Kind() == reflect.Uint8 {
425 bytes := make([]byte, v.Len())
426 for i := 0; i < v.Len(); i++ {
427 bytes[i] = uint8(v.Index(i).Uint())
428 }
429 _, err = out.Write(bytes)
430 return
431 }
432
433 var params fieldParameters
434 for i := 0; i < v.Len(); i++ {
435 var pre *forkableWriter
436 pre, out = out.fork()
437 err = marshalField(pre, v.Index(i), params)
438 if err != nil {
439 return
440 }
441 }
442 return
443 case reflect.String:
444 if params.stringType == tagIA5String {
445 return marshalIA5String(out, v.String())
446 } else {
447 return marshalPrintableString(out, v.String())
448 }
449 return
450 }
451
452 return StructuralError{"unknown Go type"}
453 }
454
455 func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
456
457 if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
458 return marshalField(out, v.Elem(), params)
459 }
460
461 if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
462 return
463 }
464
465 if v.Type() == rawValueType {
466 rv := v.Interface().(RawValue)
467 err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
468 if err != nil {
469 return
470 }
471 _, err = out.Write(rv.Bytes)
472 return
473 }
474
475 tag, isCompound, ok := getUniversalType(v.Type())
476 if !ok {
477 err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
478 return
479 }
480 class := classUniversal
481
482 if params.stringType != 0 {
483 if tag != tagPrintableString {
484 return StructuralError{"Explicit string type given to non-string member"}
485 }
486 tag = params.stringType
487 }
488
489 if params.set {
490 if tag != tagSequence {
491 return StructuralError{"Non sequence tagged as set"}
492 }
493 tag = tagSet
494 }
495
496 tags, body := out.fork()
497
498 err = marshalBody(body, v, params)
499 if err != nil {
500 return
501 }
502
503 bodyLen := body.Len()
504
505 var explicitTag *forkableWriter
506 if params.explicit {
507 explicitTag, tags = tags.fork()
508 }
509
510 if !params.explicit && params.tag != nil {
511
512 tag = *params.tag
513 class = classContextSpecific
514 }
515
516 err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
517 if err != nil {
518 return
519 }
520
521 if params.explicit {
522 err = marshalTagAndLength(explicitTag, tagAndLength{
523 class: classContextSpecific,
524 tag: *params.tag,
525 length: bodyLen + tags.Len(),
526 isCompound: true,
527 })
528 }
529
530 return nil
531 }
532
533
534 func Marshal(val interface{}) ([]byte, os.Error) {
535 var out bytes.Buffer
536 v := reflect.ValueOf(val)
537 f := newForkableWriter()
538 err := marshalField(f, v, fieldParameters{})
539 if err != nil {
540 return nil, err
541 }
542 _, err = f.writeTo(&out)
543 return out.Bytes(), nil
544 }