// Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package tls implements functionality for dealing with TLS-encoded data, // as defined in RFC 5246. This includes parsing and generation of TLS-encoded // data, together with utility functions for dealing with the DigitallySigned // TLS type. package tls import ( "bytes" "encoding/binary" "fmt" "reflect" "strconv" "strings" ) // This file holds utility functions for TLS encoding/decoding data // as per RFC 5246 section 4. // A structuralError suggests that the TLS data is valid, but the Go type // which is receiving it doesn't match. type structuralError struct { field string msg string } func (e structuralError) Error() string { var prefix string if e.field != "" { prefix = e.field + ": " } return "tls: structure error: " + prefix + e.msg } // A syntaxError suggests that the TLS data is invalid. type syntaxError struct { field string msg string } func (e syntaxError) Error() string { var prefix string if e.field != "" { prefix = e.field + ": " } return "tls: syntax error: " + prefix + e.msg } // Uint24 is an unsigned 3-byte integer. type Uint24 uint32 // Enum is an unsigned integer. type Enum uint64 var ( uint8Type = reflect.TypeOf(uint8(0)) uint16Type = reflect.TypeOf(uint16(0)) uint24Type = reflect.TypeOf(Uint24(0)) uint32Type = reflect.TypeOf(uint32(0)) uint64Type = reflect.TypeOf(uint64(0)) enumType = reflect.TypeOf(Enum(0)) ) // Unmarshal parses the TLS-encoded data in b and uses the reflect package to // fill in an arbitrary value pointed at by val. Because Unmarshal uses the // reflect package, the structs being written to must use exported fields // (upper case names). // // The mappings between TLS types and Go types is as follows; some fields // must have tags (to indicate their encoded size). // // TLS Go Required Tags // opaque byte / uint8 // uint8 byte / uint8 // uint16 uint16 // uint24 tls.Uint24 // uint32 uint32 // uint64 uint64 // enum tls.Enum size:S or maxval:N // Type []Type minlen:N,maxlen:M // opaque[N] [N]byte / [N]uint8 // uint8[N] [N]byte / [N]uint8 // struct { } struct { } // select(T) { // case e1: Type *T selector:Field,val:e1 // } // // TLS variants (RFC 5246 s4.6.1) are only supported when the value of the // associated enumeration type is available earlier in the same enclosing // struct, and each possible variant is marked with a selector tag (to // indicate which field selects the variants) and a val tag (to indicate // what value of the selector picks this particular field). // // For example, a TLS structure: // // enum { e1(1), e2(2) } EnumType; // struct { // EnumType sel; // select(sel) { // case e1: uint16 // case e2: uint32 // } data; // } VariantItem; // // would have a corresponding Go type: // // type VariantItem struct { // Sel tls.Enum `tls:"maxval:2"` // Data16 *uint16 `tls:"selector:Sel,val:1"` // Data32 *uint32 `tls:"selector:Sel,val:2"` // } // // TLS fixed-length vectors of types other than opaque or uint8 are not supported. // // For TLS variable-length vectors that are themselves used in other vectors, // create a single-field structure to represent the inner type. For example, for: // // opaque InnerType<1..65535>; // struct { // InnerType inners<1,65535>; // } Something; // // convert to: // // type InnerType struct { // Val []byte `tls:"minlen:1,maxlen:65535"` // } // type Something struct { // Inners []InnerType `tls:"minlen:1,maxlen:65535"` // } // // If the encoded value does not fit in the Go type, Unmarshal returns a parse error. func Unmarshal(b []byte, val interface{}) ([]byte, error) { return UnmarshalWithParams(b, val, "") } // UnmarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func UnmarshalWithParams(b []byte, val interface{}, params string) ([]byte, error) { info, err := fieldTagToFieldInfo(params, "") if err != nil { return nil, err } // The passed in interface{} is a pointer (to allow the value to be written // to); extract the pointed-to object as a reflect.Value, so parseField // can do various introspection things. v := reflect.ValueOf(val).Elem() offset, err := parseField(v, b, 0, info) if err != nil { return nil, err } return b[offset:], nil } // Return the number of bytes needed to encode values up to (and including) x. func byteCount(x uint64) uint { switch { case x < 0x100: return 1 case x < 0x10000: return 2 case x < 0x1000000: return 3 case x < 0x100000000: return 4 case x < 0x10000000000: return 5 case x < 0x1000000000000: return 6 case x < 0x100000000000000: return 7 default: return 8 } } type fieldInfo struct { count uint // Number of bytes countSet bool minlen uint64 // Only relevant for slices maxlen uint64 // Only relevant for slices selector string // Only relevant for select sub-values val uint64 // Only relevant for select sub-values name string // Used for better error messages } func (i *fieldInfo) fieldName() string { if i == nil { return "" } return i.name } // Given a tag string, return a fieldInfo describing the field. func fieldTagToFieldInfo(str string, name string) (*fieldInfo, error) { var info *fieldInfo // Iterate over clauses in the tag, ignoring any that don't parse properly. for _, part := range strings.Split(str, ",") { switch { case strings.HasPrefix(part, "maxval:"): if v, err := strconv.ParseUint(part[7:], 10, 64); err == nil { info = &fieldInfo{count: byteCount(v), countSet: true} } case strings.HasPrefix(part, "size:"): if sz, err := strconv.ParseUint(part[5:], 10, 32); err == nil { info = &fieldInfo{count: uint(sz), countSet: true} } case strings.HasPrefix(part, "maxlen:"): v, err := strconv.ParseUint(part[7:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.count = byteCount(v) info.countSet = true info.maxlen = v case strings.HasPrefix(part, "minlen:"): v, err := strconv.ParseUint(part[7:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.minlen = v case strings.HasPrefix(part, "selector:"): if info == nil { info = &fieldInfo{} } info.selector = part[9:] case strings.HasPrefix(part, "val:"): v, err := strconv.ParseUint(part[4:], 10, 64) if err != nil { continue } if info == nil { info = &fieldInfo{} } info.val = v } } if info != nil { info.name = name if info.selector == "" { if info.count < 1 { return nil, structuralError{name, "field of unknown size in " + str} } else if info.count > 8 { return nil, structuralError{name, "specified size too large in " + str} } else if info.minlen > info.maxlen { return nil, structuralError{name, "specified length range inverted in " + str} } else if info.val > 0 { return nil, structuralError{name, "specified selector value but not field in " + str} } } } else if name != "" { info = &fieldInfo{name: name} } return info, nil } // Check that a value fits into a field described by a fieldInfo structure. func (i fieldInfo) check(val uint64, fldName string) error { if val >= (1 << (8 * i.count)) { return structuralError{fldName, fmt.Sprintf("value %d too large for size", val)} } if i.maxlen != 0 { if val < i.minlen { return structuralError{fldName, fmt.Sprintf("value %d too small for minimum %d", val, i.minlen)} } if val > i.maxlen { return structuralError{fldName, fmt.Sprintf("value %d too large for maximum %d", val, i.maxlen)} } } return nil } // readVarUint reads an big-endian unsigned integer of the given size in // bytes. func readVarUint(data []byte, info *fieldInfo) (uint64, error) { if info == nil || !info.countSet { return 0, structuralError{info.fieldName(), "no field size information available"} } if len(data) < int(info.count) { return 0, syntaxError{info.fieldName(), "truncated variable-length integer"} } var result uint64 for i := uint(0); i < info.count; i++ { result = (result << 8) | uint64(data[i]) } if err := info.check(result, info.name); err != nil { return 0, err } return result, nil } // parseField is the main parsing function. Given a byte slice and an offset // (in bytes) into the data, it will try to parse a suitable ASN.1 value out // and store it in the given Value. func parseField(v reflect.Value, data []byte, initOffset int, info *fieldInfo) (int, error) { offset := initOffset rest := data[offset:] fieldType := v.Type() // First look for known fixed types. switch fieldType { case uint8Type: if len(rest) < 1 { return offset, syntaxError{info.fieldName(), "truncated uint8"} } v.SetUint(uint64(rest[0])) offset++ return offset, nil case uint16Type: if len(rest) < 2 { return offset, syntaxError{info.fieldName(), "truncated uint16"} } v.SetUint(uint64(binary.BigEndian.Uint16(rest))) offset += 2 return offset, nil case uint24Type: if len(rest) < 3 { return offset, syntaxError{info.fieldName(), "truncated uint24"} } v.SetUint(uint64(data[0])<<16 | uint64(data[1])<<8 | uint64(data[2])) offset += 3 return offset, nil case uint32Type: if len(rest) < 4 { return offset, syntaxError{info.fieldName(), "truncated uint32"} } v.SetUint(uint64(binary.BigEndian.Uint32(rest))) offset += 4 return offset, nil case uint64Type: if len(rest) < 8 { return offset, syntaxError{info.fieldName(), "truncated uint64"} } v.SetUint(uint64(binary.BigEndian.Uint64(rest))) offset += 8 return offset, nil } // Now deal with user-defined types. switch v.Kind() { case enumType.Kind(): // Assume that anything of the same kind as Enum is an Enum, so that // users can alias types of their own to Enum. val, err := readVarUint(rest, info) if err != nil { return offset, err } v.SetUint(val) offset += int(info.count) return offset, nil case reflect.Struct: structType := fieldType // TLS includes a select(Enum) {..} construct, where the value of an enum // indicates which variant field is present (like a C union). We require // that the enum value be an earlier field in the same structure (the selector), // and that each of the possible variant destination fields be pointers. // So the Go mapping looks like: // type variantType struct { // Which tls.Enum `tls:"size:1"` // this is the selector // Val1 *type1 `tls:"selector:Which,val:1"` // this is a destination // Val2 *type2 `tls:"selector:Which,val:1"` // this is a destination // } // To deal with this, we track any enum-like fields and their values... enums := make(map[string]uint64) // .. and we track which selector names we've seen (in the destination field tags), // and whether a destination for that selector has been chosen. selectorSeen := make(map[string]bool) for i := 0; i < structType.NumField(); i++ { // Find information about this field. tag := structType.Field(i).Tag.Get("tls") fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name) if err != nil { return offset, err } destination := v.Field(i) if fieldInfo.selector != "" { // This is a possible select(Enum) destination, so first check that the referenced // selector field has already been seen earlier in the struct. choice, ok := enums[fieldInfo.selector] if !ok { return offset, structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector} } if structType.Field(i).Type.Kind() != reflect.Ptr { return offset, structuralError{fieldInfo.name, "choice field not a pointer type"} } // Is this the first mention of the selector field name? If so, remember it. seen, ok := selectorSeen[fieldInfo.selector] if !ok { selectorSeen[fieldInfo.selector] = false } if choice != fieldInfo.val { // This destination field was not the chosen one, so make it nil (we checked // it was a pointer above). v.Field(i).Set(reflect.Zero(structType.Field(i).Type)) continue } if seen { // We already saw a different destination field receive the value for this // selector value, which indicates a badly annotated structure. return offset, structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector} } selectorSeen[fieldInfo.selector] = true // Make an object of the pointed-to type and parse into that. v.Field(i).Set(reflect.New(structType.Field(i).Type.Elem())) destination = v.Field(i).Elem() } offset, err = parseField(destination, data, offset, fieldInfo) if err != nil { return offset, err } // Remember any possible tls.Enum values encountered in case they are selectors. if structType.Field(i).Type.Kind() == enumType.Kind() { enums[structType.Field(i).Name] = v.Field(i).Uint() } } // Now we have seen all fields in the structure, check that all select(Enum) {..} selector // fields found a destination to put their data in. for selector, seen := range selectorSeen { if !seen { return offset, syntaxError{info.fieldName(), selector + ": unhandled value for selector"} } } return offset, nil case reflect.Array: datalen := v.Len() if datalen > len(rest) { return offset, syntaxError{info.fieldName(), "truncated array"} } inner := rest[:datalen] offset += datalen if fieldType.Elem().Kind() != reflect.Uint8 { // Only byte/uint8 arrays are supported return offset, structuralError{info.fieldName(), "unsupported array type: " + v.Type().String()} } reflect.Copy(v, reflect.ValueOf(inner)) return offset, nil case reflect.Slice: sliceType := fieldType // Slices represent variable-length vectors, which are prefixed by a length field. // The fieldInfo indicates the size of that length field. varlen, err := readVarUint(rest, info) if err != nil { return offset, err } datalen := int(varlen) offset += int(info.count) rest = rest[info.count:] if datalen > len(rest) { return offset, syntaxError{info.fieldName(), "truncated slice"} } inner := rest[:datalen] offset += datalen if fieldType.Elem().Kind() == reflect.Uint8 { // Fast version for []byte v.Set(reflect.MakeSlice(sliceType, datalen, datalen)) reflect.Copy(v, reflect.ValueOf(inner)) return offset, nil } v.Set(reflect.MakeSlice(sliceType, 0, datalen)) single := reflect.New(sliceType.Elem()) for innerOffset := 0; innerOffset < len(inner); { var err error innerOffset, err = parseField(single.Elem(), inner, innerOffset, nil) if err != nil { return offset, err } v.Set(reflect.Append(v, single.Elem())) } return offset, nil default: return offset, structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())} } } // Marshal returns the TLS encoding of val. func Marshal(val interface{}) ([]byte, error) { return MarshalWithParams(val, "") } // MarshalWithParams returns the TLS encoding of val, and allows field // parameters to be specified for the top-level element. The form // of the params is the same as the field tags. func MarshalWithParams(val interface{}, params string) ([]byte, error) { info, err := fieldTagToFieldInfo(params, "") if err != nil { return nil, err } var out bytes.Buffer v := reflect.ValueOf(val) if err := marshalField(&out, v, info); err != nil { return nil, err } return out.Bytes(), err } func marshalField(out *bytes.Buffer, v reflect.Value, info *fieldInfo) error { var prefix string if info != nil && len(info.name) > 0 { prefix = info.name + ": " } fieldType := v.Type() // First look for known fixed types. switch fieldType { case uint8Type: out.WriteByte(byte(v.Uint())) return nil case uint16Type: scratch := make([]byte, 2) binary.BigEndian.PutUint16(scratch, uint16(v.Uint())) out.Write(scratch) return nil case uint24Type: i := v.Uint() if i > 0xffffff { return structuralError{info.fieldName(), fmt.Sprintf("uint24 overflow %d", i)} } scratch := make([]byte, 4) binary.BigEndian.PutUint32(scratch, uint32(i)) out.Write(scratch[1:]) return nil case uint32Type: scratch := make([]byte, 4) binary.BigEndian.PutUint32(scratch, uint32(v.Uint())) out.Write(scratch) return nil case uint64Type: scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(v.Uint())) out.Write(scratch) return nil } // Now deal with user-defined types. switch v.Kind() { case enumType.Kind(): i := v.Uint() if info == nil { return structuralError{info.fieldName(), "enum field tag missing"} } if err := info.check(i, prefix); err != nil { return err } scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(i)) out.Write(scratch[(8 - info.count):]) return nil case reflect.Struct: structType := fieldType enums := make(map[string]uint64) // Values of any Enum fields // The comment parseField() describes the mapping of the TLS select(Enum) {..} construct; // here we have selector and source (rather than destination) fields. // Track which selector names we've seen (in the source field tags), and whether a source // value for that selector has been processed. selectorSeen := make(map[string]bool) for i := 0; i < structType.NumField(); i++ { // Find information about this field. tag := structType.Field(i).Tag.Get("tls") fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name) if err != nil { return err } source := v.Field(i) if fieldInfo.selector != "" { // This field is a possible source for a select(Enum) {..}. First check // the selector field name has been seen. choice, ok := enums[fieldInfo.selector] if !ok { return structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector} } if structType.Field(i).Type.Kind() != reflect.Ptr { return structuralError{fieldInfo.name, "choice field not a pointer type"} } // Is this the first mention of the selector field name? If so, remember it. seen, ok := selectorSeen[fieldInfo.selector] if !ok { selectorSeen[fieldInfo.selector] = false } if choice != fieldInfo.val { // This source was not chosen; police that it should be nil. if v.Field(i).Pointer() != uintptr(0) { return structuralError{fieldInfo.name, "unchosen field is non-nil"} } continue } if seen { // We already saw a different source field generate the value for this // selector value, which indicates a badly annotated structure. return structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector} } selectorSeen[fieldInfo.selector] = true if v.Field(i).Pointer() == uintptr(0) { return structuralError{fieldInfo.name, "chosen field is nil"} } // Marshal from the pointed-to source object. source = v.Field(i).Elem() } var fieldData bytes.Buffer if err := marshalField(&fieldData, source, fieldInfo); err != nil { return err } out.Write(fieldData.Bytes()) // Remember any tls.Enum values encountered in case they are selectors. if structType.Field(i).Type.Kind() == enumType.Kind() { enums[structType.Field(i).Name] = v.Field(i).Uint() } } // Now we have seen all fields in the structure, check that all select(Enum) {..} selector // fields found a source field get get their data from. for selector, seen := range selectorSeen { if !seen { return syntaxError{info.fieldName(), selector + ": unhandled value for selector"} } } return nil case reflect.Array: datalen := v.Len() arrayType := fieldType if arrayType.Elem().Kind() != reflect.Uint8 { // Only byte/uint8 arrays are supported return structuralError{info.fieldName(), "unsupported array type"} } bytes := make([]byte, datalen) for i := 0; i < datalen; i++ { bytes[i] = uint8(v.Index(i).Uint()) } _, err := out.Write(bytes) return err case reflect.Slice: if info == nil { return structuralError{info.fieldName(), "slice field tag missing"} } sliceType := fieldType if sliceType.Elem().Kind() == reflect.Uint8 { // Fast version for []byte: first write the length as info.count bytes. datalen := v.Len() scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, uint64(datalen)) out.Write(scratch[(8 - info.count):]) if err := info.check(uint64(datalen), prefix); err != nil { return err } // Then just write the data. bytes := make([]byte, datalen) for i := 0; i < datalen; i++ { bytes[i] = uint8(v.Index(i).Uint()) } _, err := out.Write(bytes) return err } // General version: use a separate Buffer to write the slice entries into. var innerBuf bytes.Buffer for i := 0; i < v.Len(); i++ { if err := marshalField(&innerBuf, v.Index(i), nil); err != nil { return err } } // Now insert (and check) the size. size := uint64(innerBuf.Len()) if err := info.check(size, prefix); err != nil { return err } scratch := make([]byte, 8) binary.BigEndian.PutUint64(scratch, size) out.Write(scratch[(8 - info.count):]) // Then copy the data. _, err := out.Write(innerBuf.Bytes()) return err default: return structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())} } }