bstr wrapping is working; removed old way of doing it
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 672c33a..dd1c21a 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -28,14 +28,14 @@
/* Begin PBXFileReference section */
E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
- E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; };
+ E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
E776E08D214AE07500E67947 /* UsefulBuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = UsefulBuf.c; path = src/UsefulBuf.c; sourceTree = "<group>"; };
E776E08E214AE07500E67947 /* qcbor_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_decode.c; path = src/qcbor_decode.c; sourceTree = "<group>"; };
E776E093214AE08B00E67947 /* qcbor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor.h; path = inc/qcbor.h; sourceTree = "<group>"; };
E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = "<group>"; tabWidth = 3; };
E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = "<group>"; };
E776E09B214AEEEA00E67947 /* basic_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = basic_test.h; path = test/basic_test.h; sourceTree = "<group>"; };
- E776E09C214AEEEA00E67947 /* basic_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = basic_test.c; path = test/basic_test.c; sourceTree = "<group>"; };
+ E776E09C214AEEEA00E67947 /* basic_test.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = basic_test.c; path = test/basic_test.c; sourceTree = "<group>"; tabWidth = 3; };
E776E161214EE19C00E67947 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -205,7 +205,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = s;
+ GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
@@ -262,6 +262,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 309b98b..2919bf6 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -31,8 +31,16 @@
#include "basic_test.h"
int main(int argc, const char * argv[]) {
- printf("Test Result %d\n", basic_test_one());
+ int x = cose_sign1_tbs_test();
+
+ x = bstr_wrap_nest_test();
+
+ x = bstr_wrap_error_test();
+
+ x = bstrwraptest();
+
+ printf("Test Result %d\n", basic_test_one());
return 0;
}
diff --git a/inc/qcbor.h b/inc/qcbor.h
index b555873..b21e065 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -124,7 +124,6 @@
uint32_t uStart; // uStart is the byte position where the array starts
uint16_t uCount; // Number of items in the arrary or map; counts items in a map, not pairs of items
uint8_t uMajorType; // Indicates if item is a map or an array
- uint8_t bBstrWrap; // non-zero if map/array should be wrapped in a bstring
} pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
*pCurrentNesting; // the current nesting level
} QCBORTrackNesting;
@@ -579,6 +578,10 @@
/** Returned by QCBORDecode_Finish() if all the inputs bytes have not been consumed */
#define QCBOR_ERR_EXTRA_BYTES 16
+/** Closing something different than is open */
+#define QCBOR_ERR_CLOSE_MISMATCH 17
+
+
/** See QCBORDecode_Init() */
#define QCBOR_DECODE_MODE_NORMAL 0
@@ -1161,7 +1164,6 @@
@param[in] szLabel A NULL-terminated string label for the map. May be a NULL pointer.
@param[in] nLabel An integer label for the whole map. QCBOR_NO_INT_LABEL for no integer label.
@param[in] uTag A tag for the whole map or CBOR_TAG_NONE.
- @param[in] bBstrWrap Indicates entire map should be wrapped as a binary string. Normally 0.
Arrays are the basic CBOR aggregate or structure type. Call this
function to start or open an array. The call the various AddXXX
@@ -1200,16 +1202,16 @@
to get to all the data needed for a signature verification.
*/
-void QCBOREncode_OpenArray_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag, bool bBstrWrap);
+void QCBOREncode_OpenArray_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag);
#define QCBOREncode_OpenArray(pCtx) \
- QCBOREncode_OpenArray_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenArray_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
#define QCBOREncode_OpenArrayInMap(pCtx, szLabel) \
- QCBOREncode_OpenArray_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenArray_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
#define QCBOREncode_OpenArrayInMapN(pCtx, nLabel) \
- QCBOREncode_OpenArray_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenArray_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE)
/**
@@ -1220,7 +1222,6 @@
@param[in] szLabel A NULL-terminated string label for the map. May be a NULL pointer.
@param[in] nLabel An integer label for the whole map. QCBOR_NO_INT_LABEL for no integer label.
@param[in] uTag A tag for the whole map or CBOR_TAG_NONE.
- @param[in] bBstrWrap Indicates entire map should be wrapped as a binary string. Normally 0.
See QCBOREncode_OpenArray() for more information.
@@ -1241,35 +1242,88 @@
*/
-void QCBOREncode_OpenMap_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag, uint8_t bBstrWrap);
+void QCBOREncode_OpenMap_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag);
#define QCBOREncode_OpenMap(pCtx) \
- QCBOREncode_OpenMap_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenMap_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
#define QCBOREncode_OpenMapInMap(pCtx, szLabel) \
- QCBOREncode_OpenMap_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenMap_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
#define QCBOREncode_OpenMapInMapN(pCtx, nLabel) \
- QCBOREncode_OpenMap_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, 0)
+ QCBOREncode_OpenMap_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE)
/**
- @brief Closes the current open array.
+ @brief Closes array, map or bstr wrapping
@param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+ @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes
- This reduces the nesting level by one.
+ This reduces the nesting level by one. Usually one of the
+ macros below is called rather than calling this directly.
If more Close's have been called than Open's the error state is
entered, no value is returned and the error can be discovered when
QCBOREncode_Finish() is called. The error will be
QCBOR_ERR_TOO_MANY_CLOSES.
+
+ If uMajorType doesn't match the type of what is open then
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+
+ A pointer and length of the enclosed encoded CBOR is returned
+ in *pWrappedCBOR if it is not NULL. The main purpose of this
+ is so this data can be hashed (e.g., with SHA-256) as part of
+ a COSE implementation. **WARNING**, this pointer and length
+ should be used right away before any other calls to QCBOREncode_xxxx()
+ as they will move data around and the pointer and length
+ will no longer be to the correct encoded CBOR.
+
*/
+void QCBOREncode_Close(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
-void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
+#define QCBOREncode_CloseBstrWrap(pCtx, pWrappedCBOR) \
+ QCBOREncode_Close(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, pWrappedCBOR)
-#define QCBOREncode_CloseMap(pCtx) QCBOREncode_CloseArray(pCtx)
+#define QCBOREncode_CloseArray(pCtx) \
+ QCBOREncode_Close(pCtx, CBOR_MAJOR_TYPE_ARRAY, NULL)
+
+#define QCBOREncode_CloseMap(pCtx) \
+ QCBOREncode_Close(pCtx, CBOR_MAJOR_TYPE_MAP, NULL)
+
+
+/**
+ @brief Indicate start of encoded CBOR to be wrapped in a bstr
+
+ @param[in] pCtx The context to add to.
+ @param[in] szLabel A NULL-terminated string label for the map. May be a NULL pointer.
+ @param[in] nLabel An integer label for the whole map. QCBOR_NO_INT_LABEL for no integer label.
+ @param[in] uTag A tag for the whole map or CBOR_TAG_NONE.
+
+ All added encoded items between this call and a call to QCBOREncode_CloseBstrWrap()
+ will be wrapped in a bstr. They will appear in the final output as a byte string.
+ That byte string will contain encoded CBOR.
+
+ The typical use case is for encoded CBOR that is to be
+ cryptographically hashed, typically as part of a COSE implementation. This
+ avoid having to encode the items first in one buffer (e.g., the COSE payload)
+ and then add that buffer as a bstr to another encoding (e.g. the COSE
+ to-be-signed bytes, the Sig_structure potentially saving a lot of memory.
+
+ */
+void QCBOREncode_OpenBstrWrap_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag);
+
+#define QCBOREncode_BstrWrap(pCtx) \
+ QCBOREncode_OpenBstrWrap_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
+
+#define QCBOREncode_BstrWrapInMap(pCtx, szLabel) \
+ QCBOREncode_OpenBstrWrap_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE)
+
+#define QCBOREncode_BstrWrapMapN(pCtx, nLabel) \
+ QCBOREncode_OpenBstrWrap_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE)
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 60e699f..3ad809e 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -114,7 +114,7 @@
pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
}
-inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos, bool bBstWrap)
+inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
{
int nReturn = QCBOR_SUCCESS;
@@ -126,7 +126,6 @@
pNesting->pCurrentNesting->uCount = 0;
pNesting->pCurrentNesting->uStart = uPos;
pNesting->pCurrentNesting->uMajorType = uMajorType;
- pNesting->pCurrentNesting->bBstrWrap = bBstWrap;
}
return nReturn;
}
@@ -173,10 +172,6 @@
return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
}
-inline static bool Nesting_IsBstrWrapped(QCBORTrackNesting *pNesting)
-{
- return pNesting->pCurrentNesting->bBstrWrap;
-}
@@ -411,7 +406,7 @@
successfully. Call it one more time gives an error.
*/
-static void OpenMapOrArrayInternal(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel, uint64_t uTag, bool bBstrWrap)
+static void OpenMapOrArrayInternal(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel, uint64_t uTag)
{
AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
@@ -422,9 +417,7 @@
// Increase nesting level because this is a map or array
// Cast from size_t to uin32_t is safe because the UsefulOutBuf
// size is limited to UINT32_MAX in QCBOR_Init().
- me->uError = Nesting_Increase(&(me->nesting),
- uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)),
- bBstrWrap);
+ me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
}
}
}
@@ -433,61 +426,70 @@
/*
Public functions for opening / closing arrays and maps. See header qcbor.h
*/
-void QCBOREncode_OpenArray_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, bool bBstrWrap)
+void QCBOREncode_OpenArray_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
{
- OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_ARRAY, szLabel, nLabel, uTag, bBstrWrap);
+ OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_ARRAY, szLabel, nLabel, uTag);
}
-void QCBOREncode_OpenMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, uint8_t bBstrWrap)
+void QCBOREncode_OpenMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
{
- OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_MAP, szLabel, nLabel, uTag, bBstrWrap);
+ OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_MAP, szLabel, nLabel, uTag);
}
-void QCBOREncode_CloseArray(QCBOREncodeContext *me)
+void QCBOREncode_OpenBstrWrap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
{
- if(!Nesting_IsInNest(&(me->nesting))) {
- me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
-
- } else {
- // When the array was opened, nothing was done except note the position
- // of the start of the array. This code goes back and inserts the type
- // (array or map) and length. That means all the data in the array or map
- // and any nested arrays or maps have to be slid right. This is done
- // by UsefulOutBuf's insert function that is called from inside
- // InsertEncodedTypeAndNumber()
-
- const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
-
- InsertEncodedTypeAndNumber(me,
- Nesting_GetMajorType(&(me->nesting)), // the major type (array or map)
- 0, // no minimum length for encoding
- Nesting_GetCount(&(me->nesting)), // number of items in array or map
- uInsertPosition); // position in output buffer
-
- if(Nesting_IsBstrWrapped(&(me->nesting))) {
- // This map or array is to be wrapped in a byte string. This is typically because
- // the data is to be hashed or cryprographically signed. This is what COSE
- // signing does.
+ OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_BYTE_STRING, szLabel, nLabel, uTag);
+}
+
+void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
+{
+ if(!me->uError) {
+ 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 {
+ const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
+ // When the array, map or bstr wrap was started, nothing was done except
+ // note the position of the start of it. This code goes back and inserts
+ // the actual CBOR array, map or bstr and its length. That means all the
+ // data that is in the array, map or wrapped needs to be slid to the
+ // right. This is done by UsefulOutBuf's insert function that is called
+ // from inside InsertEncodedTypeAndNumber()
// Cast from size_t to uin32_t is safe because the UsefulOutBuf
// size is limited to UINT32_MAX in QCBOR_Init().
- uint32_t uLenOfEncodedMapOrArray = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uInsertPosition;
-
- // Insert the bstring wrapping
+ const uint32_t uEndPosition = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
+ const uint32_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
+
+ // Length is number of bytes for a bstr and number of items for map & array
+ const uint32_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
+ uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
+
+ // Actually insert
InsertEncodedTypeAndNumber(me,
- CBOR_MAJOR_TYPE_BYTE_STRING, // major type bstring
- 0, // no minimum length for encoding
- uLenOfEncodedMapOrArray, // length of the map
- uInsertPosition); // position in out buffer
+ uMajorType, // major type bstr, array or map
+ 0, // no minimum length for encoding
+ uLength, // either len of bstr or num items in array or map
+ uInsertPosition); // position in out buffer
+
+ // 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 of the
+ // InsertEncodedTypeAndNumber() call that slides data to the right.
+ if(pWrappedCBOR) {
+ UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+ uint32_t uBstrLen = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
+ *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
+ }
+ Nesting_Decrease(&(me->nesting));
}
-
- Nesting_Decrease(&(me->nesting));
}
}
-
/*
Internal function for adding positive and negative integers of all different sizes
*/
diff --git a/test/basic_test.c b/test/basic_test.c
index 1f179ed..57a2b82 100644
--- a/test/basic_test.c
+++ b/test/basic_test.c
@@ -130,10 +130,457 @@
if(QCBORDecode_Finish(&DC)) {
return -2;
}
+
+ return 0;
+}
+
+/*
+ Very basic bstr wrapping test
+ */
+int bstrwraptest()
+{
+ UsefulBuf_MakeStackUB(MemoryForEncoded, 100);
+ QCBOREncodeContext EC;
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddUInt64(&EC, 451);
+ QCBOREncode_BstrWrap(&EC);
+ QCBOREncode_AddUInt64(&EC, 466);
+ UsefulBufC Wrapped;
+ QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+ QCBOREncode_CloseArray(&EC);
+
+ UsefulBufC Encoded;
+ if(QCBOREncode_Finish2(&EC, &Encoded)) {
+ return -1;
+ }
+
+ const uint8_t pExpected[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2};
+ if(UsefulBuf_Compare(UsefulBuf_FromByteArrayLiteral(pExpected), Encoded)) {
+ return -2;
+ }
+
+ return 0;
+}
+
+
+
+int bstr_wrap_error_test()
+{
+ // -------------- Test closing a bstrwrap when it is an array that is open -----------
+ UsefulBuf_MakeStackUB(MemoryForEncoded, 100);
+ QCBOREncodeContext EC;
+
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddUInt64(&EC, 451);
+
+ QCBOREncode_BstrWrap(&EC);
+ QCBOREncode_AddUInt64(&EC, 466);
+ QCBOREncode_OpenArray(&EC);
+
+ UsefulBufC Wrapped;
+ QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+
+ QCBOREncode_CloseArray(&EC);
+
+ UsefulBufC Encoded2;
+ if(QCBOREncode_Finish2(&EC, &Encoded2) != QCBOR_ERR_CLOSE_MISMATCH) {
+ return -1;
+ }
+
+ // ----------- test closing a bstrwrap when nothing is open ---------------------
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+ QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+ if(QCBOREncode_Finish2(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) {
+ return -2;
+ }
+
+ // --------------- test nesting too deep ----------------------------------
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+ for(int i = 1; i < 18; i++) {
+ QCBOREncode_BstrWrap(&EC);
+ }
+ QCBOREncode_AddBool(&EC, true);
+
+ for(int i = 1; i < 18; i++) {
+ QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+ }
+
+ if(QCBOREncode_Finish2(&EC, &Encoded2) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
+ return -3;
+ }
return 0;
}
+
+
+
+// Part of bstr_wrap_nest_test
+/*
+ 83 array with three
+ 53 byte string with 19 bytes
+ 01 #1
+ 50 byte string with 16 bytes
+ 02
+ 4D byte string with 13 bytes
+ 03
+ 4A byte string with 10 bytes
+ 04
+ 47 byte string with 7 bytes
+ 05
+ 44 byte string with 4 bytes
+ 06
+ 41 byte string with 1 byte
+ 07
+ 01
+ 02
+ 03
+ 04
+ 05
+ 06
+ 07
+
+ A2 map with two items
+ 18 20 label for byte string
+ 54 byte string of length 20
+ 82 Array with two items
+ 10 The integer value 10
+ A2 map with two items
+ 18 21 label for byte string
+ 44 byte string with 4 bytes
+ 81 array with 1 item
+ 11 integer value 11
+ 18 30 integer value 30
+ 18 40 integer label 40
+ 65 68 65 6C 6C 6F text string hello
+ 18 31 integer value 31
+ 18 41 integer label 41
+ 65 68 65 6C 6C 6F text string hello
+
+
+ */
+static const uint8_t sExpectedDeepBstr[] =
+{
+ 0x83, 0x56, 0x00, 0x53, 0x01, 0x50, 0x02, 0x4D,
+ 0x03, 0x4A, 0x04, 0x47, 0x05, 0x44, 0x06, 0x41,
+ 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0xA2, 0x18, 0x20, 0x54, 0x82, 0x10, 0xA2,
+ 0x18, 0x21, 0x44, 0x81, 0x11, 0x18, 0x30, 0x18,
+ 0x40, 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x18,
+ 0x31, 0x18, 0x41, 0x65, 0x68, 0x65, 0x6C, 0x6C,
+ 0x6F
+};
+
+// Part of bstr_wrap_nest_test
+static int decode_next_nested(UsefulBufC Wrapped)
+{
+ int nReturn;
+ QCBORDecodeContext DC;
+ QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORItem Item;
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -12;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn == QCBOR_ERR_HIT_END) {
+ return 0;
+ }
+ if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return -13;
+ }
+ nReturn = decode_next_nested(Item.val.string);
+ if(nReturn) {
+ return nReturn;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -14;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -15;
+ }
+
+ if(QCBORDecode_Finish(&DC)) {
+ return -16;
+ }
+
+ return 0;
+}
+
+// Part of bstr_wrap_nest_test
+static int decode_next_nested2(UsefulBufC Wrapped)
+{
+ int nReturn;
+ QCBORDecodeContext DC;
+ QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORItem Item;
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return -12;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -12;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP) {
+ return 0;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return -13;
+ }
+ nReturn = decode_next_nested2(Item.val.string);
+ if(nReturn) {
+ return nReturn;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return -12;
+ }
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -12;
+ }
+
+ if(QCBORDecode_Finish(&DC)) {
+ return -16;
+ }
+
+ return 0;
+}
+
+
+int bstr_wrap_nest_test()
+{
+ UsefulBuf_MakeStackUB(MemoryForEncoded, 300);
+ QCBOREncodeContext EC;
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+
+ // ---- Make a complicated nested CBOR structure ---
+ QCBOREncode_OpenArray(&EC);
+
+ for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING-2; i++) {
+ QCBOREncode_BstrWrap(&EC);
+ QCBOREncode_AddUInt64(&EC, i);
+ }
+
+ for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING-2; i++) {
+ QCBOREncode_CloseBstrWrap(&EC, NULL);
+ QCBOREncode_AddUInt64(&EC, i);
+ }
+
+ for(int i = 0; i < (QCBOR_MAX_ARRAY_NESTING-2)/3; i++) {
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_BstrWrapMapN(&EC, i+0x20);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddUInt64(&EC, i+0x10);
+ }
+
+ for(int i = 0; i < (QCBOR_MAX_ARRAY_NESTING-2)/3; i++) {
+ QCBOREncode_CloseArray(&EC);
+ QCBOREncode_AddUInt64(&EC, i+0x30);
+ QCBOREncode_CloseBstrWrap(&EC, NULL);
+ QCBOREncode_AddSZStringToMapN(&EC, i+0x40, "hello");
+ QCBOREncode_CloseMap(&EC);
+ }
+ QCBOREncode_CloseArray(&EC);
+
+ UsefulBufC Encoded;
+ if(QCBOREncode_Finish2(&EC, &Encoded)) {
+ return -1;
+ }
+
+ // ---Compare it to expected. Expected was hand checked with use of CBOR playground ----
+ if(UsefulBuf_Compare(UsefulBuf_FromByteArrayLiteral(sExpectedDeepBstr), Encoded)) {
+ return -25;
+ }
+
+
+ // ---- Decode it and see if it is OK ------
+ QCBORDecodeContext DC;
+ QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORItem Item;
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
+ return -2;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return -3;
+ }
+
+ int nReturn = decode_next_nested(Item.val.string);
+ if(nReturn) {
+ return nReturn;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -12;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 2) {
+ return -2;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return -3;
+ }
+ nReturn = decode_next_nested2(Item.val.string);
+ if(nReturn) {
+ return nReturn;
+ }
+
+ nReturn = QCBORDecode_GetNext(&DC, &Item);
+ if(nReturn) {
+ return -11;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return -12;
+ }
+
+ if(QCBORDecode_Finish(&DC)) {
+ return -16;
+ }
+
+ return 0;
+}
+
+
+/*
+ this corresponds exactly to the example in RFC 8152
+ section C.2.1. This doesn't actually verify the signature
+ though that would be nice as it would make the test
+ really good. That would require bring in ECDSA crypto
+ to this test.
+ */
+int cose_sign1_tbs_test()
+{
+ // All of this is from RFC 8152 C.2.1
+ const char *szKid = "11";
+ UsefulBufC Kid = UsefulBuf_FromSZ(szKid);
+ const char *szPayload = "This is the content.";
+ UsefulBufC Payload = UsefulBuf_FromSZ(szPayload);
+ const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26};
+ UsefulBufC ProtectedHeaders = UsefulBuf_FromByteArrayLiteral(pProtectedHeaders);
+ const uint8_t sSignature[] = {
+ 0x8e, 0xb3, 0x3e, 0x4c, 0xa3, 0x1d, 0x1c, 0x46, 0x5a, 0xb0,
+ 0x5a, 0xac, 0x34, 0xcc, 0x6b, 0x23, 0xd5, 0x8f, 0xef, 0x5c,
+ 0x08, 0x31, 0x06, 0xc4, 0xd2, 0x5a, 0x91, 0xae, 0xf0, 0xb0,
+ 0x11, 0x7e, 0x2a, 0xf9, 0xa2, 0x91, 0xaa, 0x32, 0xe1, 0x4a,
+ 0xb8, 0x34, 0xdc, 0x56, 0xed, 0x2a, 0x22, 0x34, 0x44, 0x54,
+ 0x7e, 0x01, 0xf1, 0x1d, 0x3b, 0x09, 0x16, 0xe5, 0xa4, 0xc3,
+ 0x45, 0xca, 0xcb, 0x36};
+ // It would be good to compare this to the output from
+ // a COSE implementation like COSE-C. It has been checked
+ // against the CBOR playground.
+ UsefulBufC Signature = UsefulBuf_FromByteArrayLiteral(sSignature);
+ const uint8_t sExpected[] = {
+ 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31,
+ 0x31, 0x54, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E,
+ 0x74, 0x2E, 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D,
+ 0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC, 0x6B, 0x23,
+ 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31, 0x06, 0xC4, 0xD2, 0x5A,
+ 0x91, 0xAE, 0xF0, 0xB0, 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91,
+ 0xAA, 0x32, 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A,
+ 0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D, 0x3B, 0x09,
+ 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA, 0xCB, 0x36};
+ UsefulBufC Expected = UsefulBuf_FromByteArrayLiteral(sExpected);
+
+ UsefulBuf_MakeStackUB(MemoryForEncoded, 98);
+ QCBOREncodeContext EC;
+ QCBOREncode_Init(&EC, MemoryForEncoded);
+
+ // top level array for cose sign1, 18 is the tag for COSE sign
+ QCBOREncode_OpenArray_3(&EC, NULL, QCBOR_NO_INT_LABEL, 18);
+
+ // Add protected headers
+ QCBOREncode_AddBytes(&EC, ProtectedHeaders);
+
+ // Empty map with unprotected headers
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddBytesToMapN(&EC, 4, Kid);
+ QCBOREncode_CloseMap(&EC);
+
+ // The payload
+ UsefulBufC WrappedPayload;
+ QCBOREncode_BstrWrap(&EC);
+ QCBOREncode_AddEncoded(&EC, Payload); // Payload is not actually CBOR in example C.2.1
+ QCBOREncode_CloseBstrWrap(&EC, &WrappedPayload);
+
+ // Check we got back the actual payload expected
+ if(UsefulBuf_Compare(WrappedPayload, Payload)) {
+ return -1;
+ }
+
+ // The signature
+ QCBOREncode_AddBytes(&EC, Signature);
+ QCBOREncode_CloseArray(&EC);
+
+ // Finish and check the results
+ UsefulBufC COSE_Sign1;
+ if(QCBOREncode_Finish2(&EC, &COSE_Sign1)) {
+ return -2;
+ }
+
+ // 98 is the size from RFC 8152 C.2.1
+ if(COSE_Sign1.len != 98) {
+ return -3;
+ }
+
+ if(UsefulBuf_Compare(COSE_Sign1, Expected)) {
+ return -4;
+ }
+
+ return 0;
+}
+
+
+
+
diff --git a/test/basic_test.h b/test/basic_test.h
index da5849f..011e318 100644
--- a/test/basic_test.h
+++ b/test/basic_test.h
@@ -31,4 +31,13 @@
int basic_test_one(void);
+int bstrwraptest(void);
+
+int bstr_wrap_error_test(void);
+
+int bstr_wrap_nest_test(void);
+
+int cose_sign1_tbs_test(void);
+
+
#endif /* basic_test_h */