1 /****************************************************************************
3 ** Copyright (C) 2017 Intel Corporation
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:
12 ** The above copyright notice and this permission notice shall be included in
13 ** all copies or substantial portions of the Software.
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
23 ****************************************************************************/
26 #define _DEFAULT_SOURCE 1
27 #ifndef __STDC_LIMIT_MACROS
28 # define __STDC_LIMIT_MACROS 1
32 #include "cborinternal_p.h"
33 #include "compilersupport_p.h"
38 #ifndef CBOR_NO_FLOATING_POINT
44 #ifndef CBOR_PARSER_MAX_RECURSIONS
45 # define CBOR_PARSER_MAX_RECURSIONS 1024
49 * \addtogroup CborParsing
54 * \enum CborValidationFlags
55 * The CborValidationFlags enum contains flags that control the validation of a
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.
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
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
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
90 * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
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).
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.
106 * There are no registered simple types recognized by this release of TinyCBOR
107 * (beyond those defined by RFC 7049).
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.
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.
122 * These are the tags known to the current TinyCBOR release:
131 <td>UTF-8 text string</td>
132 <td>Standard date/time string</td>
137 <td>Epoch-based date/time</td>
142 <td>Positive bignum</td>
147 <td>Negative bignum</td>
152 <td>Decimal fraction</td>
162 <td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
167 <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
172 <td>COSE Single Signer Data Object (RFC 8162)</td>
176 <td>byte string, array, map</td>
177 <td>Expected conversion to base64url encoding</td>
181 <td>byte string, array, map</td>
182 <td>Expected conversion to base64 encoding</td>
186 <td>byte string, array, map</td>
187 <td>Expected conversion to base16 encoding</td>
192 <td>Encoded CBOR data item</td>
196 <td>UTF-8 text string</td>
201 <td>UTF-8 text string</td>
206 <td>UTF-8 text string</td>
211 <td>UTF-8 text string</td>
212 <td>Regular expression</td>
216 <td>UTF-8 text string</td>
217 <td>MIME message</td>
222 <td>COSE Encrypted Data Object (RFC 8152)</td>
227 <td>COSE MACed Data Object (RFC 8152)</td>
232 <td>COSE Signed Data Object (RFC 8152)</td>
237 <td>Self-describe CBOR</td>
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
},
268 static CborError
validate_value(CborValue
*it
, uint32_t flags
, int recursionLeft
);
270 static inline CborError
validate_utf8_string(const void *ptr
, size_t n
)
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
);
277 return CborErrorInvalidUtf8TextString
;
282 static inline CborError
validate_simple_type(uint8_t simple_type
, uint32_t flags
)
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
;
293 static inline CborError
validate_number(const CborValue
*it
, CborType type
, uint32_t flags
)
295 CborError err
= CborNoError
;
296 const uint8_t *ptr
= it
->ptr
;
297 size_t bytesUsed
, bytesNeeded
;
300 if ((flags
& CborValidateShortestIntegrals
) == 0)
302 if (type
>= CborHalfFloatType
&& type
<= CborDoubleType
)
303 return err
; /* checked elsewhere */
305 err
= _cbor_value_extract_number(&ptr
, it
->parser
->end
, &value
);
309 bytesUsed
= (size_t)(ptr
- it
->ptr
- 1);
311 if (value
>= Value8Bit
)
317 if (value
> 0xffffffffU
)
319 if (bytesNeeded
< bytesUsed
)
320 return CborErrorOverlongEncoding
;
324 static inline CborError
validate_tag(CborValue
*it
, CborTag tag
, uint32_t flags
, int recursionLeft
)
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
;
332 return CborErrorNestingTooDeep
;
333 if (flags
& CborValidateNoTags
)
334 return CborErrorExcludedType
;
336 /* find the tag data, if any */
337 for ( ; tagData
!= knownTagDataEnd
; ++tagData
) {
338 if (tagData
->tag
< tag
)
340 if (tagData
->tag
> tag
)
344 if (tagData
== knownTagDataEnd
)
347 if (flags
& CborValidateNoUnknownTags
&& !tagData
) {
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
;
357 if (flags
& CborValidateTagUse
&& tagData
&& tagData
->types
) {
358 uint32_t allowedTypes
= tagData
->types
;
360 /* correct Integer so it's not zero */
361 if (type
== CborIntegerType
)
362 type
= (CborType
)(type
+ 1);
364 while (allowedTypes
) {
365 if ((uint8_t)(allowedTypes
& 0xff) == type
)
370 return CborErrorInappropriateTagForType
;
373 return validate_value(it
, flags
, recursionLeft
);
376 #ifndef CBOR_NO_FLOATING_POINT
377 static inline CborError
validate_floating_point(CborValue
*it
, CborType type
, uint32_t flags
)
385 if (type
!= CborDoubleType
) {
386 if (type
== CborFloatType
) {
387 err
= cbor_value_get_float(it
, &valf
);
390 # ifdef CBOR_NO_HALF_FLOAT_TYPE
392 return CborErrorUnsupportedType
;
394 err
= cbor_value_get_half_float(it
, &valf16
);
395 val
= decode_half(valf16
);
399 err
= cbor_value_get_double(it
, &val
);
401 cbor_assert(err
== CborNoError
); /* can't fail */
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
;
421 if (flags
& CborValidateShortestFloatingPoint
&& type
> CborHalfFloatType
) {
422 if (type
== CborDoubleType
) {
424 if ((double)valf
== val
)
425 return CborErrorOverlongEncoding
;
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
;
440 static CborError
validate_container(CborValue
*it
, int containerType
, uint32_t flags
, int recursionLeft
)
443 const uint8_t *previous
= NULL
;
444 const uint8_t *previous_end
= NULL
;
447 return CborErrorNestingTooDeep
;
449 while (!cbor_value_at_end(it
)) {
450 const uint8_t *current
= cbor_value_get_next_byte(it
);
452 if (containerType
== CborMapType
) {
453 if (flags
& CborValidateMapKeysAreString
) {
454 CborType type
= cbor_value_get_type(it
);
455 if (type
== CborTagType
) {
457 CborValue copy
= *it
;
458 err
= cbor_value_skip_tag(©
);
461 type
= cbor_value_get_type(©
);
463 if (type
!= CborTextStringType
)
464 return CborErrorMapKeyNotString
;
468 err
= validate_value(it
, flags
, recursionLeft
);
472 if (containerType
!= CborMapType
)
475 if (flags
& CborValidateMapIsSorted
) {
480 /* extract the two lengths */
482 _cbor_value_extract_number(&ptr
, it
->parser
->end
, &len1
);
484 _cbor_value_extract_number(&ptr
, it
->parser
->end
, &len2
);
487 return CborErrorMapNotSorted
;
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
);
493 if (r
== 0 && bytelen1
!= bytelen2
)
494 r
= bytelen1
< bytelen2
? -1 : +1;
496 return CborErrorMapNotSorted
;
497 if (r
== 0 && (flags
& CborValidateMapKeysAreUnique
) == CborValidateMapKeysAreUnique
)
498 return CborErrorMapKeysNotUnique
;
503 previous_end
= it
->ptr
;
506 /* map: that was the key, so get the value */
507 err
= validate_value(it
, flags
, recursionLeft
);
514 static CborError
validate_value(CborValue
*it
, uint32_t flags
, int recursionLeft
)
517 CborType type
= cbor_value_get_type(it
);
519 if (cbor_value_is_length_known(it
)) {
520 err
= validate_number(it
, type
, flags
);
524 if (flags
& CborValidateNoIndeterminateLength
)
525 return CborErrorUnknownLength
;
533 err
= cbor_value_enter_container(it
, &recursed
);
535 err
= validate_container(&recursed
, type
, flags
, recursionLeft
- 1);
537 it
->ptr
= recursed
.ptr
;
540 err
= cbor_value_leave_container(it
, &recursed
);
546 case CborIntegerType
: {
548 err
= cbor_value_get_raw_integer(it
, &val
);
549 cbor_assert(err
== CborNoError
); /* can't fail */
554 case CborByteStringType
:
555 case CborTextStringType
: {
559 err
= _cbor_value_prepare_string_iteration(it
);
564 err
= validate_number(it
, type
, flags
);
568 err
= _cbor_value_get_string_chunk(it
, &ptr
, &n
, it
);
574 if (type
== CborTextStringType
&& flags
& CborValidateUtf8
) {
575 err
= validate_utf8_string(ptr
, n
);
586 err
= cbor_value_get_tag(it
, &tag
);
587 cbor_assert(err
== CborNoError
); /* can't fail */
589 err
= cbor_value_advance_fixed(it
);
592 err
= validate_tag(it
, tag
, flags
, recursionLeft
- 1);
599 case CborSimpleType
: {
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
);
610 case CborBooleanType
:
613 case CborUndefinedType
:
614 if (flags
& CborValidateNoUndefined
)
615 return CborErrorExcludedType
;
618 case CborHalfFloatType
:
620 case CborDoubleType
: {
621 #ifdef CBOR_NO_FLOATING_POINT
622 return CborErrorUnsupportedType
;
624 err
= validate_floating_point(it
, type
, flags
);
628 #endif /* !CBOR_NO_FLOATING_POINT */
631 case CborInvalidType
:
632 return CborErrorUnknownType
;
635 err
= cbor_value_advance_fixed(it
);
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.
645 * If \a flags is CborValidateBasic, the result should be the same as
646 * cbor_value_validate_basic().
648 * This function has the same timing and memory requirements as
649 * cbor_value_advance() and cbor_value_validate_basic().
651 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
653 CborError
cbor_value_validate(const CborValue
*it
, uint32_t flags
)
655 CborValue value
= *it
;
656 CborError err
= validate_value(&value
, flags
, CBOR_PARSER_MAX_RECURSIONS
);
659 if (flags
& CborValidateCompleteData
&& it
->ptr
!= it
->parser
->end
)
660 return CborErrorGarbageAtEnd
;