From 8d4fa5c895ea0f64e1a56e32d3d7da9ba4c3e45e Mon Sep 17 00:00:00 2001 From: addie9000 Date: Tue, 11 Apr 2017 17:57:15 +0900 Subject: [PATCH] Fix indefinite form parsing to parse nested indefinite form correctly. cherry pick d25ebd6320a9025082b7e0a90b0309ca913c6266 --- ber.go | 44 ++++++++++++++++++++++++++++++++------------ ber_test.go | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/ber.go b/ber.go index 5852567..73da024 100644 --- a/ber.go +++ b/ber.go @@ -175,7 +175,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } - hack := 0 + indefinite := false if l > 0x80 { numberOfBytes := (int)(l & 0x7F) if numberOfBytes > 4 { // int is only guaranteed to be 32bit @@ -197,14 +197,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } } } else if l == 0x80 { - // find length by searching content - markerIndex := bytes.LastIndex(ber[offset:], []byte{0x0, 0x0}) - if markerIndex == -1 { - return nil, 0, errors.New("ber2der: Invalid BER format") - } - length = markerIndex - hack = 2 - debugprint("--> (compute length) marker found at offset: %d\n", markerIndex+offset) + indefinite = true } else { length = (int)(l) } @@ -220,6 +213,9 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { debugprint("--> content end : %d\n", contentEnd) debugprint("--> content : % X\n", ber[offset:contentEnd]) var obj asn1Object + if indefinite && kind == 0 { + return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") + } if kind == 0 { obj = asn1Primitive{ tagBytes: ber[tagStart:tagEnd], @@ -228,14 +224,25 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } } else { var subObjects []asn1Object - for offset < contentEnd { + for (offset < contentEnd) || indefinite { var subObj asn1Object var err error - subObj, offset, err = readObject(ber[:contentEnd], offset) + subObj, offset, err = readObject(ber, offset) if err != nil { return nil, 0, err } subObjects = append(subObjects, subObj) + + if indefinite { + terminated, err := isIndefiniteTermination(ber, offset) + if err != nil { + return nil, 0, err + } + + if terminated { + break + } + } } obj = asn1Structured{ tagBytes: ber[tagStart:tagEnd], @@ -243,7 +250,20 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } } - return obj, contentEnd + hack, nil + // Apply indefinite form length with 0x0000 terminator. + if indefinite { + contentEnd = offset + 2 + } + + return obj, contentEnd, nil +} + +func isIndefiniteTermination(ber []byte, offset int) (bool, error) { + if len(ber) - offset < 2 { + return false, errors.New("ber2der: Invalid BER format") + } + + return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil } func debugprint(format string, a ...interface{}) { diff --git a/ber_test.go b/ber_test.go index fcb4b6a..52e12cf 100644 --- a/ber_test.go +++ b/ber_test.go @@ -45,7 +45,7 @@ func TestBer2Der_Negatives(t *testing.T) { {[]byte{0x30, 0x85}, "tag length too long"}, {[]byte{0x30, 0x84, 0x80, 0x0, 0x0, 0x0}, "length is negative"}, {[]byte{0x30, 0x82, 0x0, 0x1}, "length has leading zero"}, - {[]byte{0x30, 0x80, 0x1, 0x2}, "Invalid BER format"}, + {[]byte{0x30, 0x80, 0x1, 0x2, 0x1, 0x2}, "Invalid BER format"}, {[]byte{0x30, 0x03, 0x01, 0x02}, "length is more than available data"}, {[]byte{0x30}, "end of ber data reached"}, } @@ -60,3 +60,39 @@ func TestBer2Der_Negatives(t *testing.T) { } } } + +func TestBer2Der_NestedMultipleIndefinite(t *testing.T) { + // indefinite length fixture + ber := []byte{0x30, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00, 0x30, 0x80, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00} + expected := []byte{0x30, 0x0A, 0x30, 0x03, 0x02, 0x01, 0x01, 0x30, 0x03, 0x02, 0x01, 0x02} + + der, err := ber2der(ber) + if err != nil { + t.Fatalf("ber2der failed with error: %v", err) + } + if bytes.Compare(der, expected) != 0 { + t.Errorf("ber2der result did not match.\n\tExpected: % X\n\tActual: % X", expected, der) + } + + if der2, err := ber2der(der); err != nil { + t.Errorf("ber2der on DER bytes failed with error: %v", err) + } else { + if !bytes.Equal(der, der2) { + t.Error("ber2der is not idempotent") + } + } + var thing struct { + Nest1 struct { + Number int + } + Nest2 struct { + Number int + } + } + rest, err := asn1.Unmarshal(der, &thing) + if err != nil { + t.Errorf("Cannot parse resulting DER because: %v", err) + } else if len(rest) > 0 { + t.Errorf("Resulting DER has trailing data: % X", rest) + } +}