summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/fxamacker/cbor/v2/valid.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/fxamacker/cbor/v2/valid.go')
-rw-r--r--vendor/github.com/fxamacker/cbor/v2/valid.go300
1 files changed, 300 insertions, 0 deletions
diff --git a/vendor/github.com/fxamacker/cbor/v2/valid.go b/vendor/github.com/fxamacker/cbor/v2/valid.go
new file mode 100644
index 0000000000..0d243bb691
--- /dev/null
+++ b/vendor/github.com/fxamacker/cbor/v2/valid.go
@@ -0,0 +1,300 @@
+// Copyright (c) Faye Amacker. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+package cbor
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+ "strconv"
+)
+
+// SyntaxError is a description of a CBOR syntax error.
+type SyntaxError struct {
+ msg string
+}
+
+func (e *SyntaxError) Error() string { return e.msg }
+
+// SemanticError is a description of a CBOR semantic error.
+type SemanticError struct {
+ msg string
+}
+
+func (e *SemanticError) Error() string { return e.msg }
+
+// MaxNestedLevelError indicates exceeded max nested level of any combination of CBOR arrays/maps/tags.
+type MaxNestedLevelError struct {
+ maxNestedLevels int
+}
+
+func (e *MaxNestedLevelError) Error() string {
+ return "cbor: exceeded max nested level " + strconv.Itoa(e.maxNestedLevels)
+}
+
+// MaxArrayElementsError indicates exceeded max number of elements for CBOR arrays.
+type MaxArrayElementsError struct {
+ maxArrayElements int
+}
+
+func (e *MaxArrayElementsError) Error() string {
+ return "cbor: exceeded max number of elements " + strconv.Itoa(e.maxArrayElements) + " for CBOR array"
+}
+
+// MaxMapPairsError indicates exceeded max number of key-value pairs for CBOR maps.
+type MaxMapPairsError struct {
+ maxMapPairs int
+}
+
+func (e *MaxMapPairsError) Error() string {
+ return "cbor: exceeded max number of key-value pairs " + strconv.Itoa(e.maxMapPairs) + " for CBOR map"
+}
+
+// IndefiniteLengthError indicates found disallowed indefinite length items.
+type IndefiniteLengthError struct {
+ t cborType
+}
+
+func (e *IndefiniteLengthError) Error() string {
+ return "cbor: indefinite-length " + e.t.String() + " isn't allowed"
+}
+
+// TagsMdError indicates found disallowed CBOR tags.
+type TagsMdError struct {
+}
+
+func (e *TagsMdError) Error() string {
+ return "cbor: CBOR tag isn't allowed"
+}
+
+// valid checks whether CBOR data is complete and well-formed.
+func (d *decodeState) valid() error {
+ if len(d.data) == d.off {
+ return io.EOF
+ }
+ _, err := d.validInternal(0)
+ return err
+}
+
+// validInternal checks data's well-formedness and returns max depth and error.
+func (d *decodeState) validInternal(depth int) (int, error) {
+ t, ai, val, err := d.validHead()
+ if err != nil {
+ return 0, err
+ }
+
+ switch t {
+ case cborTypeByteString, cborTypeTextString:
+ if ai == 31 {
+ if d.dm.indefLength == IndefLengthForbidden {
+ return 0, &IndefiniteLengthError{t}
+ }
+ return d.validIndefiniteString(t, depth)
+ }
+ valInt := int(val)
+ if valInt < 0 {
+ // Detect integer overflow
+ return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, causing integer overflow")
+ }
+ if len(d.data)-d.off < valInt { // valInt+off may overflow integer
+ return 0, io.ErrUnexpectedEOF
+ }
+ d.off += valInt
+ case cborTypeArray, cborTypeMap:
+ depth++
+ if depth > d.dm.maxNestedLevels {
+ return 0, &MaxNestedLevelError{d.dm.maxNestedLevels}
+ }
+
+ if ai == 31 {
+ if d.dm.indefLength == IndefLengthForbidden {
+ return 0, &IndefiniteLengthError{t}
+ }
+ return d.validIndefiniteArrayOrMap(t, depth)
+ }
+
+ valInt := int(val)
+ if valInt < 0 {
+ // Detect integer overflow
+ return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, it would cause integer overflow")
+ }
+
+ if t == cborTypeArray {
+ if valInt > d.dm.maxArrayElements {
+ return 0, &MaxArrayElementsError{d.dm.maxArrayElements}
+ }
+ } else {
+ if valInt > d.dm.maxMapPairs {
+ return 0, &MaxMapPairsError{d.dm.maxMapPairs}
+ }
+ }
+
+ count := 1
+ if t == cborTypeMap {
+ count = 2
+ }
+ maxDepth := depth
+ for j := 0; j < count; j++ {
+ for i := 0; i < valInt; i++ {
+ var dpt int
+ if dpt, err = d.validInternal(depth); err != nil {
+ return 0, err
+ }
+ if dpt > maxDepth {
+ maxDepth = dpt // Save max depth
+ }
+ }
+ }
+ depth = maxDepth
+ case cborTypeTag:
+ if d.dm.tagsMd == TagsForbidden {
+ return 0, &TagsMdError{}
+ }
+
+ // Scan nested tag numbers to avoid recursion.
+ for {
+ if len(d.data) == d.off { // Tag number must be followed by tag content.
+ return 0, io.ErrUnexpectedEOF
+ }
+ if cborType(d.data[d.off]&0xe0) != cborTypeTag {
+ break
+ }
+ if _, _, _, err = d.validHead(); err != nil {
+ return 0, err
+ }
+ depth++
+ if depth > d.dm.maxNestedLevels {
+ return 0, &MaxNestedLevelError{d.dm.maxNestedLevels}
+ }
+ }
+ // Check tag content.
+ return d.validInternal(depth)
+ }
+ return depth, nil
+}
+
+// validIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error.
+func (d *decodeState) validIndefiniteString(t cborType, depth int) (int, error) {
+ var err error
+ for {
+ if len(d.data) == d.off {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if d.data[d.off] == 0xff {
+ d.off++
+ break
+ }
+ // Peek ahead to get next type and indefinite length status.
+ nt := cborType(d.data[d.off] & 0xe0)
+ if t != nt {
+ return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()}
+ }
+ if (d.data[d.off] & 0x1f) == 31 {
+ return 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"}
+ }
+ if depth, err = d.validInternal(depth); err != nil {
+ return 0, err
+ }
+ }
+ return depth, nil
+}
+
+// validIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error.
+func (d *decodeState) validIndefiniteArrayOrMap(t cborType, depth int) (int, error) {
+ var err error
+ maxDepth := depth
+ i := 0
+ for {
+ if len(d.data) == d.off {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if d.data[d.off] == 0xff {
+ d.off++
+ break
+ }
+ var dpt int
+ if dpt, err = d.validInternal(depth); err != nil {
+ return 0, err
+ }
+ if dpt > maxDepth {
+ maxDepth = dpt
+ }
+ i++
+ if t == cborTypeArray {
+ if i > d.dm.maxArrayElements {
+ return 0, &MaxArrayElementsError{d.dm.maxArrayElements}
+ }
+ } else {
+ if i%2 == 0 && i/2 > d.dm.maxMapPairs {
+ return 0, &MaxMapPairsError{d.dm.maxMapPairs}
+ }
+ }
+ }
+ if t == cborTypeMap && i%2 == 1 {
+ return 0, &SyntaxError{"cbor: unexpected \"break\" code"}
+ }
+ return maxDepth, nil
+}
+
+func (d *decodeState) validHead() (t cborType, ai byte, val uint64, err error) {
+ dataLen := len(d.data) - d.off
+ if dataLen == 0 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+
+ t = cborType(d.data[d.off] & 0xe0)
+ ai = d.data[d.off] & 0x1f
+ val = uint64(ai)
+ d.off++
+
+ if ai < 24 {
+ return t, ai, val, nil
+ }
+ if ai == 24 {
+ if dataLen < 2 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ val = uint64(d.data[d.off])
+ d.off++
+ if t == cborTypePrimitives && val < 32 {
+ return 0, 0, 0, &SyntaxError{"cbor: invalid simple value " + strconv.Itoa(int(val)) + " for type " + t.String()}
+ }
+ return t, ai, val, nil
+ }
+ if ai == 25 {
+ if dataLen < 3 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2]))
+ d.off += 2
+ return t, ai, val, nil
+ }
+ if ai == 26 {
+ if dataLen < 5 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4]))
+ d.off += 4
+ return t, ai, val, nil
+ }
+ if ai == 27 {
+ if dataLen < 9 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ val = binary.BigEndian.Uint64(d.data[d.off : d.off+8])
+ d.off += 8
+ return t, ai, val, nil
+ }
+ if ai == 31 {
+ switch t {
+ case cborTypePositiveInt, cborTypeNegativeInt, cborTypeTag:
+ return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
+ case cborTypePrimitives: // 0xff (break code) should not be outside validIndefinite().
+ return 0, 0, 0, &SyntaxError{"cbor: unexpected \"break\" code"}
+ }
+ return t, ai, val, nil
+ }
+ // ai == 28, 29, 30
+ return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
+}