Improve error handling for not well-formed CBOR
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index cc2614c..d14ed86 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -33,6 +33,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 0F8BADA722EF40FC008B6513 /* not_well_formed_cbor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = not_well_formed_cbor.h; path = test/not_well_formed_cbor.h; sourceTree = "<group>"; };
0FA9BEB5216CE6CA00BA646B /* qcbor_decode_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_decode_tests.c; path = test/qcbor_decode_tests.c; sourceTree = "<group>"; tabWidth = 3; };
0FA9BEB6216CE6CA00BA646B /* qcbor_decode_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_decode_tests.h; path = test/qcbor_decode_tests.h; sourceTree = "<group>"; };
0FA9BEB8216DC7AD00BA646B /* qcbor_encode_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode_tests.c; path = test/qcbor_encode_tests.c; sourceTree = "<group>"; tabWidth = 3; };
@@ -124,6 +125,7 @@
E73B575C2161CA7C0080D658 /* float_tests.h */,
E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */,
E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */,
+ 0F8BADA722EF40FC008B6513 /* not_well_formed_cbor.h */,
);
name = test;
sourceTree = "<group>";
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 4c96b51..18ed472 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -43,7 +43,9 @@
when who what, where, why
-------- ---- ---------------------------------------------------
- 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
+ 08/7/19 llundblade Better handling of not well-formed encode and decode.
+ 07/31/19 llundblade New error code for better end of data handling.
+ 7/25/19 janjongboom Add indefinite length encoding for maps and arrays.
05/26/19 llundblade Add QCBOREncode_GetErrorState() and _IsBufferNULL().
04/26/19 llundblade Big documentation & style update. No interface change.
02/16/19 llundblade Redesign MemPool to fix memory access alignment bug.
@@ -395,6 +397,8 @@
#define SINGLE_PREC_FLOAT 26
#define DOUBLE_PREC_FLOAT 27
#define CBOR_SIMPLE_BREAK 31
+#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
+#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
@@ -683,13 +687,16 @@
/** During decoding, some CBOR construct was encountered that this
decoder doesn't support, primarily this is the reserved
- additional info values, 28 through 30. */
+ additional info values, 28 through 30. During encoding,
+ an attempt to create simple value between 24 and 31. */
QCBOR_ERR_UNSUPPORTED = 5,
/** During decoding, hit the end of the given data to decode. For
example, a byte string of 100 bytes was expected, but the end
of the input was hit before finding those 100 bytes. Corrupted
- CBOR input will often result in this error. */
+ CBOR input will often result in this error. See also @ref
+ QCBOR_ERR_NO_MORE_ITEMS.
+ */
QCBOR_ERR_HIT_END = 6,
/** During encoding, the length of the encoded CBOR exceeded @c
@@ -753,6 +760,13 @@
/** An integer type is encoded with a bad length (an indefinite length) */
QCBOR_ERR_BAD_INT = 21,
+ /** All well-formed data items have been consumed and there are no
+ more. If parsing a CBOR stream this indicates the non-error
+ end of the stream. If parsing a CBOR stream / sequence, this
+ probably indicates that some data items expected are not present.
+ See also @ref QCBOR_ERR_HIT_END. */
+ QCBOR_ERR_NO_MORE_ITEMS = 22
+
} QCBORError;
@@ -2088,6 +2102,10 @@
@retval QCBOR_ERR_NO_STRING_ALLOCATOR Configuration error, encountered
indefinite-length string with no
allocator configured.
+ @retval QCBOR_ERR_NO_MORE_ITEMS No more bytes to decode. The previous
+ item was successfully decoded. This
+ is usually how the non-error end of
+ a CBOR stream / sequence is detected.
@c pDecodedItem is filled in with the value parsed. Generally, the
following data is returned in the structure:
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 0c1eda9..9599b07 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -42,6 +42,8 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
+ 07/31/19 llundblade New error code for better end of data handling
02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when bAllStrings set
02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller
@@ -536,11 +538,7 @@
pDecodedItem->uDataType = uAdditionalInfo;
switch(uAdditionalInfo) {
- case ADDINFO_RESERVED1: // 28
- case ADDINFO_RESERVED2: // 29
- case ADDINFO_RESERVED3: // 30
- nReturn = QCBOR_ERR_UNSUPPORTED;
- break;
+ // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as it is caught before this is called.
case HALF_PREC_FLOAT:
pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
@@ -783,8 +781,12 @@
break;
case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
- pDecodedItem->val.uTagV = uNumber;
- pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
+ if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ nReturn = QCBOR_ERR_BAD_INT;
+ } else {
+ pDecodedItem->val.uTagV = uNumber;
+ pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
+ }
break;
case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
@@ -869,7 +871,8 @@
// Match data type of chunk to type at beginning.
// Also catches error of other non-string types that don't belong.
- if(StringChunkItem.uDataType != uStringType) {
+ // Also catches indefinite length strings inside indefinite length strings
+ if(StringChunkItem.uDataType != uStringType || StringChunkItem.val.string.len == SIZE_MAX) {
nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
break;
}
@@ -1065,6 +1068,12 @@
// All the CBOR parsing work is here and in subordinate calls.
QCBORError nReturn;
+ // Check if there are an
+ if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && !DecodeNesting_IsNested(&(me->nesting))) {
+ nReturn = QCBOR_ERR_NO_MORE_ITEMS;
+ goto Done;
+ }
+
nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
if(nReturn) {
goto Done;
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 20c6a47..28fb225 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -42,6 +42,7 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
7/25/19 janjongboom Add indefinite length encoding for maps and arrays
4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
12/30/18 llundblade Small efficient clever encode of type & argument.
@@ -189,7 +190,7 @@
structures like array/map nesting resulting in some stack memory
savings.
- Errors returned here fall into two categories:
+ Errors returned here fall into three categories:
Sizes
QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
@@ -202,6 +203,9 @@
QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
+
+ Would generate not-well-formed CBOR
+ QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
*/
@@ -463,18 +467,22 @@
void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
{
if(me->uError == QCBOR_SUCCESS) {
- // This function call takes care of endian swapping for the float / double
- InsertEncodedTypeAndNumber(me,
- // The major type for floats and doubles
- CBOR_MAJOR_TYPE_SIMPLE,
- // size makes sure floats with zeros encode correctly
- (int)uSize,
- // Bytes of the floating point number as a uint
- uNum,
- // end position because this is append
- UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+ if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
+ me->uError = QCBOR_ERR_UNSUPPORTED;
+ } else {
+ // This function call takes care of endian swapping for the float / double
+ InsertEncodedTypeAndNumber(me,
+ // The major type for floats and doubles
+ CBOR_MAJOR_TYPE_SIMPLE,
+ // size makes sure floats with zeros encode correctly
+ (int)uSize,
+ // Bytes of the floating point number as a uint
+ uNum,
+ // end position because this is append
+ UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
- me->uError = Nesting_Increment(&(me->nesting));
+ me->uError = Nesting_Increment(&(me->nesting));
+ }
}
}
diff --git a/test/not_well_formed_cbor.h b/test/not_well_formed_cbor.h
new file mode 100644
index 0000000..fa5ebde
--- /dev/null
+++ b/test/not_well_formed_cbor.h
@@ -0,0 +1,325 @@
+/*==============================================================================
+ not_well_formed_cbor.h -- vectors to test for handling of not-well-formed CBOR
+
+ This is part of QCBOR -- https://github.com/laurencelundblade/QCBOR
+
+ Copyright (c) 2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 7/27/19
+ ==============================================================================*/
+
+#ifndef not_well_formed_cbor_h
+#define not_well_formed_cbor_h
+
+#include <stdint.h> // for size_t and uint8_t
+
+
+struct someBinaryBytes {
+ const uint8_t *p; // Pointer to the bytes
+ size_t n; // Length of the bytes
+};
+
+
+static const struct someBinaryBytes paNotWellFormedCBOR[] = {
+
+ // Indefinite length strings must be closed off
+
+ // An indefinite length byte string not closed off
+ {(uint8_t[]){0x5f, 0x41, 0x00}, 3},
+ // An indefinite length text string not closed off
+ {(uint8_t[]){0x7f, 0x61, 0x00}, 3},
+
+
+ // All the chunks in an indefinite length string must be of the
+ // type of indefinite length string and indefinite
+
+ // indefinite length byte string with text string chunk
+ {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4},
+ // indefinite length text string with a byte string chunk
+ {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4},
+ // indefinite length byte string with an positive integer chunk
+ {(uint8_t[]){0x5f, 0x00, 0xff}, 3},
+ // indefinite length byte string with an negative integer chunk
+ {(uint8_t[]){0x5f, 0x21, 0xff}, 3},
+ // indefinite length byte string with an array chunk
+ {(uint8_t[]){0x5f, 0x80, 0xff}, 3},
+ // indefinite length byte string with an map chunk
+ {(uint8_t[]){0x5f, 0xa0, 0xff}, 3},
+ // indefinite length byte string with tagged integer chunk
+ {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4},
+ // indefinite length byte string with an simple type chunk
+ {(uint8_t[]){0x5f, 0xe0, 0xff}, 3},
+ // indefinite length byte string with indefinite string inside
+ {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6},
+ // indefinite length text string with indefinite string inside
+ {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6},
+
+ // Definte length maps and arrays must be closed by having the
+ // right number of items
+
+ // A definte length array that is supposed to have 1 item, but has none
+ {(uint8_t[]){0x81}, 1},
+ // A definte length array that is supposed to have 2 items, but has only 1
+ {(uint8_t[]){0x82, 0x00}, 2},
+ // A definte length array that is supposed to have 511 items, but has only 1
+ {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4},
+ // A definte length map that is supposed to have 1 item, but has none
+ {(uint8_t[]){0xa1}, 1},
+ // A definte length map that is supposed to have s item, but has only 1
+ {(uint8_t[]){0xa2, 0x01, 0x02}, 3},
+
+
+ // Indefinte length maps and arrays must be ended by a break
+
+ // Indefinite length array with zero items and no break
+ {(uint8_t[]){0x9f}, 1},
+ // Indefinite length array with two items and no break
+ {(uint8_t[]){0x9f, 0x01, 0x02}, 3},
+ // Indefinite length map with zero items and no break
+ {(uint8_t[]){0xbf}, 1},
+ // Indefinite length map with two items and no break
+ {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5},
+
+
+ // Some extra test vectors for unclosed arrays and maps
+
+ // Unclosed indefinite array containing a close definite array
+ {(uint8_t[]){0x9f, 0x80, 0x00}, 3},
+ // Definite length array containing an unclosed indefinite array
+ {(uint8_t[]){0x81, 0x9f}, 2},
+ // Deeply nested definite length arrays with deepest one unclosed
+ {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9},
+ // Deeply nested indefinite length arrays with deepest one unclosed
+ {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9},
+ // Mixed nesting with indefinite unclosed
+ {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9},
+ // Mixed nesting with definite unclosed
+ {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10},
+
+
+ // The "argument" for the data item is missing bytes
+
+ // Positive integer missing 1 byte argument
+ {(uint8_t[]){0x18}, 1},
+ // Positive integer missing 2 byte argument
+ {(uint8_t[]){0x19}, 1},
+ // Positive integer missing 4 byte argument
+ {(uint8_t[]){0x1a}, 1},
+ // Positive integer missing 8 byte argument
+ {(uint8_t[]){0x1b}, 1},
+ // Positive integer missing 1 byte of 2 byte argument
+ {(uint8_t[]){0x19, 0x01}, 2},
+ // Positive integer missing 2 bytes of 4 byte argument
+ {(uint8_t[]){0x1a, 0x01, 0x02}, 3},
+ // Positive integer missing 1 bytes of 7 byte argument
+ {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8},
+ // Negative integer missing 1 byte argument
+ {(uint8_t[]){0x38}, 1},
+ // Binary string missing 1 byte argument
+ {(uint8_t[]){0x58}, 1},
+ // Text string missing 1 byte argument
+ {(uint8_t[]){0x78}, 1},
+ // Array missing 1 byte argument
+ {(uint8_t[]){0x98}, 1},
+ // Map missing 1 byte argument
+ {(uint8_t[]){0xb8}, 1},
+ // Tag missing 1 byte argument
+ {(uint8_t[]){0xd8}, 1},
+ // Simple missing 1 byte argument
+ {(uint8_t[]){0xf8}, 1},
+ // Half-precision missing 1 byte
+ {(uint8_t[]){0xf9, 0x00}, 2},
+ // Float missing 2 bytes
+ {(uint8_t[]){0xfa, 0x00, 0x00}, 3},
+ // Double missing 5 bytes
+ {(uint8_t[]){0xfb, 0x00, 0x00, 0x00}, 4},
+
+ // Breaks must not occur in definite length arrays and maps
+
+ // Array of length 1 with sole member replaced by a break
+ {(uint8_t[]){0x81, 0xff}, 2},
+ // Array of length 2 with 2nd member replaced by a break
+ {(uint8_t[]){0x82, 0x00, 0xff}, 3},
+ // Map of length 1 with sole member label replaced by a break
+ {(uint8_t[]){0xa1, 0xff}, 2},
+ // Map of length 1 with sole member label replaced by break
+ // Alternate representation that some decoders handle difference
+ {(uint8_t[]){0xa1, 0xff, 0x00}, 3},
+ // Array of length 1 with 2nd member value replaced by a break
+ {(uint8_t[]){0xa1, 0x00, 0xff}, 3},
+ // Map of length 2 with 2nd member replaced by a break
+ {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4},
+
+
+ // Breaks must not occur on their own out of an indefinite length
+ // data item
+
+ // A bare break is not well formed
+ {(uint8_t[]){0xff}, 1},
+ // A bare break after a zero length definite length array
+ {(uint8_t[]){0x80, 0xff}, 2},
+ // A bare break after a zero length indefinite length map
+ {(uint8_t[]){0x9f, 0xff, 0xff}, 3},
+
+
+ // Forbidden two-byte encodings of simple types
+
+ // Must use 0xe0 instead
+ {(uint8_t[]){0xf8, 0x00}, 2},
+ // Should use 0xe1 instead
+ {(uint8_t[]){0xf8, 0x01}, 2},
+ // Should use 0xe2 instead
+ {(uint8_t[]){0xf8, 0x02}, 2},
+ // Should use 0xe3 instead
+ {(uint8_t[]){0xf8, 0x03}, 2},
+ // Should use 0xe4 instead
+ {(uint8_t[]){0xf8, 0x04}, 2},
+ // Should use 0xe5 instead
+ {(uint8_t[]){0xf8, 0x05}, 2},
+ // Should use 0xe6 instead
+ {(uint8_t[]){0xf8, 0x06}, 2},
+ // Should use 0xe7 instead
+ {(uint8_t[]){0xf8, 0x07}, 2},
+ // Should use 0xe8 instead
+ {(uint8_t[]){0xf8, 0x08}, 2},
+ // Should use 0xe9 instead
+ {(uint8_t[]){0xf8, 0x09}, 2},
+ // Should use 0xea instead
+ {(uint8_t[]){0xf8, 0x0a}, 2},
+ // Should use 0xeb instead
+ {(uint8_t[]){0xf8, 0x0b}, 2},
+ // Should use 0xec instead
+ {(uint8_t[]){0xf8, 0x0c}, 2},
+ // Should use 0xed instead
+ {(uint8_t[]){0xf8, 0x0d}, 2},
+ // Should use 0xee instead
+ {(uint8_t[]){0xf8, 0x0e}, 2},
+ // Should use 0xef instead
+ {(uint8_t[]){0xf8, 0x0f}, 2},
+ // Should use 0xf0 instead
+ {(uint8_t[]){0xf8, 0x10}, 2},
+ // Should use 0xf1 instead
+ {(uint8_t[]){0xf8, 0x11}, 2},
+ // Should use 0xf2 instead
+ {(uint8_t[]){0xf8, 0x12}, 2},
+ // Must use 0xf3 instead
+ {(uint8_t[]){0xf8, 0x13}, 2},
+ // Must use 0xf4 instead
+ {(uint8_t[]){0xf8, 0x14}, 2},
+ // Must use 0xf5 instead
+ {(uint8_t[]){0xf8, 0x15}, 2},
+ // Must use 0xf6 instead
+ {(uint8_t[]){0xf8, 0x16}, 2},
+ // Must use 0xf7 instead
+ {(uint8_t[]){0xf8, 0x17}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x18}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x19}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1a}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1b}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1c}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1d}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1e}, 2},
+ // Reserved (as defined in RFC 8126), considered not-well-formed
+ {(uint8_t[]){0xf8, 0x1f}, 2},
+
+ // Integers with "argument" equal to an indefinite length
+
+ // Positive integer with "argument" an indefinite length
+ {(uint8_t[]){0x1f}, 1},
+ // Negative integer with "argument" an indefinite length
+ {(uint8_t[]){0x3f}, 1},
+ // CBOR tag with "argument" an indefinite length
+ {(uint8_t[]){0xdf, 0x00}, 2},
+ // CBOR tag with "argument" an indefinite length alternate vector
+ {(uint8_t[]){0xdf}, 1},
+
+
+ // Missing content bytes from a definite length string
+
+ // A byte string is of length 1 without the 1 byte
+ {(uint8_t[]){0x41}, 1},
+ // A text string is of length 1 without the 1 byte
+ {(uint8_t[]){0x61}, 1},
+ // Byte string should have 2^32-1 bytes, but has one
+ {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6},
+ // Byte string should have 2^32-1 bytes, but has one
+ {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6},
+
+
+ // Use of unassigned additional information values
+
+ // Major type positive integer with reserved value 28
+ {(uint8_t[]){0x1c}, 1},
+ // Major type positive integer with reserved value 29
+ {(uint8_t[]){0x1d}, 1},
+ // Major type positive integer with reserved value 30
+ {(uint8_t[]){0x1e}, 1},
+ // Major type negative integer with reserved value 28
+ {(uint8_t[]){0x3c}, 1},
+ // Major type negative integer with reserved value 29
+ {(uint8_t[]){0x3d}, 1},
+ // Major type negative integer with reserved value 30
+ {(uint8_t[]){0x3e}, 1},
+ // Major type byte string with reserved value 28 length
+ {(uint8_t[]){0x5c}, 1},
+ // Major type byte string with reserved value 29 length
+ {(uint8_t[]){0x5d}, 1},
+ // Major type byte string with reserved value 30 length
+ {(uint8_t[]){0x5e}, 1},
+ // Major type text string with reserved value 28 length
+ {(uint8_t[]){0x7c}, 1},
+ // Major type text string with reserved value 29 length
+ {(uint8_t[]){0x7d}, 1},
+ // Major type text string with reserved value 30 length
+ {(uint8_t[]){0x7e}, 1},
+ // Major type array with reserved value 28 length
+ {(uint8_t[]){0x9c}, 1},
+ // Major type array with reserved value 29 length
+ {(uint8_t[]){0x9d}, 1},
+ // Major type array with reserved value 30 length
+ {(uint8_t[]){0x9e}, 1},
+ // Major type map with reserved value 28 length
+ {(uint8_t[]){0xbc}, 1},
+ // Major type map with reserved value 29 length
+ {(uint8_t[]){0xbd}, 1},
+ // Major type map with reserved value 30 length
+ {(uint8_t[]){0xbe}, 1},
+ // Major type tag with reserved value 28 length
+ {(uint8_t[]){0xdc}, 1},
+ // Major type tag with reserved value 29 length
+ {(uint8_t[]){0xdd}, 1},
+ // Major type tag with reserved value 30 length
+ {(uint8_t[]){0xde}, 1},
+ // Major type simple with reserved value 28 length
+ {(uint8_t[]){0xfc}, 1},
+ // Major type simple with reserved value 29 length
+ {(uint8_t[]){0xfd}, 1},
+ // Major type simple with reserved value 30 length
+ {(uint8_t[]){0xfe}, 1},
+
+
+ // Maps must have an even number of data items (key & value)
+
+ // Map with 1 item when it should have 2
+ {(uint8_t[]){0xa1, 0x00}, 2},
+ // Map with 3 item when it should have 4
+ {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2},
+ // Map with 1 item when it should have 2
+ {(uint8_t[]){0xbf, 0x00, 0xff}, 3},
+ // Map with 3 item when it should have 4
+ {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5},
+
+};
+
+#endif /* not_well_formed_cbor_h */
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 2f2614d..8a79bd8 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -34,6 +34,7 @@
#include "qcbor.h"
#include <string.h>
#include <math.h> // for fabs()
+#include "not_well_formed_cbor.h"
#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING
@@ -654,20 +655,16 @@
int ShortBufferParseTest()
{
- int nResult = 0;
- QCBORDecodeContext DCtx;
- int num;
+ int nResult = 0;
- for(num = sizeof(spExpectedEncodedInts)-1; num; num--) {
- int n;
+ for(int nNum = sizeof(spExpectedEncodedInts)-1; nNum; nNum--) {
+ QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, nNum}, QCBOR_DECODE_MODE_NORMAL);
- n = IntegerValuesParseTestInternal(&DCtx);
+ const QCBORError nErr = IntegerValuesParseTestInternal(&DCtx);
- //printf("Len %d, result: %d\n", num, n);
-
- if(n != QCBOR_ERR_HIT_END) {
+ if(nErr != QCBOR_ERR_HIT_END && nErr != QCBOR_ERR_NO_MORE_ITEMS) {
nResult = -1;
goto Done;
}
@@ -1329,29 +1326,330 @@
}
+static int IsNotWellFormedError(QCBORError nErr)
+{
+ switch(nErr){
+ case QCBOR_ERR_INDEFINITE_STRING_CHUNK:
+ case QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN:
+ case QCBOR_ERR_UNSUPPORTED:
+ case QCBOR_ERR_HIT_END:
+ case QCBOR_ERR_BAD_TYPE_7:
+ case QCBOR_ERR_BAD_BREAK:
+ case QCBOR_ERR_EXTRA_BYTES:
+ case QCBOR_ERR_BAD_INT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+int NotWellFormedTests()
+{
+ // Loop over all the not-well-formed instance of CBOR
+ // that are test vectors in not_well_formed_cbor.h
+ const uint16_t nArraySize = sizeof(paNotWellFormedCBOR)/sizeof(struct someBinaryBytes);
+ for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) {
+ const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate];
+ const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n};
+
+ // Set up decoder context. String allocator needed for indefinite string test cases
+ QCBORDecodeContext DCtx;
+ QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL);
+ UsefulBuf_MAKE_STACK_UB(Pool, 100);
+ QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+
+ // Loop getting items until no more to get
+ QCBORError nCBORError;
+ do {
+ QCBORItem Item;
+
+ nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ } while(nCBORError == QCBOR_SUCCESS);
+
+ // Every test vector must fail with
+ // a not-well-formed error. If not
+ // this test fails.
+ if(!IsNotWellFormedError(nCBORError)) {
+ // Return index of failure in the error code
+ return 2000 + nIterate;
+ }
+ }
+ return 0;
+}
+
+
struct FailInput {
UsefulBufC Input; // CBOR to decode
QCBORError nError; // The error expected
};
struct FailInput Failures[] = {
- { {(uint8_t[]){0xa1, 0x00}, 2}, QCBOR_ERR_HIT_END }, // map with odd number of entries
- { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, // 1 byte integer missing the byte
- { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
- { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 29
- { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 30
- { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_BAD_INT }, // Indefinite length integer
- { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
- { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
- { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
- { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_BAD_INT }, // Indefinite length negative integer
- { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, // Short byte string
- { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
- { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, // Short UTF-8 string
- { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
- { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_BAD_BREAK } , // break
- { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_BAD_TYPE_7 }, // An invalid encoding of a simple type
- { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, // An invalid encoding of a simple type
+ // Most of this is copied from not_well_formed.h. Here the error code
+ // returned is also checked.
+
+ // Indefinite length strings must be closed off
+ // An indefinite length byte string not closed off
+ { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_HIT_END },
+ // An indefinite length text string not closed off
+ { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_HIT_END },
+
+
+ // All the chunks in an indefinite length string must be of the type of indefinite length string
+ // indefinite length byte string with text string chunk
+ { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length text string with a byte string chunk
+ { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with an positive integer chunk
+ { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with an negative integer chunk
+ { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with an array chunk
+ { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with an map chunk
+ { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with tagged integer chunk
+ { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ // indefinite length byte string with an simple type chunk
+ { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK },
+ { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK},
+ // indefinite length text string with indefinite string inside
+ { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK},
+
+
+ // Definte length maps and arrays must be closed by having the right number of items
+ // A definte length array that is supposed to have 1 item, but has none
+ { {(uint8_t[]){0x81}, 1}, QCBOR_ERR_HIT_END },
+ // A definte length array that is supposed to have 2 items, but has only 1
+ { {(uint8_t[]){0x82, 0x00}, 2}, QCBOR_ERR_HIT_END },
+ // A definte length array that is supposed to have 511 items, but has only 1
+ { {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4}, QCBOR_ERR_HIT_END },
+ // A definte length map that is supposed to have 1 item, but has none
+ { {(uint8_t[]){0xa1}, 1}, QCBOR_ERR_HIT_END },
+ // A definte length map that is supposed to have s item, but has only 1
+ { {(uint8_t[]){0xa2, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END },
+
+
+ // Indefinte length maps and arrays must be ended by a break
+ // Indefinite length array with zero items and no break
+ { {(uint8_t[]){0x9f}, 1}, QCBOR_ERR_HIT_END },
+ // Indefinite length array with two items and no break
+ { {(uint8_t[]){0x9f, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END },
+ // Indefinite length map with zero items and no break
+ { {(uint8_t[]){0xbf}, 1}, QCBOR_ERR_HIT_END },
+ // Indefinite length map with two items and no break
+ { {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5}, QCBOR_ERR_HIT_END },
+
+
+ // Nested maps and arrays must be closed off (some extra nested test vectors)
+ // Unclosed indefinite array containing a close definite array
+ { {(uint8_t[]){0x9f, 0x80, 0x00}, 3}, QCBOR_ERR_HIT_END },
+ // Definite length array containing an unclosed indefinite array
+ { {(uint8_t[]){0x81, 0x9f}, 2}, QCBOR_ERR_HIT_END },
+ // Deeply nested definite length arrays with deepest one unclosed
+ { {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9}, QCBOR_ERR_HIT_END },
+ // Deeply nested indefinite length arrays with deepest one unclosed
+ { {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_HIT_END },
+ // Mixed nesting with indefinite unclosed
+ { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_BAD_BREAK }, // TODO: think through this one
+ // Mixed nesting with definite unclosed
+ { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, // TODO: think through this one
+
+
+ // The "argument" for the data item is incomplete
+ // Positive integer missing 1 byte argument
+ { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 2 byte argument
+ { {(uint8_t[]){0x19}, 1}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 4 byte argument
+ { {(uint8_t[]){0x1a}, 1}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 8 byte argument
+ { {(uint8_t[]){0x1b}, 1}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 1 byte of 2 byte argument
+ { {(uint8_t[]){0x19, 0x01}, 2}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 2 bytes of 4 byte argument
+ { {(uint8_t[]){0x1a, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END },
+ // Positive integer missing 1 bytes of 7 byte argument
+ { {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8}, QCBOR_ERR_HIT_END },
+ // Negative integer missing 1 byte argument
+ { {(uint8_t[]){0x38}, 1}, QCBOR_ERR_HIT_END },
+ // Binary string missing 1 byte argument
+ { {(uint8_t[]){0x58}, 1}, QCBOR_ERR_HIT_END },
+ // Text string missing 1 byte argument
+ { {(uint8_t[]){0x78}, 1}, QCBOR_ERR_HIT_END },
+ // Array missing 1 byte argument
+ { {(uint8_t[]){0x98}, 1}, QCBOR_ERR_HIT_END },
+ // Map missing 1 byte argument
+ { {(uint8_t[]){0xb8}, 1}, QCBOR_ERR_HIT_END },
+ // Tag missing 1 byte argument
+ { {(uint8_t[]){0xd8}, 1}, QCBOR_ERR_HIT_END },
+ // Simple missing 1 byte argument
+ { {(uint8_t[]){0xf8}, 1}, QCBOR_ERR_HIT_END },
+
+
+ // Breaks must not occur in definite length arrays and maps
+ // Array of length 1 with sole member replaced by a break
+ { {(uint8_t[]){0x81, 0xff}, 2}, QCBOR_ERR_BAD_BREAK },
+ // Array of length 2 with 2nd member replaced by a break
+ { {(uint8_t[]){0x82, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK },
+ // Map of length 1 with sole member label replaced by a break
+ { {(uint8_t[]){0xa1, 0xff}, 2}, QCBOR_ERR_BAD_BREAK },
+ // Map of length 1 with sole member label replaced by break
+ // Alternate representation that some decoders handle difference
+ { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, QCBOR_ERR_BAD_BREAK },
+ // Array of length 1 with 2nd member value replaced by a break
+ { {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK },
+ // Map of length 2 with 2nd member replaced by a break
+ { {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, QCBOR_ERR_BAD_BREAK },
+
+
+ // Breaks must not occur on their own out of an indefinite length data item
+ // A bare break is not well formed
+ { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_BAD_BREAK },
+ // A bare break after a zero length definite length array
+ { {(uint8_t[]){0x80, 0xff}, 2}, QCBOR_ERR_BAD_BREAK },
+ // A bare break after a zero length indefinite length map
+ { {(uint8_t[]){0x9f, 0xff, 0xff}, 3}, QCBOR_ERR_BAD_BREAK },
+
+
+ // Forbidden two byte encodings of simple types
+ // Must use 0xe0 instead
+ { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe1 instead
+ { {(uint8_t[]){0xf8, 0x01}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe2 instead
+ { {(uint8_t[]){0xf8, 0x02}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe3 instead
+ { {(uint8_t[]){0xf8, 0x03}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe4 instead
+ { {(uint8_t[]){0xf8, 0x04}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe5 instead
+ { {(uint8_t[]){0xf8, 0x05}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe6 instead
+ { {(uint8_t[]){0xf8, 0x06}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe7 instead
+ { {(uint8_t[]){0xf8, 0x07}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe8 instead
+ { {(uint8_t[]){0xf8, 0x08}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xe9 instead
+ { {(uint8_t[]){0xf8, 0x09}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xea instead
+ { {(uint8_t[]){0xf8, 0x0a}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xeb instead
+ { {(uint8_t[]){0xf8, 0x0b}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xec instead
+ { {(uint8_t[]){0xf8, 0x0c}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xed instead
+ { {(uint8_t[]){0xf8, 0x0d}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xee instead
+ { {(uint8_t[]){0xf8, 0x0e}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xef instead
+ { {(uint8_t[]){0xf8, 0x0f}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xf0 instead
+ { {(uint8_t[]){0xf8, 0x10}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xf1 instead
+ { {(uint8_t[]){0xf8, 0x11}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Should use 0xf2 instead
+ { {(uint8_t[]){0xf8, 0x12}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf3 instead
+ { {(uint8_t[]){0xf8, 0x13}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf4 instead
+ { {(uint8_t[]){0xf8, 0x14}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf5 instead
+ { {(uint8_t[]){0xf8, 0x15}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf6 instead
+ { {(uint8_t[]){0xf8, 0x16}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf7 instead
+ { {(uint8_t[]){0xf8, 0x17}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+ // Must use 0xf8 instead
+ { {(uint8_t[]){0xf8, 0x18}, 2}, QCBOR_ERR_BAD_TYPE_7 },
+
+
+ // Integers with additional info indefinite length
+ // Positive integer with additional info indefinite length
+ { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_BAD_INT },
+ // Negative integer with additional info indefinite length
+ { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_BAD_INT },
+ // CBOR tag with "argument" an indefinite length
+ { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_BAD_INT },
+ // CBOR tag with "argument" an indefinite length alternate vector
+ { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_BAD_INT },
+
+
+ // Missing bytes from a deterministic length string
+ // A byte string is of length 1 without the 1 byte
+ { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END },
+ // A text string is of length 1 without the 1 byte
+ { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END },
+ // Byte string should have 2^32-1 bytes, but has one
+ { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6}, QCBOR_ERR_HIT_END },
+ // Byte string should have 2^32-1 bytes, but has one
+ { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6}, QCBOR_ERR_HIT_END },
+
+
+ // Use of unassigned additional information values
+ // Major type positive integer with reserved value 28
+ { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type positive integer with reserved value 29
+ { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type positive integer with reserved value 30
+ { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type negative integer with reserved value 28
+ { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type negative integer with reserved value 29
+ { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type negative integer with reserved value 30
+ { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type byte string with reserved value 28 length
+ { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type byte string with reserved value 29 length
+ { {(uint8_t[]){0x5d}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type byte string with reserved value 30 length
+ { {(uint8_t[]){0x5e}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type text string with reserved value 28 length
+ { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type text string with reserved value 29 length
+ { {(uint8_t[]){0x7d}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type text string with reserved value 30 length
+ { {(uint8_t[]){0x7e}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type array with reserved value 28 length
+ { {(uint8_t[]){0x9c}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type array with reserved value 29 length
+ { {(uint8_t[]){0x9d}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type array with reserved value 30 length
+ { {(uint8_t[]){0x9e}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type map with reserved value 28 length
+ { {(uint8_t[]){0xbc}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type map with reserved value 29 length
+ { {(uint8_t[]){0xbd}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type map with reserved value 30 length
+ { {(uint8_t[]){0xbe}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type tag with reserved value 28 length
+ { {(uint8_t[]){0xdc}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type tag with reserved value 29 length
+ { {(uint8_t[]){0xdd}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type tag with reserved value 30 length
+ { {(uint8_t[]){0xde}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type simple with reserved value 28 length
+ { {(uint8_t[]){0xfc}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type simple with reserved value 29 length
+ { {(uint8_t[]){0xfd}, 1}, QCBOR_ERR_UNSUPPORTED },
+ // Major type simple with reserved value 30 length
+ { {(uint8_t[]){0xfe}, 1}, QCBOR_ERR_UNSUPPORTED },
+
+
+ // Maps must have an even number of data items (key & value)
+ // Map with 1 item when it should have 2
+ { {(uint8_t[]){0xa1, 0x00}, 2}, QCBOR_ERR_HIT_END },
+ // Map with 3 item when it should have 4
+ { {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2}, QCBOR_ERR_HIT_END },
+ // Map with 1 item when it should have 2
+ { {(uint8_t[]){0xbf, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK },
+ // Map with 3 item when it should have 4
+ { {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5}, QCBOR_ERR_BAD_BREAK },
+
+
+ // In addition to not-well-formed, some invalid CBOR
{ {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // Text-based date, with an integer
{ {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // Epoch date, with an byte string
{ {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // tagged as both epoch and string dates
@@ -1363,29 +1661,29 @@
// Loop over the failures
const struct FailInput * const pFEnd = &Failures[0] +
sizeof(Failures)/sizeof(struct FailInput);
-
for(const struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) {
+
+ // Set up the decoding context including a mem pool so that
+ // indefinite length items can be checked
QCBORDecodeContext DCtx;
- QCBORItem Item;
- QCBORError nCBORError;
-
QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL);
+ UsefulBuf_MAKE_STACK_UB(Pool, 100);
+ QCBORError nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+ if(nCBORError) {
+ return -9;
+ }
- while(1) {
+ // Iterate until there is an error of some sort
+ do {
+ QCBORItem Item;
+
nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
- if(QCBOR_SUCCESS == nCBORError) {
- // Must end in an error, so if success keep going
- continue;
- }
+ } while(nCBORError == QCBOR_SUCCESS);
- if(nCBORError != pF->nError) {
- // Not success, nor error expected so a test failure
- // Return code is 1000 plus index into Failures of test that failed
- return 1000 + (int)(pF - &Failures[0]);
- } else {
- // Got the error expected
- break;
- }
+ // Must get the expected error or the this test fails
+ if(nCBORError != pF->nError) {
+ // return index of CBOR + 1000
+ return 1000 + (int)(pF - &Failures[0]);
}
}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 79d5e46..6159c8b 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -130,6 +130,13 @@
int ParseSimpleTest(void);
+/*
+ This tests all the not-well-formed CBOR from the CBOR RFC.
+ (This is the CBORbis RFC which is not yet published at the
+ time this test was added).
+ */
+int NotWellFormedTests(void);
+
/*
Tests a number of failure cases on bad CBOR to get the right error code
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index ea6363b..7866b37 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -1852,7 +1852,7 @@
}
nReturn = QCBORDecode_GetNext(&DC, &Item);
- if(nReturn == QCBOR_ERR_HIT_END) {
+ if(nReturn == QCBOR_ERR_HIT_END || nReturn == QCBOR_ERR_NO_MORE_ITEMS) {
return 0;
}
if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
@@ -2314,5 +2314,20 @@
return -11;
}
+ // ------ QCBOR_ERR_UNSUPPORTED --------
+ QCBOREncode_Init(&EC, Large);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddSimple(&EC, 24); // CBOR_SIMPLEV_RESERVED_START
+ if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_UNSUPPORTED) {
+ return -12;
+ }
+
+ QCBOREncode_Init(&EC, Large);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddSimple(&EC, 31); // CBOR_SIMPLEV_RESERVED_END
+ if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_UNSUPPORTED) {
+ return -13;
+ }
+
return 0;
}
diff --git a/test/run_tests.c b/test/run_tests.c
index 9094e35..374b40e 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -100,6 +100,7 @@
test_entry s_tests[] = {
+ TEST_ENTRY(NotWellFormedTests),
TEST_ENTRY(ParseMapAsArrayTest),
TEST_ENTRY(AllocAllStringsTest),
TEST_ENTRY(IndefiniteLengthNestTest),