github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/encoding/asn1/marshal.go (about)

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