src/pkg/encoding/asn1/marshal.go - The Go Programming Language

Golang

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	}