diff --git a/ietf-cms/protocol/ber.go b/ietf-cms/protocol/ber.go index f1bdb7d..c7535d1 100644 --- a/ietf-cms/protocol/ber.go +++ b/ietf-cms/protocol/ber.go @@ -206,14 +206,8 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } else { var subObjects []asn1Object for (offset < contentEnd) || indefinite { - var subObj asn1Object - var err error - subObj, offset, err = readObject(ber, offset) - if err != nil { - return nil, 0, err - } - subObjects = append(subObjects, subObj) - + // Check for the terminator before reading, since an indefinite + // length object may be empty. if indefinite { terminated, err := isIndefiniteTermination(ber, offset) if err != nil { @@ -224,6 +218,14 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { break } } + + var subObj asn1Object + var err error + subObj, offset, err = readObject(ber, offset) + if err != nil { + return nil, 0, err + } + subObjects = append(subObjects, subObj) } obj = asn1Structured{ tagBytes: ber[tagStart:tagEnd], diff --git a/ietf-cms/protocol/ber_test.go b/ietf-cms/protocol/ber_test.go index accc3b8..4071974 100644 --- a/ietf-cms/protocol/ber_test.go +++ b/ietf-cms/protocol/ber_test.go @@ -97,3 +97,25 @@ func TestBer2Der_NestedMultipleIndefinite(t *testing.T) { t.Errorf("Resulting DER has trailing data: % X", rest) } } + +func TestBer2Der_EmptyIndefinite(t *testing.T) { + fixtures := []struct { + Name string + Input []byte + Expected []byte + }{ + {"empty sequence", []byte{0x30, 0x80, 0x00, 0x00}, []byte{0x30, 0x00}}, + {"empty set followed by sibling", []byte{0x30, 0x80, 0x31, 0x80, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00}, []byte{0x30, 0x05, 0x31, 0x00, 0x02, 0x01, 0x01}}, + } + + for _, fixture := range fixtures { + der, err := BER2DER(fixture.Input) + if err != nil { + t.Errorf("%s: ber2der failed with error: %v", fixture.Name, err) + continue + } + if !bytes.Equal(der, fixture.Expected) { + t.Errorf("%s: ber2der result did not match.\n\tExpected: % X\n\tActual: % X", fixture.Name, fixture.Expected, der) + } + } +}