// TestVarStringOverflowErrors performs tests to ensure deserializing variable // length strings intentionally crafted to use large values for the string // length are handled properly. This could otherwise potentially be used as an // attack vector. func TestVarStringOverflowErrors(t *testing.T) { pver := btcwire.ProtocolVersion tests := []struct { buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding err error // Expected error }{ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, pver, &btcwire.MessageError{}}, {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, pver, &btcwire.MessageError{}}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. rbuf := bytes.NewBuffer(test.buf) _, err := btcwire.TstReadVarString(rbuf, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("readVarString #%d wrong error got: %v, "+ "want: %v", i, err, reflect.TypeOf(test.err)) continue } } }
// TestVarStringWire tests wire encode and decode for variable length strings. func TestVarStringWire(t *testing.T) { pver := btcwire.ProtocolVersion // str256 is a string that takes a 2-byte varint to encode. str256 := strings.Repeat("test", 64) tests := []struct { in string // String to encode out string // String to decoded value buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. // Empty string {"", "", []byte{0x00}, pver}, // Single byte varint + string {"Test", "Test", append([]byte{0x04}, []byte("Test")...), pver}, // 2-byte varint + string {str256, str256, append([]byte{0xfd, 0x00, 0x01}, []byte(str256)...), pver}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. var buf bytes.Buffer err := btcwire.TstWriteVarString(&buf, test.pver, test.in) if err != nil { t.Errorf("writeVarString #%d error %v", i, err) continue } if !bytes.Equal(buf.Bytes(), test.buf) { t.Errorf("writeVarString #%d\n got: %s want: %s", i, spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) continue } // Decode from wire format. rbuf := bytes.NewBuffer(test.buf) val, err := btcwire.TstReadVarString(rbuf, test.pver) if err != nil { t.Errorf("readVarString #%d error %v", i, err) continue } if val != test.out { t.Errorf("readVarString #%d\n got: %d want: %d", i, val, test.out) continue } } }
// TestVarStringWireErrors performs negative tests against wire encode and // decode of variable length strings to confirm error paths work correctly. func TestVarStringWireErrors(t *testing.T) { pver := btcwire.ProtocolVersion // str256 is a string that takes a 2-byte varint to encode. str256 := strings.Repeat("test", 64) tests := []struct { in string // Value to encode buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding max int // Max size of fixed buffer to induce errors writeErr error // Expected write error readErr error // Expected read error }{ // Latest protocol version with intentional read/write errors. // Force errors on empty string. {"", []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF}, // Force error on single byte varint + string. {"Test", []byte{0x04}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force errors on 2-byte varint + string. {str256, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) err := btcwire.TstWriteVarString(w, test.pver, test.in) if err != test.writeErr { t.Errorf("writeVarString #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } // Decode from wire format. r := newFixedReader(test.max, test.buf) _, err = btcwire.TstReadVarString(r, test.pver) if err != test.readErr { t.Errorf("readVarString #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } } }
// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a // ten byte variable length string. func BenchmarkReadVarStr10(b *testing.B) { buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'} for i := 0; i < b.N; i++ { btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) } }
// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a // four byte variable length string. func BenchmarkReadVarStr4(b *testing.B) { buf := []byte{0x04, 't', 'e', 's', 't'} for i := 0; i < b.N; i++ { btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) } }