Black Lives Matter. Support the Equal Justice Initiative.

Source file src/encoding/asn1/marshal.go

Documentation: encoding/asn1

     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  	"math/big"
    12  	"reflect"
    13  	"sort"
    14  	"time"
    15  	"unicode/utf8"
    16  )
    17  
    18  var (
    19  	byte00Encoder encoder = byteEncoder(0x00)
    20  	byteFFEncoder encoder = byteEncoder(0xff)
    21  )
    22  
    23  // encoder represents an ASN.1 element that is waiting to be marshaled.
    24  type encoder interface {
    25  	// Len returns the number of bytes needed to marshal this element.
    26  	Len() int
    27  	// Encode encodes this element by writing Len() bytes to dst.
    28  	Encode(dst []byte)
    29  }
    30  
    31  type byteEncoder byte
    32  
    33  func (c byteEncoder) Len() int {
    34  	return 1
    35  }
    36  
    37  func (c byteEncoder) Encode(dst []byte) {
    38  	dst[0] = byte(c)
    39  }
    40  
    41  type bytesEncoder []byte
    42  
    43  func (b bytesEncoder) Len() int {
    44  	return len(b)
    45  }
    46  
    47  func (b bytesEncoder) Encode(dst []byte) {
    48  	if copy(dst, b) != len(b) {
    49  		panic("internal error")
    50  	}
    51  }
    52  
    53  type stringEncoder string
    54  
    55  func (s stringEncoder) Len() int {
    56  	return len(s)
    57  }
    58  
    59  func (s stringEncoder) Encode(dst []byte) {
    60  	if copy(dst, s) != len(s) {
    61  		panic("internal error")
    62  	}
    63  }
    64  
    65  type multiEncoder []encoder
    66  
    67  func (m multiEncoder) Len() int {
    68  	var size int
    69  	for _, e := range m {
    70  		size += e.Len()
    71  	}
    72  	return size
    73  }
    74  
    75  func (m multiEncoder) Encode(dst []byte) {
    76  	var off int
    77  	for _, e := range m {
    78  		e.Encode(dst[off:])
    79  		off += e.Len()
    80  	}
    81  }
    82  
    83  type setEncoder []encoder
    84  
    85  func (s setEncoder) Len() int {
    86  	var size int
    87  	for _, e := range s {
    88  		size += e.Len()
    89  	}
    90  	return size
    91  }
    92  
    93  func (s setEncoder) Encode(dst []byte) {
    94  	// Per X690 Section 11.6: The encodings of the component values of a
    95  	// set-of value shall appear in ascending order, the encodings being
    96  	// compared as octet strings with the shorter components being padded
    97  	// at their trailing end with 0-octets.
    98  	//
    99  	// First we encode each element to its TLV encoding and then use
   100  	// octetSort to get the ordering expected by X690 DER rules before
   101  	// writing the sorted encodings out to dst.
   102  	l := make([][]byte, len(s))
   103  	for i, e := range s {
   104  		l[i] = make([]byte, e.Len())
   105  		e.Encode(l[i])
   106  	}
   107  
   108  	sort.Slice(l, func(i, j int) bool {
   109  		// Since we are using bytes.Compare to compare TLV encodings we
   110  		// don't need to right pad s[i] and s[j] to the same length as
   111  		// suggested in X690. If len(s[i]) < len(s[j]) the length octet of
   112  		// s[i], which is the first determining byte, will inherently be
   113  		// smaller than the length octet of s[j]. This lets us skip the
   114  		// padding step.
   115  		return bytes.Compare(l[i], l[j]) < 0
   116  	})
   117  
   118  	var off int
   119  	for _, b := range l {
   120  		copy(dst[off:], b)
   121  		off += len(b)
   122  	}
   123  }
   124  
   125  type taggedEncoder struct {
   126  	// scratch contains temporary space for encoding the tag and length of
   127  	// an element in order to avoid extra allocations.
   128  	scratch [8]byte
   129  	tag     encoder
   130  	body    encoder
   131  }
   132  
   133  func (t *taggedEncoder) Len() int {
   134  	return t.tag.Len() + t.body.Len()
   135  }
   136  
   137  func (t *taggedEncoder) Encode(dst []byte) {
   138  	t.tag.Encode(dst)
   139  	t.body.Encode(dst[t.tag.Len():])
   140  }
   141  
   142  type int64Encoder int64
   143  
   144  func (i int64Encoder) Len() int {
   145  	n := 1
   146  
   147  	for i > 127 {
   148  		n++
   149  		i >>= 8
   150  	}
   151  
   152  	for i < -128 {
   153  		n++
   154  		i >>= 8
   155  	}
   156  
   157  	return n
   158  }
   159  
   160  func (i int64Encoder) Encode(dst []byte) {
   161  	n := i.Len()
   162  
   163  	for j := 0; j < n; j++ {
   164  		dst[j] = byte(i >> uint((n-1-j)*8))
   165  	}
   166  }
   167  
   168  func base128IntLength(n int64) int {
   169  	if n == 0 {
   170  		return 1
   171  	}
   172  
   173  	l := 0
   174  	for i := n; i > 0; i >>= 7 {
   175  		l++
   176  	}
   177  
   178  	return l
   179  }
   180  
   181  func appendBase128Int(dst []byte, n int64) []byte {
   182  	l := base128IntLength(n)
   183  
   184  	for i := l - 1; i >= 0; i-- {
   185  		o := byte(n >> uint(i*7))
   186  		o &= 0x7f
   187  		if i != 0 {
   188  			o |= 0x80
   189  		}
   190  
   191  		dst = append(dst, o)
   192  	}
   193  
   194  	return dst
   195  }
   196  
   197  func makeBigInt(n *big.Int) (encoder, error) {
   198  	if n == nil {
   199  		return nil, StructuralError{"empty integer"}
   200  	}
   201  
   202  	if n.Sign() < 0 {
   203  		// A negative number has to be converted to two's-complement
   204  		// form. So we'll invert and subtract 1. If the
   205  		// most-significant-bit isn't set then we'll need to pad the
   206  		// beginning with 0xff in order to keep the number negative.
   207  		nMinus1 := new(big.Int).Neg(n)
   208  		nMinus1.Sub(nMinus1, bigOne)
   209  		bytes := nMinus1.Bytes()
   210  		for i := range bytes {
   211  			bytes[i] ^= 0xff
   212  		}
   213  		if len(bytes) == 0 || bytes[0]&0x80 == 0 {
   214  			return multiEncoder([]encoder{byteFFEncoder, bytesEncoder(bytes)}), nil
   215  		}
   216  		return bytesEncoder(bytes), nil
   217  	} else if n.Sign() == 0 {
   218  		// Zero is written as a single 0 zero rather than no bytes.
   219  		return byte00Encoder, nil
   220  	} else {
   221  		bytes := n.Bytes()
   222  		if len(bytes) > 0 && bytes[0]&0x80 != 0 {
   223  			// We'll have to pad this with 0x00 in order to stop it
   224  			// looking like a negative number.
   225  			return multiEncoder([]encoder{byte00Encoder, bytesEncoder(bytes)}), nil
   226  		}
   227  		return bytesEncoder(bytes), nil
   228  	}
   229  }
   230  
   231  func appendLength(dst []byte, i int) []byte {
   232  	n := lengthLength(i)
   233  
   234  	for ; n > 0; n-- {
   235  		dst = append(dst, byte(i>>uint((n-1)*8)))
   236  	}
   237  
   238  	return dst
   239  }
   240  
   241  func lengthLength(i int) (numBytes int) {
   242  	numBytes = 1
   243  	for i > 255 {
   244  		numBytes++
   245  		i >>= 8
   246  	}
   247  	return
   248  }
   249  
   250  func appendTagAndLength(dst []byte, t tagAndLength) []byte {
   251  	b := uint8(t.class) << 6
   252  	if t.isCompound {
   253  		b |= 0x20
   254  	}
   255  	if t.tag >= 31 {
   256  		b |= 0x1f
   257  		dst = append(dst, b)
   258  		dst = appendBase128Int(dst, int64(t.tag))
   259  	} else {
   260  		b |= uint8(t.tag)
   261  		dst = append(dst, b)
   262  	}
   263  
   264  	if t.length >= 128 {
   265  		l := lengthLength(t.length)
   266  		dst = append(dst, 0x80|byte(l))
   267  		dst = appendLength(dst, t.length)
   268  	} else {
   269  		dst = append(dst, byte(t.length))
   270  	}
   271  
   272  	return dst
   273  }
   274  
   275  type bitStringEncoder BitString
   276  
   277  func (b bitStringEncoder) Len() int {
   278  	return len(b.Bytes) + 1
   279  }
   280  
   281  func (b bitStringEncoder) Encode(dst []byte) {
   282  	dst[0] = byte((8 - b.BitLength%8) % 8)
   283  	if copy(dst[1:], b.Bytes) != len(b.Bytes) {
   284  		panic("internal error")
   285  	}
   286  }
   287  
   288  type oidEncoder []int
   289  
   290  func (oid oidEncoder) Len() int {
   291  	l := base128IntLength(int64(oid[0]*40 + oid[1]))
   292  	for i := 2; i < len(oid); i++ {
   293  		l += base128IntLength(int64(oid[i]))
   294  	}
   295  	return l
   296  }
   297  
   298  func (oid oidEncoder) Encode(dst []byte) {
   299  	dst = appendBase128Int(dst[:0], int64(oid[0]*40+oid[1]))
   300  	for i := 2; i < len(oid); i++ {
   301  		dst = appendBase128Int(dst, int64(oid[i]))
   302  	}
   303  }
   304  
   305  func makeObjectIdentifier(oid []int) (e encoder, err error) {
   306  	if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
   307  		return nil, StructuralError{"invalid object identifier"}
   308  	}
   309  
   310  	return oidEncoder(oid), nil
   311  }
   312  
   313  func makePrintableString(s string) (e encoder, err error) {
   314  	for i := 0; i < len(s); i++ {
   315  		// The asterisk is often used in PrintableString, even though
   316  		// it is invalid. If a PrintableString was specifically
   317  		// requested then the asterisk is permitted by this code.
   318  		// Ampersand is allowed in parsing due a handful of CA
   319  		// certificates, however when making new certificates
   320  		// it is rejected.
   321  		if !isPrintable(s[i], allowAsterisk, rejectAmpersand) {
   322  			return nil, StructuralError{"PrintableString contains invalid character"}
   323  		}
   324  	}
   325  
   326  	return stringEncoder(s), nil
   327  }
   328  
   329  func makeIA5String(s string) (e encoder, err error) {
   330  	for i := 0; i < len(s); i++ {
   331  		if s[i] > 127 {
   332  			return nil, StructuralError{"IA5String contains invalid character"}
   333  		}
   334  	}
   335  
   336  	return stringEncoder(s), nil
   337  }
   338  
   339  func makeNumericString(s string) (e encoder, err error) {
   340  	for i := 0; i < len(s); i++ {
   341  		if !isNumeric(s[i]) {
   342  			return nil, StructuralError{"NumericString contains invalid character"}
   343  		}
   344  	}
   345  
   346  	return stringEncoder(s), nil
   347  }
   348  
   349  func makeUTF8String(s string) encoder {
   350  	return stringEncoder(s)
   351  }
   352  
   353  func appendTwoDigits(dst []byte, v int) []byte {
   354  	return append(dst, byte('0'+(v/10)%10), byte('0'+v%10))
   355  }
   356  
   357  func appendFourDigits(dst []byte, v int) []byte {
   358  	var bytes [4]byte
   359  	for i := range bytes {
   360  		bytes[3-i] = '0' + byte(v%10)
   361  		v /= 10
   362  	}
   363  	return append(dst, bytes[:]...)
   364  }
   365  
   366  func outsideUTCRange(t time.Time) bool {
   367  	year := t.Year()
   368  	return year < 1950 || year >= 2050
   369  }
   370  
   371  func makeUTCTime(t time.Time) (e encoder, err error) {
   372  	dst := make([]byte, 0, 18)
   373  
   374  	dst, err = appendUTCTime(dst, t)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  
   379  	return bytesEncoder(dst), nil
   380  }
   381  
   382  func makeGeneralizedTime(t time.Time) (e encoder, err error) {
   383  	dst := make([]byte, 0, 20)
   384  
   385  	dst, err = appendGeneralizedTime(dst, t)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	return bytesEncoder(dst), nil
   391  }
   392  
   393  func appendUTCTime(dst []byte, t time.Time) (ret []byte, err error) {
   394  	year := t.Year()
   395  
   396  	switch {
   397  	case 1950 <= year && year < 2000:
   398  		dst = appendTwoDigits(dst, year-1900)
   399  	case 2000 <= year && year < 2050:
   400  		dst = appendTwoDigits(dst, year-2000)
   401  	default:
   402  		return nil, StructuralError{"cannot represent time as UTCTime"}
   403  	}
   404  
   405  	return appendTimeCommon(dst, t), nil
   406  }
   407  
   408  func appendGeneralizedTime(dst []byte, t time.Time) (ret []byte, err error) {
   409  	year := t.Year()
   410  	if year < 0 || year > 9999 {
   411  		return nil, StructuralError{"cannot represent time as GeneralizedTime"}
   412  	}
   413  
   414  	dst = appendFourDigits(dst, year)
   415  
   416  	return appendTimeCommon(dst, t), nil
   417  }
   418  
   419  func appendTimeCommon(dst []byte, t time.Time) []byte {
   420  	_, month, day := t.Date()
   421  
   422  	dst = appendTwoDigits(dst, int(month))
   423  	dst = appendTwoDigits(dst, day)
   424  
   425  	hour, min, sec := t.Clock()
   426  
   427  	dst = appendTwoDigits(dst, hour)
   428  	dst = appendTwoDigits(dst, min)
   429  	dst = appendTwoDigits(dst, sec)
   430  
   431  	_, offset := t.Zone()
   432  
   433  	switch {
   434  	case offset/60 == 0:
   435  		return append(dst, 'Z')
   436  	case offset > 0:
   437  		dst = append(dst, '+')
   438  	case offset < 0:
   439  		dst = append(dst, '-')
   440  	}
   441  
   442  	offsetMinutes := offset / 60
   443  	if offsetMinutes < 0 {
   444  		offsetMinutes = -offsetMinutes
   445  	}
   446  
   447  	dst = appendTwoDigits(dst, offsetMinutes/60)
   448  	dst = appendTwoDigits(dst, offsetMinutes%60)
   449  
   450  	return dst
   451  }
   452  
   453  func stripTagAndLength(in []byte) []byte {
   454  	_, offset, err := parseTagAndLength(in, 0)
   455  	if err != nil {
   456  		return in
   457  	}
   458  	return in[offset:]
   459  }
   460  
   461  func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error) {
   462  	switch value.Type() {
   463  	case flagType:
   464  		return bytesEncoder(nil), nil
   465  	case timeType:
   466  		t := value.Interface().(time.Time)
   467  		if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
   468  			return makeGeneralizedTime(t)
   469  		}
   470  		return makeUTCTime(t)
   471  	case bitStringType:
   472  		return bitStringEncoder(value.Interface().(BitString)), nil
   473  	case objectIdentifierType:
   474  		return makeObjectIdentifier(value.Interface().(ObjectIdentifier))
   475  	case bigIntType:
   476  		return makeBigInt(value.Interface().(*big.Int))
   477  	}
   478  
   479  	switch v := value; v.Kind() {
   480  	case reflect.Bool:
   481  		if v.Bool() {
   482  			return byteFFEncoder, nil
   483  		}
   484  		return byte00Encoder, nil
   485  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   486  		return int64Encoder(v.Int()), nil
   487  	case reflect.Struct:
   488  		t := v.Type()
   489  
   490  		for i := 0; i < t.NumField(); i++ {
   491  			if t.Field(i).PkgPath != "" {
   492  				return nil, StructuralError{"struct contains unexported fields"}
   493  			}
   494  		}
   495  
   496  		startingField := 0
   497  
   498  		n := t.NumField()
   499  		if n == 0 {
   500  			return bytesEncoder(nil), nil
   501  		}
   502  
   503  		// If the first element of the structure is a non-empty
   504  		// RawContents, then we don't bother serializing the rest.
   505  		if t.Field(0).Type == rawContentsType {
   506  			s := v.Field(0)
   507  			if s.Len() > 0 {
   508  				bytes := s.Bytes()
   509  				/* The RawContents will contain the tag and
   510  				 * length fields but we'll also be writing
   511  				 * those ourselves, so we strip them out of
   512  				 * bytes */
   513  				return bytesEncoder(stripTagAndLength(bytes)), nil
   514  			}
   515  
   516  			startingField = 1
   517  		}
   518  
   519  		switch n1 := n - startingField; n1 {
   520  		case 0:
   521  			return bytesEncoder(nil), nil
   522  		case 1:
   523  			return makeField(v.Field(startingField), parseFieldParameters(t.Field(startingField).Tag.Get("asn1")))
   524  		default:
   525  			m := make([]encoder, n1)
   526  			for i := 0; i < n1; i++ {
   527  				m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1")))
   528  				if err != nil {
   529  					return nil, err
   530  				}
   531  			}
   532  
   533  			return multiEncoder(m), nil
   534  		}
   535  	case reflect.Slice:
   536  		sliceType := v.Type()
   537  		if sliceType.Elem().Kind() == reflect.Uint8 {
   538  			return bytesEncoder(v.Bytes()), nil
   539  		}
   540  
   541  		var fp fieldParameters
   542  
   543  		switch l := v.Len(); l {
   544  		case 0:
   545  			return bytesEncoder(nil), nil
   546  		case 1:
   547  			return makeField(v.Index(0), fp)
   548  		default:
   549  			m := make([]encoder, l)
   550  
   551  			for i := 0; i < l; i++ {
   552  				m[i], err = makeField(v.Index(i), fp)
   553  				if err != nil {
   554  					return nil, err
   555  				}
   556  			}
   557  
   558  			if params.set {
   559  				return setEncoder(m), nil
   560  			}
   561  			return multiEncoder(m), nil
   562  		}
   563  	case reflect.String:
   564  		switch params.stringType {
   565  		case TagIA5String:
   566  			return makeIA5String(v.String())
   567  		case TagPrintableString:
   568  			return makePrintableString(v.String())
   569  		case TagNumericString:
   570  			return makeNumericString(v.String())
   571  		default:
   572  			return makeUTF8String(v.String()), nil
   573  		}
   574  	}
   575  
   576  	return nil, StructuralError{"unknown Go type"}
   577  }
   578  
   579  func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
   580  	if !v.IsValid() {
   581  		return nil, fmt.Errorf("asn1: cannot marshal nil value")
   582  	}
   583  	// If the field is an interface{} then recurse into it.
   584  	if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
   585  		return makeField(v.Elem(), params)
   586  	}
   587  
   588  	if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
   589  		return bytesEncoder(nil), nil
   590  	}
   591  
   592  	if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
   593  		defaultValue := reflect.New(v.Type()).Elem()
   594  		defaultValue.SetInt(*params.defaultValue)
   595  
   596  		if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
   597  			return bytesEncoder(nil), nil
   598  		}
   599  	}
   600  
   601  	// If no default value is given then the zero value for the type is
   602  	// assumed to be the default value. This isn't obviously the correct
   603  	// behavior, but it's what Go has traditionally done.
   604  	if params.optional && params.defaultValue == nil {
   605  		if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
   606  			return bytesEncoder(nil), nil
   607  		}
   608  	}
   609  
   610  	if v.Type() == rawValueType {
   611  		rv := v.Interface().(RawValue)
   612  		if len(rv.FullBytes) != 0 {
   613  			return bytesEncoder(rv.FullBytes), nil
   614  		}
   615  
   616  		t := new(taggedEncoder)
   617  
   618  		t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}))
   619  		t.body = bytesEncoder(rv.Bytes)
   620  
   621  		return t, nil
   622  	}
   623  
   624  	matchAny, tag, isCompound, ok := getUniversalType(v.Type())
   625  	if !ok || matchAny {
   626  		return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
   627  	}
   628  
   629  	if params.timeType != 0 && tag != TagUTCTime {
   630  		return nil, StructuralError{"explicit time type given to non-time member"}
   631  	}
   632  
   633  	if params.stringType != 0 && tag != TagPrintableString {
   634  		return nil, StructuralError{"explicit string type given to non-string member"}
   635  	}
   636  
   637  	switch tag {
   638  	case TagPrintableString:
   639  		if params.stringType == 0 {
   640  			// This is a string without an explicit string type. We'll use
   641  			// a PrintableString if the character set in the string is
   642  			// sufficiently limited, otherwise we'll use a UTF8String.
   643  			for _, r := range v.String() {
   644  				if r >= utf8.RuneSelf || !isPrintable(byte(r), rejectAsterisk, rejectAmpersand) {
   645  					if !utf8.ValidString(v.String()) {
   646  						return nil, errors.New("asn1: string not valid UTF-8")
   647  					}
   648  					tag = TagUTF8String
   649  					break
   650  				}
   651  			}
   652  		} else {
   653  			tag = params.stringType
   654  		}
   655  	case TagUTCTime:
   656  		if params.timeType == TagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
   657  			tag = TagGeneralizedTime
   658  		}
   659  	}
   660  
   661  	if params.set {
   662  		if tag != TagSequence {
   663  			return nil, StructuralError{"non sequence tagged as set"}
   664  		}
   665  		tag = TagSet
   666  	}
   667  
   668  	// makeField can be called for a slice that should be treated as a SET
   669  	// but doesn't have params.set set, for instance when using a slice
   670  	// with the SET type name suffix. In this case getUniversalType returns
   671  	// TagSet, but makeBody doesn't know about that so will treat the slice
   672  	// as a sequence. To work around this we set params.set.
   673  	if tag == TagSet && !params.set {
   674  		params.set = true
   675  	}
   676  
   677  	t := new(taggedEncoder)
   678  
   679  	t.body, err = makeBody(v, params)
   680  	if err != nil {
   681  		return nil, err
   682  	}
   683  
   684  	bodyLen := t.body.Len()
   685  
   686  	class := ClassUniversal
   687  	if params.tag != nil {
   688  		if params.application {
   689  			class = ClassApplication
   690  		} else if params.private {
   691  			class = ClassPrivate
   692  		} else {
   693  			class = ClassContextSpecific
   694  		}
   695  
   696  		if params.explicit {
   697  			t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound}))
   698  
   699  			tt := new(taggedEncoder)
   700  
   701  			tt.body = t
   702  
   703  			tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{
   704  				class:      class,
   705  				tag:        *params.tag,
   706  				length:     bodyLen + t.tag.Len(),
   707  				isCompound: true,
   708  			}))
   709  
   710  			return tt, nil
   711  		}
   712  
   713  		// implicit tag.
   714  		tag = *params.tag
   715  	}
   716  
   717  	t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
   718  
   719  	return t, nil
   720  }
   721  
   722  // Marshal returns the ASN.1 encoding of val.
   723  //
   724  // In addition to the struct tags recognised by Unmarshal, the following can be
   725  // used:
   726  //
   727  //	ia5:         causes strings to be marshaled as ASN.1, IA5String values
   728  //	omitempty:   causes empty slices to be skipped
   729  //	printable:   causes strings to be marshaled as ASN.1, PrintableString values
   730  //	utf8:        causes strings to be marshaled as ASN.1, UTF8String values
   731  //	utc:         causes time.Time to be marshaled as ASN.1, UTCTime values
   732  //	generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values
   733  func Marshal(val interface{}) ([]byte, error) {
   734  	return MarshalWithParams(val, "")
   735  }
   736  
   737  // MarshalWithParams allows field parameters to be specified for the
   738  // top-level element. The form of the params is the same as the field tags.
   739  func MarshalWithParams(val interface{}, params string) ([]byte, error) {
   740  	e, err := makeField(reflect.ValueOf(val), parseFieldParameters(params))
   741  	if err != nil {
   742  		return nil, err
   743  	}
   744  	b := make([]byte, e.Len())
   745  	e.Encode(b)
   746  	return b, nil
   747  }
   748  

View as plain text