package ber import ( "bytes" "fmt" "io" "io/ioutil" "math" "testing" ) var errEOF = io.ErrUnexpectedEOF.Error() // Tests from http://www.strozhevsky.com/free_docs/free_asn1_testsuite_descr.pdf // Source files and descriptions at http://www.strozhevsky.com/free_docs/TEST_SUITE.zip var testcases = []struct { // File contains the path to the BER-encoded file File string // Error indicates whether a decoding error is expected Error string // AbnormalEncoding indicates whether a normalized re-encoding is expected to differ from the original source AbnormalEncoding bool // IndefiniteEncoding indicates the source file used indefinite-length encoding, so the re-encoding is expected to differ (since the length is known) IndefiniteEncoding bool }{ // Common blocks {File: "tests/tc1.ber", Error: "high-tag-number tag overflow"}, {File: "tests/tc2.ber", Error: errEOF}, {File: "tests/tc3.ber", Error: errEOF}, {File: "tests/tc4.ber", Error: "invalid length byte 0xff"}, {File: "tests/tc5.ber", Error: "", AbnormalEncoding: true}, // Real numbers (some expected failures are disabled until support is added) {File: "tests/tc6.ber", Error: ""}, // Error: "REAL value +0 must be encoded with zero-length value block"}, {File: "tests/tc7.ber", Error: ""}, // Error: "REAL value -0 must be encoded as a special value"}, {File: "tests/tc8.ber", Error: ""}, {File: "tests/tc9.ber", Error: ""}, // Error: "Bits 6 and 5 of information octet for REAL are equal to 11" {File: "tests/tc10.ber", Error: ""}, {File: "tests/tc11.ber", Error: ""}, // Error: "Incorrect NR form" {File: "tests/tc12.ber", Error: ""}, // Error: "Encoding of "special value" not from ASN.1 standard" {File: "tests/tc13.ber", Error: errEOF}, {File: "tests/tc14.ber", Error: errEOF}, {File: "tests/tc15.ber", Error: ""}, // Error: "Too big value of exponent" {File: "tests/tc16.ber", Error: ""}, // Error: "Too big value of mantissa" {File: "tests/tc17.ber", Error: ""}, // Error: "Too big values for exponent and mantissa + using of "scaling factor" value" // Integers {File: "tests/tc18.ber", Error: ""}, {File: "tests/tc19.ber", Error: errEOF}, {File: "tests/tc20.ber", Error: ""}, // Object identifiers {File: "tests/tc21.ber", Error: ""}, {File: "tests/tc22.ber", Error: ""}, {File: "tests/tc23.ber", Error: errEOF}, {File: "tests/tc24.ber", Error: ""}, // Booleans {File: "tests/tc25.ber", Error: ""}, {File: "tests/tc26.ber", Error: ""}, {File: "tests/tc27.ber", Error: errEOF}, {File: "tests/tc28.ber", Error: ""}, {File: "tests/tc29.ber", Error: ""}, // Null {File: "tests/tc30.ber", Error: ""}, {File: "tests/tc31.ber", Error: errEOF}, {File: "tests/tc32.ber", Error: ""}, // Bitstring (some expected failures are disabled until support is added) {File: "tests/tc33.ber", Error: ""}, // Error: "Too big value for "unused bits"" {File: "tests/tc34.ber", Error: errEOF}, {File: "tests/tc35.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from BIT STRING types as internal types for constructive encoding" {File: "tests/tc36.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of "unused bits" in internal BIT STRINGs with constructive form of encoding" {File: "tests/tc37.ber", Error: ""}, {File: "tests/tc38.ber", Error: "", IndefiniteEncoding: true}, {File: "tests/tc39.ber", Error: ""}, {File: "tests/tc40.ber", Error: ""}, // Octet string (some expected failures are disabled until support is added) {File: "tests/tc41.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from OCTET STRING types as internal types for constructive encoding" {File: "tests/tc42.ber", Error: errEOF}, {File: "tests/tc43.ber", Error: errEOF}, {File: "tests/tc44.ber", Error: ""}, {File: "tests/tc45.ber", Error: ""}, // Bitstring {File: "tests/tc46.ber", Error: "indefinite length used with primitive type"}, {File: "tests/tc47.ber", Error: "eoc child not allowed with definite length"}, {File: "tests/tc48.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of more than 7 "unused bits" in BIT STRING with constrictive encoding form" {File: "tests/tc49.ber", Error: ""}, {File: "tests/tc50.ber", Error: is64bit("length cannot be less than -1", "long-form length overflow")}, {File: "tests/tc51.ber", Error: is64bit(fmt.Sprintf("length 206966894640 greater than maximum %v", MaxPacketLengthBytes), "long-form length overflow")}, } func is64bit(a, b string) string { maxInt64 := int64(math.MaxInt64) length := int(maxInt64) if int64(length) != maxInt64 { return b } return a } func TestSuiteDecodePacket(t *testing.T) { // Debug = true for _, tc := range testcases { file := tc.File dataIn, err := ioutil.ReadFile(file) if err != nil { t.Errorf("%s: %v", file, err) continue } // fmt.Printf("%s: decode %d\n", file, len(dataIn)) packet, err := DecodePacketErr(dataIn) if err != nil { if tc.Error == "" { t.Errorf("%s: unexpected error during DecodePacket: %v", file, err) } else if tc.Error != err.Error() { t.Errorf("%s: expected error %q during DecodePacket, got %q", file, tc.Error, err) } continue } if tc.Error != "" { t.Errorf("%s: expected error %q, got none", file, tc.Error) continue } dataOut := packet.Bytes() if tc.AbnormalEncoding || tc.IndefiniteEncoding { // Abnormal encodings and encodings that used indefinite length should re-encode differently if bytes.Equal(dataOut, dataIn) { t.Errorf("%s: data should have been re-encoded differently", file) } } else if !bytes.Equal(dataOut, dataIn) { // Make sure the serialized data matches the source t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataIn, dataOut) } packet, err = DecodePacketErr(dataOut) if err != nil { t.Errorf("%s: unexpected error: %v", file, err) continue } // Make sure the re-serialized data matches our original serialization dataOut2 := packet.Bytes() if !bytes.Equal(dataOut, dataOut2) { t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataOut, dataOut2) } } } func TestSuiteReadPacket(t *testing.T) { for _, tc := range testcases { file := tc.File dataIn, err := ioutil.ReadFile(file) if err != nil { t.Errorf("%s: %v", file, err) continue } buffer := bytes.NewBuffer(dataIn) packet, err := ReadPacket(buffer) if err != nil { if tc.Error == "" { t.Errorf("%s: unexpected error during ReadPacket: %v", file, err) } else if tc.Error != err.Error() { t.Errorf("%s: expected error %q during ReadPacket, got %q", file, tc.Error, err) } continue } if tc.Error != "" { t.Errorf("%s: expected error %q, got none", file, tc.Error) continue } dataOut := packet.Bytes() if tc.AbnormalEncoding || tc.IndefiniteEncoding { // Abnormal encodings and encodings that used indefinite length should re-encode differently if bytes.Equal(dataOut, dataIn) { t.Errorf("%s: data should have been re-encoded differently", file) } } else if !bytes.Equal(dataOut, dataIn) { // Make sure the serialized data matches the source t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataIn, dataOut) } packet, err = DecodePacketErr(dataOut) if err != nil { t.Errorf("%s: unexpected error: %v", file, err) continue } // Make sure the re-serialized data matches our original serialization dataOut2 := packet.Bytes() if !bytes.Equal(dataOut, dataOut2) { t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataOut, dataOut2) } } }