Add QCBOREncode_AddBytesLenOnly(), special for COSE sig verification
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 157325d..eddf3fe 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -214,6 +214,7 @@
// Must not conflict with any of the official CBOR types
#define CBOR_MAJOR_NONE_TYPE_RAW 9
#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
+#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
/* ===========================================================================
@@ -2198,6 +2199,35 @@
*/
void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, uint64_t uNum);
+
+/**
+ @brief Semi-private method to add only the type and length of a byte string.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] Bytes Pointer and length of the input data.
+
+ This is the same as QCBOREncode_AddBytes() except it only adds the
+ CBOR encoding for the type and the length. It doesn't actually add
+ the bytes. You can't actually produce correct CBOR with this and the
+ rest of this API. It is only used for a special case where
+ the valid CBOR is created manually by putting this type and length in
+ and then adding the actual bytes. In particular, when only a hash of
+ the encoded CBOR is needed, where the type and header are hashed
+ separately and then the bytes is hashed. This makes it possible to
+ implement COSE Sign1 with only one copy of the payload in the output
+ buffer, rather than two, roughly cutting memory use in half.
+
+ This is only used for this odd case, but this is a supported
+ tested function.
+*/
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
{
@@ -2312,6 +2342,22 @@
QCBOREncode_AddBytes(pCtx, Bytes);
}
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
{
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index ab30940..c652f79 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -393,26 +393,41 @@
/*
- Semi-private function. It is exposed to user of the interface,
- but they will usually call one of the inline wrappers rather than this.
+ Semi-private 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
- Does the work of adding some bytes to the CBOR output. Works for a
- byte and text strings, which are the same in in CBOR though they have
- different major types. This is also used to insert raw
- pre-encoded CBOR.
+ Does the work of adding actual strings bytes to the CBOR output (as
+ opposed to numbers and opening / closing aggregate types).
+
+ There are four use cases:
+ CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
+ CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
+ CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
+ CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
+
+ The first two add the type and length plus the actual bytes. The
+ third just adds the bytes as the type and length are presumed to be
+ in the bytes. The fourth just adds the type and length for the very
+ special case of QCBOREncode_AddBytesLenOnly().
*/
void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
{
if(me->uError == QCBOR_SUCCESS) {
// If it is not Raw CBOR, add the type and the length
if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
- AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
+ uint8_t uRealMajorType = uMajorType;
+ if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
+ uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
+ }
+ AppendEncodedTypeAndNumber(me, uRealMajorType, Bytes.len);
}
- // Actually add the bytes
- UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
+ if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
+ // Actually add the bytes
+ UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
+ }
// Update the array counting if there is any nesting at all
me->uError = Nesting_Increment(&(me->nesting));
@@ -573,7 +588,7 @@
}
if(UsefulOutBuf_GetError(&(me->OutBuf))) {
- // items didn't fit in the buffer.
+ // 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
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index ad17feb..f08927c 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -1380,6 +1380,12 @@
static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2};
/*
+ 81 #array(1)
+ 0x58 0x25 # string of length 37 (length of "This is longer than twenty four bytes")
+ */
+static const uint8_t spExpectedTypeAndLen[] = {0x81, 0x58, 0x25};
+
+/*
Very basic bstr wrapping test
*/
int BstrWrapTest()
@@ -1424,6 +1430,20 @@
if(BStr.ptr != NULL || BStr.len != 3) {
return -5;
}
+
+ // Third, test QCBOREncode_AddBytesLenOnly() here as it is part of the
+ // bstr wrapping use cases.
+ UsefulBuf_MAKE_STACK_UB(StuffBuf, 50);
+ QCBOREncode_Init(&EC, StuffBuf);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddBytesLenOnly(&EC, UsefulBuf_FROM_SZ_LITERAL("This is longer than twenty four bytes"));
+ QCBOREncode_CloseArray(&EC);
+ if(QCBOREncode_Finish(&EC, &Encoded)) {
+ return -6;
+ }
+ if(CheckResults(Encoded, spExpectedTypeAndLen)) {
+ return -7;
+ }
return 0;
}