blob: 7bbf3440b7a7503cf98c733df6f02ae21dfd8a12 [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 Macieirac85bcf52017-03-06 09:04:40 +0100208struct KnownTagData { uint32_t tag; uint32_t types; };
Thiago Macieira0342d722017-02-26 13:12:50 -0800209static const struct KnownTagData knownTagData[] = {
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100210 { 0, (uint8_t)CborTextStringType },
211 { 1, (uint8_t)(CborIntegerType+1) },
212 { 2, (uint8_t)CborByteStringType },
213 { 3, (uint8_t)CborByteStringType },
214 { 4, (uint8_t)CborArrayType },
215 { 5, (uint8_t)CborArrayType },
216 { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
217 { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
218 { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
219 { 24, (uint8_t)CborByteStringType },
220 { 32, (uint8_t)CborTextStringType },
221 { 33, (uint8_t)CborTextStringType },
222 { 34, (uint8_t)CborTextStringType },
223 { 35, (uint8_t)CborTextStringType },
224 { 36, (uint8_t)CborTextStringType },
225 { 55799, 0U }
Thiago Macieira0342d722017-02-26 13:12:50 -0800226};
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
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100274 if (flags & CborValidateTagUse && tagData && tagData->types) {
275 uint32_t allowedTypes = tagData->types;
276
277 /* correct Integer so it's not zero */
278 if (type == CborIntegerType)
279 ++type;
280
281 while (allowedTypes) {
282 if ((uint8_t)(allowedTypes & 0xff) == type)
283 break;
284 allowedTypes >>= 8;
285 }
286 if (!allowedTypes)
287 return CborErrorInappropriateTagForType;
288 }
289
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800290 return validate_value(it, flags, recursionLeft);
291}
292
293#ifndef CBOR_NO_FLOATING_POINT
294static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
295{
296 CborError err;
297 double val;
298 float valf;
299 uint16_t valf16;
300
301 if (type != CborDoubleType) {
302 if (type == CborFloatType) {
303 err = cbor_value_get_float(it, &valf);
304 val = valf;
305 } else {
306# ifdef CBOR_NO_HALF_FLOAT_TYPE
307 (void)val16;
308 return CborErrorUnsupportedType;
309# else
310 err = cbor_value_get_half_float(it, &valf16);
311 val = decode_half(valf16);
312# endif
313 }
314 } else {
315 err = cbor_value_get_double(it, &val);
316 }
317 cbor_assert(err == CborNoError); /* can't fail */
318
319 int r = fpclassify(val);
320 if (r == FP_NAN || r == FP_INFINITE) {
321 if (flags & CborValidateFiniteFloatingPoint)
322 return CborErrorExcludedValue;
323 if (flags & CborValidateShortestFloatingPoint) {
324 if (type == CborDoubleType)
325 return CborErrorOverlongEncoding;
326# ifndef CBOR_NO_HALF_FLOAT_TYPE
327 if (type == CborFloatType)
328 return CborErrorOverlongEncoding;
329 if (r == FP_NAN && valf16 != 0x7e00)
330 return CborErrorImproperValue;
331 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
332 return CborErrorImproperValue;
333# endif
334 }
335 }
336
337 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
338 if (type == CborDoubleType) {
339 valf = (float)val;
340 if ((double)valf == val)
341 return CborErrorOverlongEncoding;
342 }
343# ifndef CBOR_NO_HALF_FLOAT_TYPE
344 if (type == CborFloatType) {
345 valf16 = encode_half(valf);
346 if (valf == decode_half(valf16))
347 return CborErrorOverlongEncoding;
348 }
349# endif
350 }
351
352 return CborNoError;
353}
354#endif
355
356static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
357{
358 CborError err;
359 if (!recursionLeft)
360 return CborErrorNestingTooDeep;
361
362 while (!cbor_value_at_end(it)) {
363 err = validate_value(it, flags, recursionLeft);
364 if (err)
365 return err;
366
367 if (containerType == CborArrayType)
368 continue;
369
370 /* map: that was the key, so get he value */
371 err = validate_value(it, flags, recursionLeft);
372 if (err)
373 return err;
374 }
375 return CborNoError;
376}
377
378static CborError validate_value(CborValue *it, int flags, int recursionLeft)
379{
380 CborError err;
381 if (flags & CborValidateNoIndeterminateLength) {
382 if (!cbor_value_is_length_known(it))
383 return CborErrorUnknownLength;
384 }
385
386 CborType type = cbor_value_get_type(it);
387 switch (type) {
388 case CborArrayType:
389 case CborMapType: {
390 /* recursive type */
391 CborValue recursed;
392 err = cbor_value_enter_container(it, &recursed);
393 if (!err)
394 err = validate_container(&recursed, type, flags, recursionLeft - 1);
395 if (err) {
396 it->ptr = recursed.ptr;
397 return err;
398 }
399 err = cbor_value_leave_container(it, &recursed);
400 if (err)
401 return err;
402 return CborNoError;
403 }
404
405 case CborIntegerType: {
406 uint64_t val;
407 err = cbor_value_get_raw_integer(it, &val);
408 cbor_assert(err == CborNoError); /* can't fail */
409
410 break;
411 }
412
413 case CborByteStringType:
414 case CborTextStringType: {
415 size_t n = 0;
416 const void *ptr;
417
418 while (1) {
419 err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
420 if (err)
421 return err;
422 if (!ptr)
423 break;
424 }
425
426 return CborNoError;
427 }
428
429 case CborTagType: {
430 CborTag tag;
431 err = cbor_value_get_tag(it, &tag);
432 cbor_assert(err == CborNoError); /* can't fail */
433
434 err = cbor_value_advance_fixed(it);
435 if (err)
436 return err;
437 err = validate_tag(it, tag, flags, recursionLeft - 1);
438 if (err)
439 return err;
440
441 return CborNoError;
442 }
443
444 case CborSimpleType: {
445 uint8_t simple_type;
446 err = cbor_value_get_simple_type(it, &simple_type);
447 cbor_assert(err == CborNoError); /* can't fail */
448 err = validate_simple_type(simple_type, flags);
449 if (err)
450 return err;
451 break;
452 }
453
454 case CborNullType:
455 case CborBooleanType:
456 break;
457
458 case CborUndefinedType:
459 if (flags & CborValidateNoUndefined)
460 return CborErrorExcludedType;
461 break;
462
463 case CborHalfFloatType:
464 case CborFloatType:
465 case CborDoubleType: {
466#ifdef CBOR_NO_FLOATING_POINT
467 return CborErrorUnsupportedType;
468#else
469 err = validate_floating_point(it, type, flags);
470 if (err)
471 return err;
472 break;
473 }
474#endif /* !CBOR_NO_FLOATING_POINT */
475
476 case CborInvalidType:
477 return CborErrorUnknownType;
478 }
479
480 err = cbor_value_advance_fixed(it);
481 return err;
482}
483
484/**
485 * Performs a full validation controlled by the \a flags options of the CBOR
486 * stream pointed by \a it and returns the error it found. If no error was
487 * found, it returns CborNoError and the application can iterate over the items
488 * with certainty that no other errors will appear during parsing.
489 *
490 * If \a flags is CborValidateBasic, the result should be the same as
491 * cbor_value_validate_basic().
492 *
493 * This function has the same timing and memory requirements as
494 * cbor_value_advance() and cbor_value_validate_basic().
495 *
496 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
497 */
498CborError cbor_value_validate(const CborValue *it, int flags)
499{
500 CborValue value = *it;
501 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
502 if (err)
503 return err;
504 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
505 return CborErrorGarbageAtEnd;
506 return CborNoError;
507}
508
509/**
510 * @}
511 */