270 lines
6.0 KiB
Go
270 lines
6.0 KiB
Go
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)
|
|
}
|
|
}
|