From: Kyle Isom Date: Thu, 4 Jun 2015 20:23:25 +0000 (-0700) Subject: encoding/asn1: check bounds when parsing tag and length X-Git-Tag: go1.5beta1~271 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=38e3427b2ffd90c4eca3643069a21c6e936566de;p=gostls13.git encoding/asn1: check bounds when parsing tag and length This was found while fuzzing another program, triggering a panic in x509.ParseECPrivateKey. Fixes #11154 Change-Id: Ief35ead38adf14caec4d37b9eacf8a92e67cd1e6 Reviewed-on: https://go-review.googlesource.com/10712 Reviewed-by: Adam Langley Run-TryBot: Adam Langley --- diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index 7172c1c786..b4457e02dc 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -20,6 +20,7 @@ package asn1 // everything by any means. import ( + "errors" "fmt" "math/big" "reflect" @@ -389,6 +390,12 @@ type RawContent []byte // don't distinguish between ordered and unordered objects in this code. func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) { offset = initOffset + // parseTagAndLength should not be called without at least a single + // byte to read. Thus this check is for robustness: + if offset >= len(bytes) { + err = errors.New("asn1: internal error in parseTagAndLength") + return + } b := bytes[offset] offset++ ret.class = int(b >> 6) @@ -611,6 +618,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if params.application { expectedClass = classApplication } + if offset == len(bytes) { + err = StructuralError{"explicit tag has no child"} + return + } if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) { if t.length > 0 { t, offset, err = parseTagAndLength(bytes, offset) diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index 1a2ae2569f..32e9ff2b0c 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -867,3 +867,22 @@ func TestImplicitTaggedTime(t *testing.T) { t.Errorf("Wrong result. Got %v, want %v", result.Time, expected) } } + +type truncatedExplicitTagTest struct { + Test int `asn1:"explicit,tag:0"` +} + +func TestTruncatedExplicitTag(t *testing.T) { + // This crashed Unmarshal in the past. See #11154. + der := []byte{ + 0x30, // SEQUENCE + 0x02, // two bytes long + 0xa0, // context-specific, tag 0 + 0x30, // 48 bytes long + } + + var result truncatedExplicitTagTest + if _, err := Unmarshal(der, &result); err == nil { + t.Error("Unmarshal returned without error") + } +}