Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix indefinite form parsing to parse nested indefinite form correctly. #17

Merged
merged 1 commit into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions ber.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
var length int
l := ber[offset]
offset++
hack := 0
indefinite := false
if l > 0x80 {
numberOfBytes := (int)(l & 0x7F)
if numberOfBytes > 4 { // int is only guaranteed to be 32bit
Expand All @@ -180,14 +180,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
offset++
}
} 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
//fmt.Printf("--> (compute length) marker found at offset: %d\n", markerIndex+offset)
indefinite = true
} else {
length = (int)(l)
}
Expand All @@ -201,6 +194,9 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
//fmt.Printf("--> content end : %d\n", contentEnd)
//fmt.Printf("--> 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],
Expand All @@ -209,20 +205,44 @@ 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],
content: subObjects,
}
}

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
}
38 changes: 37 additions & 1 deletion ber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestBer2Der_Negatives(t *testing.T) {
{[]byte{0x30, 0x85}, "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"},
}

Expand All @@ -59,3 +59,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)
}
}