]>
Commit | Line | Data |
---|---|---|
0bb51450 OM |
1 | /**************************************************************************** |
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" | |
34 | #include "utf8_p.h" | |
35 | ||
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 | * | |
58 | * \value CborValidateBasic Validates only the syntactic correctedness of the stream. | |
59 | * \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. | |
68 | * \value CborValidateShortestNumbers (Canonical) Validate both integral and floating-point numbers | |
69 | * 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 | |
77 | * 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. | |
81 | * \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: | |
123 | <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> | |
160 | <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> | |
175 | <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> | |
220 | <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> | |
235 | <td>55799</td> | |
236 | <td>any</td> | |
237 | <td>Self-describe CBOR</td> | |
238 | </td> | |
239 | </table> | |
240 | */ | |
241 | ||
242 | struct KnownTagData { uint32_t tag; uint32_t types; }; | |
243 | static const struct KnownTagData knownTagData[] = { | |
244 | { 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 }, | |
265 | { 55799, 0U } | |
266 | }; | |
267 | ||
268 | static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft); | |
269 | ||
270 | static 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 | ||
282 | static inline CborError validate_simple_type(uint8_t simple_type, uint32_t 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 | ||
293 | static inline CborError validate_number(const CborValue *it, CborType type, uint32_t flags) | |
294 | { | |
295 | CborError err = CborNoError; | |
296 | const uint8_t *ptr = it->ptr; | |
297 | size_t bytesUsed, bytesNeeded; | |
298 | 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 | ||
309 | bytesUsed = (size_t)(ptr - it->ptr - 1); | |
310 | bytesNeeded = 0; | |
311 | 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 | ||
324 | static inline CborError validate_tag(CborValue *it, CborTag tag, uint32_t flags, int recursionLeft) | |
325 | { | |
326 | CborType type = cbor_value_get_type(it); | |
327 | const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]); | |
328 | const struct KnownTagData *tagData = knownTagData; | |
329 | const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount; | |
330 | ||
331 | if (!recursionLeft) | |
332 | return CborErrorNestingTooDeep; | |
333 | if (flags & CborValidateNoTags) | |
334 | return CborErrorExcludedType; | |
335 | ||
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) | |
350 | return CborErrorUnknownTag; | |
351 | if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256) | |
352 | return CborErrorUnknownTag; | |
353 | if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags) | |
354 | return CborErrorUnknownTag; | |
355 | } | |
356 | ||
357 | 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) | |
362 | type = (CborType)(type + 1); | |
363 | ||
364 | while (allowedTypes) { | |
365 | if ((uint8_t)(allowedTypes & 0xff) == type) | |
366 | break; | |
367 | allowedTypes >>= 8; | |
368 | } | |
369 | if (!allowedTypes) | |
370 | return CborErrorInappropriateTagForType; | |
371 | } | |
372 | ||
373 | return validate_value(it, flags, recursionLeft); | |
374 | } | |
375 | ||
376 | #ifndef CBOR_NO_FLOATING_POINT | |
377 | static inline CborError validate_floating_point(CborValue *it, CborType type, uint32_t flags) | |
378 | { | |
379 | CborError err; | |
380 | int r; | |
381 | 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 | |
391 | (void)valf16; | |
392 | 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 | ||
403 | r = fpclassify(val); | |
404 | 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 | ||
440 | static CborError validate_container(CborValue *it, int containerType, uint32_t flags, int recursionLeft) | |
441 | { | |
442 | CborError err; | |
443 | const uint8_t *previous = NULL; | |
444 | const uint8_t *previous_end = NULL; | |
445 | ||
446 | if (!recursionLeft) | |
447 | return CborErrorNestingTooDeep; | |
448 | ||
449 | while (!cbor_value_at_end(it)) { | |
450 | const uint8_t *current = cbor_value_get_next_byte(it); | |
451 | ||
452 | if (containerType == CborMapType) { | |
453 | 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(©); | |
459 | if (err) | |
460 | return err; | |
461 | type = cbor_value_get_type(©); | |
462 | } | |
463 | if (type != CborTextStringType) | |
464 | return CborErrorMapKeyNotString; | |
465 | } | |
466 | } | |
467 | ||
468 | err = validate_value(it, flags, recursionLeft); | |
469 | if (err) | |
470 | return err; | |
471 | ||
472 | if (containerType != CborMapType) | |
473 | continue; | |
474 | ||
475 | 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 */ | |
507 | err = validate_value(it, flags, recursionLeft); | |
508 | if (err) | |
509 | return err; | |
510 | } | |
511 | return CborNoError; | |
512 | } | |
513 | ||
514 | static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft) | |
515 | { | |
516 | CborError err; | |
517 | 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) | |
525 | return CborErrorUnknownLength; | |
526 | } | |
527 | ||
528 | 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 | ||
559 | err = _cbor_value_prepare_string_iteration(it); | |
560 | if (err) | |
561 | return err; | |
562 | ||
563 | while (1) { | |
564 | err = validate_number(it, type, flags); | |
565 | if (err) | |
566 | return err; | |
567 | ||
568 | err = _cbor_value_get_string_chunk(it, &ptr, &n, it); | |
569 | if (err) | |
570 | return err; | |
571 | if (!ptr) | |
572 | break; | |
573 | ||
574 | if (type == CborTextStringType && flags & CborValidateUtf8) { | |
575 | err = validate_utf8_string(ptr, n); | |
576 | if (err) | |
577 | return err; | |
578 | } | |
579 | } | |
580 | ||
581 | return CborNoError; | |
582 | } | |
583 | ||
584 | case CborTagType: { | |
585 | CborTag tag; | |
586 | err = cbor_value_get_tag(it, &tag); | |
587 | cbor_assert(err == CborNoError); /* can't fail */ | |
588 | ||
589 | err = cbor_value_advance_fixed(it); | |
590 | if (err) | |
591 | return err; | |
592 | err = validate_tag(it, tag, flags, recursionLeft - 1); | |
593 | if (err) | |
594 | return err; | |
595 | ||
596 | return CborNoError; | |
597 | } | |
598 | ||
599 | case CborSimpleType: { | |
600 | uint8_t simple_type; | |
601 | err = cbor_value_get_simple_type(it, &simple_type); | |
602 | cbor_assert(err == CborNoError); /* can't fail */ | |
603 | err = validate_simple_type(simple_type, flags); | |
604 | if (err) | |
605 | return err; | |
606 | break; | |
607 | } | |
608 | ||
609 | case CborNullType: | |
610 | case CborBooleanType: | |
611 | break; | |
612 | ||
613 | case CborUndefinedType: | |
614 | if (flags & CborValidateNoUndefined) | |
615 | return CborErrorExcludedType; | |
616 | break; | |
617 | ||
618 | case CborHalfFloatType: | |
619 | case CborFloatType: | |
620 | case CborDoubleType: { | |
621 | #ifdef CBOR_NO_FLOATING_POINT | |
622 | return CborErrorUnsupportedType; | |
623 | #else | |
624 | err = validate_floating_point(it, type, flags); | |
625 | if (err) | |
626 | return err; | |
627 | break; | |
628 | #endif /* !CBOR_NO_FLOATING_POINT */ | |
629 | } | |
630 | ||
631 | case CborInvalidType: | |
632 | return CborErrorUnknownType; | |
633 | } | |
634 | ||
635 | err = cbor_value_advance_fixed(it); | |
636 | return err; | |
637 | } | |
638 | ||
639 | /** | |
640 | * Performs a full validation, controlled by the \a flags options, of the CBOR | |
641 | * stream pointed by \a it and returns the error it found. If no error was | |
642 | * found, it returns CborNoError and the application can iterate over the items | |
643 | * with certainty that no errors will appear during parsing. | |
644 | * | |
645 | * If \a flags is CborValidateBasic, the result should be the same as | |
646 | * cbor_value_validate_basic(). | |
647 | * | |
648 | * This function has the same timing and memory requirements as | |
649 | * cbor_value_advance() and cbor_value_validate_basic(). | |
650 | * | |
651 | * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance() | |
652 | */ | |
653 | CborError cbor_value_validate(const CborValue *it, uint32_t flags) | |
654 | { | |
655 | CborValue value = *it; | |
656 | CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS); | |
657 | if (err) | |
658 | return err; | |
659 | if (flags & CborValidateCompleteData && it->ptr != it->parser->end) | |
660 | return CborErrorGarbageAtEnd; | |
661 | return CborNoError; | |
662 | } | |
663 | ||
664 | /** | |
665 | * @} | |
666 | */ |