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