blob: dbc5008c59d2bd122460f46f7079aa8ea9f9d47e [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"
34
35#include <string.h>
36
37#ifndef CBOR_NO_FLOATING_POINT
38# include <float.h>
39# include <math.h>
40#endif
41
42
43#ifndef CBOR_PARSER_MAX_RECURSIONS
44# define CBOR_PARSER_MAX_RECURSIONS 1024
45#endif
46
47/**
48 * \addtogroup CborParsing
49 * @{
50 */
51
52/**
53 * \enum CborValidationFlags
54 * The CborValidationFlags enum contains flags that control the validation of a
55 * CBOR stream.
56 *
57 * \value CborValidateBasic Validates only the syntax correctedness of the stream.
58 * \value CborValidateCanonical Validates that the stream is in canonical format, according to
59 * RFC 7049 section 3.9.
60 * \value CborValidateStrictMode Performs strict validation, according to RFC 7049 section 3.10.
61 * \value CborValidateStrictest Attempt to perform the strictest validation we know of.
62 *
63 * \value CborValidateShortestIntegrals (Canonical) Validate that integral numbers and lengths are
64 * enconded in their shortest form possible.
65 * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
66 * in their shortest form possible.
67 * \value CborValidateShortestNumbers (Canonical) Validate both integrals and floating-point numbers
68 * are in their shortest form possible.
69 * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
70 * indeterminate length encoding.
71 * \value CborValidateMapIsSorted (Canonical & Strict mode) Validate that map keys appear in
72 * sorted order.
73 * \value CborValidateMapKeysAreUnique (Strict mode) Validate that map keys are unique.
74 * \value CborValidateTagUse (Strict mode) Validate that known tags are used with the
75 * correct types. This does not validate that the content of
76 * those types is syntactically correct.
77 * \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately
78 * encoded in UTF-8.
79 * \value CborValidateMapKeysAreString Validate that all map keys are text strings.
80 * \value CborValidateNoUndefined Validate that no elements of type "undefined" are present.
81 * \value CborValidateNoTags Validate that no tags are used.
82 * \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or
83 * infinities are allowed).
84 * \value CborValidateCompleteData Validate that the stream is complete and there is no more data
85 * in the buffer.
86 * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
87 * with IANA.
88 * \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA.
89 * \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA.
90 * \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags
91 * are registered with IANA (see below for limitations).
92 * \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA
93 * (see below for limitations).
94 *
95 * \par Simple type registry
96 * The CBOR specification requires that registration for use of the first 19
97 * simple types must be done by way of Standards Action. The rest of the simple
98 * types only require a specification. The official list can be obtained from
99 * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
100 *
101 * \par
102 * There are no registered simple types recognized by this release of TinyCBOR
103 * (beyond those defined by RFC 7049).
104 *
105 * \par Tag registry
106 * The CBOR specification requires that registration for use of the first 23
107 * tags must be done by way of Standards Action. The next up to tag 255 only
108 * require a specification. Finally, all other tags can be registered on a
109 * first-come-first-serve basis. The official list can be ontained from
110 * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
111 *
112 * \par
113 * Given the variability of this list, TinyCBOR cannot recognize all tags
114 * registered with IANA. Instead, the implementation only recognizes tags
115 * that are backed by an RFC.
116 *
117 * \par
118 * These are the tags known to the current TinyCBOR release:
Thiago Macieira0342d722017-02-26 13:12:50 -0800119<table>
120 <tr>
121 <th>Tag</th>
122 <th>Data Item</th>
123 <th>Semantics</th>
124 </tr>
125 <tr>
126 <td>0</td>
127 <td>UTF-8 text string</td>
128 <td>Standard date/time string</td>
129 </td>
130 <tr>
131 <td>1</td>
132 <td>integer</td>
133 <td>Epoch-based date/time</td>
134 </td>
135 <tr>
136 <td>2</td>
137 <td>byte string</td>
138 <td>Positive bignum</td>
139 </td>
140 <tr>
141 <td>3</td>
142 <td>byte string</td>
143 <td>Negative bignum</td>
144 </td>
145 <tr>
146 <td>4</td>
147 <td>array</td>
148 <td>Decimal fraction</td>
149 </td>
150 <tr>
151 <td>5</td>
152 <td>array</td>
153 <td>Bigfloat</td>
154 </td>
155 <tr>
156 <td>21</td>
157 <td>byte string, array, map</td>
158 <td>Expected conversion to base64url encoding</td>
159 </td>
160 <tr>
161 <td>22</td>
162 <td>byte string, array, map</td>
163 <td>Expected conversion to base64 encoding</td>
164 </td>
165 <tr>
166 <td>23</td>
167 <td>byte string, array, map</td>
168 <td>Expected conversion to base16 encoding</td>
169 </td>
170 <tr>
171 <td>24</td>
172 <td>byte string</td>
173 <td>Encoded CBOR data item</td>
174 </td>
175 <tr>
176 <td>32</td>
177 <td>UTF-8 text string</td>
178 <td>URI</td>
179 </td>
180 <tr>
181 <td>33</td>
182 <td>UTF-8 text string</td>
183 <td>base64url</td>
184 </td>
185 <tr>
186 <td>34</td>
187 <td>UTF-8 text string</td>
188 <td>base64</td>
189 </td>
190 <tr>
191 <td>35</td>
192 <td>UTF-8 text string</td>
193 <td>Regular expression</td>
194 </td>
195 <tr>
196 <td>36</td>
197 <td>UTF-8 text string</td>
198 <td>MIME message</td>
199 </td>
200 <tr>
201 <td>55799</td>
202 <td>any</td>
203 <td>Self-describe CBOR</td>
204 </td>
205</table>
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800206 */
207
Thiago Macieira0342d722017-02-26 13:12:50 -0800208struct KnownTagData { uint32_t tag; };
209static const struct KnownTagData knownTagData[] = {
210 { 0 },
211 { 1 },
212 { 2 },
213 { 3 },
214 { 4 },
215 { 5 },
216 { 21 },
217 { 22 },
218 { 23 },
219 { 24 },
220 { 32 },
221 { 33 },
222 { 34 },
223 { 35 },
224 { 36 },
225 { 55799 }
226};
227
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800228static CborError validate_value(CborValue *it, int flags, int recursionLeft);
229
230static inline CborError validate_simple_type(uint8_t simple_type, int flags)
231{
232 /* At current time, all known simple types are those from RFC 7049,
233 * which are parsed by the parser into different CBOR types.
234 * That means that if we've got here, the type is unknown */
235 if (simple_type < 32)
236 return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
237 return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
238 CborErrorUnknownSimpleType : CborNoError;
239}
240
241static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
242{
243 CborType type = cbor_value_get_type(it);
Thiago Macieira0342d722017-02-26 13:12:50 -0800244 const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
245 const struct KnownTagData *tagData = knownTagData;
246 const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
247
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800248 if (!recursionLeft)
249 return CborErrorNestingTooDeep;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800250 if (flags & CborValidateNoTags)
251 return CborErrorExcludedType;
Thiago Macieira0342d722017-02-26 13:12:50 -0800252
253 /* find the tag data, if any */
254 for ( ; tagData != knownTagDataEnd; ++tagData) {
255 if (tagData->tag < tag)
256 continue;
257 if (tagData->tag > tag)
258 tagData = NULL;
259 break;
260 }
261 if (tagData == knownTagDataEnd)
262 tagData = NULL;
263
264 if (flags & CborValidateNoUnknownTags && !tagData) {
265 /* tag not found */
266 if (flags & CborValidateNoUnknownTagsSA && tag < 24)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800267 return CborErrorUnknownTag;
Thiago Macieira0342d722017-02-26 13:12:50 -0800268 if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
269 return CborErrorUnknownTag;
270 if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
271 return CborErrorUnknownTag;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800272 }
273
274 return validate_value(it, flags, recursionLeft);
275}
276
277#ifndef CBOR_NO_FLOATING_POINT
278static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
279{
280 CborError err;
281 double val;
282 float valf;
283 uint16_t valf16;
284
285 if (type != CborDoubleType) {
286 if (type == CborFloatType) {
287 err = cbor_value_get_float(it, &valf);
288 val = valf;
289 } else {
290# ifdef CBOR_NO_HALF_FLOAT_TYPE
291 (void)val16;
292 return CborErrorUnsupportedType;
293# else
294 err = cbor_value_get_half_float(it, &valf16);
295 val = decode_half(valf16);
296# endif
297 }
298 } else {
299 err = cbor_value_get_double(it, &val);
300 }
301 cbor_assert(err == CborNoError); /* can't fail */
302
303 int r = fpclassify(val);
304 if (r == FP_NAN || r == FP_INFINITE) {
305 if (flags & CborValidateFiniteFloatingPoint)
306 return CborErrorExcludedValue;
307 if (flags & CborValidateShortestFloatingPoint) {
308 if (type == CborDoubleType)
309 return CborErrorOverlongEncoding;
310# ifndef CBOR_NO_HALF_FLOAT_TYPE
311 if (type == CborFloatType)
312 return CborErrorOverlongEncoding;
313 if (r == FP_NAN && valf16 != 0x7e00)
314 return CborErrorImproperValue;
315 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
316 return CborErrorImproperValue;
317# endif
318 }
319 }
320
321 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
322 if (type == CborDoubleType) {
323 valf = (float)val;
324 if ((double)valf == val)
325 return CborErrorOverlongEncoding;
326 }
327# ifndef CBOR_NO_HALF_FLOAT_TYPE
328 if (type == CborFloatType) {
329 valf16 = encode_half(valf);
330 if (valf == decode_half(valf16))
331 return CborErrorOverlongEncoding;
332 }
333# endif
334 }
335
336 return CborNoError;
337}
338#endif
339
340static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
341{
342 CborError err;
343 if (!recursionLeft)
344 return CborErrorNestingTooDeep;
345
346 while (!cbor_value_at_end(it)) {
347 err = validate_value(it, flags, recursionLeft);
348 if (err)
349 return err;
350
351 if (containerType == CborArrayType)
352 continue;
353
354 /* map: that was the key, so get he value */
355 err = validate_value(it, flags, recursionLeft);
356 if (err)
357 return err;
358 }
359 return CborNoError;
360}
361
362static CborError validate_value(CborValue *it, int flags, int recursionLeft)
363{
364 CborError err;
365 if (flags & CborValidateNoIndeterminateLength) {
366 if (!cbor_value_is_length_known(it))
367 return CborErrorUnknownLength;
368 }
369
370 CborType type = cbor_value_get_type(it);
371 switch (type) {
372 case CborArrayType:
373 case CborMapType: {
374 /* recursive type */
375 CborValue recursed;
376 err = cbor_value_enter_container(it, &recursed);
377 if (!err)
378 err = validate_container(&recursed, type, flags, recursionLeft - 1);
379 if (err) {
380 it->ptr = recursed.ptr;
381 return err;
382 }
383 err = cbor_value_leave_container(it, &recursed);
384 if (err)
385 return err;
386 return CborNoError;
387 }
388
389 case CborIntegerType: {
390 uint64_t val;
391 err = cbor_value_get_raw_integer(it, &val);
392 cbor_assert(err == CborNoError); /* can't fail */
393
394 break;
395 }
396
397 case CborByteStringType:
398 case CborTextStringType: {
399 size_t n = 0;
400 const void *ptr;
401
402 while (1) {
403 err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
404 if (err)
405 return err;
406 if (!ptr)
407 break;
408 }
409
410 return CborNoError;
411 }
412
413 case CborTagType: {
414 CborTag tag;
415 err = cbor_value_get_tag(it, &tag);
416 cbor_assert(err == CborNoError); /* can't fail */
417
418 err = cbor_value_advance_fixed(it);
419 if (err)
420 return err;
421 err = validate_tag(it, tag, flags, recursionLeft - 1);
422 if (err)
423 return err;
424
425 return CborNoError;
426 }
427
428 case CborSimpleType: {
429 uint8_t simple_type;
430 err = cbor_value_get_simple_type(it, &simple_type);
431 cbor_assert(err == CborNoError); /* can't fail */
432 err = validate_simple_type(simple_type, flags);
433 if (err)
434 return err;
435 break;
436 }
437
438 case CborNullType:
439 case CborBooleanType:
440 break;
441
442 case CborUndefinedType:
443 if (flags & CborValidateNoUndefined)
444 return CborErrorExcludedType;
445 break;
446
447 case CborHalfFloatType:
448 case CborFloatType:
449 case CborDoubleType: {
450#ifdef CBOR_NO_FLOATING_POINT
451 return CborErrorUnsupportedType;
452#else
453 err = validate_floating_point(it, type, flags);
454 if (err)
455 return err;
456 break;
457 }
458#endif /* !CBOR_NO_FLOATING_POINT */
459
460 case CborInvalidType:
461 return CborErrorUnknownType;
462 }
463
464 err = cbor_value_advance_fixed(it);
465 return err;
466}
467
468/**
469 * Performs a full validation controlled by the \a flags options of the CBOR
470 * stream pointed by \a it and returns the error it found. If no error was
471 * found, it returns CborNoError and the application can iterate over the items
472 * with certainty that no other errors will appear during parsing.
473 *
474 * If \a flags is CborValidateBasic, the result should be the same as
475 * cbor_value_validate_basic().
476 *
477 * This function has the same timing and memory requirements as
478 * cbor_value_advance() and cbor_value_validate_basic().
479 *
480 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
481 */
482CborError cbor_value_validate(const CborValue *it, int flags)
483{
484 CborValue value = *it;
485 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
486 if (err)
487 return err;
488 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
489 return CborErrorGarbageAtEnd;
490 return CborNoError;
491}
492
493/**
494 * @}
495 */