...

Source file src/github.com/google/certificate-transparency-go/tls/tls.go

Documentation: github.com/google/certificate-transparency-go/tls

     1  // Copyright 2016 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package tls implements functionality for dealing with TLS-encoded data,
    16  // as defined in RFC 5246.  This includes parsing and generation of TLS-encoded
    17  // data, together with utility functions for dealing with the DigitallySigned
    18  // TLS type.
    19  package tls
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/binary"
    24  	"fmt"
    25  	"reflect"
    26  	"strconv"
    27  	"strings"
    28  )
    29  
    30  // This file holds utility functions for TLS encoding/decoding data
    31  // as per RFC 5246 section 4.
    32  
    33  // A structuralError suggests that the TLS data is valid, but the Go type
    34  // which is receiving it doesn't match.
    35  type structuralError struct {
    36  	field string
    37  	msg   string
    38  }
    39  
    40  func (e structuralError) Error() string {
    41  	var prefix string
    42  	if e.field != "" {
    43  		prefix = e.field + ": "
    44  	}
    45  	return "tls: structure error: " + prefix + e.msg
    46  }
    47  
    48  // A syntaxError suggests that the TLS data is invalid.
    49  type syntaxError struct {
    50  	field string
    51  	msg   string
    52  }
    53  
    54  func (e syntaxError) Error() string {
    55  	var prefix string
    56  	if e.field != "" {
    57  		prefix = e.field + ": "
    58  	}
    59  	return "tls: syntax error: " + prefix + e.msg
    60  }
    61  
    62  // Uint24 is an unsigned 3-byte integer.
    63  type Uint24 uint32
    64  
    65  // Enum is an unsigned integer.
    66  type Enum uint64
    67  
    68  var (
    69  	uint8Type  = reflect.TypeOf(uint8(0))
    70  	uint16Type = reflect.TypeOf(uint16(0))
    71  	uint24Type = reflect.TypeOf(Uint24(0))
    72  	uint32Type = reflect.TypeOf(uint32(0))
    73  	uint64Type = reflect.TypeOf(uint64(0))
    74  	enumType   = reflect.TypeOf(Enum(0))
    75  )
    76  
    77  // Unmarshal parses the TLS-encoded data in b and uses the reflect package to
    78  // fill in an arbitrary value pointed at by val.  Because Unmarshal uses the
    79  // reflect package, the structs being written to must use exported fields
    80  // (upper case names).
    81  //
    82  // The mappings between TLS types and Go types is as follows; some fields
    83  // must have tags (to indicate their encoded size).
    84  //
    85  //	TLS		Go		Required Tags
    86  //	opaque		byte / uint8
    87  //	uint8		byte / uint8
    88  //	uint16		uint16
    89  //	uint24		tls.Uint24
    90  //	uint32		uint32
    91  //	uint64		uint64
    92  //	enum		tls.Enum	size:S or maxval:N
    93  //	Type<N,M>	[]Type		minlen:N,maxlen:M
    94  //	opaque[N]	[N]byte / [N]uint8
    95  //	uint8[N]	[N]byte / [N]uint8
    96  //	struct { }	struct { }
    97  //	select(T) {
    98  //	 case e1: Type	*T		selector:Field,val:e1
    99  //	}
   100  //
   101  // TLS variants (RFC 5246 s4.6.1) are only supported when the value of the
   102  // associated enumeration type is available earlier in the same enclosing
   103  // struct, and each possible variant is marked with a selector tag (to
   104  // indicate which field selects the variants) and a val tag (to indicate
   105  // what value of the selector picks this particular field).
   106  //
   107  // For example, a TLS structure:
   108  //
   109  //	enum { e1(1), e2(2) } EnumType;
   110  //	struct {
   111  //	   EnumType sel;
   112  //	   select(sel) {
   113  //	      case e1: uint16
   114  //	      case e2: uint32
   115  //	   } data;
   116  //	} VariantItem;
   117  //
   118  // would have a corresponding Go type:
   119  //
   120  //	type VariantItem struct {
   121  //	   Sel    tls.Enum  `tls:"maxval:2"`
   122  //	   Data16 *uint16   `tls:"selector:Sel,val:1"`
   123  //	   Data32 *uint32   `tls:"selector:Sel,val:2"`
   124  //	 }
   125  //
   126  // TLS fixed-length vectors of types other than opaque or uint8 are not supported.
   127  //
   128  // For TLS variable-length vectors that are themselves used in other vectors,
   129  // create a single-field structure to represent the inner type. For example, for:
   130  //
   131  //	opaque InnerType<1..65535>;
   132  //	struct {
   133  //	  InnerType inners<1,65535>;
   134  //	} Something;
   135  //
   136  // convert to:
   137  //
   138  //	type InnerType struct {
   139  //	   Val    []byte       `tls:"minlen:1,maxlen:65535"`
   140  //	}
   141  //	type Something struct {
   142  //	   Inners []InnerType  `tls:"minlen:1,maxlen:65535"`
   143  //	}
   144  //
   145  // If the encoded value does not fit in the Go type, Unmarshal returns a parse error.
   146  func Unmarshal(b []byte, val interface{}) ([]byte, error) {
   147  	return UnmarshalWithParams(b, val, "")
   148  }
   149  
   150  // UnmarshalWithParams allows field parameters to be specified for the
   151  // top-level element. The form of the params is the same as the field tags.
   152  func UnmarshalWithParams(b []byte, val interface{}, params string) ([]byte, error) {
   153  	info, err := fieldTagToFieldInfo(params, "")
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	// The passed in interface{} is a pointer (to allow the value to be written
   158  	// to); extract the pointed-to object as a reflect.Value, so parseField
   159  	// can do various introspection things.
   160  	v := reflect.ValueOf(val).Elem()
   161  	offset, err := parseField(v, b, 0, info)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	return b[offset:], nil
   166  }
   167  
   168  // Return the number of bytes needed to encode values up to (and including) x.
   169  func byteCount(x uint64) uint {
   170  	switch {
   171  	case x < 0x100:
   172  		return 1
   173  	case x < 0x10000:
   174  		return 2
   175  	case x < 0x1000000:
   176  		return 3
   177  	case x < 0x100000000:
   178  		return 4
   179  	case x < 0x10000000000:
   180  		return 5
   181  	case x < 0x1000000000000:
   182  		return 6
   183  	case x < 0x100000000000000:
   184  		return 7
   185  	default:
   186  		return 8
   187  	}
   188  }
   189  
   190  type fieldInfo struct {
   191  	count    uint // Number of bytes
   192  	countSet bool
   193  	minlen   uint64 // Only relevant for slices
   194  	maxlen   uint64 // Only relevant for slices
   195  	selector string // Only relevant for select sub-values
   196  	val      uint64 // Only relevant for select sub-values
   197  	name     string // Used for better error messages
   198  }
   199  
   200  func (i *fieldInfo) fieldName() string {
   201  	if i == nil {
   202  		return ""
   203  	}
   204  	return i.name
   205  }
   206  
   207  // Given a tag string, return a fieldInfo describing the field.
   208  func fieldTagToFieldInfo(str string, name string) (*fieldInfo, error) {
   209  	var info *fieldInfo
   210  	// Iterate over clauses in the tag, ignoring any that don't parse properly.
   211  	for _, part := range strings.Split(str, ",") {
   212  		switch {
   213  		case strings.HasPrefix(part, "maxval:"):
   214  			if v, err := strconv.ParseUint(part[7:], 10, 64); err == nil {
   215  				info = &fieldInfo{count: byteCount(v), countSet: true}
   216  			}
   217  		case strings.HasPrefix(part, "size:"):
   218  			if sz, err := strconv.ParseUint(part[5:], 10, 32); err == nil {
   219  				info = &fieldInfo{count: uint(sz), countSet: true}
   220  			}
   221  		case strings.HasPrefix(part, "maxlen:"):
   222  			v, err := strconv.ParseUint(part[7:], 10, 64)
   223  			if err != nil {
   224  				continue
   225  			}
   226  			if info == nil {
   227  				info = &fieldInfo{}
   228  			}
   229  			info.count = byteCount(v)
   230  			info.countSet = true
   231  			info.maxlen = v
   232  		case strings.HasPrefix(part, "minlen:"):
   233  			v, err := strconv.ParseUint(part[7:], 10, 64)
   234  			if err != nil {
   235  				continue
   236  			}
   237  			if info == nil {
   238  				info = &fieldInfo{}
   239  			}
   240  			info.minlen = v
   241  		case strings.HasPrefix(part, "selector:"):
   242  			if info == nil {
   243  				info = &fieldInfo{}
   244  			}
   245  			info.selector = part[9:]
   246  		case strings.HasPrefix(part, "val:"):
   247  			v, err := strconv.ParseUint(part[4:], 10, 64)
   248  			if err != nil {
   249  				continue
   250  			}
   251  			if info == nil {
   252  				info = &fieldInfo{}
   253  			}
   254  			info.val = v
   255  		}
   256  	}
   257  	if info != nil {
   258  		info.name = name
   259  		if info.selector == "" {
   260  			if info.count < 1 {
   261  				return nil, structuralError{name, "field of unknown size in " + str}
   262  			} else if info.count > 8 {
   263  				return nil, structuralError{name, "specified size too large in " + str}
   264  			} else if info.minlen > info.maxlen {
   265  				return nil, structuralError{name, "specified length range inverted in " + str}
   266  			} else if info.val > 0 {
   267  				return nil, structuralError{name, "specified selector value but not field in " + str}
   268  			}
   269  		}
   270  	} else if name != "" {
   271  		info = &fieldInfo{name: name}
   272  	}
   273  	return info, nil
   274  }
   275  
   276  // Check that a value fits into a field described by a fieldInfo structure.
   277  func (i fieldInfo) check(val uint64, fldName string) error {
   278  	if val >= (1 << (8 * i.count)) {
   279  		return structuralError{fldName, fmt.Sprintf("value %d too large for size", val)}
   280  	}
   281  	if i.maxlen != 0 {
   282  		if val < i.minlen {
   283  			return structuralError{fldName, fmt.Sprintf("value %d too small for minimum %d", val, i.minlen)}
   284  		}
   285  		if val > i.maxlen {
   286  			return structuralError{fldName, fmt.Sprintf("value %d too large for maximum %d", val, i.maxlen)}
   287  		}
   288  	}
   289  	return nil
   290  }
   291  
   292  // readVarUint reads an big-endian unsigned integer of the given size in
   293  // bytes.
   294  func readVarUint(data []byte, info *fieldInfo) (uint64, error) {
   295  	if info == nil || !info.countSet {
   296  		return 0, structuralError{info.fieldName(), "no field size information available"}
   297  	}
   298  	if len(data) < int(info.count) {
   299  		return 0, syntaxError{info.fieldName(), "truncated variable-length integer"}
   300  	}
   301  	var result uint64
   302  	for i := uint(0); i < info.count; i++ {
   303  		result = (result << 8) | uint64(data[i])
   304  	}
   305  	if err := info.check(result, info.name); err != nil {
   306  		return 0, err
   307  	}
   308  	return result, nil
   309  }
   310  
   311  // parseField is the main parsing function. Given a byte slice and an offset
   312  // (in bytes) into the data, it will try to parse a suitable ASN.1 value out
   313  // and store it in the given Value.
   314  func parseField(v reflect.Value, data []byte, initOffset int, info *fieldInfo) (int, error) {
   315  	offset := initOffset
   316  	rest := data[offset:]
   317  
   318  	fieldType := v.Type()
   319  	// First look for known fixed types.
   320  	switch fieldType {
   321  	case uint8Type:
   322  		if len(rest) < 1 {
   323  			return offset, syntaxError{info.fieldName(), "truncated uint8"}
   324  		}
   325  		v.SetUint(uint64(rest[0]))
   326  		offset++
   327  		return offset, nil
   328  	case uint16Type:
   329  		if len(rest) < 2 {
   330  			return offset, syntaxError{info.fieldName(), "truncated uint16"}
   331  		}
   332  		v.SetUint(uint64(binary.BigEndian.Uint16(rest)))
   333  		offset += 2
   334  		return offset, nil
   335  	case uint24Type:
   336  		if len(rest) < 3 {
   337  			return offset, syntaxError{info.fieldName(), "truncated uint24"}
   338  		}
   339  		v.SetUint(uint64(data[0])<<16 | uint64(data[1])<<8 | uint64(data[2]))
   340  		offset += 3
   341  		return offset, nil
   342  	case uint32Type:
   343  		if len(rest) < 4 {
   344  			return offset, syntaxError{info.fieldName(), "truncated uint32"}
   345  		}
   346  		v.SetUint(uint64(binary.BigEndian.Uint32(rest)))
   347  		offset += 4
   348  		return offset, nil
   349  	case uint64Type:
   350  		if len(rest) < 8 {
   351  			return offset, syntaxError{info.fieldName(), "truncated uint64"}
   352  		}
   353  		v.SetUint(uint64(binary.BigEndian.Uint64(rest)))
   354  		offset += 8
   355  		return offset, nil
   356  	}
   357  
   358  	// Now deal with user-defined types.
   359  	switch v.Kind() {
   360  	case enumType.Kind():
   361  		// Assume that anything of the same kind as Enum is an Enum, so that
   362  		// users can alias types of their own to Enum.
   363  		val, err := readVarUint(rest, info)
   364  		if err != nil {
   365  			return offset, err
   366  		}
   367  		v.SetUint(val)
   368  		offset += int(info.count)
   369  		return offset, nil
   370  	case reflect.Struct:
   371  		structType := fieldType
   372  		// TLS includes a select(Enum) {..} construct, where the value of an enum
   373  		// indicates which variant field is present (like a C union). We require
   374  		// that the enum value be an earlier field in the same structure (the selector),
   375  		// and that each of the possible variant destination fields be pointers.
   376  		// So the Go mapping looks like:
   377  		//     type variantType struct {
   378  		//         Which  tls.Enum  `tls:"size:1"`                // this is the selector
   379  		//         Val1   *type1    `tls:"selector:Which,val:1"`  // this is a destination
   380  		//         Val2   *type2    `tls:"selector:Which,val:1"`  // this is a destination
   381  		//     }
   382  
   383  		// To deal with this, we track any enum-like fields and their values...
   384  		enums := make(map[string]uint64)
   385  		// .. and we track which selector names we've seen (in the destination field tags),
   386  		// and whether a destination for that selector has been chosen.
   387  		selectorSeen := make(map[string]bool)
   388  		for i := 0; i < structType.NumField(); i++ {
   389  			// Find information about this field.
   390  			tag := structType.Field(i).Tag.Get("tls")
   391  			fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name)
   392  			if err != nil {
   393  				return offset, err
   394  			}
   395  
   396  			destination := v.Field(i)
   397  			if fieldInfo.selector != "" {
   398  				// This is a possible select(Enum) destination, so first check that the referenced
   399  				// selector field has already been seen earlier in the struct.
   400  				choice, ok := enums[fieldInfo.selector]
   401  				if !ok {
   402  					return offset, structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector}
   403  				}
   404  				if structType.Field(i).Type.Kind() != reflect.Ptr {
   405  					return offset, structuralError{fieldInfo.name, "choice field not a pointer type"}
   406  				}
   407  				// Is this the first mention of the selector field name?  If so, remember it.
   408  				seen, ok := selectorSeen[fieldInfo.selector]
   409  				if !ok {
   410  					selectorSeen[fieldInfo.selector] = false
   411  				}
   412  				if choice != fieldInfo.val {
   413  					// This destination field was not the chosen one, so make it nil (we checked
   414  					// it was a pointer above).
   415  					v.Field(i).Set(reflect.Zero(structType.Field(i).Type))
   416  					continue
   417  				}
   418  				if seen {
   419  					// We already saw a different destination field receive the value for this
   420  					// selector value, which indicates a badly annotated structure.
   421  					return offset, structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector}
   422  				}
   423  				selectorSeen[fieldInfo.selector] = true
   424  				// Make an object of the pointed-to type and parse into that.
   425  				v.Field(i).Set(reflect.New(structType.Field(i).Type.Elem()))
   426  				destination = v.Field(i).Elem()
   427  			}
   428  			offset, err = parseField(destination, data, offset, fieldInfo)
   429  			if err != nil {
   430  				return offset, err
   431  			}
   432  
   433  			// Remember any possible tls.Enum values encountered in case they are selectors.
   434  			if structType.Field(i).Type.Kind() == enumType.Kind() {
   435  				enums[structType.Field(i).Name] = v.Field(i).Uint()
   436  			}
   437  
   438  		}
   439  
   440  		// Now we have seen all fields in the structure, check that all select(Enum) {..} selector
   441  		// fields found a destination to put their data in.
   442  		for selector, seen := range selectorSeen {
   443  			if !seen {
   444  				return offset, syntaxError{info.fieldName(), selector + ": unhandled value for selector"}
   445  			}
   446  		}
   447  		return offset, nil
   448  	case reflect.Array:
   449  		datalen := v.Len()
   450  
   451  		if datalen > len(rest) {
   452  			return offset, syntaxError{info.fieldName(), "truncated array"}
   453  		}
   454  		inner := rest[:datalen]
   455  		offset += datalen
   456  		if fieldType.Elem().Kind() != reflect.Uint8 {
   457  			// Only byte/uint8 arrays are supported
   458  			return offset, structuralError{info.fieldName(), "unsupported array type: " + v.Type().String()}
   459  		}
   460  		reflect.Copy(v, reflect.ValueOf(inner))
   461  		return offset, nil
   462  
   463  	case reflect.Slice:
   464  		sliceType := fieldType
   465  		// Slices represent variable-length vectors, which are prefixed by a length field.
   466  		// The fieldInfo indicates the size of that length field.
   467  		varlen, err := readVarUint(rest, info)
   468  		if err != nil {
   469  			return offset, err
   470  		}
   471  		datalen := int(varlen)
   472  		offset += int(info.count)
   473  		rest = rest[info.count:]
   474  
   475  		if datalen > len(rest) {
   476  			return offset, syntaxError{info.fieldName(), "truncated slice"}
   477  		}
   478  		inner := rest[:datalen]
   479  		offset += datalen
   480  		if fieldType.Elem().Kind() == reflect.Uint8 {
   481  			// Fast version for []byte
   482  			v.Set(reflect.MakeSlice(sliceType, datalen, datalen))
   483  			reflect.Copy(v, reflect.ValueOf(inner))
   484  			return offset, nil
   485  		}
   486  
   487  		v.Set(reflect.MakeSlice(sliceType, 0, datalen))
   488  		single := reflect.New(sliceType.Elem())
   489  		for innerOffset := 0; innerOffset < len(inner); {
   490  			var err error
   491  			innerOffset, err = parseField(single.Elem(), inner, innerOffset, nil)
   492  			if err != nil {
   493  				return offset, err
   494  			}
   495  			v.Set(reflect.Append(v, single.Elem()))
   496  		}
   497  		return offset, nil
   498  
   499  	default:
   500  		return offset, structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())}
   501  	}
   502  }
   503  
   504  // Marshal returns the TLS encoding of val.
   505  func Marshal(val interface{}) ([]byte, error) {
   506  	return MarshalWithParams(val, "")
   507  }
   508  
   509  // MarshalWithParams returns the TLS encoding of val, and allows field
   510  // parameters to be specified for the top-level element.  The form
   511  // of the params is the same as the field tags.
   512  func MarshalWithParams(val interface{}, params string) ([]byte, error) {
   513  	info, err := fieldTagToFieldInfo(params, "")
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  	var out bytes.Buffer
   518  	v := reflect.ValueOf(val)
   519  	if err := marshalField(&out, v, info); err != nil {
   520  		return nil, err
   521  	}
   522  	return out.Bytes(), err
   523  }
   524  
   525  func marshalField(out *bytes.Buffer, v reflect.Value, info *fieldInfo) error {
   526  	var prefix string
   527  	if info != nil && len(info.name) > 0 {
   528  		prefix = info.name + ": "
   529  	}
   530  	fieldType := v.Type()
   531  	// First look for known fixed types.
   532  	switch fieldType {
   533  	case uint8Type:
   534  		out.WriteByte(byte(v.Uint()))
   535  		return nil
   536  	case uint16Type:
   537  		scratch := make([]byte, 2)
   538  		binary.BigEndian.PutUint16(scratch, uint16(v.Uint()))
   539  		out.Write(scratch)
   540  		return nil
   541  	case uint24Type:
   542  		i := v.Uint()
   543  		if i > 0xffffff {
   544  			return structuralError{info.fieldName(), fmt.Sprintf("uint24 overflow %d", i)}
   545  		}
   546  		scratch := make([]byte, 4)
   547  		binary.BigEndian.PutUint32(scratch, uint32(i))
   548  		out.Write(scratch[1:])
   549  		return nil
   550  	case uint32Type:
   551  		scratch := make([]byte, 4)
   552  		binary.BigEndian.PutUint32(scratch, uint32(v.Uint()))
   553  		out.Write(scratch)
   554  		return nil
   555  	case uint64Type:
   556  		scratch := make([]byte, 8)
   557  		binary.BigEndian.PutUint64(scratch, uint64(v.Uint()))
   558  		out.Write(scratch)
   559  		return nil
   560  	}
   561  
   562  	// Now deal with user-defined types.
   563  	switch v.Kind() {
   564  	case enumType.Kind():
   565  		i := v.Uint()
   566  		if info == nil {
   567  			return structuralError{info.fieldName(), "enum field tag missing"}
   568  		}
   569  		if err := info.check(i, prefix); err != nil {
   570  			return err
   571  		}
   572  		scratch := make([]byte, 8)
   573  		binary.BigEndian.PutUint64(scratch, uint64(i))
   574  		out.Write(scratch[(8 - info.count):])
   575  		return nil
   576  	case reflect.Struct:
   577  		structType := fieldType
   578  		enums := make(map[string]uint64) // Values of any Enum fields
   579  		// The comment parseField() describes the mapping of the TLS select(Enum) {..} construct;
   580  		// here we have selector and source (rather than destination) fields.
   581  
   582  		// Track which selector names we've seen (in the source field tags), and whether a source
   583  		// value for that selector has been processed.
   584  		selectorSeen := make(map[string]bool)
   585  		for i := 0; i < structType.NumField(); i++ {
   586  			// Find information about this field.
   587  			tag := structType.Field(i).Tag.Get("tls")
   588  			fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name)
   589  			if err != nil {
   590  				return err
   591  			}
   592  
   593  			source := v.Field(i)
   594  			if fieldInfo.selector != "" {
   595  				// This field is a possible source for a select(Enum) {..}.  First check
   596  				// the selector field name has been seen.
   597  				choice, ok := enums[fieldInfo.selector]
   598  				if !ok {
   599  					return structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector}
   600  				}
   601  				if structType.Field(i).Type.Kind() != reflect.Ptr {
   602  					return structuralError{fieldInfo.name, "choice field not a pointer type"}
   603  				}
   604  				// Is this the first mention of the selector field name? If so, remember it.
   605  				seen, ok := selectorSeen[fieldInfo.selector]
   606  				if !ok {
   607  					selectorSeen[fieldInfo.selector] = false
   608  				}
   609  				if choice != fieldInfo.val {
   610  					// This source was not chosen; police that it should be nil.
   611  					if v.Field(i).Pointer() != uintptr(0) {
   612  						return structuralError{fieldInfo.name, "unchosen field is non-nil"}
   613  					}
   614  					continue
   615  				}
   616  				if seen {
   617  					// We already saw a different source field generate the value for this
   618  					// selector value, which indicates a badly annotated structure.
   619  					return structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector}
   620  				}
   621  				selectorSeen[fieldInfo.selector] = true
   622  				if v.Field(i).Pointer() == uintptr(0) {
   623  					return structuralError{fieldInfo.name, "chosen field is nil"}
   624  				}
   625  				// Marshal from the pointed-to source object.
   626  				source = v.Field(i).Elem()
   627  			}
   628  
   629  			var fieldData bytes.Buffer
   630  			if err := marshalField(&fieldData, source, fieldInfo); err != nil {
   631  				return err
   632  			}
   633  			out.Write(fieldData.Bytes())
   634  
   635  			// Remember any tls.Enum values encountered in case they are selectors.
   636  			if structType.Field(i).Type.Kind() == enumType.Kind() {
   637  				enums[structType.Field(i).Name] = v.Field(i).Uint()
   638  			}
   639  		}
   640  		// Now we have seen all fields in the structure, check that all select(Enum) {..} selector
   641  		// fields found a source field to get their data from.
   642  		for selector, seen := range selectorSeen {
   643  			if !seen {
   644  				return syntaxError{info.fieldName(), selector + ": unhandled value for selector"}
   645  			}
   646  		}
   647  		return nil
   648  
   649  	case reflect.Array:
   650  		datalen := v.Len()
   651  		arrayType := fieldType
   652  		if arrayType.Elem().Kind() != reflect.Uint8 {
   653  			// Only byte/uint8 arrays are supported
   654  			return structuralError{info.fieldName(), "unsupported array type"}
   655  		}
   656  		bytes := make([]byte, datalen)
   657  		for i := 0; i < datalen; i++ {
   658  			bytes[i] = uint8(v.Index(i).Uint())
   659  		}
   660  		_, err := out.Write(bytes)
   661  		return err
   662  
   663  	case reflect.Slice:
   664  		if info == nil {
   665  			return structuralError{info.fieldName(), "slice field tag missing"}
   666  		}
   667  
   668  		sliceType := fieldType
   669  		if sliceType.Elem().Kind() == reflect.Uint8 {
   670  			// Fast version for []byte: first write the length as info.count bytes.
   671  			datalen := v.Len()
   672  			scratch := make([]byte, 8)
   673  			binary.BigEndian.PutUint64(scratch, uint64(datalen))
   674  			out.Write(scratch[(8 - info.count):])
   675  
   676  			if err := info.check(uint64(datalen), prefix); err != nil {
   677  				return err
   678  			}
   679  			// Then just write the data.
   680  			bytes := make([]byte, datalen)
   681  			for i := 0; i < datalen; i++ {
   682  				bytes[i] = uint8(v.Index(i).Uint())
   683  			}
   684  			_, err := out.Write(bytes)
   685  			return err
   686  		}
   687  		// General version: use a separate Buffer to write the slice entries into.
   688  		var innerBuf bytes.Buffer
   689  		for i := 0; i < v.Len(); i++ {
   690  			if err := marshalField(&innerBuf, v.Index(i), nil); err != nil {
   691  				return err
   692  			}
   693  		}
   694  
   695  		// Now insert (and check) the size.
   696  		size := uint64(innerBuf.Len())
   697  		if err := info.check(size, prefix); err != nil {
   698  			return err
   699  		}
   700  		scratch := make([]byte, 8)
   701  		binary.BigEndian.PutUint64(scratch, size)
   702  		out.Write(scratch[(8 - info.count):])
   703  
   704  		// Then copy the data.
   705  		_, err := out.Write(innerBuf.Bytes())
   706  		return err
   707  
   708  	default:
   709  		return structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())}
   710  	}
   711  }
   712  

View as plain text