blob: 6c9d383cfe8fdec48c3055488aa55bf0c9b58566 [file] [log] [blame]
Thiago Macieiraaddf8042017-02-26 11:37:06 -08001/****************************************************************************
2**
Thiago Macieira57b66a82019-03-05 12:49:38 -08003** Copyright (C) 2019 Intel Corporation
Thiago Macieiraaddf8042017-02-26 11:37:06 -08004**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
25#define _BSD_SOURCE 1
26#define _DEFAULT_SOURCE 1
27#ifndef __STDC_LIMIT_MACROS
28# define __STDC_LIMIT_MACROS 1
29#endif
30
31#include "cbor.h"
32#include "cborinternal_p.h"
33#include "compilersupport_p.h"
Thiago Macieira17d42a12017-02-26 14:42:37 -080034#include "utf8_p.h"
Thiago Macieiraaddf8042017-02-26 11:37:06 -080035
36#include <string.h>
37
38#ifndef CBOR_NO_FLOATING_POINT
39# include <float.h>
40# include <math.h>
41#endif
42
43
44#ifndef CBOR_PARSER_MAX_RECURSIONS
45# define CBOR_PARSER_MAX_RECURSIONS 1024
46#endif
47
48/**
49 * \addtogroup CborParsing
50 * @{
51 */
52
53/**
54 * \enum CborValidationFlags
55 * The CborValidationFlags enum contains flags that control the validation of a
56 * CBOR stream.
57 *
Thiago Macieiraf5a172b2018-02-05 14:53:14 -080058 * \value CborValidateBasic Validates only the syntactic correctedness of the stream.
Thiago Macieiraaddf8042017-02-26 11:37:06 -080059 * \value CborValidateCanonical Validates that the stream is in canonical format, according to
60 * RFC 7049 section 3.9.
61 * \value CborValidateStrictMode Performs strict validation, according to RFC 7049 section 3.10.
62 * \value CborValidateStrictest Attempt to perform the strictest validation we know of.
63 *
64 * \value CborValidateShortestIntegrals (Canonical) Validate that integral numbers and lengths are
65 * enconded in their shortest form possible.
66 * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
67 * in their shortest form possible.
Thiago Macieiraf5a172b2018-02-05 14:53:14 -080068 * \value CborValidateShortestNumbers (Canonical) Validate both integral and floating-point numbers
Thiago Macieiraaddf8042017-02-26 11:37:06 -080069 * are in their shortest form possible.
70 * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
71 * indeterminate length encoding.
72 * \value CborValidateMapIsSorted (Canonical & Strict mode) Validate that map keys appear in
73 * sorted order.
74 * \value CborValidateMapKeysAreUnique (Strict mode) Validate that map keys are unique.
75 * \value CborValidateTagUse (Strict mode) Validate that known tags are used with the
76 * correct types. This does not validate that the content of
Thiago Macieiraf5a172b2018-02-05 14:53:14 -080077 * those types is syntactically correct. For example, this
78 * option validates that tag 1 (DateTimeString) is used with
79 * a Text String, but it does not validate that the string is
80 * a valid date/time representation.
Thiago Macieiraaddf8042017-02-26 11:37:06 -080081 * \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately
82 * encoded in UTF-8.
83 * \value CborValidateMapKeysAreString Validate that all map keys are text strings.
84 * \value CborValidateNoUndefined Validate that no elements of type "undefined" are present.
85 * \value CborValidateNoTags Validate that no tags are used.
86 * \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or
87 * infinities are allowed).
88 * \value CborValidateCompleteData Validate that the stream is complete and there is no more data
89 * in the buffer.
90 * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
91 * with IANA.
92 * \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA.
93 * \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA.
94 * \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags
95 * are registered with IANA (see below for limitations).
96 * \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA
97 * (see below for limitations).
98 *
99 * \par Simple type registry
100 * The CBOR specification requires that registration for use of the first 19
101 * simple types must be done by way of Standards Action. The rest of the simple
102 * types only require a specification. The official list can be obtained from
103 * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
104 *
105 * \par
106 * There are no registered simple types recognized by this release of TinyCBOR
107 * (beyond those defined by RFC 7049).
108 *
109 * \par Tag registry
110 * The CBOR specification requires that registration for use of the first 23
111 * tags must be done by way of Standards Action. The next up to tag 255 only
112 * require a specification. Finally, all other tags can be registered on a
113 * first-come-first-serve basis. The official list can be ontained from
114 * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
115 *
116 * \par
117 * Given the variability of this list, TinyCBOR cannot recognize all tags
118 * registered with IANA. Instead, the implementation only recognizes tags
119 * that are backed by an RFC.
120 *
121 * \par
122 * These are the tags known to the current TinyCBOR release:
Thiago Macieira0342d722017-02-26 13:12:50 -0800123<table>
124 <tr>
125 <th>Tag</th>
126 <th>Data Item</th>
127 <th>Semantics</th>
128 </tr>
129 <tr>
130 <td>0</td>
131 <td>UTF-8 text string</td>
132 <td>Standard date/time string</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000133 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800134 <tr>
135 <td>1</td>
136 <td>integer</td>
137 <td>Epoch-based date/time</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000138 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800139 <tr>
140 <td>2</td>
141 <td>byte string</td>
142 <td>Positive bignum</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000143 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800144 <tr>
145 <td>3</td>
146 <td>byte string</td>
147 <td>Negative bignum</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000148 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800149 <tr>
150 <td>4</td>
151 <td>array</td>
152 <td>Decimal fraction</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000153 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800154 <tr>
155 <td>5</td>
156 <td>array</td>
157 <td>Bigfloat</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000158 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800159 <tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700160 <td>16</td>
161 <td>array</td>
162 <td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000163 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700164 <tr>
165 <td>17</td>
166 <td>array</td>
167 <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000168 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700169 <tr>
170 <td>18</td>
171 <td>array</td>
172 <td>COSE Single Signer Data Object (RFC 8162)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000173 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700174 <tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800175 <td>21</td>
176 <td>byte string, array, map</td>
177 <td>Expected conversion to base64url encoding</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000178 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800179 <tr>
180 <td>22</td>
181 <td>byte string, array, map</td>
182 <td>Expected conversion to base64 encoding</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000183 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800184 <tr>
185 <td>23</td>
186 <td>byte string, array, map</td>
187 <td>Expected conversion to base16 encoding</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000188 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800189 <tr>
190 <td>24</td>
191 <td>byte string</td>
192 <td>Encoded CBOR data item</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000193 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800194 <tr>
195 <td>32</td>
196 <td>UTF-8 text string</td>
197 <td>URI</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000198 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800199 <tr>
200 <td>33</td>
201 <td>UTF-8 text string</td>
202 <td>base64url</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000203 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800204 <tr>
205 <td>34</td>
206 <td>UTF-8 text string</td>
207 <td>base64</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000208 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800209 <tr>
210 <td>35</td>
211 <td>UTF-8 text string</td>
212 <td>Regular expression</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000213 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800214 <tr>
215 <td>36</td>
216 <td>UTF-8 text string</td>
217 <td>MIME message</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000218 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800219 <tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700220 <td>96</td>
221 <td>array</td>
222 <td>COSE Encrypted Data Object (RFC 8152)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000223 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700224 <tr>
225 <td>97</td>
226 <td>array</td>
227 <td>COSE MACed Data Object (RFC 8152)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000228 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700229 <tr>
230 <td>98</td>
231 <td>array</td>
232 <td>COSE Signed Data Object (RFC 8152)</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000233 </tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700234 <tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800235 <td>55799</td>
236 <td>any</td>
237 <td>Self-describe CBOR</td>
Hamilton Chapmane373de22020-02-07 12:46:01 +0000238 </tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800239</table>
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800240 */
241
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100242struct KnownTagData { uint32_t tag; uint32_t types; };
Thiago Macieira0342d722017-02-26 13:12:50 -0800243static const struct KnownTagData knownTagData[] = {
Koen Zandbergfac1e572018-05-24 11:37:52 +0200244 { 0, (uint32_t)CborTextStringType },
245 { 1, (uint32_t)(CborIntegerType+1) },
246 { 2, (uint32_t)CborByteStringType },
247 { 3, (uint32_t)CborByteStringType },
248 { 4, (uint32_t)CborArrayType },
249 { 5, (uint32_t)CborArrayType },
250 { 16, (uint32_t)CborArrayType },
251 { 17, (uint32_t)CborArrayType },
252 { 18, (uint32_t)CborArrayType },
253 { 21, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
254 { 22, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
255 { 23, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
256 { 24, (uint32_t)CborByteStringType },
257 { 32, (uint32_t)CborTextStringType },
258 { 33, (uint32_t)CborTextStringType },
259 { 34, (uint32_t)CborTextStringType },
260 { 35, (uint32_t)CborTextStringType },
261 { 36, (uint32_t)CborTextStringType },
262 { 96, (uint32_t)CborArrayType },
263 { 97, (uint32_t)CborArrayType },
264 { 98, (uint32_t)CborArrayType },
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100265 { 55799, 0U }
Thiago Macieira0342d722017-02-26 13:12:50 -0800266};
267
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200268static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft);
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800269
Thiago Macieira17d42a12017-02-26 14:42:37 -0800270static inline CborError validate_utf8_string(const void *ptr, size_t n)
271{
272 const uint8_t *buffer = (const uint8_t *)ptr;
273 const uint8_t * const end = buffer + n;
274 while (buffer < end) {
275 uint32_t uc = get_utf8(&buffer, end);
276 if (uc == ~0U)
277 return CborErrorInvalidUtf8TextString;
278 }
279 return CborNoError;
280}
281
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200282static inline CborError validate_simple_type(uint8_t simple_type, uint32_t flags)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800283{
284 /* At current time, all known simple types are those from RFC 7049,
285 * which are parsed by the parser into different CBOR types.
286 * That means that if we've got here, the type is unknown */
287 if (simple_type < 32)
288 return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
289 return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
290 CborErrorUnknownSimpleType : CborNoError;
291}
292
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200293static inline CborError validate_number(const CborValue *it, CborType type, uint32_t flags)
Thiago Macieira63d143b2017-02-26 17:43:50 -0800294{
295 CborError err = CborNoError;
296 const uint8_t *ptr = it->ptr;
Thiago Macieirad2603492018-07-08 10:57:22 -0700297 size_t bytesUsed, bytesNeeded;
Thiago Macieira63d143b2017-02-26 17:43:50 -0800298 uint64_t value;
299
300 if ((flags & CborValidateShortestIntegrals) == 0)
301 return err;
302 if (type >= CborHalfFloatType && type <= CborDoubleType)
303 return err; /* checked elsewhere */
304
305 err = _cbor_value_extract_number(&ptr, it->parser->end, &value);
306 if (err)
307 return err;
308
Thiago Macieirad2603492018-07-08 10:57:22 -0700309 bytesUsed = (size_t)(ptr - it->ptr - 1);
310 bytesNeeded = 0;
Thiago Macieira63d143b2017-02-26 17:43:50 -0800311 if (value >= Value8Bit)
312 ++bytesNeeded;
313 if (value > 0xffU)
314 ++bytesNeeded;
315 if (value > 0xffffU)
316 bytesNeeded += 2;
317 if (value > 0xffffffffU)
318 bytesNeeded += 4;
319 if (bytesNeeded < bytesUsed)
320 return CborErrorOverlongEncoding;
321 return CborNoError;
322}
323
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200324static inline CborError validate_tag(CborValue *it, CborTag tag, uint32_t flags, int recursionLeft)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800325{
326 CborType type = cbor_value_get_type(it);
Thiago Macieira0342d722017-02-26 13:12:50 -0800327 const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
328 const struct KnownTagData *tagData = knownTagData;
329 const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
330
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800331 if (!recursionLeft)
332 return CborErrorNestingTooDeep;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800333 if (flags & CborValidateNoTags)
334 return CborErrorExcludedType;
Thiago Macieira0342d722017-02-26 13:12:50 -0800335
336 /* find the tag data, if any */
337 for ( ; tagData != knownTagDataEnd; ++tagData) {
338 if (tagData->tag < tag)
339 continue;
340 if (tagData->tag > tag)
341 tagData = NULL;
342 break;
343 }
344 if (tagData == knownTagDataEnd)
345 tagData = NULL;
346
347 if (flags & CborValidateNoUnknownTags && !tagData) {
348 /* tag not found */
349 if (flags & CborValidateNoUnknownTagsSA && tag < 24)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800350 return CborErrorUnknownTag;
Thiago Macieira0342d722017-02-26 13:12:50 -0800351 if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
352 return CborErrorUnknownTag;
353 if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
354 return CborErrorUnknownTag;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800355 }
356
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100357 if (flags & CborValidateTagUse && tagData && tagData->types) {
358 uint32_t allowedTypes = tagData->types;
359
360 /* correct Integer so it's not zero */
361 if (type == CborIntegerType)
Thiago Macieirac4fa09e2017-12-19 09:19:56 -0800362 type = (CborType)(type + 1);
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100363
364 while (allowedTypes) {
365 if ((uint8_t)(allowedTypes & 0xff) == type)
366 break;
367 allowedTypes >>= 8;
368 }
369 if (!allowedTypes)
370 return CborErrorInappropriateTagForType;
371 }
372
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800373 return validate_value(it, flags, recursionLeft);
374}
375
376#ifndef CBOR_NO_FLOATING_POINT
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200377static inline CborError validate_floating_point(CborValue *it, CborType type, uint32_t flags)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800378{
379 CborError err;
Thiago Macieirad2603492018-07-08 10:57:22 -0700380 int r;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800381 double val;
382 float valf;
383 uint16_t valf16;
384
385 if (type != CborDoubleType) {
386 if (type == CborFloatType) {
387 err = cbor_value_get_float(it, &valf);
388 val = valf;
389 } else {
390# ifdef CBOR_NO_HALF_FLOAT_TYPE
Koen Zandbergf1b32582018-05-28 09:51:35 +0200391 (void)valf16;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800392 return CborErrorUnsupportedType;
393# else
394 err = cbor_value_get_half_float(it, &valf16);
395 val = decode_half(valf16);
396# endif
397 }
398 } else {
399 err = cbor_value_get_double(it, &val);
400 }
401 cbor_assert(err == CborNoError); /* can't fail */
402
Thiago Macieirad2603492018-07-08 10:57:22 -0700403 r = fpclassify(val);
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800404 if (r == FP_NAN || r == FP_INFINITE) {
405 if (flags & CborValidateFiniteFloatingPoint)
406 return CborErrorExcludedValue;
407 if (flags & CborValidateShortestFloatingPoint) {
408 if (type == CborDoubleType)
409 return CborErrorOverlongEncoding;
410# ifndef CBOR_NO_HALF_FLOAT_TYPE
411 if (type == CborFloatType)
412 return CborErrorOverlongEncoding;
413 if (r == FP_NAN && valf16 != 0x7e00)
414 return CborErrorImproperValue;
415 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
416 return CborErrorImproperValue;
417# endif
418 }
419 }
420
421 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
422 if (type == CborDoubleType) {
423 valf = (float)val;
424 if ((double)valf == val)
425 return CborErrorOverlongEncoding;
426 }
427# ifndef CBOR_NO_HALF_FLOAT_TYPE
428 if (type == CborFloatType) {
429 valf16 = encode_half(valf);
430 if (valf == decode_half(valf16))
431 return CborErrorOverlongEncoding;
432 }
433# endif
434 }
435
436 return CborNoError;
437}
438#endif
439
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200440static CborError validate_container(CborValue *it, int containerType, uint32_t flags, int recursionLeft)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800441{
442 CborError err;
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800443 const uint8_t *previous = NULL;
Thiago Macieirad3c47d22017-12-26 20:11:27 -0200444 const uint8_t *previous_end = NULL;
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800445
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800446 if (!recursionLeft)
447 return CborErrorNestingTooDeep;
448
449 while (!cbor_value_at_end(it)) {
Thiago Macieirad3c47d22017-12-26 20:11:27 -0200450 const uint8_t *current = cbor_value_get_next_byte(it);
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800451
452 if (containerType == CborMapType) {
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800453 if (flags & CborValidateMapKeysAreString) {
454 CborType type = cbor_value_get_type(it);
455 if (type == CborTagType) {
456 /* skip the tags */
457 CborValue copy = *it;
458 err = cbor_value_skip_tag(&copy);
459 if (err)
460 return err;
461 type = cbor_value_get_type(&copy);
462 }
463 if (type != CborTextStringType)
464 return CborErrorMapKeyNotString;
465 }
466 }
467
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800468 err = validate_value(it, flags, recursionLeft);
469 if (err)
470 return err;
471
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800472 if (containerType != CborMapType)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800473 continue;
474
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800475 if (flags & CborValidateMapIsSorted) {
476 if (previous) {
477 uint64_t len1, len2;
478 const uint8_t *ptr;
479
480 /* extract the two lengths */
481 ptr = previous;
482 _cbor_value_extract_number(&ptr, it->parser->end, &len1);
483 ptr = current;
484 _cbor_value_extract_number(&ptr, it->parser->end, &len2);
485
486 if (len1 > len2)
487 return CborErrorMapNotSorted;
488 if (len1 == len2) {
489 size_t bytelen1 = (size_t)(previous_end - previous);
490 size_t bytelen2 = (size_t)(it->ptr - current);
491 int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2);
492
493 if (r == 0 && bytelen1 != bytelen2)
494 r = bytelen1 < bytelen2 ? -1 : +1;
495 if (r > 0)
496 return CborErrorMapNotSorted;
497 if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
498 return CborErrorMapKeysNotUnique;
499 }
500 }
501
502 previous = current;
503 previous_end = it->ptr;
504 }
505
506 /* map: that was the key, so get the value */
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800507 err = validate_value(it, flags, recursionLeft);
508 if (err)
509 return err;
510 }
511 return CborNoError;
512}
513
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200514static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800515{
516 CborError err;
Thiago Macieira63d143b2017-02-26 17:43:50 -0800517 CborType type = cbor_value_get_type(it);
518
519 if (cbor_value_is_length_known(it)) {
520 err = validate_number(it, type, flags);
521 if (err)
522 return err;
523 } else {
524 if (flags & CborValidateNoIndeterminateLength)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800525 return CborErrorUnknownLength;
526 }
527
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800528 switch (type) {
529 case CborArrayType:
530 case CborMapType: {
531 /* recursive type */
532 CborValue recursed;
533 err = cbor_value_enter_container(it, &recursed);
534 if (!err)
535 err = validate_container(&recursed, type, flags, recursionLeft - 1);
536 if (err) {
537 it->ptr = recursed.ptr;
538 return err;
539 }
540 err = cbor_value_leave_container(it, &recursed);
541 if (err)
542 return err;
543 return CborNoError;
544 }
545
546 case CborIntegerType: {
547 uint64_t val;
548 err = cbor_value_get_raw_integer(it, &val);
549 cbor_assert(err == CborNoError); /* can't fail */
550
551 break;
552 }
553
554 case CborByteStringType:
555 case CborTextStringType: {
556 size_t n = 0;
557 const void *ptr;
558
Thiago Macieira63d143b2017-02-26 17:43:50 -0800559 err = _cbor_value_prepare_string_iteration(it);
560 if (err)
561 return err;
562
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800563 while (1) {
Thiago Macieira57b66a82019-03-05 12:49:38 -0800564 CborValue next;
565 err = _cbor_value_get_string_chunk(it, &ptr, &n, &next);
Thiago Macieira63d143b2017-02-26 17:43:50 -0800566 if (err)
567 return err;
Thiago Macieira57b66a82019-03-05 12:49:38 -0800568 if (ptr) {
569 err = validate_number(it, type, flags);
570 if (err)
571 return err;
572 }
Thiago Macieira63d143b2017-02-26 17:43:50 -0800573
Thiago Macieira57b66a82019-03-05 12:49:38 -0800574 *it = next;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800575 if (!ptr)
576 break;
Thiago Macieira17d42a12017-02-26 14:42:37 -0800577
578 if (type == CborTextStringType && flags & CborValidateUtf8) {
579 err = validate_utf8_string(ptr, n);
580 if (err)
581 return err;
582 }
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800583 }
584
585 return CborNoError;
586 }
587
588 case CborTagType: {
589 CborTag tag;
590 err = cbor_value_get_tag(it, &tag);
591 cbor_assert(err == CborNoError); /* can't fail */
592
593 err = cbor_value_advance_fixed(it);
594 if (err)
595 return err;
596 err = validate_tag(it, tag, flags, recursionLeft - 1);
597 if (err)
598 return err;
599
600 return CborNoError;
601 }
602
603 case CborSimpleType: {
604 uint8_t simple_type;
605 err = cbor_value_get_simple_type(it, &simple_type);
606 cbor_assert(err == CborNoError); /* can't fail */
607 err = validate_simple_type(simple_type, flags);
608 if (err)
609 return err;
610 break;
611 }
612
613 case CborNullType:
614 case CborBooleanType:
615 break;
616
617 case CborUndefinedType:
618 if (flags & CborValidateNoUndefined)
619 return CborErrorExcludedType;
620 break;
621
622 case CborHalfFloatType:
623 case CborFloatType:
624 case CborDoubleType: {
625#ifdef CBOR_NO_FLOATING_POINT
626 return CborErrorUnsupportedType;
627#else
628 err = validate_floating_point(it, type, flags);
629 if (err)
630 return err;
631 break;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800632#endif /* !CBOR_NO_FLOATING_POINT */
Koen Zandberg66f0e782018-05-24 10:02:33 +0200633 }
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800634
635 case CborInvalidType:
636 return CborErrorUnknownType;
637 }
638
639 err = cbor_value_advance_fixed(it);
640 return err;
641}
642
643/**
Thiago Macieiraf5a172b2018-02-05 14:53:14 -0800644 * Performs a full validation, controlled by the \a flags options, of the CBOR
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800645 * stream pointed by \a it and returns the error it found. If no error was
646 * found, it returns CborNoError and the application can iterate over the items
Thiago Macieiraf5a172b2018-02-05 14:53:14 -0800647 * with certainty that no errors will appear during parsing.
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800648 *
649 * If \a flags is CborValidateBasic, the result should be the same as
650 * cbor_value_validate_basic().
651 *
652 * This function has the same timing and memory requirements as
653 * cbor_value_advance() and cbor_value_validate_basic().
654 *
655 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
656 */
Koen Zandberg81fbe2e2018-05-24 11:48:24 +0200657CborError cbor_value_validate(const CborValue *it, uint32_t flags)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800658{
659 CborValue value = *it;
660 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
661 if (err)
662 return err;
663 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
664 return CborErrorGarbageAtEnd;
665 return CborNoError;
666}
667
668/**
669 * @}
670 */