blob: 2a99110655b0a070dd5dc3d60f933d4a5866fc83 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_encode.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070036#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080039/**
40 * @file qcbor_encode.c
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080041 *
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080042 * The entire implementation of the QCBOR encoder.
43 */
44
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070045
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070046/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080047 * == Nesting Tracking ==
48 *
49 * The following functions and data type QCBORTrackNesting implement
50 * the nesting management for encoding.
51 *
52 * CBOR's two nesting types, arrays and maps, are tracked here. There
53 * is a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and
54 * maps that can be nested in one encoding so the encoding context
55 * stays small enough to fit on the stack.
56 *
57 * When an array/map is opened, pCurrentNesting points to the element
58 * in pArrays that records the type, start position and accumulates a
59 * count of the number of items added. When closed the start position
60 * is used to go back and fill in the type and number of items in the
61 * array/map.
62 *
63 * Encoded output can be a CBOR Sequence (RFC 8742) in which case
64 * there is no top-level array or map. It starts out with a string,
65 * integer or other non-aggregate type. It may have an array or map
66 * other than at the start, in which case that nesting is tracked
67 * here.
68 *
69 * QCBOR has a special feature to allow constructing byte string
70 * wrapped CBOR directly into the output buffer, so no extra buffer is
71 * needed for byte string wrapping. This is implemented as nesting
72 * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte
73 * string wrapped CBOR is used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070074 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -070075static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -070076Nesting_Init(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070077{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080078 /* Assumes pNesting has been zeroed. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079 pNesting->pCurrentNesting = &pNesting->pArrays[0];
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080080 /* Implied CBOR array at the top nesting level. This is never
81 * returned, but makes the item count work correctly.
82 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070083 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
84}
85
Laurence Lundblade8e36f812024-01-26 10:59:29 -070086static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -070087Nesting_Increase(QCBORTrackNesting *pNesting,
Laurence Lundblade8e36f812024-01-26 10:59:29 -070088 const uint8_t uMajorType,
89 const uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070090{
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070091 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundblade29497c02020-07-11 15:44:03 -070092 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070093 } else {
94 pNesting->pCurrentNesting++;
95 pNesting->pCurrentNesting->uCount = 0;
96 pNesting->pCurrentNesting->uStart = uPos;
97 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundblade29497c02020-07-11 15:44:03 -070098 return QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100}
101
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700102static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700103Nesting_Decrease(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104{
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700105 if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) {
106 pNesting->pCurrentNesting--;
107 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700108}
109
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700110static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700111Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700112{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800113#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800114 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700115 return QCBOR_ERR_ARRAY_TOO_LONG;
116 }
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700117#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800118
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700119 pNesting->pCurrentNesting->uCount++;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800120
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700121 return QCBOR_SUCCESS;
122}
123
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700124static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700125Nesting_Decrement(QCBORTrackNesting *pNesting)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700126{
127 /* No error check for going below 0 here needed because this
128 * is only used by QCBOREncode_CancelBstrWrap() and it checks
129 * the nesting level before calling this. */
130 pNesting->pCurrentNesting->uCount--;
131}
132
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700133static uint16_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700134Nesting_GetCount(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700135{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800136 /* The nesting count recorded is always the actual number of
137 * individual data items in the array or map. For arrays CBOR uses
138 * the actual item count. For maps, CBOR uses the number of pairs.
139 * This function returns the number needed for the CBOR encoding,
140 * so it divides the number of items by two for maps to get the
141 * number of pairs.
142 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800143 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800144 /* Cast back to uint16_t after integer promotion from bit shift */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800145 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
146 } else {
147 return pNesting->pCurrentNesting->uCount;
148 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700149}
150
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700151static uint32_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700152Nesting_GetStartPos(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700153{
154 return pNesting->pCurrentNesting->uStart;
155}
156
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800157#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700158static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700159Nesting_GetMajorType(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700160{
161 return pNesting->pCurrentNesting->uMajorType;
162}
163
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700164static bool
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700165Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700166{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800167 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700168}
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800169#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700171
172
173
174/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800175 * == Major CBOR Types ==
176 *
177 * Encoding of the major CBOR types is by these functions:
178 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800179 * CBOR Major Type Public Function
180 * 0 QCBOREncode_AddUInt64()
181 * 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
182 * 2, 3 QCBOREncode_AddBuffer()
183 * 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
184 * QCBOREncode_OpenMapOrArrayIndefiniteLength(),
185 * QCBOREncode_CloseMapOrArrayIndefiniteLength()
186 * 6 QCBOREncode_AddTag()
187 * 7 QCBOREncode_AddDouble(), QCBOREncode_AddFloat(),
188 * QCBOREncode_AddDoubleNoPreferred(),
189 * QCBOREncode_AddFloatNoPreferred(), QCBOREncode_AddType7()
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800190 *
191 * Additionally, encoding of decimal fractions and bigfloats is by
192 * QCBOREncode_AddExponentAndMantissa() and byte strings that wrap
193 * encoded CBOR are handled by QCBOREncode_OpenMapOrArray() and
194 * QCBOREncode_CloseBstrWrap2().
195 *
196 *
197 * == Error Tracking Plan ==
198 *
199 * Errors are tracked internally and not returned until
200 * QCBOREncode_Finish() or QCBOREncode_GetErrorState() is called. The
201 * CBOR errors are in me->uError. UsefulOutBuf also tracks whether
202 * the buffer is full or not in its context. Once either of these
203 * errors is set they are never cleared. Only QCBOREncode_Init()
204 * resets them. Or said another way, they must never be cleared or
205 * we'll tell the caller all is good when it is not.
206 *
207 * Only one error code is reported by QCBOREncode_Finish() even if
208 * there are multiple errors. The last one set wins. The caller might
209 * have to fix one error to reveal the next one they have to fix.
210 * This is OK.
211 *
212 * The buffer full error tracked by UsefulBuf is only pulled out of
213 * UsefulBuf in QCBOREncode_Finish() so it is the one that usually
214 * wins. UsefulBuf will never go off the end of the buffer even if it
215 * is called again and again when full.
216 *
217 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS disables about half of the error
218 * checks here to reduce code size by about 150 bytes leaving only the
219 * checks for size to avoid buffer overflow. If the calling code is
220 * completely correct, checks are completely unnecessary. For
221 * example, there is no need to check that all the opens are matched
222 * by a close.
223 *
224 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more
225 * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since
226 * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,535) it is very unlikely
227 * to be reached. If it is reached, the count will wrap around to zero
228 * and CBOR that is not well formed will be produced, but there will
229 * be no buffers overrun and new security issues in the code.
230 *
231 * The 8 errors returned here fall into three categories:
232 *
233 * Sizes
234 * QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
235 * QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
236 * QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
237 * QCBOR_ERR_ARRAY_TOO_LONG -- Too many items added to an array/map [1]
238 *
239 * Nesting constructed incorrectly
240 * QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens [1]
241 * QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open [1]
242 * QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes [1]
243 *
244 * Would generate not-well-formed CBOR
245 * QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31 [1]
246 *
247 * [1] indicated disabled by QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248 */
249
250
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700251/*
Laurence Lundbladeb9ccd6b2024-02-06 05:44:25 -0700252 * Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700254void
255QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700256{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700257 memset(pMe, 0, sizeof(QCBOREncodeContext));
258 UsefulOutBuf_Init(&(pMe->OutBuf), Storage);
259 Nesting_Init(&(pMe->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700260}
261
262
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000263/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800264 * Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700265 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700266UsefulBufC
267QCBOREncode_EncodeHead(UsefulBuf Buffer,
268 uint8_t uMajorType,
269 uint8_t uMinLen,
270 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700271{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272 /*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800273 * == Description of the CBOR Head ==
274 *
275 * The head of a CBOR data item
276 * +---+-----+ +--------+ +--------+ +--------+ +--------+
277 * |M T| A R G U M E N T . . . |
278 * +---+-----+ +--------+ +--------+ +--------+ ... +--------+
279 *
280 * Every CBOR data item has a "head". It is made up of the "major
281 * type" and the "argument".
282 *
283 * The major type indicates whether the data item is an integer,
284 * string, array or such. It is encoded in 3 bits giving it a range
285 * from 0 to 7. 0 indicates the major type is a positive integer,
286 * 1 a negative integer, 2 a byte string and so on.
287 *
288 * These 3 bits are the first part of the "initial byte" in a data
289 * item. Every data item has an initial byte, and some only have
290 * the initial byte.
291 *
292 * The argument is essentially a number between 0 and UINT64_MAX
293 * (18446744073709551615). This number is interpreted to mean
294 * different things for the different major types. For major type
295 * 0, a positive integer, it is value of the data item. For major
296 * type 2, a byte string, it is the length in bytes of the byte
297 * string. For major type 4, an array, it is the number of data
298 * items in the array.
299 *
300 * Special encoding is used so that the argument values less than
301 * 24 can be encoded very compactly in the same byte as the major
302 * type is encoded. When the lower 5 bits of the initial byte have
303 * a value less than 24, then that is the value of the argument.
304 *
305 * If the lower 5 bits of the initial byte are less than 24, then
306 * they are the value of the argument. This allows integer values 0
307 * - 23 to be CBOR encoded in just one byte.
308 *
309 * When the value of lower 5 bits are 24, 25, 26, or 27 the
310 * argument is encoded in 1, 2, 4 or 8 bytes following the initial
311 * byte in network byte order (bit endian). The cases when it is
312 * 28, 29 and 30 are reserved for future use. The value 31 is a
313 * special indicator for indefinite length strings, arrays and
314 * maps.
315 *
316 * The lower 5 bits are called the "additional information."
317 *
318 * Thus the CBOR head may be 1, 2, 3, 5 or 9 bytes long.
319 *
320 * It is legal in CBOR to encode the argument using any of these
321 * lengths even if it could be encoded in a shorter length. For
322 * example it is legal to encode a data item representing the
323 * positive integer 0 in 9 bytes even though it could be encoded in
324 * only 0. This is legal to allow for for very simple code or even
325 * hardware-only implementations that just output a register
326 * directly.
327 *
328 * CBOR defines preferred encoding as the encoding of the argument
329 * in the smallest number of bytes needed to encode it.
330 *
331 * This function takes the major type and argument as inputs and
332 * outputs the encoded CBOR head for them. It does conversion to
333 * network byte order. It implements CBOR preferred encoding,
334 * outputting the shortest representation of the argument.
335 *
336 * == Endian Conversion ==
337 *
338 * This code does endian conversion without hton() or knowing the
339 * endianness of the machine by using masks and shifts. This avoids
340 * the dependency on hton() and the mess of figuring out how to
341 * find the machine's endianness.
342 *
343 * This is a good efficient implementation on little-endian
344 * machines. A faster and smaller implementation is possible on
345 * big-endian machines because CBOR/network byte order is
346 * big-endian. However big-endian machines are uncommon.
347 *
348 * On x86, this is about 150 bytes instead of 500 bytes for the
349 * original, more formal unoptimized code.
350 *
351 * This also does the CBOR preferred shortest encoding for integers
352 * and is called to do endian conversion for floats.
353 *
354 * It works backwards from the least significant byte to the most
355 * significant byte.
356 *
357 * == Floating Point ==
358 *
359 * When the major type is 7 and the 5 lower bits have the values
360 * 25, 26 or 27, the argument is a floating-point number that is
361 * half, single or double-precision. Note that it is not the
362 * conversion from a floating-point value to an integer value like
363 * converting 0x00 to 0.00, it is the interpretation of the bits in
364 * the argument as an IEEE 754 float-point number.
365 *
366 * Floating-point numbers must be converted to network byte
367 * order. That is accomplished here by exactly the same code that
368 * converts integer arguments to network byte order.
369 *
370 * There is preferred encoding for floating-point numbers in CBOR,
371 * but it is very different than for integers and it is not
372 * implemented here. Half-precision is preferred to
373 * single-precision which is preferred to double-precision only if
374 * the conversion can be performed without loss of precision. Zero
375 * and infinity can always be converted to half-precision, without
376 * loss but 3.141592653589 cannot.
377 *
378 * The way this function knows to not do preferred encoding on the
379 * argument passed here when it is a floating point number is the
380 * uMinLen parameter. It should be 2, 4 or 8 for half, single and
381 * double precision floating point values. This prevents and the
382 * incorrect removal of leading zeros when encoding arguments that
383 * are floating-point numbers.
384 *
385 * == Use of Type int and Static Analyzers ==
386 *
387 * The type int is used here for several variables because of the
388 * way integer promotion works in C for variables that are uint8_t
389 * or uint16_t. The basic rule is that they will always be promoted
390 * to int if they will fit. These integer variables here need only
391 * hold values less than 255 so they will always fit into an int.
392 *
393 * Most of values stored are never negative, so one might think
394 * that unsigned int would be more correct than int. However the C
395 * integer promotion rules only promote to unsigned int if the
396 * result won't fit into an int even if the promotion is for an
397 * unsigned variable like uint8_t.
398 *
399 * By declaring these int, there are few implicit conversions and
400 * fewer casts needed. Code size is reduced a little. It makes
401 * static analyzers happier.
402 *
403 * Note also that declaring these uint8_t won't stop integer wrap
404 * around if the code is wrong. It won't make the code more
405 * correct.
406 *
407 * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
408 * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
409 *
410 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800411 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800412
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800413 /* The buffer must have room for the largest CBOR HEAD + one
414 * extra. The one extra is needed for this code to work as it does
415 * a pre-decrement.
416 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700417 if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000418 return NULLUsefulBufC;
419 }
420
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800421 /* Pointer to last valid byte in the buffer */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700422 uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000423
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800424 /* Point to the last byte and work backwards */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000425 uint8_t *pByte = pBufferEnd;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800426 /* The 5 bits in the initial byte that are not the major type */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800427 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800428
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700429#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800430 if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800431 /* Special case for start & end of indefinite length */
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800432 uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800433 /* This takes advantage of design of CBOR where additional info
434 * is 31 for both opening and closing indefinite length
435 * maps and arrays.
436 */
437 #if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE
438 #error additional info for opening array not the same as for closing
439 #endif
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800440 nAdditionalInfo = CBOR_SIMPLE_BREAK;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800441
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700442 } else
443#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
444 if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800445 /* Simple case where argument is < 24 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000446 nAdditionalInfo = (int)uArgument;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800447
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800448 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800449 /* This encodes the argument in 1,2,4 or 8 bytes. The outer loop
450 * runs once for 1 byte and 4 times for 8 bytes. The inner loop
451 * runs 1, 2 or 4 times depending on outer loop counter. This
452 * works backwards shifting 8 bits off the argument being
453 * encoded at a time until all bits from uArgument have been
454 * encoded and the minimum encoding size is reached. Minimum
455 * encoding size is for floating-point numbers that have some
456 * zero-value bytes that must be output.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800457 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800458 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000459
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800460 /* uMinLen passed in is unsigned, but goes negative in the loop
461 * so it must be converted to a signed value.
462 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000463 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800464 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000465 for(i = 0; uArgument || nMinLen > 0; i++) {
466 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800467 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000468 *--pByte = (uint8_t)(uArgument & 0xff);
469 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800470 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800471 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800472 }
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800473
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800474 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700475 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800476
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800477 /* This expression integer-promotes to type int. The code above in
478 * function guarantees that nAdditionalInfo will never be larger
479 * than 0x1f. The caller may pass in a too-large uMajor type. The
Laurence Lundblade11654912024-05-09 11:49:24 -0700480 * conversion to uint8_t will cause an integer wrap around and
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800481 * incorrect CBOR will be generated, but no security issue will
482 * occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800483 */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800484 const int nInitialByte = (uMajorType << 5) + nAdditionalInfo;
485 *--pByte = (uint8_t)nInitialByte;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800486
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000487#ifdef EXTRA_ENCODE_HEAD_CHECK
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800488 /* This is a sanity check that can be turned on to verify the
489 * pointer math in this function is not going wrong. Turn it on and
490 * run the whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800491 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000492 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
493 return NULLUsefulBufC;
494 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800495#endif /* EXTRA_ENCODE_HEAD_CHECK */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800496
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800497 /* Length will not go negative because the loops run for at most 8 decrements
498 * of pByte, only one other decrement is made, and the array is sized
499 * for this.
500 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000501 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502}
503
504
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000505/**
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700506 * @brief Increment item counter for maps and arrays.
507 *
508 * @param pMe QCBOR encoding context.
509 *
510 * This is mostly a separate function to make code more readable and
511 * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
512 */
513static void
514QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
515{
516#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
517 if(pMe->uError == QCBOR_SUCCESS) {
518 pMe->uError = Nesting_Increment(&(pMe->nesting));
519 }
520#else
521 (void)Nesting_Increment(&(pMe->nesting));
522#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
523}
524
525
526/**
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800527 * @brief Append the CBOR head, the major type and argument
528 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700529 * @param pMe Encoder context.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800530 * @param uMajorType Major type to insert.
531 * @param uArgument The argument (an integer value or a length).
532 * @param uMinLen The minimum number of bytes for encoding the CBOR argument.
533 *
534 * This formats the CBOR "head" and appends it to the output.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700535 *
536 * This also increments the array/map item counter in most cases.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000537 */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700538void
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700539QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
540 const uint8_t uMajorType,
541 const uint64_t uArgument,
542 const uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700543{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800544 /* A stack buffer large enough for a CBOR head */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000545 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
546
547 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
548 uMajorType,
549 uMinLen,
550 uArgument);
551
552 /* No check for EncodedHead == NULLUsefulBufC is performed here to
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800553 * save object code. It is very clear that pBufferForEncodedHead is
554 * the correct size. If EncodedHead == NULLUsefulBufC then
555 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no
556 * security hole introduced.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000557 */
558
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700559 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700560
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700561 if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) {
562 /* Don't increment the map count for tag or break because that is
563 * not needed. Don't do it for indefinite-length arrays and maps
564 * because it is done elsewhere. This is never called for definite-length
565 * arrays and maps.
566 */
567 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700568 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700569}
570
Laurence Lundblade56230d12018-11-01 11:14:51 +0700571
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800573 * Public functions for adding signed integers. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800574 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575void
576QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800577{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800578 uint8_t uMajorType;
579 uint64_t uValue;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800580
581 if(nNum < 0) {
Laurence Lundblade9c5c0ef2022-12-23 17:56:27 -0700582 /* In CBOR -1 encodes as 0x00 with major type negative int.
583 * First add one as a signed integer because that will not
584 * overflow. Then change the sign as needed for encoding. (The
585 * opposite order, changing the sign and subtracting, can cause
586 * an overflow when encoding INT64_MIN. */
587 int64_t nTmp = nNum + 1;
588 uValue = (uint64_t)-nTmp;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800589 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
590 } else {
591 uValue = (uint64_t)nNum;
592 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
593 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700594 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800595}
596
597
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700598/**
599 * @brief Semi-private method to add a buffer full of bytes to encoded output.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800600 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700601 * @param[in] pMe The encoding context to add the string to.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700602 * @param[in] uMajorType The CBOR major type of the bytes.
603 * @param[in] Bytes The bytes to add.
604 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700605 * Called by inline functions to add text and byte strings.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700606 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700607 * (This used to support QCBOREncode_AddEncoded() and
608 * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this
609 * smaller. This is one of the most used methods and they are some of
610 * the least used).
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700611 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700612void
613QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe,
614 const uint8_t uMajorType,
615 const UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700616{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700617 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0);
618 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700619}
620
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700621
Laurence Lundblade55a24832018-10-30 04:35:08 +0700622/*
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700623 * Public functions for adding raw encoded CBOR. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700624 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625void
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700626QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700627{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700628 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700629 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700630}
631
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700632
Laurence Lundblade223849d2024-05-24 20:32:57 -0700633#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
634/**
635 * @brief Semi-private method to add a double using preferred encoding.
636 *
637 * @param[in] pMe The encode context.
638 * @param[in] dNum The double to add.
639 *
640 * This converts the double to a float or half-precision if it can be done
641 * without a loss of precision. See QCBOREncode_AddDouble().
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800642 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700643void
Laurence Lundblade223849d2024-05-24 20:32:57 -0700644QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700646 const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700647 QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700648}
Laurence Lundblade9682a532020-06-06 18:33:04 -0700649
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700650
Laurence Lundblade223849d2024-05-24 20:32:57 -0700651/**
652 * @brief Semi-private method to add a float using preferred encoding.
653 *
654 * @param[in] pMe The encode context.
655 * @param[in] fNum The float to add.
656 *
657 * This converts the float to a half-precision if it can be done
658 * without a loss of precision. See QCBOREncode_AddFloat().
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800659 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700660void
Laurence Lundblade223849d2024-05-24 20:32:57 -0700661QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum)
Laurence Lundblade9682a532020-06-06 18:33:04 -0700662{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700663 const IEEE754_union uNum = IEEE754_SingleToHalf(fNum);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700664 QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800665}
Laurence Lundblade223849d2024-05-24 20:32:57 -0700666#endif /* !QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800667
668
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -0700669#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700670/**
671 * @brief Semi-private method to add bigfloats and decimal fractions.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800672 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700673 * @param[in] pMe The encoding context to add the value to.
674 * @param[in] uTag The type 6 tag indicating what this is to be.
675 * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
676 * @c int64_t or the actual big number mantissa
677 * if not.
678 * @param[in] bBigNumIsNegative This is @c true if the big number is negative.
679 * @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
680 * @param[in] nExponent The exponent.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800681 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682 * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or
683 * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64,
684 * then this outputs the "borrowed" content format.
685 *
686 * The tag content output by this is an array with two members, the
687 * exponent and then the mantissa. The mantissa can be either a big
688 * number or an @c int64_t.
689 *
690 * This implementation cannot output an exponent further from 0 than
691 * @c INT64_MAX.
692 *
693 * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0,
694 * it must be as a big number.
695 *
696 * Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
697 * QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
698 * is called instead of this.
Laurence Lundblade59289e52019-12-30 13:44:37 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe,
702 const uint64_t uTag,
703 const UsefulBufC BigNumMantissa,
704 const bool bBigNumIsNegative,
705 const int64_t nMantissa,
706 const int64_t nExponent)
Laurence Lundblade59289e52019-12-30 13:44:37 -0800707{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800708 /* This is for encoding either a big float or a decimal fraction,
709 * both of which are an array of two items, an exponent and a
710 * mantissa. The difference between the two is that the exponent
711 * is base-2 for big floats and base-10 for decimal fractions, but
712 * that has no effect on the code here.
Laurence Lundbladeee851742020-01-08 08:37:05 -0800713 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -0700714 if(uTag != CBOR_TAG_INVALID64) {
715 QCBOREncode_AddTag(pMe, uTag);
716 }
Laurence Lundblade59289e52019-12-30 13:44:37 -0800717 QCBOREncode_OpenArray(pMe);
718 QCBOREncode_AddInt64(pMe, nExponent);
719 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
720 if(bBigNumIsNegative) {
721 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
722 } else {
723 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
724 }
725 } else {
726 QCBOREncode_AddInt64(pMe, nMantissa);
727 }
728 QCBOREncode_CloseArray(pMe);
729}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -0700730#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800731
732
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700733/**
734 * @brief Semi-private method to open a map, array or bstr-wrapped CBOR
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800735 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700736 * @param[in] pMe The context to add to.
737 * @param[in] uMajorType The major CBOR type to close
738 *
739 * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
740 * QCBOREncode_BstrWrap() instead of this.
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700741 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700742void
743QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe,
744 const uint8_t uMajorType)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800745{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800746 /* Add one item to the nesting level we are in for the new map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700747 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800748
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800749 /* The offset where the length of an array or map will get written
750 * is stored in a uint32_t, not a size_t to keep stack usage
751 * smaller. This checks to be sure there is no wrap around when
752 * recording the offset. Note that on 64-bit machines CBOR larger
753 * than 4GB can be encoded as long as no array/map offsets occur
754 * past the 4GB mark, but the public interface says that the
755 * maximum is 4GB to keep the discussion simpler.
756 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700757 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800758
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800759 /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
760 * code can run on a 32-bit machine and tests can pass on a 32-bit
761 * machine. If it was exactly UINT32_MAX, then this code would not
762 * compile or run on a 32-bit machine and an #ifdef or some machine
763 * size detection would be needed reducing portability.
764 */
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800765 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700766 pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800767
768 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800769 /* Increase nesting level because this is a map or array. Cast
770 * from size_t to uin32_t is safe because of check above.
771 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700772 pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800773 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700774}
775
Laurence Lundblade59289e52019-12-30 13:44:37 -0800776
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700777#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700778/**
779 * @brief Semi-private method to open a map, array with indefinite length
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800780 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700781 * @param[in] pMe The context to add to.
782 * @param[in] uMajorType The major CBOR type to close
783 *
784 * Call QCBOREncode_OpenArrayIndefiniteLength() or
785 * QCBOREncode_OpenMapIndefiniteLength() instead of this.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800786 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700787void
788QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
789 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200790{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800791 /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700792 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800793
794 /* Call the definite-length opener just to do the bookkeeping for
795 * nesting. It will record the position of the opening item in the
796 * encoded output but this is not used when closing this open.
797 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700798 QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
Jan Jongboom4a93a662019-07-25 08:44:58 +0200799}
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700800#endif
801
802
803/**
804 * @brief Check for errors when decreasing nesting.
805 *
806 * @param pMe QCBOR encoding context.
807 * @param uMajorType The major type of the nesting.
808 *
809 * Check that there is no previous error, that there is actually some
810 * nesting and that the major type of the opening of the nesting
811 * matches the major type of the nesting being closed.
812 *
813 * This is called when closing maps, arrays, byte string wrapping and
814 * open/close of byte strings.
815 */
816static bool
817QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
818 const uint8_t uMajorType)
819{
820#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
821 if(pMe->uError != QCBOR_SUCCESS) {
822 return true;
823 }
824
825 if(!Nesting_IsInNest(&(pMe->nesting))) {
826 pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
827 return true;
828 }
829
830 if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
831 pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
832 return true;
833 }
834
835#else /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
836 /* None of these checks are performed if the encode guards are
837 * turned off as they all relate to correct calling.
838 *
839 * Turning off all these checks does not turn off any checking for
840 * buffer overflows or pointer issues.
841 */
842
843 (void)uMajorType;
844 (void)pMe;
845#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
846
847 return false;
848}
849
850
851/**
852 * @brief Insert the CBOR head for a map, array or wrapped bstr
853 *
854 * @param pMe QCBOR encoding context.
855 * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
856 * @param uLen The length of the data item.
857 *
858 * When an array, map or bstr was opened, nothing was done but note
859 * the position. This function goes back to that position and inserts
860 * the CBOR Head with the major type and length.
861 */
862static void
863QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
864 uint8_t uMajorType,
865 size_t uLen)
866{
867 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
868 return;
869 }
870
871 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
872 uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
873 }
874
875 /* A stack buffer large enough for a CBOR head (9 bytes) */
876 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
877
878 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
879 uMajorType,
880 0,
881 uLen);
882
883 /* No check for EncodedHead == NULLUsefulBufC is performed here to
884 * save object code. It is very clear that pBufferForEncodedHead is
885 * the correct size. If EncodedHead == NULLUsefulBufC then
886 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
887 * security hole introduced.
888 */
889 UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
890 EncodedHead,
891 Nesting_GetStartPos(&(pMe->nesting)));
892
893 Nesting_Decrease(&(pMe->nesting));
894}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700895
Laurence Lundbladeee851742020-01-08 08:37:05 -0800896
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700897/**
898 * @brief Semi-private method to close a map, array or bstr wrapped CBOR
899 *
900 * @param[in] pMe The context to add to.
901 * @param[in] uMajorType The major CBOR type to close.
902 *
903 * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700905void
906QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
907 const uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700908{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700909 QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000910}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800912
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000913/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800914 * Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000915 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700916void
917QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe,
918 const bool bIncludeCBORHead,
919 UsefulBufC *pWrappedCBOR)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000920{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700921 const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting));
922 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800923
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800924 /* This subtraction can't go negative because the UsefulOutBuf
925 * always only grows and never shrinks. UsefulOutBut itself also
926 * has defenses such that it won't write where it should not even
927 * if given incorrect input lengths.
928 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000929 const size_t uBstrLen = uEndPosition - uInsertPosition;
930
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800931 /* Actually insert */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700932 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000933
934 if(pWrappedCBOR) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800935 /* Return pointer and length to the enclosed encoded CBOR. The
936 * intended use is for it to be hashed (e.g., SHA-256) in a COSE
937 * implementation. This must be used right away, as the pointer
938 * and length go invalid on any subsequent calls to this
939 * function because there might be calls to
940 * InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000941 */
942 size_t uStartOfNew = uInsertPosition;
943 if(!bIncludeCBORHead) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800944 /* Skip over the CBOR head to just get the inserted bstr */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700945 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000946 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700947 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700948 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000949 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700950 }
951}
952
Laurence Lundbladeee851742020-01-08 08:37:05 -0800953
Jan Jongboom4a93a662019-07-25 08:44:58 +0200954/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700955 * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h
956 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700957void
958QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700959{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700960 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700961 return;
962 }
963
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700964#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700965 const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
966 if(pMe->nesting.pCurrentNesting->uStart != uCurrent) {
967 pMe->uError = QCBOR_ERR_CANNOT_CANCEL;
968 return;
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700969 }
970 /* QCBOREncode_CancelBstrWrap() can't correctly undo
971 * QCBOREncode_BstrWrapInMap() or QCBOREncode_BstrWrapInMapN(). It
972 * can't undo the labels they add. It also doesn't catch the error
973 * of using it this way. QCBOREncode_CancelBstrWrap() is used
974 * infrequently and the the result is incorrect CBOR, not a
975 * security hole, so no extra code or state is added to handle this
976 * condition.
977 */
978#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
979
980 Nesting_Decrease(&(pMe->nesting));
981 Nesting_Decrement(&(pMe->nesting));
982}
983
984
985/*
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600986 * Public function for opening a byte string. See qcbor/qcbor_encode.h
987 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700988void
989QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600990{
991 *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600992#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Paul Liétar79789772022-07-26 20:33:18 +0100993 uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
994 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
Laurence Lundblade716d10c2024-02-07 16:54:42 -0800995 /* It's OK to nest a byte string in any type but
996 * another open byte string. */
Paul Liétar79789772022-07-26 20:33:18 +0100997 pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
998 return;
999 }
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001000#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
1001
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001002 QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001003}
1004
1005
1006/*
1007 * Public function for closing a byte string. See qcbor/qcbor_encode.h
1008 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001009void
1010QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001011{
1012 UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
1013 if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
1014 /* Advance too far. Normal off-end error handling in effect here. */
1015 return;
1016 }
1017
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001018 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001019}
1020
1021
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001022#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1023
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001024/**
1025 * @brief Semi-private method to close a map, array with indefinite length
1026 *
1027 * @param[in] pMe The context to add to.
1028 * @param[in] uMajorType The major CBOR type to close.
1029 *
1030 * Call QCBOREncode_CloseArrayIndefiniteLength() or
1031 * QCBOREncode_CloseMapIndefiniteLength() instead of this.
Jan Jongboom4a93a662019-07-25 08:44:58 +02001032 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001033void
1034QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1035 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001036{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001037 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001038 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +02001039 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001040
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001041 /* Append the break marker (0xff for both arrays and maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001042 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001043 Nesting_Decrease(&(pMe->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +02001044}
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001045#endif
Jan Jongboom4a93a662019-07-25 08:44:58 +02001046
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001048/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001049 * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001050 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001051QCBORError
1052QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001053{
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001054 if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001055 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -08001056 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001057
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001058#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001059 if(Nesting_IsInNest(&(pMe->nesting))) {
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001060 pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001061 goto Done;
1062 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001063#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001064
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001065 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001066
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001067Done:
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001068 return pMe->uError;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001069}
1070
Laurence Lundblade0595e932018-11-02 22:22:47 +07001071
Laurence Lundblade067035b2018-11-28 17:35:25 -08001072/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001073 * Public functions to get size of the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -08001074 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001075QCBORError
1076QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001077{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001078 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001079
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001080 QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001081
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001082 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001083 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001084 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001085
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001086 return nReturn;
1087}