Repository: fxamacker/cbor (go)

Issue:
[stream-mode branch] Add support for CBOR bignum in NextSize()
Add support for CBOR bignum in NextSize().

This is a requested feature that must be merged before security audit.


Pull request description:
[stream-mode branch] Support CBOR bignum in NextSize()
### Description (motivation)

Add requested feature in stream-mode branch that is required before security audit.

### PR Was Proposed and Welcomed in Currently Open Issue
This PR was proposed and welcomed by maintainer(s) in issue #324

Closes #324



Patch:
diff --git a/stream_decode.go b/stream_decode.go
index 0929c83..8d1bd92 100644
--- a/stream_decode.go
+++ b/stream_decode.go
@@ -158,13 +158,14 @@ func (sd *StreamDecoder) NextType() (Type, error) {
 	return UndefinedType, errors.New("cbor: unrecognized type")
 }
 
-// NextSize returns the next CBOR data size for four CBOR types.
+// NextSize returns the next CBOR data size for five types.
 // Returned uint64 represents different kind of size depending on
-// the CBOR type:
-// - byte string: length (in bytes) of byte string
-// - text string: length (in bytes) of text string
-// - array: number of array elements
-// - map: number of key/value pairs
+// the type:
+// - ByteStringType : length (in bytes) of byte string
+// - TextStringType : length (in bytes) of text string
+// - ArrayType      : number of array elements
+// - MapType        : number of key/value pairs
+// - BigNumType     : length (in bytes) of encoded big number
 // Error is returned for indef length data and unsupported types.
 // Support for additional types wasn't added for simplicity.
 func (sd *StreamDecoder) NextSize() (uint64, error) {
@@ -173,12 +174,20 @@ func (sd *StreamDecoder) NextSize() (uint64, error) {
 		return 0, err
 	}
 
-	ai := sd.dec.d.data[sd.dec.d.off] & 0x1f
+	off := sd.dec.d.off
+
+	if t == BigNumType {
+		// NextType() validates CBOR tag data (tag number + tag content),
+		// so it's safe to increment offset to access tag content.
+		off++              // Increment offset to point to tag content
+		t = ByteStringType // tag content type is CBOR byte string
+	}
 
 	switch t {
 
 	case ByteStringType, TextStringType, ArrayType, MapType:
-		off := sd.dec.d.off + 1
+		ai := sd.dec.d.data[off] & 0x1f
+		off++
 
 		// This function only interprets valid head because
 		// CBOR data is validated in NextType().


Test patch:
diff --git a/stream_decode_test.go b/stream_decode_test.go
index 7898b9c..3f9254d 100644
--- a/stream_decode_test.go
+++ b/stream_decode_test.go
@@ -1752,11 +1752,11 @@ func TestStreamDecodeNextSize(t *testing.T) {
 		{"false", []byte{0xf4}, 0, "size operation is not supported"},
 		{"true", []byte{0xf5}, 0, "size operation is not supported"},
 		{"nil", []byte{0xf6}, 0, "size operation is not supported"},
-		{"uint", []byte{0x01}, 0, "size operation is not supported"},                                                            // 1
-		{"int", []byte{0x20}, 0, "size operation is not supported"},                                                             // -1
-		{"tag", []byte{0xc2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, "size operation is not supported"}, // bignum(18446744073709551616)
-		{"empty byte string", []byte{0x40}, 0, ""},                                                                              // []
-		{"byte string", []byte{0x45, 0x01, 0x02, 0x03, 0x04, 0x05}, 5, ""},                                                      // [1, 2, 3, 4, 5]
+		{"uint", []byte{0x01}, 0, "size operation is not supported"},                              // 1
+		{"int", []byte{0x20}, 0, "size operation is not supported"},                               // -1
+		{"tag", []byte{0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0}, 0, "size operation is not supported"}, // epoch-based date/time
+		{"empty byte string", []byte{0x40}, 0, ""},                                                // []
+		{"byte string", []byte{0x45, 0x01, 0x02, 0x03, 0x04, 0x05}, 5, ""},                        // [1, 2, 3, 4, 5]
 		{"indef length byte string", []byte{0x5f, 0x42, 0x01, 0x02, 0x043, 0x03, 0x04, 0x05, 0xff}, 0, "size is unavailable for indefinite length"},
 		{"empty text string", []byte{0x60}, 0, ""},                                                 // ""
 		{"text string", []byte{0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, 5, ""},                         // "hello"
@@ -1765,9 +1765,14 @@ func TestStreamDecodeNextSize(t *testing.T) {
 		{"text string", []byte{0x7a, 0x00, 0x00, 0x00, 0x01, 0x61}, 1, ""},                         // "a"
 		{"text string", []byte{0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x61}, 1, ""}, // "a"
 		{"indef length text string", []byte{0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x67, 0xff}, 0, "size is unavailable for indefinite length"},
-		{"empty array", []byte{0x80}, 0, ""},                                                                         // []
-		{"array", []byte{0x83, 0x01, 0x02, 0x03}, 3, ""},                                                             // [1, 2, 3]
-		{"indef length array", []byte{0x9f, 0x01, 0x02, 0x03, 0xff}, 0, "size is unavailable for indefinite length"}, // [1, 2, 3]
+		{"empty array", []byte{0x80}, 0, ""},                                                                               // []
+		{"array", []byte{0x83, 0x01, 0x02, 0x03}, 3, ""},                                                                   // [1, 2, 3]
+		{"indef length array", []byte{0x9f, 0x01, 0x02, 0x03, 0xff}, 0, "size is unavailable for indefinite length"},       // [1, 2, 3]
+		{"big int 0", []byte{0xc2, 0x40}, 0, ""},                                                                           // bignum: 0
+		{"big int 1", []byte{0xc2, 0x41, 0x01}, 1, ""},                                                                     // bignum: 1
+		{"big int 18446744073709551616", []byte{0xc2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 9, ""},  // bignum: 18446744073709551616
+		{"big int -1", []byte{0xc3, 0x40}, 0, ""},                                                                          // bignum: -1
+		{"big int -18446744073709551617", []byte{0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 9, ""}, // bignum: -18446744073709551617
 	}
 
 	for _, tc := range testCases {