]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/tinycbor/cborvalidation.c
Allow skipping or trying different keys in hf mf dump (#759)
[proxmark3-svn] / client / tinycbor / cborvalidation.c
... / ...
CommitLineData
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
242struct KnownTagData { uint32_t tag; uint32_t types; };
243static 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
268static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft);
269
270static 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
282static 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
293static 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
324static 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
377static 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
440static 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(&copy);
459 if (err)
460 return err;
461 type = cbor_value_get_type(&copy);
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
514static 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 */
653CborError 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 */
Impressum, Datenschutz