blob: 0f28ce9cd8ede061620ef5a6848cc4a385f92e1e [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 *
58 * \value CborValidateBasic Validates only the syntax 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 integrals 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.
78 * \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately
79 * encoded in UTF-8.
80 * \value CborValidateMapKeysAreString Validate that all map keys are text strings.
81 * \value CborValidateNoUndefined Validate that no elements of type "undefined" are present.
82 * \value CborValidateNoTags Validate that no tags are used.
83 * \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or
84 * infinities are allowed).
85 * \value CborValidateCompleteData Validate that the stream is complete and there is no more data
86 * in the buffer.
87 * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
88 * with IANA.
89 * \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA.
90 * \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA.
91 * \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags
92 * are registered with IANA (see below for limitations).
93 * \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA
94 * (see below for limitations).
95 *
96 * \par Simple type registry
97 * The CBOR specification requires that registration for use of the first 19
98 * simple types must be done by way of Standards Action. The rest of the simple
99 * types only require a specification. The official list can be obtained from
100 * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
101 *
102 * \par
103 * There are no registered simple types recognized by this release of TinyCBOR
104 * (beyond those defined by RFC 7049).
105 *
106 * \par Tag registry
107 * The CBOR specification requires that registration for use of the first 23
108 * tags must be done by way of Standards Action. The next up to tag 255 only
109 * require a specification. Finally, all other tags can be registered on a
110 * first-come-first-serve basis. The official list can be ontained from
111 * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
112 *
113 * \par
114 * Given the variability of this list, TinyCBOR cannot recognize all tags
115 * registered with IANA. Instead, the implementation only recognizes tags
116 * that are backed by an RFC.
117 *
118 * \par
119 * These are the tags known to the current TinyCBOR release:
Thiago Macieira0342d722017-02-26 13:12:50 -0800120<table>
121 <tr>
122 <th>Tag</th>
123 <th>Data Item</th>
124 <th>Semantics</th>
125 </tr>
126 <tr>
127 <td>0</td>
128 <td>UTF-8 text string</td>
129 <td>Standard date/time string</td>
130 </td>
131 <tr>
132 <td>1</td>
133 <td>integer</td>
134 <td>Epoch-based date/time</td>
135 </td>
136 <tr>
137 <td>2</td>
138 <td>byte string</td>
139 <td>Positive bignum</td>
140 </td>
141 <tr>
142 <td>3</td>
143 <td>byte string</td>
144 <td>Negative bignum</td>
145 </td>
146 <tr>
147 <td>4</td>
148 <td>array</td>
149 <td>Decimal fraction</td>
150 </td>
151 <tr>
152 <td>5</td>
153 <td>array</td>
154 <td>Bigfloat</td>
155 </td>
156 <tr>
157 <td>21</td>
158 <td>byte string, array, map</td>
159 <td>Expected conversion to base64url encoding</td>
160 </td>
161 <tr>
162 <td>22</td>
163 <td>byte string, array, map</td>
164 <td>Expected conversion to base64 encoding</td>
165 </td>
166 <tr>
167 <td>23</td>
168 <td>byte string, array, map</td>
169 <td>Expected conversion to base16 encoding</td>
170 </td>
171 <tr>
172 <td>24</td>
173 <td>byte string</td>
174 <td>Encoded CBOR data item</td>
175 </td>
176 <tr>
177 <td>32</td>
178 <td>UTF-8 text string</td>
179 <td>URI</td>
180 </td>
181 <tr>
182 <td>33</td>
183 <td>UTF-8 text string</td>
184 <td>base64url</td>
185 </td>
186 <tr>
187 <td>34</td>
188 <td>UTF-8 text string</td>
189 <td>base64</td>
190 </td>
191 <tr>
192 <td>35</td>
193 <td>UTF-8 text string</td>
194 <td>Regular expression</td>
195 </td>
196 <tr>
197 <td>36</td>
198 <td>UTF-8 text string</td>
199 <td>MIME message</td>
200 </td>
201 <tr>
202 <td>55799</td>
203 <td>any</td>
204 <td>Self-describe CBOR</td>
205 </td>
206</table>
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800207 */
208
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100209struct KnownTagData { uint32_t tag; uint32_t types; };
Thiago Macieira0342d722017-02-26 13:12:50 -0800210static const struct KnownTagData knownTagData[] = {
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100211 { 0, (uint8_t)CborTextStringType },
212 { 1, (uint8_t)(CborIntegerType+1) },
213 { 2, (uint8_t)CborByteStringType },
214 { 3, (uint8_t)CborByteStringType },
215 { 4, (uint8_t)CborArrayType },
216 { 5, (uint8_t)CborArrayType },
217 { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
218 { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
219 { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
220 { 24, (uint8_t)CborByteStringType },
221 { 32, (uint8_t)CborTextStringType },
222 { 33, (uint8_t)CborTextStringType },
223 { 34, (uint8_t)CborTextStringType },
224 { 35, (uint8_t)CborTextStringType },
225 { 36, (uint8_t)CborTextStringType },
226 { 55799, 0U }
Thiago Macieira0342d722017-02-26 13:12:50 -0800227};
228
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800229static CborError validate_value(CborValue *it, int flags, int recursionLeft);
230
Thiago Macieira17d42a12017-02-26 14:42:37 -0800231static inline CborError validate_utf8_string(const void *ptr, size_t n)
232{
233 const uint8_t *buffer = (const uint8_t *)ptr;
234 const uint8_t * const end = buffer + n;
235 while (buffer < end) {
236 uint32_t uc = get_utf8(&buffer, end);
237 if (uc == ~0U)
238 return CborErrorInvalidUtf8TextString;
239 }
240 return CborNoError;
241}
242
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800243static inline CborError validate_simple_type(uint8_t simple_type, int flags)
244{
245 /* At current time, all known simple types are those from RFC 7049,
246 * which are parsed by the parser into different CBOR types.
247 * That means that if we've got here, the type is unknown */
248 if (simple_type < 32)
249 return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
250 return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
251 CborErrorUnknownSimpleType : CborNoError;
252}
253
254static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
255{
256 CborType type = cbor_value_get_type(it);
Thiago Macieira0342d722017-02-26 13:12:50 -0800257 const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
258 const struct KnownTagData *tagData = knownTagData;
259 const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
260
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800261 if (!recursionLeft)
262 return CborErrorNestingTooDeep;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800263 if (flags & CborValidateNoTags)
264 return CborErrorExcludedType;
Thiago Macieira0342d722017-02-26 13:12:50 -0800265
266 /* find the tag data, if any */
267 for ( ; tagData != knownTagDataEnd; ++tagData) {
268 if (tagData->tag < tag)
269 continue;
270 if (tagData->tag > tag)
271 tagData = NULL;
272 break;
273 }
274 if (tagData == knownTagDataEnd)
275 tagData = NULL;
276
277 if (flags & CborValidateNoUnknownTags && !tagData) {
278 /* tag not found */
279 if (flags & CborValidateNoUnknownTagsSA && tag < 24)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800280 return CborErrorUnknownTag;
Thiago Macieira0342d722017-02-26 13:12:50 -0800281 if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
282 return CborErrorUnknownTag;
283 if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
284 return CborErrorUnknownTag;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800285 }
286
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100287 if (flags & CborValidateTagUse && tagData && tagData->types) {
288 uint32_t allowedTypes = tagData->types;
289
290 /* correct Integer so it's not zero */
291 if (type == CborIntegerType)
292 ++type;
293
294 while (allowedTypes) {
295 if ((uint8_t)(allowedTypes & 0xff) == type)
296 break;
297 allowedTypes >>= 8;
298 }
299 if (!allowedTypes)
300 return CborErrorInappropriateTagForType;
301 }
302
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800303 return validate_value(it, flags, recursionLeft);
304}
305
306#ifndef CBOR_NO_FLOATING_POINT
307static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
308{
309 CborError err;
310 double val;
311 float valf;
312 uint16_t valf16;
313
314 if (type != CborDoubleType) {
315 if (type == CborFloatType) {
316 err = cbor_value_get_float(it, &valf);
317 val = valf;
318 } else {
319# ifdef CBOR_NO_HALF_FLOAT_TYPE
320 (void)val16;
321 return CborErrorUnsupportedType;
322# else
323 err = cbor_value_get_half_float(it, &valf16);
324 val = decode_half(valf16);
325# endif
326 }
327 } else {
328 err = cbor_value_get_double(it, &val);
329 }
330 cbor_assert(err == CborNoError); /* can't fail */
331
332 int r = fpclassify(val);
333 if (r == FP_NAN || r == FP_INFINITE) {
334 if (flags & CborValidateFiniteFloatingPoint)
335 return CborErrorExcludedValue;
336 if (flags & CborValidateShortestFloatingPoint) {
337 if (type == CborDoubleType)
338 return CborErrorOverlongEncoding;
339# ifndef CBOR_NO_HALF_FLOAT_TYPE
340 if (type == CborFloatType)
341 return CborErrorOverlongEncoding;
342 if (r == FP_NAN && valf16 != 0x7e00)
343 return CborErrorImproperValue;
344 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
345 return CborErrorImproperValue;
346# endif
347 }
348 }
349
350 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
351 if (type == CborDoubleType) {
352 valf = (float)val;
353 if ((double)valf == val)
354 return CborErrorOverlongEncoding;
355 }
356# ifndef CBOR_NO_HALF_FLOAT_TYPE
357 if (type == CborFloatType) {
358 valf16 = encode_half(valf);
359 if (valf == decode_half(valf16))
360 return CborErrorOverlongEncoding;
361 }
362# endif
363 }
364
365 return CborNoError;
366}
367#endif
368
369static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
370{
371 CborError err;
372 if (!recursionLeft)
373 return CborErrorNestingTooDeep;
374
375 while (!cbor_value_at_end(it)) {
376 err = validate_value(it, flags, recursionLeft);
377 if (err)
378 return err;
379
380 if (containerType == CborArrayType)
381 continue;
382
383 /* map: that was the key, so get he value */
384 err = validate_value(it, flags, recursionLeft);
385 if (err)
386 return err;
387 }
388 return CborNoError;
389}
390
391static CborError validate_value(CborValue *it, int flags, int recursionLeft)
392{
393 CborError err;
394 if (flags & CborValidateNoIndeterminateLength) {
395 if (!cbor_value_is_length_known(it))
396 return CborErrorUnknownLength;
397 }
398
399 CborType type = cbor_value_get_type(it);
400 switch (type) {
401 case CborArrayType:
402 case CborMapType: {
403 /* recursive type */
404 CborValue recursed;
405 err = cbor_value_enter_container(it, &recursed);
406 if (!err)
407 err = validate_container(&recursed, type, flags, recursionLeft - 1);
408 if (err) {
409 it->ptr = recursed.ptr;
410 return err;
411 }
412 err = cbor_value_leave_container(it, &recursed);
413 if (err)
414 return err;
415 return CborNoError;
416 }
417
418 case CborIntegerType: {
419 uint64_t val;
420 err = cbor_value_get_raw_integer(it, &val);
421 cbor_assert(err == CborNoError); /* can't fail */
422
423 break;
424 }
425
426 case CborByteStringType:
427 case CborTextStringType: {
428 size_t n = 0;
429 const void *ptr;
430
431 while (1) {
432 err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
433 if (err)
434 return err;
435 if (!ptr)
436 break;
Thiago Macieira17d42a12017-02-26 14:42:37 -0800437
438 if (type == CborTextStringType && flags & CborValidateUtf8) {
439 err = validate_utf8_string(ptr, n);
440 if (err)
441 return err;
442 }
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800443 }
444
445 return CborNoError;
446 }
447
448 case CborTagType: {
449 CborTag tag;
450 err = cbor_value_get_tag(it, &tag);
451 cbor_assert(err == CborNoError); /* can't fail */
452
453 err = cbor_value_advance_fixed(it);
454 if (err)
455 return err;
456 err = validate_tag(it, tag, flags, recursionLeft - 1);
457 if (err)
458 return err;
459
460 return CborNoError;
461 }
462
463 case CborSimpleType: {
464 uint8_t simple_type;
465 err = cbor_value_get_simple_type(it, &simple_type);
466 cbor_assert(err == CborNoError); /* can't fail */
467 err = validate_simple_type(simple_type, flags);
468 if (err)
469 return err;
470 break;
471 }
472
473 case CborNullType:
474 case CborBooleanType:
475 break;
476
477 case CborUndefinedType:
478 if (flags & CborValidateNoUndefined)
479 return CborErrorExcludedType;
480 break;
481
482 case CborHalfFloatType:
483 case CborFloatType:
484 case CborDoubleType: {
485#ifdef CBOR_NO_FLOATING_POINT
486 return CborErrorUnsupportedType;
487#else
488 err = validate_floating_point(it, type, flags);
489 if (err)
490 return err;
491 break;
492 }
493#endif /* !CBOR_NO_FLOATING_POINT */
494
495 case CborInvalidType:
496 return CborErrorUnknownType;
497 }
498
499 err = cbor_value_advance_fixed(it);
500 return err;
501}
502
503/**
504 * Performs a full validation controlled by the \a flags options of the CBOR
505 * stream pointed by \a it and returns the error it found. If no error was
506 * found, it returns CborNoError and the application can iterate over the items
507 * with certainty that no other errors will appear during parsing.
508 *
509 * If \a flags is CborValidateBasic, the result should be the same as
510 * cbor_value_validate_basic().
511 *
512 * This function has the same timing and memory requirements as
513 * cbor_value_advance() and cbor_value_validate_basic().
514 *
515 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
516 */
517CborError cbor_value_validate(const CborValue *it, int flags)
518{
519 CborValue value = *it;
520 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
521 if (err)
522 return err;
523 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
524 return CborErrorGarbageAtEnd;
525 return CborNoError;
526}
527
528/**
529 * @}
530 */