]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/asn1: support 31 bit identifiers with OID
authorMonis Khan <mkhan@redhat.com>
Wed, 12 Apr 2017 20:00:58 +0000 (16:00 -0400)
committerAdam Langley <agl@golang.org>
Thu, 13 Apr 2017 00:49:49 +0000 (00:49 +0000)
The current implementation uses a max of 28 bits when decoding an
ObjectIdentifier.  This change makes it so that an int64 is used to
accumulate up to 35 bits.  If the resulting data would not overflow
an int32, it is used as an int.  Thus up to 31 bits may be used to
represent each subidentifier of an ObjectIdentifier.

Fixes #19933

Change-Id: I95d74b64b24cdb1339ff13421055bce61c80243c
Reviewed-on: https://go-review.googlesource.com/40436
Reviewed-by: Adam Langley <agl@golang.org>
Run-TryBot: Adam Langley <agl@golang.org>

src/encoding/asn1/asn1.go
src/encoding/asn1/asn1_test.go

index c2c0ee420ac878ea7d4e3e221e0e7876038e0498..65f018d0148285506dab76828f1b312b1b55ed90 100644 (file)
@@ -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
                }
        }
index 9976656df8938aeb374b263f383dbd80a6b280c8..2dd799f23626a34d95b3e22a840d399298428776 100644 (file)
@@ -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{}},
 }