The Go Programming Language

Source file src/pkg/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		"big"
     9		"bytes"
    10		"fmt"
    11		"io"
    12		"os"
    13		"reflect"
    14		"time"
    15	)
    16	
    17	// A forkableWriter is an in-memory buffer that can be
    18	// 'forked' to create new forkableWriters that bracket the
    19	// original.  After
    20	//    pre, post := w.fork();
    21	// the overall sequence of bytes represented is logically w+pre+post.
    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			// A negative number has to be converted to two's-complement
   132			// form. So we'll subtract 1 and invert. If the
   133			// most-significant-bit isn't set then we'll need to pad the
   134			// beginning with 0xff in order to keep the number negative.
   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			// Zero is written as a single 0 zero rather than no bytes.
   150			err = out.WriteByte(0x00)
   151		} else {
   152			bytes := n.Bytes()
   153			if len(bytes) > 0 && bytes[0]&0x80 != 0 {
   154				// We'll have to pad this with 0x00 in order to stop it
   155				// looking like a negative number.
   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			// If the first element of the structure is a non-empty
   394			// RawContents, then we don't bother serializing the rest.
   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					/* The RawContents will contain the tag and
   403					 * length fields but we'll also be writing
   404					 * those ourselves, so we strip them out of
   405					 * bytes */
   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		// If the field is an interface{} then recurse into it.
   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			// implicit tag.
   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	// Marshal returns the ASN.1 encoding of val.
   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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.