package syntax import ( "bytes" "encoding/hex" "fmt" "strings" "testing" ) type CrypticString string var ( crypticStringMarshalCalls = 0 crypticStringUnmarshalCalls = 0 ) // A CrypticString marshalls as one length octet followed by the // UTF-8 bytes of the string, XOR'ed with an increasing sequence // starting with the length plus one (L+1, L+2, ...). func (cs CrypticString) MarshalTLS() ([]byte, error) { crypticStringMarshalCalls += 1 l := byte(len(cs)) b := []byte(cs) for i := range b { b[i] ^= l + byte(i) + 1 } return append([]byte{l}, b...), nil } func (cs *CrypticString) UnmarshalTLS(data []byte) (int, error) { crypticStringUnmarshalCalls += 1 if len(data) == 0 { return 0, fmt.Errorf("Length of CrypticString must be at least 1") } l := data[0] if len(data) < int(l)+1 { return 0, fmt.Errorf("TLS data not long enough for CrypticString") } b := data[1 : l+1] for i := range b { b[i] ^= l + byte(i) + 1 } *cs = CrypticString(string(b)) return int(l + 1), nil } // Test cases to use for encode and decode var ( x8 uint8 = 0xA0 z8 = []byte{0xA0} x16 uint16 = 0xB0A0 z16, _ = hex.DecodeString("B0A0") x32 uint32 = 0xD0C0B0A0 z32, _ = hex.DecodeString("D0C0B0A0") x64 uint64 = 0xD0C0B0A090807060 z64, _ = hex.DecodeString("D0C0B0A090807060") xvi = struct { U8 uint8 `tls:"varint"` U16 uint16 `tls:"varint"` U32 uint32 `tls:"varint"` U64 uint64 `tls:"varint"` }{ U8: 0x3f, U16: 0x3fff, U32: 0x3fffffff, U64: 0x3fffffffffffffff, } zvi, _ = hex.DecodeString("3f" + "7fff" + "bfffffff" + "ffffffffffffffff") xa = [5]uint16{0x1111, 0x2222, 0x3333, 0x4444, 0x5555} za, _ = hex.DecodeString("11112222333344445555") xv20 = struct { V []byte `tls:"head=1"` }{V: bytes.Repeat([]byte{0xA0}, 0x20)} zv20, _ = hex.DecodeString("20" + strings.Repeat("A0", 0x20)) xv200 = struct { V []byte `tls:"head=2"` }{V: bytes.Repeat([]byte{0xA0}, 0x200)} zv200, _ = hex.DecodeString("0200" + strings.Repeat("A0", 0x200)) xv20000 = struct { V []byte `tls:"head=3"` }{V: bytes.Repeat([]byte{0xA0}, 0x20000)} zv20000, _ = hex.DecodeString("020000" + strings.Repeat("A0", 0x20000)) xvENohead = struct { V []byte }{V: xv20.V} xvEhead = struct { V []byte `tls:"head=1"` }{V: bytes.Repeat([]byte{0xA0}, 0x100)} xvEmax = struct { V []byte `tls:"head=1,max=31"` }{V: xv20.V} xvEmin = struct { V []byte `tls:"head=1,min=33"` }{V: xv20.V} xs1 = struct { A uint16 B []uint8 `tls:"head=2"` C [4]uint32 }{ A: 0xB0A0, B: []uint8{0xA0, 0xA1, 0xA2, 0xA3, 0xA4}, C: [4]uint32{0x10111213, 0x20212223, 0x30313233, 0x40414243}, } zs1, _ = hex.DecodeString("B0A0" + "0005A0A1A2A3A4" + "10111213202122233031323340414243") xm = CrypticString("hello") zm, _ = hex.DecodeString("056e62646565") xsm = struct { A CrypticString B uint16 C CrypticString }{ A: CrypticString("hello"), B: x16, C: CrypticString("... world!"), } zsm, _ = hex.DecodeString("056e62646565" + "B0A0" + "0a2522232e787f637e7735") xsp = struct { A uint16 B *CrypticString }{ A: x16, B: &xm, } zsp, _ = hex.DecodeString("B0A0" + "056e62646565") ) func TestEncodeInvalidCases(t *testing.T) { x := struct { Strings []string }{Strings: []string{"asdf"}} _, err := Marshal(x) if err == nil { t.Fatalf("Agreed to marshal an unsupported type") } } func TestEncodeBasicTypes(t *testing.T) { y8, err := Marshal(x8) if err != nil || !bytes.Equal(y8, z8) { t.Fatalf("uint8 encode failed [%v] [%x]", err, y8) } y16, err := Marshal(x16) if err != nil || !bytes.Equal(y16, z16) { t.Fatalf("uint16 encode failed [%v] [%x]", err, y16) } y32, err := Marshal(x32) if err != nil || !bytes.Equal(y32, z32) { t.Fatalf("uint32 encode failed [%v] [%x]", err, y32) } y64, err := Marshal(x64) if err != nil || !bytes.Equal(y64, z64) { t.Fatalf("uint64 encode failed [%v] [%x]", err, y64) } } func TestEncodeVarint(t *testing.T) { yvi, err := Marshal(xvi) if err != nil || !bytes.Equal(yvi, zvi) { t.Fatalf("varint encode failed [%v] [%x]", err, yvi) } } func TestEncodeArray(t *testing.T) { ya, err := Marshal(xa) if err != nil || !bytes.Equal(ya, za) { t.Fatalf("[5]uint8 encode failed [%v] [%x]", err, ya) } } func TestEncodeSlice(t *testing.T) { yv20, err := Marshal(xv20) if err != nil || !bytes.Equal(yv20, zv20) { t.Fatalf("[0x20]uint8 encode failed [%v] [%x]", err, yv20) } yv200, err := Marshal(xv200) if err != nil || !bytes.Equal(yv200, zv200) { t.Fatalf("[0x200]uint8 encode failed [%v] [%x]", err, yv200) } yv20000, err := Marshal(xv20000) if err != nil || !bytes.Equal(yv20000, zv20000) { t.Fatalf("[0x20000]uint8 encode failed [%v] [%x]", err, yv20000) } yE, err := Marshal(xvENohead) if err == nil { t.Fatalf("Allowed marshal with no header size [%x]", yE) } yE, err = Marshal(xvEhead) if err == nil { t.Fatalf("Allowed marshal exceeding header size [%x]", yE) } yE, err = Marshal(xvEmax) if err == nil { t.Fatalf("Allowed marshal exceeding max [%x]", yE) } yE, err = Marshal(xvEmin) if err == nil { t.Fatalf("Allowed marshal below min [%x]", yE) } } func TestEncodeStruct(t *testing.T) { ys1, err := Marshal(xs1) if err != nil || !bytes.Equal(ys1, zs1) { t.Fatalf("struct encode failed [%v] [%x]", err, ys1) } } func TestEncodeMarshaler(t *testing.T) { crypticStringMarshalCalls = 0 ym, err := Marshal(xm) if err != nil || !bytes.Equal(ym, zm) { t.Fatalf("Marshaler encode failed [%v] [%x]", err, ym) } if crypticStringMarshalCalls != 1 { t.Fatalf("MarshalTLS() was not called exactly once [%v]", crypticStringMarshalCalls) } crypticStringMarshalCalls = 0 ysm, err := Marshal(xsm) if err != nil || !bytes.Equal(ysm, zsm) { t.Fatalf("Struct-embedded marshaler encode failed [%v] [%x]", err, ysm) } if crypticStringMarshalCalls != 2 { t.Fatalf("MarshalTLS() was not called exactly twice [%v]", crypticStringMarshalCalls) } } func TestEncodeStructWithPointer(t *testing.T) { ysp, err := Marshal(xsp) if err != nil || !bytes.Equal(ysp, zsp) { t.Fatalf("struct encode failed [%v] [%x]", err, ysp) } }