New encode feature allows direct writing of byte string value (#137)
New features for UsefulBuf and for QCBOREncode allows direct writing to the output buffer. For QCBOREncode, this is the direct writing of the value of a byte string. This allows it to be written in chunks or be the output buffer of some function like symmetric encryption.
* fix grammer in security policy
* Half-way start a encoding feature to write byte string values into output
* Add documentation for OpenBstr
* UsefulBuf_Advance mostly working and testing
* OpenBytes() is mostly working and somewhat tested
* Finish up OpenBytes -- error handing, documentation...
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index e5be98a..f5149a5 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2018-2022, Laurence Lundblade.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -41,6 +41,7 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf
3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
01/28/2020 llundblade Refine integer signedness to quiet static analysis.
01/08/2020 llundblade Documentation corrections & improved code formatting.
@@ -304,6 +305,64 @@
/*
+ * Public function for advancing data length. See qcbor/UsefulBuf.h
+ */
+void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount)
+{
+ /* This function is a trimmed down version of
+ * UsefulOutBuf_InsertUsefulBuf(). This could be combined with the
+ * code in UsefulOutBuf_InsertUsefulBuf(), but that would make
+ * UsefulOutBuf_InsertUsefulBuf() bigger and this will be very
+ * rarely used.
+ */
+
+ if(pMe->err) {
+ /* Already in error state. */
+ return;
+ }
+
+ /* 0. Sanity check the UsefulOutBuf structure
+ *
+ * A "counter measure". If magic number is not the right number it
+ * probably means me was not initialized or it was
+ * corrupted. Attackers can defeat this, but it is a hurdle and
+ * does good with very little code.
+ */
+ if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
+ pMe->err = 1;
+ return; /* Magic number is wrong due to uninitalization or corrption */
+ }
+
+ /* Make sure valid data is less than buffer size. This would only
+ * occur if there was corruption of me, but it is also part of the
+ * checks to be sure there is no pointer arithmatic
+ * under/overflow.
+ */
+ if(pMe->data_len > pMe->UB.len) { // Check #1
+ pMe->err = 1;
+ /* Offset of valid data is off the end of the UsefulOutBuf due
+ * to uninitialization or corruption.
+ */
+ return;
+ }
+
+ /* 1. Will it fit?
+ *
+ * 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, uAmount)) { /* Check #2 */
+ /* The new data will not fit into the the buffer. */
+ pMe->err = 1;
+ return;
+ }
+
+ pMe->data_len += uAmount;
+}
+
+
+/*
Public function -- see UsefulBuf.h
*/
UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe)
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 7f9c169..af0e38b 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2018-2022, Laurence Lundblade.
Copyright (c) 2021, Arm Limited.
All rights reserved.
@@ -541,6 +541,9 @@
}
}
#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+ if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
+ uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
+ }
/* A stack buffer large enough for a CBOR head */
UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
@@ -932,6 +935,41 @@
/*
+ * Public function for opening a byte string. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
+{
+ *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
+ if(!UsefulBuf_IsNULL(*pPlace)){
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+ uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
+ if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
+ pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
+ return;
+ }
+#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+ QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
+ }
+}
+
+
+/*
+ * Public function for closing a byte string. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
+{
+ UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
+ if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
+ /* Advance too far. Normal off-end error handling in effect here. */
+ return;
+ }
+
+ InsertCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
+}
+
+
+/*
* Public function for closing arrays and maps. See qcbor/qcbor_encode.h
*/
void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)