...

Source file src/github.com/google/certificate-transparency-go/tls/tls_test.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
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/hex"
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  )
    24  
    25  type testStruct struct {
    26  	Data   []byte `tls:"minlen:2,maxlen:4"`
    27  	IntVal uint16
    28  	Other  [4]byte
    29  	Enum   Enum `tls:"size:2"`
    30  }
    31  
    32  type testVariant struct {
    33  	Which Enum    `tls:"size:1"`
    34  	Val16 *uint16 `tls:"selector:Which,val:0"`
    35  	Val32 *uint32 `tls:"selector:Which,val:1"`
    36  }
    37  
    38  type testTwoVariants struct {
    39  	Which    Enum    `tls:"size:1"`
    40  	Val16    *uint16 `tls:"selector:Which,val:0"`
    41  	Val32    *uint32 `tls:"selector:Which,val:1"`
    42  	Second   Enum    `tls:"size:1"`
    43  	Second16 *uint16 `tls:"selector:Second,val:0"`
    44  	Second32 *uint32 `tls:"selector:Second,val:1"`
    45  }
    46  
    47  // Check that library users can define their own Enum types.
    48  type aliasEnum Enum
    49  type testAliasEnum struct {
    50  	Val   aliasEnum `tls:"size:1"`
    51  	Val16 *uint16   `tls:"selector:Val,val:1"`
    52  	Val32 *uint32   `tls:"selector:Val,val:2"`
    53  }
    54  
    55  type testNonByteSlice struct {
    56  	Vals []uint16 `tls:"minlen:2,maxlen:6"`
    57  }
    58  
    59  type testSliceOfStructs struct {
    60  	Vals []testVariant `tls:"minlen:0,maxlen:100"`
    61  }
    62  
    63  type testInnerType struct {
    64  	Val []byte `tls:"minlen:0,maxlen:65535"`
    65  }
    66  
    67  type testSliceOfSlices struct {
    68  	Inners []testInnerType `tls:"minlen:0,maxlen:65535"`
    69  }
    70  
    71  func TestMarshalUnmarshalRoundTrip(t *testing.T) {
    72  	thing := testStruct{Data: []byte{0x01, 0x02, 0x03}, IntVal: 42, Other: [4]byte{1, 2, 3, 4}, Enum: 17}
    73  	data, err := Marshal(thing)
    74  	if err != nil {
    75  		t.Fatalf("Failed to Marshal(%+v): %s", thing, err.Error())
    76  	}
    77  	var other testStruct
    78  	rest, err := Unmarshal(data, &other)
    79  	if err != nil {
    80  		t.Fatalf("Failed to Unmarshal(%s)", hex.EncodeToString(data))
    81  	}
    82  	if len(rest) > 0 {
    83  		t.Errorf("Data left over after Unmarshal(%s): %s", hex.EncodeToString(data), hex.EncodeToString(rest))
    84  	}
    85  }
    86  
    87  func TestFieldTagToFieldInfo(t *testing.T) {
    88  	var tests = []struct {
    89  		tag    string
    90  		want   *fieldInfo
    91  		errstr string
    92  	}{
    93  		{"", nil, ""},
    94  		{"bogus", nil, ""},
    95  		{"also,bogus", nil, ""},
    96  		{"also,bogus:99", nil, ""},
    97  		{"maxval:1xyz", nil, ""},
    98  		{"maxval:1", &fieldInfo{count: 1, countSet: true}, ""},
    99  		{"maxval:255", &fieldInfo{count: 1, countSet: true}, ""},
   100  		{"maxval:256", &fieldInfo{count: 2, countSet: true}, ""},
   101  		{"maxval:65535", &fieldInfo{count: 2, countSet: true}, ""},
   102  		{"maxval:65536", &fieldInfo{count: 3, countSet: true}, ""},
   103  		{"maxval:16777215", &fieldInfo{count: 3, countSet: true}, ""},
   104  		{"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
   105  		{"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
   106  		{"maxval:4294967295", &fieldInfo{count: 4, countSet: true}, ""},
   107  		{"maxval:4294967296", &fieldInfo{count: 5, countSet: true}, ""},
   108  		{"maxval:1099511627775", &fieldInfo{count: 5, countSet: true}, ""},
   109  		{"maxval:1099511627776", &fieldInfo{count: 6, countSet: true}, ""},
   110  		{"maxval:281474976710655", &fieldInfo{count: 6, countSet: true}, ""},
   111  		{"maxval:281474976710656", &fieldInfo{count: 7, countSet: true}, ""},
   112  		{"maxval:72057594037927935", &fieldInfo{count: 7, countSet: true}, ""},
   113  		{"maxval:72057594037927936", &fieldInfo{count: 8, countSet: true}, ""},
   114  		{"minlen:1x", nil, ""},
   115  		{"maxlen:1x", nil, ""},
   116  		{"maxlen:1", &fieldInfo{count: 1, countSet: true, maxlen: 1}, ""},
   117  		{"maxlen:255", &fieldInfo{count: 1, countSet: true, maxlen: 255}, ""},
   118  		{"maxlen:65535", &fieldInfo{count: 2, countSet: true, maxlen: 65535}, ""},
   119  		{"minlen:65530,maxlen:65535", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
   120  		{"maxlen:65535,minlen:65530", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
   121  		{"minlen:65536,maxlen:65535", nil, "inverted"},
   122  		{"maxlen:16777215", &fieldInfo{count: 3, countSet: true, maxlen: 16777215}, ""},
   123  		{"maxlen:281474976710655", &fieldInfo{count: 6, countSet: true, maxlen: 281474976710655}, ""},
   124  		{"maxlen:72057594037927936", &fieldInfo{count: 8, countSet: true, maxlen: 72057594037927936}, ""},
   125  		{"size:0", nil, "unknown size"},
   126  		{"size:1", &fieldInfo{count: 1, countSet: true}, ""},
   127  		{"size:2", &fieldInfo{count: 2, countSet: true}, ""},
   128  		{"size:3", &fieldInfo{count: 3, countSet: true}, ""},
   129  		{"size:4", &fieldInfo{count: 4, countSet: true}, ""},
   130  		{"size:5", &fieldInfo{count: 5, countSet: true}, ""},
   131  		{"size:6", &fieldInfo{count: 6, countSet: true}, ""},
   132  		{"size:7", &fieldInfo{count: 7, countSet: true}, ""},
   133  		{"size:8", &fieldInfo{count: 8, countSet: true}, ""},
   134  		{"size:9", nil, "too large"},
   135  		{"size:1x", nil, ""},
   136  		{"size:1,val:9", nil, "selector value"},
   137  		{"selector:Bob,val:x9", &fieldInfo{selector: "Bob"}, ""},
   138  		{"selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
   139  		{"val:9,selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
   140  	}
   141  	for _, test := range tests {
   142  		got, err := fieldTagToFieldInfo(test.tag, "")
   143  		if test.errstr != "" {
   144  			if err == nil {
   145  				t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want error %q", test.tag, got, test.errstr)
   146  			} else if !strings.Contains(err.Error(), test.errstr) {
   147  				t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want error %q", test.tag, err.Error(), test.errstr)
   148  			}
   149  			continue
   150  		}
   151  		if err != nil {
   152  			t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want %+v", test.tag, err.Error(), test.want)
   153  		} else if !reflect.DeepEqual(got, test.want) {
   154  			t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want %+v", test.tag, got, test.want)
   155  		}
   156  	}
   157  }
   158  
   159  // Can't take the address of a numeric constant so use helper functions
   160  func newByte(n byte) *byte       { return &n }
   161  func newUint8(n uint8) *uint8    { return &n }
   162  func newUint16(n uint16) *uint16 { return &n }
   163  func newUint24(n Uint24) *Uint24 { return &n }
   164  func newUint32(n uint32) *uint32 { return &n }
   165  func newUint64(n uint64) *uint64 { return &n }
   166  func newInt16(n int16) *int16    { return &n }
   167  func newEnum(n Enum) *Enum       { return &n }
   168  
   169  func TestUnmarshalMarshalWithParamsRoundTrip(t *testing.T) {
   170  	var tests = []struct {
   171  		data   string // hex encoded
   172  		params string
   173  		item   interface{}
   174  	}{
   175  		{"00", "", newUint8(0)},
   176  		{"03", "", newByte(3)},
   177  		{"0101", "", newUint16(0x0101)},
   178  		{"010203", "", newUint24(0x010203)},
   179  		{"000000", "", newUint24(0x00)},
   180  		{"00000009", "", newUint32(0x09)},
   181  		{"0000000901020304", "", newUint64(0x0901020304)},
   182  		{"030405", "", &[3]byte{3, 4, 5}},
   183  		{"03", "", &[1]byte{3}},
   184  		{"0001", "size:2", newEnum(1)},
   185  		{"0100000001", "size:5", newEnum(0x100000001)},
   186  		{"12", "maxval:18", newEnum(18)},
   187  		// Note that maxval is just used to give enum size; it's not policed
   188  		{"20", "maxval:18", newEnum(32)},
   189  		{"020a0b", "minlen:1,maxlen:5", &[]byte{0xa, 0xb}},
   190  		{"020a0b0101010203040011", "", &testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}},
   191  		{"000102", "", &testVariant{Which: 0, Val16: newUint16(0x0102)}},
   192  		{"0101020304", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}},
   193  		{"0001020104030201", "", &testTwoVariants{Which: 0, Val16: newUint16(0x0102), Second: 1, Second32: newUint32(0x04030201)}},
   194  		{"06010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}},
   195  		{"00", "", &testSliceOfStructs{Vals: []testVariant{}}},
   196  		{"080001020101020304", "",
   197  			&testSliceOfStructs{
   198  				Vals: []testVariant{
   199  					{Which: 0, Val16: newUint16(0x0102)},
   200  					{Which: 1, Val32: newUint32(0x01020304)},
   201  				},
   202  			},
   203  		},
   204  		{"000a00030102030003040506", "",
   205  			&testSliceOfSlices{
   206  				Inners: []testInnerType{
   207  					{Val: []byte{1, 2, 3}},
   208  					{Val: []byte{4, 5, 6}},
   209  				},
   210  			},
   211  		},
   212  		{"011011", "", &testAliasEnum{Val: 1, Val16: newUint16(0x1011)}},
   213  		{"0403", "", &SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA}},
   214  		{"04030003010203", "",
   215  			&DigitallySigned{
   216  				Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
   217  				Signature: []byte{1, 2, 3},
   218  			},
   219  		},
   220  	}
   221  	for _, test := range tests {
   222  		inVal := reflect.ValueOf(test.item).Elem()
   223  		pv := reflect.New(reflect.TypeOf(test.item).Elem())
   224  		val := pv.Interface()
   225  		inData, _ := hex.DecodeString(test.data)
   226  		if _, err := UnmarshalWithParams(inData, val, test.params); err != nil {
   227  			t.Errorf("Unmarshal(%s)=nil,%q; want %+v", test.data, err.Error(), inVal)
   228  		} else if !reflect.DeepEqual(val, test.item) {
   229  			t.Errorf("Unmarshal(%s)=%+v,nil; want %+v", test.data, reflect.ValueOf(val).Elem(), inVal)
   230  		}
   231  
   232  		if data, err := MarshalWithParams(inVal.Interface(), test.params); err != nil {
   233  			t.Errorf("Marshal(%+v)=nil,%q; want %s", inVal, err.Error(), test.data)
   234  		} else if !bytes.Equal(data, inData) {
   235  			t.Errorf("Marshal(%+v)=%s,nil; want %s", inVal, hex.EncodeToString(data), test.data)
   236  		}
   237  	}
   238  }
   239  
   240  type testInvalidFieldTag struct {
   241  	Data []byte `tls:"minlen:3,maxlen:2"`
   242  }
   243  
   244  type testDuplicateSelectorVal struct {
   245  	Which  Enum    `tls:"size:1"`
   246  	Val    *uint16 `tls:"selector:Which,val:0"`
   247  	DupVal *uint32 `tls:"selector:Which"` // implicit val:0
   248  }
   249  
   250  type testMissingSelector struct {
   251  	Val *uint16 `tls:"selector:Missing,val:0"`
   252  }
   253  
   254  type testChoiceNotPointer struct {
   255  	Which Enum   `tls:"size:1"`
   256  	Val   uint16 `tls:"selector:Which,val:0"`
   257  }
   258  
   259  type nonEnumAlias uint16
   260  
   261  func newNonEnumAlias(n nonEnumAlias) *nonEnumAlias { return &n }
   262  
   263  func TestUnmarshalWithParamsFailures(t *testing.T) {
   264  	var tests = []struct {
   265  		data   string // hex encoded
   266  		params string
   267  		item   interface{}
   268  		errstr string
   269  	}{
   270  		{"", "", newUint8(0), "truncated"},
   271  		{"0x01", "", newUint16(0x0101), "truncated"},
   272  		{"0103", "", newUint24(0x010203), "truncated"},
   273  		{"00", "", newUint24(0x00), "truncated"},
   274  		{"000009", "", newUint32(0x09), "truncated"},
   275  		{"00000901020304", "", newUint64(0x0901020304), "truncated"},
   276  		{"0102", "", newInt16(0x0102), "unsupported type"}, // TLS encoding only supports unsigned integers
   277  		{"0607", "", &[3]byte{6, 7, 8}, "truncated array"},
   278  		{"01010202", "", &[3]uint16{0x101, 0x202}, "unsupported array"},
   279  		{"01", "", newEnum(1), "no field size"},
   280  		{"00", "size:2", newEnum(0), "truncated"},
   281  		{"00", "size:9", newEnum(0), "too large"},
   282  		{"020a0b", "minlen:4,maxlen:8", &[]byte{0x0a, 0x0b}, "too small"},
   283  		{"040a0b0c0d", "minlen:1,maxlen:3", &[]byte{0x0a, 0x0b, 0x0c, 0x0d}, "too large"},
   284  		{"020a0b", "minlen:8,maxlen:6", &[]byte{0x0a, 0x0b}, "inverted"},
   285  		{"020a", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
   286  		{"02", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
   287  		{"0001", "minlen:0,maxlen:256", &[]byte{0x0a, 0x0b}, "truncated"},
   288  		{"020a", "minlen:0", &[]byte{0x0a, 0x0b}, "unknown size"},
   289  		{"020a", "", &[]byte{0x0a, 0x0b}, "no field size information"},
   290  		{"020a0b", "", &testInvalidFieldTag{}, "range inverted"},
   291  		{"020a0b01010102030400", "",
   292  			&testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "truncated"},
   293  		{"010102", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}, "truncated"},
   294  		{"092122", "", &testVariant{Which: 0, Val16: newUint16(0x2122)}, "unhandled value for selector"},
   295  		{"0001020304", "", &testDuplicateSelectorVal{Which: 0, Val: newUint16(0x0102)}, "duplicate selector value"},
   296  		{"0102", "", &testMissingSelector{Val: newUint16(1)}, "selector not seen"},
   297  		{"000007", "", &testChoiceNotPointer{Which: 0, Val: 7}, "choice field not a pointer type"},
   298  		{"05010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}, "truncated"},
   299  		{"0101", "size:2", newNonEnumAlias(0x0102), "unsupported type"},
   300  		{"0403010203", "",
   301  			&DigitallySigned{
   302  				Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
   303  				Signature: []byte{1, 2, 3}}, "truncated"},
   304  	}
   305  	for _, test := range tests {
   306  		pv := reflect.New(reflect.TypeOf(test.item).Elem())
   307  		val := pv.Interface()
   308  		in, _ := hex.DecodeString(test.data)
   309  		if _, err := UnmarshalWithParams(in, val, test.params); err == nil {
   310  			t.Errorf("Unmarshal(%s)=%+v,nil; want error %q", test.data, reflect.ValueOf(val).Elem(), test.errstr)
   311  		} else if !strings.Contains(err.Error(), test.errstr) {
   312  			t.Errorf("Unmarshal(%s)=nil,%q; want error %q", test.data, err.Error(), test.errstr)
   313  		}
   314  	}
   315  }
   316  
   317  func TestMarshalWithParamsFailures(t *testing.T) {
   318  	var tests = []struct {
   319  		item   interface{}
   320  		params string
   321  		errstr string
   322  	}{
   323  		{Uint24(0x1000000), "", "overflow"},
   324  		{int16(0x0102), "", "unsupported type"}, // All TLS ints are unsigned
   325  		{Enum(1), "", "field tag missing"},
   326  		{Enum(256), "size:1", "too large"},
   327  		{Enum(256), "maxval:255", "too large"},
   328  		{Enum(2), "", "field tag missing"},
   329  		{Enum(256), "size:9", "too large"},
   330  		{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:1,maxlen:3", "too large"},
   331  		{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:13", "too small"},
   332  		{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:3", "inverted"},
   333  		{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6", "unknown size"},
   334  		{[]byte{0xa, 0xb, 0xc, 0xd}, "", "field tag missing"},
   335  		{[3]uint16{0x101, 0x202}, "", "unsupported array"},
   336  		{testInvalidFieldTag{}, "", "inverted"},
   337  		{testStruct{Data: []byte{0xa}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "", "too small"},
   338  		{testVariant{Which: 0, Val32: newUint32(0x01020304)}, "", "chosen field is nil"},
   339  		{testVariant{Which: 0, Val16: newUint16(11), Val32: newUint32(0x01020304)}, "", "unchosen field is non-nil"},
   340  		{testVariant{Which: 3}, "", "unhandled value for selector"},
   341  		{testMissingSelector{Val: newUint16(1)}, "", "selector not seen"},
   342  		{testChoiceNotPointer{Which: 0, Val: 7}, "", "choice field not a pointer"},
   343  		{testDuplicateSelectorVal{Which: 0, Val: newUint16(1)}, "", "duplicate selector value"},
   344  		{testNonByteSlice{Vals: []uint16{1, 2, 3, 4}}, "", "too large"},
   345  		{testSliceOfStructs{[]testVariant{{Which: 3}}}, "", "unhandled value for selector"},
   346  		{nonEnumAlias(0x0102), "", "unsupported type"},
   347  	}
   348  	for _, test := range tests {
   349  		if data, err := MarshalWithParams(test.item, test.params); err == nil {
   350  			t.Errorf("Marshal(%+v)=%x,nil; want error %q", test.item, data, test.errstr)
   351  		} else if !strings.Contains(err.Error(), test.errstr) {
   352  			t.Errorf("Marshal(%+v)=nil,%q; want error %q", test.item, err.Error(), test.errstr)
   353  		}
   354  	}
   355  }
   356  

View as plain text