diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index c2c0ee420a..65f018d014 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -22,6 +22,7 @@ package asn1 import ( "errors" "fmt" + "math" "math/big" "reflect" "strconv" @@ -293,16 +294,24 @@ type Flag bool // given byte slice. It returns the value and the new offset. func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) { offset = initOffset + var ret64 int64 for shifted := 0; offset < len(bytes); shifted++ { - if shifted == 4 { + // 5 * 7 bits per byte == 35 bits of data + // Thus the representation is either non-minimal or too large for an int32 + if shifted == 5 { err = StructuralError{"base 128 integer too large"} return } - ret <<= 7 + ret64 <<= 7 b := bytes[offset] - ret |= int(b & 0x7f) + ret64 |= int64(b & 0x7f) offset++ if b&0x80 == 0 { + ret = int(ret64) + // Ensure that the returned value fits in an int on all platforms + if ret64 > math.MaxInt32 { + err = StructuralError{"base 128 integer too large"} + } return } } diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index 9976656df8..2dd799f236 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -7,6 +7,7 @@ package asn1 import ( "bytes" "fmt" + "math" "math/big" "reflect" "strings" @@ -386,6 +387,8 @@ var tagAndLengthData = []tagAndLengthTest{ {[]byte{0xa0, 0x81, 0x7f}, false, tagAndLength{}}, // Tag numbers which would overflow int32 are rejected. (The value below is 2^31.) {[]byte{0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00}, false, tagAndLength{}}, + // Tag numbers that fit in an int32 are valid. (The value below is 2^31 - 1.) + {[]byte{0x1f, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x00}, true, tagAndLength{tag: math.MaxInt32}}, // Long tag number form may not be used for tags that fit in short form. {[]byte{0x1f, 0x1e, 0x00}, false, tagAndLength{}}, }