blob: ee9369b817469ca482c5c5a0446a1d9784e5a873 [file] [log] [blame]
Thiago Macieiraaddf8042017-02-26 11:37:06 -08001/****************************************************************************
2**
3** Copyright (C) 2017 Intel Corporation
4**
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>
133 </td>
134 <tr>
135 <td>1</td>
136 <td>integer</td>
137 <td>Epoch-based date/time</td>
138 </td>
139 <tr>
140 <td>2</td>
141 <td>byte string</td>
142 <td>Positive bignum</td>
143 </td>
144 <tr>
145 <td>3</td>
146 <td>byte string</td>
147 <td>Negative bignum</td>
148 </td>
149 <tr>
150 <td>4</td>
151 <td>array</td>
152 <td>Decimal fraction</td>
153 </td>
154 <tr>
155 <td>5</td>
156 <td>array</td>
157 <td>Bigfloat</td>
158 </td>
159 <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>
163 </td>
164 <tr>
165 <td>17</td>
166 <td>array</td>
167 <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
168 </td>
169 <tr>
170 <td>18</td>
171 <td>array</td>
172 <td>COSE Single Signer Data Object (RFC 8162)</td>
173 </td>
174 <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>
178 </td>
179 <tr>
180 <td>22</td>
181 <td>byte string, array, map</td>
182 <td>Expected conversion to base64 encoding</td>
183 </td>
184 <tr>
185 <td>23</td>
186 <td>byte string, array, map</td>
187 <td>Expected conversion to base16 encoding</td>
188 </td>
189 <tr>
190 <td>24</td>
191 <td>byte string</td>
192 <td>Encoded CBOR data item</td>
193 </td>
194 <tr>
195 <td>32</td>
196 <td>UTF-8 text string</td>
197 <td>URI</td>
198 </td>
199 <tr>
200 <td>33</td>
201 <td>UTF-8 text string</td>
202 <td>base64url</td>
203 </td>
204 <tr>
205 <td>34</td>
206 <td>UTF-8 text string</td>
207 <td>base64</td>
208 </td>
209 <tr>
210 <td>35</td>
211 <td>UTF-8 text string</td>
212 <td>Regular expression</td>
213 </td>
214 <tr>
215 <td>36</td>
216 <td>UTF-8 text string</td>
217 <td>MIME message</td>
218 </td>
219 <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>
223 </td>
224 <tr>
225 <td>97</td>
226 <td>array</td>
227 <td>COSE MACed Data Object (RFC 8152)</td>
228 </td>
229 <tr>
230 <td>98</td>
231 <td>array</td>
232 <td>COSE Signed Data Object (RFC 8152)</td>
233 </td>
234 <tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800235 <td>55799</td>
236 <td>any</td>
237 <td>Self-describe CBOR</td>
238 </td>
239</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[] = {
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100244 { 0, (uint8_t)CborTextStringType },
245 { 1, (uint8_t)(CborIntegerType+1) },
246 { 2, (uint8_t)CborByteStringType },
247 { 3, (uint8_t)CborByteStringType },
248 { 4, (uint8_t)CborArrayType },
249 { 5, (uint8_t)CborArrayType },
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700250 { 16, (uint8_t)CborArrayType },
251 { 17, (uint8_t)CborArrayType },
252 { 18, (uint8_t)CborArrayType },
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100253 { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
254 { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
255 { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
256 { 24, (uint8_t)CborByteStringType },
257 { 32, (uint8_t)CborTextStringType },
258 { 33, (uint8_t)CborTextStringType },
259 { 34, (uint8_t)CborTextStringType },
260 { 35, (uint8_t)CborTextStringType },
261 { 36, (uint8_t)CborTextStringType },
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700262 { 96, (uint8_t)CborArrayType },
263 { 97, (uint8_t)CborArrayType },
264 { 98, (uint8_t)CborArrayType },
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100265 { 55799, 0U }
Thiago Macieira0342d722017-02-26 13:12:50 -0800266};
267
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800268static CborError validate_value(CborValue *it, int flags, int recursionLeft);
269
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
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800282static inline CborError validate_simple_type(uint8_t simple_type, int flags)
283{
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
Thiago Macieira63d143b2017-02-26 17:43:50 -0800293static inline CborError validate_number(const CborValue *it, CborType type, int flags)
294{
295 CborError err = CborNoError;
296 const uint8_t *ptr = it->ptr;
297 uint64_t value;
298
299 if ((flags & CborValidateShortestIntegrals) == 0)
300 return err;
301 if (type >= CborHalfFloatType && type <= CborDoubleType)
302 return err; /* checked elsewhere */
303
304 err = _cbor_value_extract_number(&ptr, it->parser->end, &value);
305 if (err)
306 return err;
307
308 size_t bytesUsed = (size_t)(ptr - it->ptr - 1);
309 size_t bytesNeeded = 0;
310 if (value >= Value8Bit)
311 ++bytesNeeded;
312 if (value > 0xffU)
313 ++bytesNeeded;
314 if (value > 0xffffU)
315 bytesNeeded += 2;
316 if (value > 0xffffffffU)
317 bytesNeeded += 4;
318 if (bytesNeeded < bytesUsed)
319 return CborErrorOverlongEncoding;
320 return CborNoError;
321}
322
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800323static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
324{
325 CborType type = cbor_value_get_type(it);
Thiago Macieira0342d722017-02-26 13:12:50 -0800326 const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
327 const struct KnownTagData *tagData = knownTagData;
328 const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
329
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800330 if (!recursionLeft)
331 return CborErrorNestingTooDeep;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800332 if (flags & CborValidateNoTags)
333 return CborErrorExcludedType;
Thiago Macieira0342d722017-02-26 13:12:50 -0800334
335 /* find the tag data, if any */
336 for ( ; tagData != knownTagDataEnd; ++tagData) {
337 if (tagData->tag < tag)
338 continue;
339 if (tagData->tag > tag)
340 tagData = NULL;
341 break;
342 }
343 if (tagData == knownTagDataEnd)
344 tagData = NULL;
345
346 if (flags & CborValidateNoUnknownTags && !tagData) {
347 /* tag not found */
348 if (flags & CborValidateNoUnknownTagsSA && tag < 24)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800349 return CborErrorUnknownTag;
Thiago Macieira0342d722017-02-26 13:12:50 -0800350 if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
351 return CborErrorUnknownTag;
352 if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
353 return CborErrorUnknownTag;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800354 }
355
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100356 if (flags & CborValidateTagUse && tagData && tagData->types) {
357 uint32_t allowedTypes = tagData->types;
358
359 /* correct Integer so it's not zero */
360 if (type == CborIntegerType)
Thiago Macieirac4fa09e2017-12-19 09:19:56 -0800361 type = (CborType)(type + 1);
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100362
363 while (allowedTypes) {
364 if ((uint8_t)(allowedTypes & 0xff) == type)
365 break;
366 allowedTypes >>= 8;
367 }
368 if (!allowedTypes)
369 return CborErrorInappropriateTagForType;
370 }
371
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800372 return validate_value(it, flags, recursionLeft);
373}
374
375#ifndef CBOR_NO_FLOATING_POINT
376static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
377{
378 CborError err;
379 double val;
380 float valf;
381 uint16_t valf16;
382
383 if (type != CborDoubleType) {
384 if (type == CborFloatType) {
385 err = cbor_value_get_float(it, &valf);
386 val = valf;
387 } else {
388# ifdef CBOR_NO_HALF_FLOAT_TYPE
389 (void)val16;
390 return CborErrorUnsupportedType;
391# else
392 err = cbor_value_get_half_float(it, &valf16);
393 val = decode_half(valf16);
394# endif
395 }
396 } else {
397 err = cbor_value_get_double(it, &val);
398 }
399 cbor_assert(err == CborNoError); /* can't fail */
400
401 int r = fpclassify(val);
402 if (r == FP_NAN || r == FP_INFINITE) {
403 if (flags & CborValidateFiniteFloatingPoint)
404 return CborErrorExcludedValue;
405 if (flags & CborValidateShortestFloatingPoint) {
406 if (type == CborDoubleType)
407 return CborErrorOverlongEncoding;
408# ifndef CBOR_NO_HALF_FLOAT_TYPE
409 if (type == CborFloatType)
410 return CborErrorOverlongEncoding;
411 if (r == FP_NAN && valf16 != 0x7e00)
412 return CborErrorImproperValue;
413 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
414 return CborErrorImproperValue;
415# endif
416 }
417 }
418
419 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
420 if (type == CborDoubleType) {
421 valf = (float)val;
422 if ((double)valf == val)
423 return CborErrorOverlongEncoding;
424 }
425# ifndef CBOR_NO_HALF_FLOAT_TYPE
426 if (type == CborFloatType) {
427 valf16 = encode_half(valf);
428 if (valf == decode_half(valf16))
429 return CborErrorOverlongEncoding;
430 }
431# endif
432 }
433
434 return CborNoError;
435}
436#endif
437
438static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
439{
440 CborError err;
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800441 const uint8_t *previous = NULL;
Thiago Macieirad3c47d22017-12-26 20:11:27 -0200442 const uint8_t *previous_end = NULL;
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800443
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800444 if (!recursionLeft)
445 return CborErrorNestingTooDeep;
446
447 while (!cbor_value_at_end(it)) {
Thiago Macieirad3c47d22017-12-26 20:11:27 -0200448 const uint8_t *current = cbor_value_get_next_byte(it);
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800449
450 if (containerType == CborMapType) {
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800451 if (flags & CborValidateMapKeysAreString) {
452 CborType type = cbor_value_get_type(it);
453 if (type == CborTagType) {
454 /* skip the tags */
455 CborValue copy = *it;
456 err = cbor_value_skip_tag(&copy);
457 if (err)
458 return err;
459 type = cbor_value_get_type(&copy);
460 }
461 if (type != CborTextStringType)
462 return CborErrorMapKeyNotString;
463 }
464 }
465
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800466 err = validate_value(it, flags, recursionLeft);
467 if (err)
468 return err;
469
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800470 if (containerType != CborMapType)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800471 continue;
472
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800473 if (flags & CborValidateMapIsSorted) {
474 if (previous) {
475 uint64_t len1, len2;
476 const uint8_t *ptr;
477
478 /* extract the two lengths */
479 ptr = previous;
480 _cbor_value_extract_number(&ptr, it->parser->end, &len1);
481 ptr = current;
482 _cbor_value_extract_number(&ptr, it->parser->end, &len2);
483
484 if (len1 > len2)
485 return CborErrorMapNotSorted;
486 if (len1 == len2) {
487 size_t bytelen1 = (size_t)(previous_end - previous);
488 size_t bytelen2 = (size_t)(it->ptr - current);
489 int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2);
490
491 if (r == 0 && bytelen1 != bytelen2)
492 r = bytelen1 < bytelen2 ? -1 : +1;
493 if (r > 0)
494 return CborErrorMapNotSorted;
495 if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
496 return CborErrorMapKeysNotUnique;
497 }
498 }
499
500 previous = current;
501 previous_end = it->ptr;
502 }
503
504 /* map: that was the key, so get the value */
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800505 err = validate_value(it, flags, recursionLeft);
506 if (err)
507 return err;
508 }
509 return CborNoError;
510}
511
512static CborError validate_value(CborValue *it, int flags, int recursionLeft)
513{
514 CborError err;
Thiago Macieira63d143b2017-02-26 17:43:50 -0800515 CborType type = cbor_value_get_type(it);
516
517 if (cbor_value_is_length_known(it)) {
518 err = validate_number(it, type, flags);
519 if (err)
520 return err;
521 } else {
522 if (flags & CborValidateNoIndeterminateLength)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800523 return CborErrorUnknownLength;
524 }
525
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800526 switch (type) {
527 case CborArrayType:
528 case CborMapType: {
529 /* recursive type */
530 CborValue recursed;
531 err = cbor_value_enter_container(it, &recursed);
532 if (!err)
533 err = validate_container(&recursed, type, flags, recursionLeft - 1);
534 if (err) {
535 it->ptr = recursed.ptr;
536 return err;
537 }
538 err = cbor_value_leave_container(it, &recursed);
539 if (err)
540 return err;
541 return CborNoError;
542 }
543
544 case CborIntegerType: {
545 uint64_t val;
546 err = cbor_value_get_raw_integer(it, &val);
547 cbor_assert(err == CborNoError); /* can't fail */
548
549 break;
550 }
551
552 case CborByteStringType:
553 case CborTextStringType: {
554 size_t n = 0;
555 const void *ptr;
556
Thiago Macieira63d143b2017-02-26 17:43:50 -0800557 err = _cbor_value_prepare_string_iteration(it);
558 if (err)
559 return err;
560
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800561 while (1) {
Thiago Macieira63d143b2017-02-26 17:43:50 -0800562 err = validate_number(it, type, flags);
563 if (err)
564 return err;
565
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800566 err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
567 if (err)
568 return err;
569 if (!ptr)
570 break;
Thiago Macieira17d42a12017-02-26 14:42:37 -0800571
572 if (type == CborTextStringType && flags & CborValidateUtf8) {
573 err = validate_utf8_string(ptr, n);
574 if (err)
575 return err;
576 }
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800577 }
578
579 return CborNoError;
580 }
581
582 case CborTagType: {
583 CborTag tag;
584 err = cbor_value_get_tag(it, &tag);
585 cbor_assert(err == CborNoError); /* can't fail */
586
587 err = cbor_value_advance_fixed(it);
588 if (err)
589 return err;
590 err = validate_tag(it, tag, flags, recursionLeft - 1);
591 if (err)
592 return err;
593
594 return CborNoError;
595 }
596
597 case CborSimpleType: {
598 uint8_t simple_type;
599 err = cbor_value_get_simple_type(it, &simple_type);
600 cbor_assert(err == CborNoError); /* can't fail */
601 err = validate_simple_type(simple_type, flags);
602 if (err)
603 return err;
604 break;
605 }
606
607 case CborNullType:
608 case CborBooleanType:
609 break;
610
611 case CborUndefinedType:
612 if (flags & CborValidateNoUndefined)
613 return CborErrorExcludedType;
614 break;
615
616 case CborHalfFloatType:
617 case CborFloatType:
618 case CborDoubleType: {
619#ifdef CBOR_NO_FLOATING_POINT
620 return CborErrorUnsupportedType;
621#else
622 err = validate_floating_point(it, type, flags);
623 if (err)
624 return err;
625 break;
626 }
627#endif /* !CBOR_NO_FLOATING_POINT */
628
629 case CborInvalidType:
630 return CborErrorUnknownType;
631 }
632
633 err = cbor_value_advance_fixed(it);
634 return err;
635}
636
637/**
Thiago Macieiraf5a172b2018-02-05 14:53:14 -0800638 * Performs a full validation, controlled by the \a flags options, of the CBOR
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800639 * stream pointed by \a it and returns the error it found. If no error was
640 * found, it returns CborNoError and the application can iterate over the items
Thiago Macieiraf5a172b2018-02-05 14:53:14 -0800641 * with certainty that no errors will appear during parsing.
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800642 *
643 * If \a flags is CborValidateBasic, the result should be the same as
644 * cbor_value_validate_basic().
645 *
646 * This function has the same timing and memory requirements as
647 * cbor_value_advance() and cbor_value_validate_basic().
648 *
649 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
650 */
651CborError cbor_value_validate(const CborValue *it, int flags)
652{
653 CborValue value = *it;
654 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
655 if (err)
656 return err;
657 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
658 return CborErrorGarbageAtEnd;
659 return CborNoError;
660}
661
662/**
663 * @}
664 */