aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurence Lundblade <lgl@securitytheory.com>2019-12-02 13:04:34 -0800
committerTamas Ban <tamas.ban@arm.com>2020-01-23 13:33:03 +0000
commit234fe42429e6a814626bb7f7c2dd6a41279154b9 (patch)
treeb62bcc2d57e34b047a90293e77c2ff3a338b0f54
parenta995432c475dcf14fc189b2d689e05573a0c85a2 (diff)
downloadtrusted-firmware-m-234fe42429e6a814626bb7f7c2dd6a41279154b9.tar.gz
QCBOR: Improve handling of end of data and error; add indefinite length encoding
* Minor improvements / fixes in run_test framework * Add CBOR indefinite length encoding * Recheck pointer math in UsefulBuf and remove "TODO" * Better error handling of not-well-formed CBOR when decoding * Better handling of end of data when decoding * Better handling of encode error when out of space in output buffer Change-Id: Ib8dc2af95bc533b7905648d8f8c3b1bf1c42ba44 Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
-rw-r--r--lib/ext/qcbor/inc/qcbor.h141
-rw-r--r--lib/ext/qcbor/src/UsefulBuf.c16
-rw-r--r--lib/ext/qcbor/src/qcbor_decode.c110
-rw-r--r--lib/ext/qcbor/src/qcbor_encode.c102
-rw-r--r--lib/ext/qcbor/test/float_tests.c4
-rw-r--r--lib/ext/qcbor/test/not_well_formed_cbor.h325
-rw-r--r--lib/ext/qcbor/test/qcbor_decode_tests.c625
-rw-r--r--lib/ext/qcbor/test/qcbor_decode_tests.h41
-rw-r--r--lib/ext/qcbor/test/qcbor_encode_tests.c340
-rw-r--r--lib/ext/qcbor/test/qcbor_encode_tests.h36
-rw-r--r--lib/ext/qcbor/test/run_tests.c116
11 files changed, 1601 insertions, 255 deletions
diff --git a/lib/ext/qcbor/inc/qcbor.h b/lib/ext/qcbor/inc/qcbor.h
index 2945192047..d541a10647 100644
--- a/lib/ext/qcbor/inc/qcbor.h
+++ b/lib/ext/qcbor/inc/qcbor.h
@@ -43,6 +43,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
when who what, where, why
-------- ---- ---------------------------------------------------
+ 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.
@@ -217,6 +220,8 @@ struct _QCBORDecodeContext {
#define CBOR_MAJOR_NONE_TYPE_RAW 9
#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
+#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN 12
+#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN 13
/* ===========================================================================
@@ -392,6 +397,8 @@ struct _QCBORDecodeContext {
#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
@@ -529,10 +536,12 @@ struct _QCBORDecodeContext {
The encoding error handling is simple. The only possible errors are
trying to encode structures that are too large or too complex. There
are no internal malloc calls so there will be no failures for out of
- memory. Only the final call, QCBOREncode_Finish(), returns an error
- code. Once an error happens, the encoder goes into an error state
- and calls to it will do nothing so the encoding can just go on. An
- error check is not needed after every data item is added.
+ memory. The error state is tracked internally, so there is no need
+ to check for errors when encoding. Only the return code from
+ QCBOREncode_Finish() need be checked as once an error happens, the
+ encoder goes into an error state and calls to it to add more data
+ will do nothing. An error check is not needed after every data item
+ is added.
Encoding generally proceeds by calling QCBOREncode_Init(), calling
lots of @c QCBOREncode_AddXxx() functions and calling
@@ -605,7 +614,6 @@ struct _QCBORDecodeContext {
@ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
- Max items in an array or map when encoding / decoding is
@ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
- - Does not support encoding indefinite lengths (decoding is supported).
- Does not directly support some tagged types: decimal fractions, big floats
- Does not directly support labels in maps other than text strings and integers.
- Does not directly support integer labels greater than @c INT64_MAX.
@@ -679,13 +687,16 @@ typedef enum {
/** 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
@@ -746,6 +757,16 @@ typedef enum {
list, or not enough space in @ref QCBORTagListOut. */
QCBOR_ERR_TOO_MANY_TAGS = 20,
+ /** 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;
@@ -1781,8 +1802,8 @@ static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabe
was computed. If a buffer was passed, then the encoded CBOR is in the
buffer.
- All encoding errors manifest here as no other encoding function
- returns any errors. They just set the error state in the encode
+ Encoding errors primarily manifest here as most other encoding function
+ do no return an error. They just set the error state in the encode
context after which no encoding function does anything.
Three types of errors manifest here. The first type are nesting
@@ -1809,6 +1830,10 @@ static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabe
This may be called multiple times. It will always return the same. It
can also be interleaved with calls to QCBOREncode_FinishGetSize().
+
+ QCBOREncode_GetErrorState() can be called to get the current
+ error state and abort encoding early as an optimization, but is
+ is never required.
*/
QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
@@ -1853,7 +1878,7 @@ static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
Normally encoding errors need only be handled at the end of encoding
when QCBOREncode_Finish() is called. This can be called to get the
error result before finish should there be a need to halt encoding
- before QCBOREncode_Finish(). is called.
+ before QCBOREncode_Finish() is called.
*/
static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);
@@ -2039,7 +2064,7 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO
@retval QCBOR_ERR_UNSUPPORTED Not well-formed, input contains
unsupported CBOR.
- @retval QCBOR_ERR_HIT_END Not well-formed, unexpected ran out
+ @retval QCBOR_ERR_HIT_END Not well-formed, unexpectedly ran out
of bytes.
@retval QCBOR_ERR_BAD_TYPE_7 Not well-formed, bad simple type value.
@@ -2050,6 +2075,9 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO
@retval QCBOR_ERR_EXTRA_BYTES Not well-formed, unprocessed bytes at
the end.
+ @retval QCBOR_ERR_BAD_INT Not well-formed, length of integer is
+ bad.
+
@retval QCBOR_ERR_BAD_OPT_TAG Invalid CBOR, tag on wrong type.
@retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit, array or map
@@ -2074,6 +2102,10 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO
@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:
@@ -2194,6 +2226,11 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO
to handle newly defined tags, while using very little memory, in
particular keeping @ref QCBORItem as small as possible.
+ If any error occurs, \c uDataType and \c uLabelType will be set
+ to \ref QCBOR_TYPE_NONE. If there is no need to know the specific
+ error, \ref QCBOR_TYPE_NONE can be checked for and the return value
+ ignored.
+
Errors fall in several categories as noted in list above:
- Not well-formed errors are those where there is something
@@ -2455,6 +2492,18 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
/**
+ @brief Semi-private method to open a map, array or bstr wrapped CBOR with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArrayIndefiniteLength() or QCBOREncode_OpenMapIndefiniteLength()
+ instead of this.
+ */
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
@brief Semi-private method to close a map, array or bstr wrapped CBOR
@param[in] pCtx The context to add to.
@@ -2466,6 +2515,17 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
*/
void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
+/**
+ @brief Semi-private method to close a map, array or bstr wrapped CBOR with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+ @param[out] pWrappedCBOR Pointer to @ref UsefulBufC containing wrapped bytes.
+
+ Call QCBOREncode_CloseArrayIndefiniteLength() or QCBOREncode_CloseMapIndefiniteLength()
+ instead of this.
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
/**
@brief Semi-private method to add simple types.
@@ -2961,6 +3021,50 @@ static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP, NULL);
}
+static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN, NULL);
+}
+
+
+static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN, NULL);
+}
static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
{
@@ -3010,7 +3114,19 @@ static inline int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx)
static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
{
- return pCtx->uError;
+ if(UsefulOutBuf_GetError(&(pCtx->OutBuf))) {
+ // Items didn't fit in the buffer.
+ // This check catches this condition for all the appends and inserts
+ // so checks aren't needed when the appends and inserts are performed.
+ // And of course UsefulBuf will never overrun the input buffer given
+ // to it. No complex analysis of the error handling in this file is
+ // needed to know that is true. Just read the UsefulBuf code.
+ pCtx->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
+ // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
+ // OK. Once the caller fixes this, they'll be unmasked.
+ }
+
+ return (QCBORError)pCtx->uError;
}
@@ -3024,4 +3140,3 @@ static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
#endif
#endif /* defined(__QCBOR__qcbor__) */
-
diff --git a/lib/ext/qcbor/src/UsefulBuf.c b/lib/ext/qcbor/src/UsefulBuf.c
index f13dad273c..0c336b8e7e 100644
--- a/lib/ext/qcbor/src/UsefulBuf.c
+++ b/lib/ext/qcbor/src/UsefulBuf.c
@@ -41,6 +41,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
when who what, where, why
-------- ---- ---------------------------------------------------
+ 11/08/2019 llundblade Re check pointer math and update comments
3/6/2019 llundblade Add UsefulBuf_IsValue()
09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
the end of memory when the bytes to find is longer
@@ -222,7 +223,7 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
}
/* 1. Will it fit? */
- // WillItFit() is the same as: NewData.len <= (me->size - me->data_len)
+ // WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len)
// Check #1 makes sure subtraction in RoomLeft will not wrap around
if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { // Check #2
// The new data will not fit into the the buffer.
@@ -231,7 +232,9 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
}
/* 2. Check the Insertion Position */
- // This, with Check #1, also confirms that uInsertionPos <= me->data_len
+ // This, with Check #1, also confirms that uInsertionPos <= me->data_len and
+ // that uInsertionPos + pMe->UB.ptr will not wrap around the end of the
+ // address space.
if(uInsertionPos > pMe->data_len) { // Check #3
// Off the end of the valid data in the buffer.
pMe->err = 1;
@@ -245,6 +248,7 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
if(uNumBytesToMove && pMe->UB.ptr) {
// To know memmove won't go off end of destination, see PtrMath #4
+ // Use memove because it handles overlapping buffers
memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
}
@@ -254,7 +258,7 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
// To know memmove won't go off end of destination, see PtrMath #6
memmove(pInsertionPoint, NewData.ptr, NewData.len);
}
- pMe->data_len += NewData.len ;
+ pMe->data_len += NewData.len;
}
@@ -269,9 +273,9 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
PtrMath #2 will never wrap around under because
Check #3 makes sure uInsertionPos is less than me->data_len
- PtrMath #3 will never wrap around over because todo
- PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and a maximum valid ptr
- Check #2 that NewData.len will fit
+ PtrMath #3 will never wrap around over because
+ PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len
+ Check #2 that NewData.len will fit in the unused space left in me->UB
PtrMath #4 will never wrap under because
Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len)
diff --git a/lib/ext/qcbor/src/qcbor_decode.c b/lib/ext/qcbor/src/qcbor_decode.c
index fa89b091da..36a9d116e4 100644
--- a/lib/ext/qcbor/src/qcbor_decode.c
+++ b/lib/ext/qcbor/src/qcbor_decode.c
@@ -42,6 +42,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
when who what, where, why
-------- ---- ---------------------------------------------------
+ 11/07/19 llundblade Fix long long conversion to double compiler warning
+ 09/07/19 llundblade Fix bug decoding empty arrays and maps
+ 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
@@ -127,28 +131,27 @@ inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
// Called on every single item except breaks including the opening of a map/array
inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
{
- if(!DecodeNesting_IsNested(pNesting)) {
- // at top level where there is no tracking
- return;
- }
-
- if(DecodeNesting_IsIndefiniteLength(pNesting)) {
- // There is no count for indefinite length arrays/maps
- return;
- }
-
- // Decrement the count of items in this array/map
- pNesting->pCurrent->uCount--;
+ while(DecodeNesting_IsNested(pNesting)) {
+ // Not at the top level, so there is decrementing to be done.
- // Pop up nesting levels if the counts at the levels are zero
- while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) {
- pNesting->pCurrent--;
if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
+ // Decrement the current nesting level if it is not indefinite.
pNesting->pCurrent->uCount--;
}
+
+ if(pNesting->pCurrent->uCount != 0) {
+ // Did not close out an array or map, so nothing further
+ break;
+ }
+
+ // Closed out an array or map so level up
+ pNesting->pCurrent--;
+
+ // Continue with loop to see if closing out this doesn't close out more
}
}
+
// Called on every map/array
inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
{
@@ -485,7 +488,7 @@ inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORIt
} else {
// C can't represent a negative integer in this range
- // so it is an error. todo -- test this condition
+ // so it is an error.
nReturn = QCBOR_ERR_INT_OVERFLOW;
}
}
@@ -536,11 +539,7 @@ inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber,
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);
@@ -660,7 +659,7 @@ inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
/*
The epoch formatted date. Turns lots of different forms of encoding date into uniform one
*/
-static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
+static int DecodeDateEpoch(QCBORItem *pDecodedItem)
{
// Stack usage: 1
QCBORError nReturn = QCBOR_SUCCESS;
@@ -683,13 +682,33 @@ static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
case QCBOR_TYPE_DOUBLE:
{
+ // This comparison needs to be done as a float before
+ // conversion to an int64_t to be able to detect doubles
+ // that are too large to fit into an int64_t. A double
+ // has 52 bits of preceision. An int64_t has 63. Casting
+ // INT64_MAX to a double actually causes a round up which
+ // is bad and wrong for the comparison because it will
+ // allow conversion of doubles that can't fit into a
+ // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
+ // the cutoff point as if that rounds up in conversion to
+ // double it will still be less than INT64_MAX. 0x7ff is
+ // picked because it has 11 bits set.
+ //
+ // INT64_MAX seconds is on the order of 10 billion years,
+ // and the earth is less than 5 billion years old, so for
+ // most uses this conversion error won't occur even though
+ // doubles can go much larger.
+ //
+ // Without the 0x7ff there is a ~30 minute range of time
+ // values 10 billion years in the past and in the future
+ // where this this code would go wrong.
const double d = pDecodedItem->val.dfnum;
- if(d > INT64_MAX) {
+ if(d > (double)(INT64_MAX - 0x7ff)) {
nReturn = QCBOR_ERR_DATE_OVERFLOW;
goto Done;
}
- pDecodedItem->val.epochDate.nSeconds = (int64_t) d; // Float to integer conversion happening here.
- pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds;
+ pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
+ pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
}
break;
@@ -735,21 +754,26 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
uint64_t uNumber;
uint8_t uAdditionalInfo;
+ memset(pDecodedItem, 0, sizeof(QCBORItem));
+
nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
// Error out here if we got into trouble on the type and number.
// The code after this will not work if the type and number is not good.
- if(nReturn)
+ if(nReturn) {
goto Done;
-
- memset(pDecodedItem, 0, sizeof(QCBORItem));
+ }
// At this point the major type and the value are valid. We've got the type and the number that
// starts every CBOR data item.
switch (uMajorType) {
case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
- nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
+ if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ nReturn = QCBOR_ERR_BAD_INT;
+ } else {
+ nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
+ }
break;
case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
@@ -778,8 +802,12 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
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...
@@ -864,7 +892,8 @@ static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDe
// 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;
}
@@ -1060,6 +1089,12 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod
// 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;
@@ -1084,7 +1119,10 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod
// Maps and arrays do count in as items in the map/array that encloses
// them so a decrement needs to be done for them too, but that is done
// only when all the items in them have been processed, not when they
- // are opened.
+ // are opened with the exception of an empty map or array.
+ if(pDecodedItem->val.uCount == 0) {
+ DecodeNesting_DecrementCount(&(me->nesting));
+ }
} else {
// Decrement the count of items in the enclosing map/array
// If the count in the enclosing map/array goes to zero, that
@@ -1130,6 +1168,10 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod
pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
Done:
+ if(nReturn != QCBOR_SUCCESS) {
+ // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
+ memset(pDecodedItem, 0, sizeof(QCBORItem));
+ }
return nReturn;
}
@@ -1199,7 +1241,7 @@ int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
{
- QCBORError nReturn = QCBOR_SUCCESS;
+ int nReturn = QCBOR_SUCCESS;
// Error out if all the maps/arrays are not closed out
if(DecodeNesting_IsNested(&(me->nesting))) {
diff --git a/lib/ext/qcbor/src/qcbor_encode.c b/lib/ext/qcbor/src/qcbor_encode.c
index 1155cdae87..28fb225ff5 100644
--- a/lib/ext/qcbor/src/qcbor_encode.c
+++ b/lib/ext/qcbor/src/qcbor_encode.c
@@ -42,6 +42,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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.
11/29/18 llundblade Rework to simpler handling of tags and labels.
@@ -188,7 +190,7 @@ inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
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
@@ -201,6 +203,9 @@ inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
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
*/
@@ -300,9 +305,18 @@ static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
// This is the 5 bits in the initial byte that is not the major type
uint8_t uAdditionalInfo;
- if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
+ if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
+ uMajorType = CBOR_MAJOR_TYPE_ARRAY;
+ uAdditionalInfo = LEN_IS_INDEFINITE;
+ } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
+ uMajorType = CBOR_MAJOR_TYPE_MAP;
+ uAdditionalInfo = LEN_IS_INDEFINITE;
+ } else if (uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
// Simple case where argument is < 24
uAdditionalInfo = uNumber;
+ } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
+ // Break statement can be encoded in single byte too (0xff)
+ uAdditionalInfo = uNumber;
} else {
/*
Encode argument in 1,2,4 or 8 bytes. Outer loop
@@ -453,18 +467,22 @@ void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
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)));
-
- me->uError = Nesting_Increment(&(me->nesting));
+ 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));
+ }
}
}
@@ -515,6 +533,19 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
}
}
+/*
+ Semi-public function. It is exposed to user of the interface,
+ but they will usually call one of the inline wrappers rather than this.
+
+ See header qcbor.h
+*/
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
+{
+ // insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
+ InsertEncodedTypeAndNumber(me, uMajorType, 0, 0, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+
+ QCBOREncode_OpenMapOrArray(me, uMajorType);
+}
/*
Public functions for closing arrays and maps. See header qcbor.h
@@ -568,7 +599,35 @@ void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
}
}
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
+{
+ if(me->uError == QCBOR_SUCCESS) {
+ if(!Nesting_IsInNest(&(me->nesting))) {
+ me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
+ } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
+ me->uError = QCBOR_ERR_CLOSE_MISMATCH;
+ } else {
+ // insert the break marker (0xff for both arrays and maps)
+ InsertEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_SIMPLE, 0, CBOR_SIMPLE_BREAK, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+
+ // Return pointer and length to the enclosed encoded CBOR. The intended
+ // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
+ // This must be used right away, as the pointer and length go invalid
+ // on any subsequent calls to this function because there might be calls to
+ // InsertEncodedTypeAndNumber() that slides data to the right.
+ if(pWrappedCBOR) {
+ const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+ *pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+ }
+ // Decrease nesting level
+ Nesting_Decrease(&(me->nesting));
+ }
+ }
+}
/*
@@ -576,7 +635,7 @@ void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
*/
QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
{
- QCBORError uReturn = (QCBORError) me->uError;
+ QCBORError uReturn = QCBOREncode_GetErrorState(me);
if(uReturn != QCBOR_SUCCESS) {
goto Done;
@@ -587,17 +646,6 @@ QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
goto Done;
}
- if(UsefulOutBuf_GetError(&(me->OutBuf))) {
- // Items didn't fit in the buffer.
- // This check catches this condition for all the appends and inserts
- // so checks aren't needed when the appends and inserts are performed.
- // And of course UsefulBuf will never overrun the input buffer given
- // to it. No complex analysis of the error handling in this file is
- // needed to know that is true. Just read the UsefulBuf code.
- uReturn = QCBOR_ERR_BUFFER_TOO_SMALL;
- goto Done;
- }
-
*pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Done:
@@ -605,6 +653,7 @@ Done:
}
+
/*
Public functions to finish and get the encoded result. See header qcbor.h
*/
@@ -662,4 +711,3 @@ QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLe
instance can be removed, saving some code.
*/
-
diff --git a/lib/ext/qcbor/test/float_tests.c b/lib/ext/qcbor/test/float_tests.c
index 4f12ca6d37..eaf75aa3ef 100644
--- a/lib/ext/qcbor/test/float_tests.c
+++ b/lib/ext/qcbor/test/float_tests.c
@@ -73,7 +73,7 @@ int HalfPrecisionDecodeBasicTests()
UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
QCBORDecodeContext DC;
- QCBORDecode_Init(&DC, HalfPrecision, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC, HalfPrecision, 0);
QCBORItem Item;
@@ -194,7 +194,7 @@ int HalfPrecisionAgainstRFCCodeTest()
// Now parse the hand-constructed CBOR. This will invoke the conversion to a float
QCBORDecodeContext DC;
- QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
QCBORItem Item;
diff --git a/lib/ext/qcbor/test/not_well_formed_cbor.h b/lib/ext/qcbor/test/not_well_formed_cbor.h
new file mode 100644
index 0000000000..d5bd233561
--- /dev/null
+++ b/lib/ext/qcbor/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},
+
+ // Definite length maps and arrays must be closed by having the
+ // right number of items
+
+ // A definite length array that is supposed to have 1 item, but has none
+ {(uint8_t[]){0x81}, 1},
+ // A definite length array that is supposed to have 2 items, but has only 1
+ {(uint8_t[]){0x82, 0x00}, 2},
+ // A definite length array that is supposed to have 511 items, but has only 1
+ {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4},
+ // A definite length map that is supposed to have 1 item, but has none
+ {(uint8_t[]){0xa1}, 1},
+ // A definite length map that is supposed to have s item, but has only 1
+ {(uint8_t[]){0xa2, 0x01, 0x02}, 3},
+
+
+ // Indefinite 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/lib/ext/qcbor/test/qcbor_decode_tests.c b/lib/ext/qcbor/test/qcbor_decode_tests.c
index 680c86b4a0..7de8c6cc8f 100644
--- a/lib/ext/qcbor/test/qcbor_decode_tests.c
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.c
@@ -34,6 +34,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "qcbor.h"
#include <string.h>
#include <math.h> // for fabs()
+#include "not_well_formed_cbor.h"
#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING
@@ -418,21 +419,43 @@ static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
}
+// The largest negative int possible in CBOR.
+// Not possible in C.
+static const uint8_t spTooBigNegative[] = {
+ 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
/*
Tests the decoding of lots of different integers sizes
and values.
*/
-
int IntegerValuesParseTest()
{
- int n;
+ int nReturn;
QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts),
+ QCBOR_DECODE_MODE_NORMAL);
- n = IntegerValuesParseTestInternal(&DCtx);
+ // The really big test of all successes
+ nReturn = IntegerValuesParseTestInternal(&DCtx);
+ if(nReturn) {
+ return nReturn;
+ }
- return(n);
+ // The one large negative integer that can be parsed
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooBigNegative),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORItem item;
+ if(QCBORDecode_GetNext(&DCtx, &item) != QCBOR_ERR_INT_OVERFLOW) {
+ nReturn = -4000;
+ }
+
+ return(nReturn);
}
@@ -592,6 +615,149 @@ int SimpleArrayTest()
}
+/*
+ [
+ 0,
+ [],
+ [
+ [],
+ [
+ 0
+ ],
+ {},
+ {
+ 1: {},
+ 2: {},
+ 3: []
+ }
+ ]
+ ]
+ */
+static uint8_t sEmpties[] = {0x83, 0x00, 0x80, 0x84, 0x80, 0x81, 0x00, 0xa0,
+ 0xa3, 0x01, 0xa0, 0x02, 0xa0, 0x03, 0x80};
+
+int EmptyMapsAndArraysTest()
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties), QCBOR_DECODE_MODE_NORMAL);
+
+ // Array with 3 items
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 0 ||
+ Item.uNextNestLevel != 1 ||
+ Item.val.uCount != 3) {
+ return -1;
+ }
+
+ // An integer 0
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.uNestingLevel != 1 ||
+ Item.uNextNestLevel != 1 ||
+ Item.val.uint64 != 0) {
+ return -2;
+ }
+
+ // An empty array
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 1 ||
+ Item.uNextNestLevel != 1 ||
+ Item.val.uCount != 0) {
+ return -3;
+ }
+
+ // An array with 4 items
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 1 ||
+ Item.uNextNestLevel != 2 ||
+ Item.val.uCount != 4) {
+ return -4;
+ }
+
+ // An empty array
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 2 ||
+ Item.uNextNestLevel != 2 ||
+ Item.val.uCount != 0) {
+ return -5;
+ }
+
+ // An array with 1 item
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 2 ||
+ Item.uNextNestLevel != 3 ||
+ Item.val.uCount != 1) {
+ return -6;
+ }
+
+ // An integer 0
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.uNestingLevel != 3 ||
+ Item.uNextNestLevel != 2 ||
+ Item.val.uint64 != 0) {
+ return -7;
+ }
+
+ // An empty map
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.uNestingLevel != 2 ||
+ Item.uNextNestLevel != 2 ||
+ Item.val.uCount != 0) {
+ return -8;
+ }
+
+ // An map with 3 items
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.uNestingLevel != 2 ||
+ Item.uNextNestLevel != 3 ||
+ Item.val.uCount != 3) {
+ return -9;
+ }
+
+ // An empty map
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.uNestingLevel != 3 ||
+ Item.uNextNestLevel != 3 ||
+ Item.val.uCount != 0) {
+ return -10;
+ }
+
+ // An empty map
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.uNestingLevel != 3 ||
+ Item.uNextNestLevel != 3 ||
+ Item.val.uCount != 0) {
+ return -11;
+ }
+
+ // An empty array
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.uNestingLevel != 3 ||
+ Item.uNextNestLevel != 0 ||
+ Item.val.uCount != 0) {
+ return -12;
+ }
+
+ if(QCBORDecode_Finish(&DCtx) != QCBOR_SUCCESS) {
+ return -13;
+ }
+
+ return 0;
+}
+
static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80};
@@ -654,20 +820,16 @@ int ParseTooDeepArrayTest()
int ShortBufferParseTest()
{
- int nResult = 0;
- QCBORDecodeContext DCtx;
- int num;
-
- for(num = sizeof(spExpectedEncodedInts)-1; num; num--) {
- int n;
+ int nResult = 0;
- QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL);
+ for(int nNum = sizeof(spExpectedEncodedInts)-1; nNum; nNum--) {
+ QCBORDecodeContext DCtx;
- n = IntegerValuesParseTestInternal(&DCtx);
+ QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, nNum}, QCBOR_DECODE_MODE_NORMAL);
- //printf("Len %d, result: %d\n", num, n);
+ const QCBORError nErr = IntegerValuesParseTestInternal(&DCtx);
- if(n != QCBOR_ERR_HIT_END) {
+ if(nErr != QCBOR_ERR_HIT_END && nErr != QCBOR_ERR_NO_MORE_ITEMS) {
nResult = -1;
goto Done;
}
@@ -1329,86 +1491,401 @@ int ParseSimpleTest()
}
+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;
- int nError;
+ UsefulBufC Input; // CBOR to decode
+ QCBORError nError; // The error expected
};
-
struct FailInput Failures[] = {
- { {(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_UNSUPPORTED }, // 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_UNSUPPORTED }, // 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[]){0x5f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length byte string
- { {(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[]){0x7f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length UTF-8 string
- { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_UNSUPPORTED } , // 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
- { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG } // big num tagged an int, not a byte string
-
+ { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // big num tagged an int, not a byte string
};
-
-int FailureTests()
+int DecodeFailureTests()
{
- int nResult = 0;
-
- struct FailInput *pFEnd = &Failures[0] + sizeof(Failures)/sizeof(struct FailInput);
+ // 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++) {
- for(struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) {
+ // Set up the decoding context including a memory pool so that
+ // indefinite length items can be checked
QCBORDecodeContext DCtx;
- QCBORItem Item;
- int 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;
+ }
+
+ // Iterate until there is an error of some sort error
+ QCBORItem Item;
+ do {
+ // Set to something none-zero other than QCBOR_TYPE_NONE
+ memset(&Item, 0x33, sizeof(Item));
- while(1) {
nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
- if(QCBOR_ERR_HIT_END == nCBORError) {
- break;
- }
- if(nCBORError != pF->nError) {
- nResult = 1;
- break;
- }
+ } while(nCBORError == QCBOR_SUCCESS);
+
+ // Must get the expected error or the this test fails
+ // The data and label type must also be QCBOR_TYPE_NONE
+ if(nCBORError != pF->nError ||
+ Item.uDataType != QCBOR_TYPE_NONE ||
+ Item.uLabelType != QCBOR_TYPE_NONE) {
+ // return index of CBOR + 1000
+ return 1000 + (int)(pF - &Failures[0]);
}
}
+ // Corrupt the UsefulInputBuf and see that
+ // it reflected correctly for CBOR decoding
{
QCBORDecodeContext DCtx;
- QCBORItem Item;
- int nCBORError;
+ QCBORItem Item;
+ QCBORError nCBORError;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues),
+ QCBOR_DECODE_MODE_NORMAL);
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
- Item.val.uCount != 10)
+ Item.val.uCount != 10) {
+ // This wasn't supposed to happen
return -1;
+ }
- DCtx.InBuf.magic = 0; // Corrupt the UsefulInputBuf
+ DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf
nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
- if(nCBORError != QCBOR_ERR_HIT_END)
- return -1;
+ if(nCBORError != QCBOR_ERR_HIT_END) {
+ // Did not get back the error expected
+ return -2;
+ }
}
-
- return nResult;
+ return 0;
}
@@ -1499,8 +1976,14 @@ static uint8_t spDateTestInput[] = {
0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1
0xc1, // tag for epoch date
- 0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large
+ 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large
+
+ 0xc1, // tag for epoch date
+ 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large
+ //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large
+ 0xc1, // tag for epoch date
+ 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe // 9223372036854773760 largest supported
};
@@ -1575,6 +2058,18 @@ int DateParseTest()
return -10;
}
+ // Epoch date double that is just slightly too large
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+ return -11;
+ }
+
+ // Largest double epoch date supported
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_SUCCESS ||
+ Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
+ Item.val.epochDate.nSeconds != 9223372036854773760 ||
+ Item.val.epochDate.nSeconds == 0) {
+ return -12;
+ }
// TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good)
return 0;
diff --git a/lib/ext/qcbor/test/qcbor_decode_tests.h b/lib/ext/qcbor/test/qcbor_decode_tests.h
index 3ef0ca399c..6423ccff33 100644
--- a/lib/ext/qcbor/test/qcbor_decode_tests.h
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.h
@@ -33,8 +33,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __QCBOR__qcbort_decode_tests__
#define __QCBOR__qcbort_decode_tests__
-#include "qcbor.h"
-
/*
Notes:
@@ -49,8 +47,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
-
/*
Parse a well-known set of integers including those around the boundaries and
make sure the expected values come out
@@ -58,9 +54,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
int IntegerValuesParseTest(void);
-
-
-
/*
Decode a simple CBOR encoded array and make sure it returns all the correct values.
This is a decode test.
@@ -69,6 +62,12 @@ int SimpleArrayTest(void);
/*
+ Tests with empty maps and arrays
+ */
+int EmptyMapsAndArraysTest(void);
+
+
+/*
Make sure a maximally deep array can be parsed and that the
reported nesting level is correct. This uses test vector
of CBOR encoded data with a depth of 10. This a parse test.
@@ -112,29 +111,30 @@ int ShortBufferParseTest2(void);
int ParseMapTest(void);
-
-int FloatValuesTest1(void);
-
-
-
-int SimpleValuesTest1(void);
-
-
/*
-
+Test the decoder mode where maps are treated as arrays.
*/
int ParseMapAsArrayTest(void);
-
+/*
+ Test parsing of some simple values like true, false, null...
+ */
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
*/
-int FailureTests(void);
+int DecodeFailureTests(void);
/*
@@ -176,6 +176,9 @@ int OptTagParseTest(void);
int BignumParseTest(void);
+/*
+ Test of mode where only string labels are allowed
+ */
int StringDecoderModeFailTest(void);
@@ -232,6 +235,4 @@ int MemPoolTest(void);
int SetUpAllocatorTest(void);
-
-
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/lib/ext/qcbor/test/qcbor_encode_tests.c b/lib/ext/qcbor/test/qcbor_encode_tests.c
index 458331c645..7866b375f0 100644
--- a/lib/ext/qcbor/test/qcbor_encode_tests.c
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.c
@@ -653,7 +653,7 @@ Done:
}
/*
- 98 2F # array(47)
+ 98 30 # array(48)
3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807)
3B 0000000100000000 # negative(4294967296)
3A FFFFFFFF # negative(4294967295)
@@ -682,6 +682,7 @@ Done:
18 18 # unsigned(24)
18 19 # unsigned(25)
18 1A # unsigned(26)
+ 18 1F # unsigned(31)
18 FE # unsigned(254)
18 FF # unsigned(255)
19 0100 # unsigned(256)
@@ -703,7 +704,7 @@ Done:
1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615)
*/
static const uint8_t spExpectedEncodedInts[] = {
- 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0x98, 0x30, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff,
0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff,
@@ -714,19 +715,19 @@ static const uint8_t spExpectedEncodedInts[] = {
0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38,
0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00,
0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18,
- 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00,
- 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff,
- 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00,
- 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02,
- 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff,
- 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a,
- 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff,
- 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
- 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff};
+ 0x1a, 0x18, 0x1f, 0x18, 0xfe, 0x18, 0xff, 0x19,
+ 0x01, 0x00, 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe,
+ 0x19, 0xff, 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00,
+ 0x1a, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01,
+ 0x00, 0x02, 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a,
+ 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00,
+ 0x00, 0x1a, 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff,
+ 0xff, 0xff, 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff,
+ 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff};
/*
@@ -773,6 +774,7 @@ int IntegerValuesTest1()
QCBOREncode_AddInt64(&ECtx, 24);
QCBOREncode_AddInt64(&ECtx, 25);
QCBOREncode_AddInt64(&ECtx, 26);
+ QCBOREncode_AddInt64(&ECtx, 31);
QCBOREncode_AddInt64(&ECtx, 254);
QCBOREncode_AddInt64(&ECtx, 255);
QCBOREncode_AddInt64(&ECtx, 256);
@@ -852,6 +854,266 @@ int SimpleValuesTest1()
return(nReturn);
}
+/*
+ 9F # array(5)
+ F5 # primitive(21)
+ F4 # primitive(20)
+ F6 # primitive(22)
+ F7 # primitive(23)
+ BF # map(1)
+ 65 # text(5)
+ 554E446566 # "UNDef"
+ F7 # primitive(23)
+ FF # break
+ FF # break
+ */
+static const uint8_t spExpectedEncodedSimpleIndefiniteLength[] = {
+ 0x9f, 0xf5, 0xf4, 0xf6, 0xf7, 0xbf, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7, 0xff, 0xff};
+
+int SimpleValuesIndefiniteLengthTest1()
+{
+ QCBOREncodeContext ECtx;
+ int nReturn = 0;
+
+ QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+ QCBOREncode_OpenArrayIndefiniteLength(&ECtx);
+
+ QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE);
+ QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE);
+ QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL);
+ QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
+
+ QCBOREncode_OpenMapIndefiniteLength(&ECtx);
+
+ QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF);
+ QCBOREncode_CloseMapIndefiniteLength(&ECtx);
+
+ QCBOREncode_CloseArrayIndefiniteLength(&ECtx);
+
+ UsefulBufC ECBOR;
+ if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
+ nReturn = -1;
+ }
+
+ if(CheckResults(ECBOR, spExpectedEncodedSimpleIndefiniteLength))
+ return -2;
+
+ return(nReturn);
+}
+
+/*
+A5 # map(5)
+ 63 # text(3)
+ 617272 # "arr"
+ 98 1F # array(31)
+ 00 # unsigned(0)
+ 01 # unsigned(1)
+ 02 # unsigned(2)
+ 03 # unsigned(3)
+ 04 # unsigned(4)
+ 05 # unsigned(5)
+ 06 # unsigned(6)
+ 07 # unsigned(7)
+ 08 # unsigned(8)
+ 09 # unsigned(9)
+ 0A # unsigned(10)
+ 0B # unsigned(11)
+ 0C # unsigned(12)
+ 0D # unsigned(13)
+ 0E # unsigned(14)
+ 0F # unsigned(15)
+ 10 # unsigned(16)
+ 11 # unsigned(17)
+ 12 # unsigned(18)
+ 13 # unsigned(19)
+ 14 # unsigned(20)
+ 15 # unsigned(21)
+ 16 # unsigned(22)
+ 17 # unsigned(23)
+ 18 18 # unsigned(24)
+ 18 19 # unsigned(25)
+ 18 1A # unsigned(26)
+ 18 1B # unsigned(27)
+ 18 1C # unsigned(28)
+ 18 1D # unsigned(29)
+ 18 1E # unsigned(30)
+ 63 # text(3)
+ 6D6170 # "map"
+ B8 1F # map(31)
+ 61 # text(1)
+ 61 # "a"
+ 00 # unsigned(0)
+ 61 # text(1)
+ 62 # "b"
+ 01 # unsigned(1)
+ 61 # text(1)
+ 63 # "c"
+ 02 # unsigned(2)
+ 61 # text(1)
+ 64 # "d"
+ 03 # unsigned(3)
+ 61 # text(1)
+ 65 # "e"
+ 04 # unsigned(4)
+ 61 # text(1)
+ 66 # "f"
+ 05 # unsigned(5)
+ 61 # text(1)
+ 67 # "g"
+ 06 # unsigned(6)
+ 61 # text(1)
+ 68 # "h"
+ 07 # unsigned(7)
+ 61 # text(1)
+ 69 # "i"
+ 08 # unsigned(8)
+ 61 # text(1)
+ 6A # "j"
+ 09 # unsigned(9)
+ 61 # text(1)
+ 6B # "k"
+ 0A # unsigned(10)
+ 61 # text(1)
+ 6C # "l"
+ 0B # unsigned(11)
+ 61 # text(1)
+ 6D # "m"
+ 0C # unsigned(12)
+ 61 # text(1)
+ 6E # "n"
+ 0D # unsigned(13)
+ 61 # text(1)
+ 6F # "o"
+ 0E # unsigned(14)
+ 61 # text(1)
+ 70 # "p"
+ 0F # unsigned(15)
+ 61 # text(1)
+ 71 # "q"
+ 10 # unsigned(16)
+ 61 # text(1)
+ 72 # "r"
+ 11 # unsigned(17)
+ 61 # text(1)
+ 73 # "s"
+ 12 # unsigned(18)
+ 61 # text(1)
+ 74 # "t"
+ 13 # unsigned(19)
+ 61 # text(1)
+ 75 # "u"
+ 14 # unsigned(20)
+ 61 # text(1)
+ 76 # "v"
+ 15 # unsigned(21)
+ 61 # text(1)
+ 77 # "w"
+ 16 # unsigned(22)
+ 61 # text(1)
+ 78 # "x"
+ 17 # unsigned(23)
+ 61 # text(1)
+ 79 # "y"
+ 18 18 # unsigned(24)
+ 61 # text(1)
+ 7A # "z"
+ 18 19 # unsigned(25)
+ 61 # text(1)
+ 41 # "A"
+ 18 1A # unsigned(26)
+ 61 # text(1)
+ 42 # "B"
+ 18 1B # unsigned(27)
+ 61 # text(1)
+ 43 # "C"
+ 18 1C # unsigned(28)
+ 61 # text(1)
+ 44 # "D"
+ 18 1D # unsigned(29)
+ 61 # text(1)
+ 45 # "E"
+ 18 1E # unsigned(30)
+ 65 # text(5)
+ 6D696E3331 # "min31"
+ 38 1E # negative(30)
+ 66 # text(6)
+ 706C75733331 # "plus31"
+ 18 1F # unsigned(31)
+ 63 # text(3)
+ 737472 # "str"
+ 78 1F # text(31)
+ 7465737474657374746573747465737474657374746573747163626F723131 # "testtesttesttesttesttestqcbor11"
+ */
+static const uint8_t EncodeLengthThirtyone[] = {
+ 0xa5, 0x63, 0x61, 0x72, 0x72, 0x98, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18,
+ 0x1a, 0x18, 0x1b, 0x18, 0x1c, 0x18, 0x1d, 0x18, 0x1e, 0x63, 0x6d, 0x61,
+ 0x70, 0xb8, 0x1f, 0x61, 0x61, 0x00, 0x61, 0x62, 0x01, 0x61, 0x63, 0x02,
+ 0x61, 0x64, 0x03, 0x61, 0x65, 0x04, 0x61, 0x66, 0x05, 0x61, 0x67, 0x06,
+ 0x61, 0x68, 0x07, 0x61, 0x69, 0x08, 0x61, 0x6a, 0x09, 0x61, 0x6b, 0x0a,
+ 0x61, 0x6c, 0x0b, 0x61, 0x6d, 0x0c, 0x61, 0x6e, 0x0d, 0x61, 0x6f, 0x0e,
+ 0x61, 0x70, 0x0f, 0x61, 0x71, 0x10, 0x61, 0x72, 0x11, 0x61, 0x73, 0x12,
+ 0x61, 0x74, 0x13, 0x61, 0x75, 0x14, 0x61, 0x76, 0x15, 0x61, 0x77, 0x16,
+ 0x61, 0x78, 0x17, 0x61, 0x79, 0x18, 0x18, 0x61, 0x7a, 0x18, 0x19, 0x61,
+ 0x41, 0x18, 0x1a, 0x61, 0x42, 0x18, 0x1b, 0x61, 0x43, 0x18, 0x1c, 0x61,
+ 0x44, 0x18, 0x1d, 0x61, 0x45, 0x18, 0x1e, 0x65, 0x6d, 0x69, 0x6e, 0x33,
+ 0x31, 0x38, 0x1e, 0x66, 0x70, 0x6c, 0x75, 0x73, 0x33, 0x31, 0x18, 0x1f,
+ 0x63, 0x73, 0x74, 0x72, 0x78, 0x1f, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65,
+ 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x74, 0x65,
+ 0x73, 0x74, 0x74, 0x65, 0x73, 0x74, 0x71, 0x63, 0x62, 0x6f, 0x72, 0x31,
+ 0x31
+};
+
+int EncodeLengthThirtyoneTest()
+{
+ QCBOREncodeContext ECtx;
+ int nReturn = 0;
+
+ QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+ QCBOREncode_OpenMap(&ECtx);
+
+ // add array with 31 items
+ QCBOREncode_OpenArrayInMap(&ECtx, "arr");
+ for (size_t ix = 0; ix < 31; ix++) {
+ QCBOREncode_AddInt64(&ECtx, ix);
+ }
+ QCBOREncode_CloseArray(&ECtx);
+
+ // add map with 31 items
+ QCBOREncode_OpenMapInMap(&ECtx, "map");
+ for (size_t ix = 0; ix < 31; ix++) {
+ // make sure we have unique keys in the map (a-z then follow by A-Z)
+ char c = 'a';
+ if (ix < 26) c = c + ix;
+ else c = 'A' + (ix - 26);
+ char buffer[2] = { c, 0 };
+ QCBOREncode_AddInt64ToMap(&ECtx, buffer, ix);
+ }
+ QCBOREncode_CloseMap(&ECtx);
+
+ // add -31 and +31
+ QCBOREncode_AddInt64ToMap(&ECtx, "min31", -31);
+ QCBOREncode_AddInt64ToMap(&ECtx, "plus31", 31);
+
+ // add string with length 31
+ const char *str = "testtesttesttesttesttestqcbor11";
+ UsefulBufC str_b = { str, 31 };
+ QCBOREncode_AddTextToMap(&ECtx, "str", str_b);
+
+ QCBOREncode_CloseMap(&ECtx);
+
+ UsefulBufC ECBOR;
+ if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
+ nReturn = -1;
+ }
+
+ if(CheckResults(ECBOR, EncodeLengthThirtyone))
+ return -2;
+
+ return(nReturn);
+}
+
/*
83 # array(3)
@@ -1006,7 +1268,7 @@ static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80};
81 # array(1)
81 # array(1)
80 # array(0)
- 98 2F # array(47)
+ 98 30 # array(48)
3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807)
3B 0000000100000000 # negative(4294967296)
3A FFFFFFFF # negative(4294967295)
@@ -1035,6 +1297,7 @@ static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80};
18 18 # unsigned(24)
18 19 # unsigned(25)
18 1A # unsigned(26)
+ 18 1F # unsigned(31)
18 FE # unsigned(254)
18 FF # unsigned(255)
19 0100 # unsigned(256)
@@ -1056,7 +1319,7 @@ static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80};
1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615)
*/
static const uint8_t spEncodeRawExpected[] = {
- 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x98, 0x2f,
+ 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x98, 0x30,
0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, 0xff, 0x3a,
@@ -1068,18 +1331,19 @@ static const uint8_t spEncodeRawExpected[] = {
0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, 0xfd, 0x38,
0x18, 0x37, 0x36, 0x20, 0x00, 0x00, 0x01, 0x16,
0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x1a, 0x18,
- 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, 0x19, 0x01,
- 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, 0xff, 0x1a,
- 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x00,
- 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, 0x1a, 0x7f,
- 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, 0xff, 0xff,
- 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, 0x80, 0x00,
- 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, 0xfe, 0x1a,
- 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x7f,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ 0x1f, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00,
+ 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff,
+ 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00,
+ 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02,
+ 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff,
+ 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a,
+ 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff,
+ 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff};
int EncodeRawTest()
@@ -1588,7 +1852,7 @@ static int DecodeNextNested(UsefulBufC Wrapped)
}
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) {
@@ -2050,6 +2314,20 @@ int EncodeErrorTests()
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/lib/ext/qcbor/test/qcbor_encode_tests.h b/lib/ext/qcbor/test/qcbor_encode_tests.h
index 33703d831a..790928834a 100644
--- a/lib/ext/qcbor/test/qcbor_encode_tests.h
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.h
@@ -33,8 +33,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __QCBOR__qcbor_encode_tests__
#define __QCBOR__qcbor_encode_tests__
-#include "qcbor.h"
-
/*
Notes:
@@ -62,7 +60,6 @@ int BasicEncodeTest(void);
int IntegerValuesTest1(void);
-
/*
Create nested arrays to the max depth allowed and make sure it succeeds.
This is an encoding test.
@@ -98,7 +95,6 @@ int EncodeRawTest(void);
int MapEncodeTest(void);
-
/*
Encodes a goodly number of floats and doubles and checks encoding is right
*/
@@ -112,6 +108,18 @@ int SimpleValuesTest1(void);
/*
+ Encodes basic maps and arrays with indefinite length
+ */
+int SimpleValuesIndefiniteLengthTest1(void);
+
+/*
+ Indefinite length arrays and maps use the 'magic' number 31, verify that
+ everything with length 31 still works properly
+ */
+int EncodeLengthThirtyoneTest(void);
+
+
+/*
Encodes most data formats that are supported */
int EncodeDateTest(void);
@@ -132,14 +140,32 @@ int AllAddMethodsTest(void);
*/
int BstrWrapTest(void);
+
+/*
+ Test error cases for bstr wrapping encoding such as closing an open
+ array with CloseBstrWrap
+ */
int BstrWrapErrorTest(void);
+
+/*
+ Test complicated nested bstr wrapping
+ */
int BstrWrapNestTest(void);
+
+/*
+ Test encoding a COSE_Sign1 with bstr wrapping
+ */
int CoseSign1TBSTest(void);
-int EncodeErrorTests(void);
+/*
+ Test the error cases when encoding CBOR such as buffer too large,
+ buffer too small, array nesting too deep. Aims to cover the error
+ codes returned when encoding CBOR
+ */
+int EncodeErrorTests(void);
#endif /* defined(__QCBOR__qcbor_encode_tests__) */
diff --git a/lib/ext/qcbor/test/run_tests.c b/lib/ext/qcbor/test/run_tests.c
index 9a51290f89..52c4f8f0e8 100644
--- a/lib/ext/qcbor/test/run_tests.c
+++ b/lib/ext/qcbor/test/run_tests.c
@@ -20,54 +20,9 @@
#include "UsefulBuf_Tests.h"
-
-// Used to test RunTests
-int fail_test()
-{
- return -44;
-}
-
-
-
-
/*
- Convert a number up to 999999999 to a string. This is so sprintf doesn't
- have to be linked in so as to minimized dependencies even in test code.
- */
-const char *NumToString(int32_t nNum, UsefulBuf StringMem)
-{
- const int32_t nMax = 1000000000;
-
- UsefulOutBuf OutBuf;
- UsefulOutBuf_Init(&OutBuf, StringMem);
-
- if(nNum < 0) {
- UsefulOutBuf_AppendByte(&OutBuf, '-');
- nNum = -nNum;
- }
- if(nNum > nMax-1) {
- return "XXX";
- }
-
- bool bDidSomeOutput = false;
- for(int n = nMax; n > 0; n/=10) {
- int x = nNum/n;
- if(x || bDidSomeOutput){
- bDidSomeOutput = true;
- UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
- nNum -= x * n;
- }
- }
- if(!bDidSomeOutput){
- UsefulOutBuf_AppendByte(&OutBuf, '0');
- }
- UsefulOutBuf_AppendByte(&OutBuf, '\0');
-
- return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
-}
-
-
-
+ Test configuration
+ */
typedef int (test_fun_t)(void);
typedef const char * (test_fun2_t)(void);
@@ -88,7 +43,8 @@ typedef struct {
bool bEnabled;
} test_entry2;
-test_entry2 s_tests2[] = {
+
+static test_entry2 s_tests2[] = {
TEST_ENTRY(UBUTest_CopyUtil),
TEST_ENTRY(UOBTest_NonAdversarial),
TEST_ENTRY(TestBasicSanity),
@@ -99,12 +55,15 @@ test_entry2 s_tests2[] = {
};
-test_entry s_tests[] = {
+static test_entry s_tests[] = {
+ TEST_ENTRY(EmptyMapsAndArraysTest),
+ TEST_ENTRY(NotWellFormedTests),
TEST_ENTRY(ParseMapAsArrayTest),
TEST_ENTRY(AllocAllStringsTest),
TEST_ENTRY(IndefiniteLengthNestTest),
TEST_ENTRY(NestedMapTestIndefLen),
TEST_ENTRY(ParseSimpleTest),
+ TEST_ENTRY(DecodeFailureTests),
TEST_ENTRY(EncodeRawTest),
TEST_ENTRY(RTICResultsTest),
TEST_ENTRY(MapEncodeTest),
@@ -142,15 +101,61 @@ test_entry s_tests[] = {
TEST_ENTRY_DISABLED(BigComprehensiveInputTest),
TEST_ENTRY(EncodeErrorTests),
TEST_ENTRY(SetUpAllocatorTest),
- //TEST_ENTRY(fail_test),
+ TEST_ENTRY(SimpleValuesIndefiniteLengthTest1),
+ TEST_ENTRY(EncodeLengthThirtyoneTest),
};
+
+
+/*
+ Convert a number up to 999999999 to a string. This is so sprintf doesn't
+ have to be linked in so as to minimized dependencies even in test code.
+
+ StringMem should be 12 bytes long, 9 for digits, 1 for minus and
+ 1 for \0 termination.
+ */
+static const char *NumToString(int32_t nNum, UsefulBuf StringMem)
+{
+ const int32_t nMax = 1000000000;
+
+ UsefulOutBuf OutBuf;
+ UsefulOutBuf_Init(&OutBuf, StringMem);
+
+ if(nNum < 0) {
+ UsefulOutBuf_AppendByte(&OutBuf, '-');
+ nNum = -nNum;
+ }
+ if(nNum > nMax-1) {
+ return "XXX";
+ }
+
+ bool bDidSomeOutput = false;
+ for(int n = nMax; n > 0; n/=10) {
+ int x = nNum/n;
+ if(x || bDidSomeOutput){
+ bDidSomeOutput = true;
+ UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
+ nNum -= x * n;
+ }
+ }
+ if(!bDidSomeOutput){
+ UsefulOutBuf_AppendByte(&OutBuf, '0');
+ }
+ UsefulOutBuf_AppendByte(&OutBuf, '\0');
+
+ return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
+}
+
+
+/*
+ Public function. See run_test.h.
+ */
int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun)
{
int nTestsFailed = 0;
int nTestsRun = 0;
- UsefulBuf_MAKE_STACK_UB(StringStorage, 5);
+ UsefulBuf_MAKE_STACK_UB(StringStorage, 12);
test_entry2 *t2;
const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2);
@@ -259,8 +264,11 @@ int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx,
}
+#include "qcbor.h" // For size printing
-
+/*
+ Public function. See run_test.h.
+ */
static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx)
{
UsefulBuf_MAKE_STACK_UB(buffer, 20);
@@ -271,6 +279,10 @@ static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutpu
(*pfOutput)("", pOutCtx, 1);
}
+
+/*
+ Public function. See run_test.h.
+ */
void PrintSizes(OutputStringCB pfOutput, void *pOutCtx)
{
// Type and size of return from sizeof() varies. These will never be large so cast is safe