Skip to content

Commit 8d91f25

Browse files
feat(asn1): allow ber integers (#2)
This adds a functional option which permits the use of BER encoded ASN.1 integers.
1 parent 179bead commit 8d91f25

3 files changed

Lines changed: 254 additions & 105 deletions

File tree

encoding/asn1/unmarshal.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,29 @@ func parseBool(bytes []byte) (ret bool, err error) {
7979

8080
// checkInteger returns nil if the given bytes are a valid DER-encoded
8181
// INTEGER and an error otherwise.
82-
func checkInteger(bytes []byte) error {
82+
func checkInteger(bytes []byte, allowBER bool) error {
8383
if len(bytes) == 0 {
8484
return StructuralError{"empty integer"}
8585
}
86+
if allowBER {
87+
return nil
88+
}
8689
if len(bytes) == 1 {
8790
return nil
8891
}
89-
if (bytes[0] == 0 && bytes[1]&0x80 == 0) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) {
92+
if (bytes[0] == 0x00 && bytes[1]&0x80 == 0x00) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) {
9093
return StructuralError{"integer not minimally-encoded"}
9194
}
9295
return nil
9396
}
9497

9598
// parseInt64 treats the given bytes as a big-endian, signed integer and
9699
// returns the result.
97-
func parseInt64(bytes []byte) (ret int64, err error) {
98-
err = checkInteger(bytes)
99-
if err != nil {
100+
func parseInt64(bytes []byte, allowBER bool) (ret int64, err error) {
101+
if err = checkInteger(bytes, allowBER); err != nil {
100102
return
101103
}
104+
102105
if len(bytes) > 8 {
103106
// We'll overflow an int64 in this case.
104107
err = StructuralError{"integer too large"}
@@ -117,11 +120,8 @@ func parseInt64(bytes []byte) (ret int64, err error) {
117120

118121
// parseInt32 treats the given bytes as a big-endian, signed integer and returns
119122
// the result.
120-
func parseInt32(bytes []byte) (int32, error) {
121-
if err := checkInteger(bytes); err != nil {
122-
return 0, err
123-
}
124-
ret64, err := parseInt64(bytes)
123+
func parseInt32(bytes []byte, ber bool) (int32, error) {
124+
ret64, err := parseInt64(bytes, ber)
125125
if err != nil {
126126
return 0, err
127127
}
@@ -135,8 +135,8 @@ var bigOne = big.NewInt(1)
135135

136136
// parseBigInt treats the given bytes as a big-endian, signed integer and returns
137137
// the result.
138-
func parseBigInt(bytes []byte) (*big.Int, error) {
139-
if err := checkInteger(bytes); err != nil {
138+
func parseBigInt(bytes []byte, allowBER bool) (*big.Int, error) {
139+
if err := checkInteger(bytes, allowBER); err != nil {
140140
return nil, err
141141
}
142142
ret := new(big.Int)
@@ -751,7 +751,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
751751
case TagUTF8String:
752752
result, err = parseUTF8String(innerBytes)
753753
case TagInteger:
754-
result, err = parseInt64(innerBytes)
754+
result, err = parseInt64(innerBytes, opts.allowBERIntegers)
755755
case TagBitString:
756756
result, err = parseBitString(innerBytes)
757757
case TagOID:
@@ -919,7 +919,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
919919
*v, err = parseGeneralizedTime(innerBytes)
920920
return
921921
case *Enumerated:
922-
parsedInt, err1 := parseInt32(innerBytes)
922+
parsedInt, err1 := parseInt32(innerBytes, opts.allowBERIntegers)
923923
if err1 == nil {
924924
*v = Enumerated(parsedInt)
925925
}
@@ -929,7 +929,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
929929
*v = true
930930
return
931931
case **big.Int:
932-
parsedInt, err1 := parseBigInt(innerBytes)
932+
parsedInt, err1 := parseBigInt(innerBytes, opts.allowBERIntegers)
933933
if err1 == nil {
934934
*v = parsedInt
935935
}
@@ -946,13 +946,13 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
946946
return
947947
case reflect.Int, reflect.Int32, reflect.Int64:
948948
if val.Type().Size() == 4 {
949-
parsedInt, err1 := parseInt32(innerBytes)
949+
parsedInt, err1 := parseInt32(innerBytes, opts.allowBERIntegers)
950950
if err1 == nil {
951951
val.SetInt(int64(parsedInt))
952952
}
953953
err = err1
954954
} else {
955-
parsedInt, err1 := parseInt64(innerBytes)
955+
parsedInt, err1 := parseInt64(innerBytes, opts.allowBERIntegers)
956956
if err1 == nil {
957957
val.SetInt(parsedInt)
958958
}

encoding/asn1/unmarshal_opts.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package asn1
22

33
type unmarshalOpts struct {
44
allowTypeGeneralString bool
5+
allowBERIntegers bool
56
}
67

78
// UnmarshalOpt describes a functional option for unmarshalling.
@@ -14,3 +15,11 @@ func WithUnmarshalAllowTypeGeneralString(value bool) UnmarshalOpt {
1415
opts.allowTypeGeneralString = value
1516
}
1617
}
18+
19+
// WithUnmarshalAllowBERIntegers permits the use of ASN.1 BER integer types. This is an option since it deviates from
20+
// stdlib.
21+
func WithUnmarshalAllowBERIntegers(value bool) UnmarshalOpt {
22+
return func(opts *unmarshalOpts) {
23+
opts.allowBERIntegers = value
24+
}
25+
}

0 commit comments

Comments
 (0)