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
) {
271 const uint8_t *buffer
= (const uint8_t *)ptr
;
272 const uint8_t *const end
= buffer
+ n
;
273 while (buffer
< end
) {
274 uint32_t uc
= get_utf8(&buffer
, end
);
276 return CborErrorInvalidUtf8TextString
;
281 static inline CborError
validate_simple_type(uint8_t simple_type
, uint32_t flags
) {
282 /* At current time, all known simple types are those from RFC 7049,
283 * which are parsed by the parser into different CBOR types.
284 * That means that if we've got here, the type is unknown */
285 if (simple_type
< 32)
286 return (flags
& CborValidateNoUnknownSimpleTypesSA
) ? CborErrorUnknownSimpleType
: CborNoError
;
287 return (flags
& CborValidateNoUnknownSimpleTypes
) == CborValidateNoUnknownSimpleTypes
?
288 CborErrorUnknownSimpleType
: CborNoError
;
291 static inline CborError
validate_number(const CborValue
*it
, CborType type
, uint32_t flags
) {
292 CborError err
= CborNoError
;
293 const uint8_t *ptr
= it
->ptr
;
294 size_t bytesUsed
, bytesNeeded
;
297 if ((flags
& CborValidateShortestIntegrals
) == 0)
299 if (type
>= CborHalfFloatType
&& type
<= CborDoubleType
)
300 return err
; /* checked elsewhere */
302 err
= _cbor_value_extract_number(&ptr
, it
->parser
->end
, &value
);
306 bytesUsed
= (size_t)(ptr
- it
->ptr
- 1);
308 if (value
>= Value8Bit
)
314 if (value
> 0xffffffffU
)
316 if (bytesNeeded
< bytesUsed
)
317 return CborErrorOverlongEncoding
;
321 static inline CborError
validate_tag(CborValue
*it
, CborTag tag
, uint32_t flags
, int recursionLeft
) {
322 CborType type
= cbor_value_get_type(it
);
323 const size_t knownTagCount
= sizeof(knownTagData
) / sizeof(knownTagData
[0]);
324 const struct KnownTagData
*tagData
= knownTagData
;
325 const struct KnownTagData
*const knownTagDataEnd
= knownTagData
+ knownTagCount
;
328 return CborErrorNestingTooDeep
;
329 if (flags
& CborValidateNoTags
)
330 return CborErrorExcludedType
;
332 /* find the tag data, if any */
333 for (; tagData
!= knownTagDataEnd
; ++tagData
) {
334 if (tagData
->tag
< tag
)
336 if (tagData
->tag
> tag
)
340 if (tagData
== knownTagDataEnd
)
343 if (flags
& CborValidateNoUnknownTags
&& !tagData
) {
345 if (flags
& CborValidateNoUnknownTagsSA
&& tag
< 24)
346 return CborErrorUnknownTag
;
347 if ((flags
& CborValidateNoUnknownTagsSR
) == CborValidateNoUnknownTagsSR
&& tag
< 256)
348 return CborErrorUnknownTag
;
349 if ((flags
& CborValidateNoUnknownTags
) == CborValidateNoUnknownTags
)
350 return CborErrorUnknownTag
;
353 if (flags
& CborValidateTagUse
&& tagData
&& tagData
->types
) {
354 uint32_t allowedTypes
= tagData
->types
;
356 /* correct Integer so it's not zero */
357 if (type
== CborIntegerType
)
358 type
= (CborType
)(type
+ 1);
360 while (allowedTypes
) {
361 if ((uint8_t)(allowedTypes
& 0xff) == type
)
366 return CborErrorInappropriateTagForType
;
369 return validate_value(it
, flags
, recursionLeft
);
372 #ifndef CBOR_NO_FLOATING_POINT
373 static inline CborError
validate_floating_point(CborValue
*it
, CborType type
, uint32_t flags
) {
380 if (type
!= CborDoubleType
) {
381 if (type
== CborFloatType
) {
382 err
= cbor_value_get_float(it
, &valf
);
385 # ifdef CBOR_NO_HALF_FLOAT_TYPE
387 return CborErrorUnsupportedType
;
389 err
= cbor_value_get_half_float(it
, &valf16
);
390 val
= decode_half(valf16
);
394 err
= cbor_value_get_double(it
, &val
);
396 cbor_assert(err
== CborNoError
); /* can't fail */
399 if (r
== FP_NAN
|| r
== FP_INFINITE
) {
400 if (flags
& CborValidateFiniteFloatingPoint
)
401 return CborErrorExcludedValue
;
402 if (flags
& CborValidateShortestFloatingPoint
) {
403 if (type
== CborDoubleType
)
404 return CborErrorOverlongEncoding
;
405 # ifndef CBOR_NO_HALF_FLOAT_TYPE
406 if (type
== CborFloatType
)
407 return CborErrorOverlongEncoding
;
408 if (r
== FP_NAN
&& valf16
!= 0x7e00)
409 return CborErrorImproperValue
;
410 if (r
== FP_INFINITE
&& valf16
!= 0x7c00 && valf16
!= 0xfc00)
411 return CborErrorImproperValue
;
416 if (flags
& CborValidateShortestFloatingPoint
&& type
> CborHalfFloatType
) {
417 if (type
== CborDoubleType
) {
419 if ((double)valf
== val
)
420 return CborErrorOverlongEncoding
;
422 # ifndef CBOR_NO_HALF_FLOAT_TYPE
423 if (type
== CborFloatType
) {
424 valf16
= encode_half(valf
);
425 if (valf
== decode_half(valf16
))
426 return CborErrorOverlongEncoding
;
435 static CborError
validate_container(CborValue
*it
, int containerType
, uint32_t flags
, int recursionLeft
) {
437 const uint8_t *previous
= NULL
;
438 const uint8_t *previous_end
= NULL
;
441 return CborErrorNestingTooDeep
;
443 while (!cbor_value_at_end(it
)) {
444 const uint8_t *current
= cbor_value_get_next_byte(it
);
446 if (containerType
== CborMapType
) {
447 if (flags
& CborValidateMapKeysAreString
) {
448 CborType type
= cbor_value_get_type(it
);
449 if (type
== CborTagType
) {
451 CborValue copy
= *it
;
452 err
= cbor_value_skip_tag(©
);
455 type
= cbor_value_get_type(©
);
457 if (type
!= CborTextStringType
)
458 return CborErrorMapKeyNotString
;
462 err
= validate_value(it
, flags
, recursionLeft
);
466 if (containerType
!= CborMapType
)
469 if (flags
& CborValidateMapIsSorted
) {
474 /* extract the two lengths */
476 _cbor_value_extract_number(&ptr
, it
->parser
->end
, &len1
);
478 _cbor_value_extract_number(&ptr
, it
->parser
->end
, &len2
);
481 return CborErrorMapNotSorted
;
483 size_t bytelen1
= (size_t)(previous_end
- previous
);
484 size_t bytelen2
= (size_t)(it
->ptr
- current
);
485 int r
= memcmp(previous
, current
, bytelen1
<= bytelen2
? bytelen1
: bytelen2
);
487 if (r
== 0 && bytelen1
!= bytelen2
)
488 r
= bytelen1
< bytelen2
? -1 : +1;
490 return CborErrorMapNotSorted
;
491 if (r
== 0 && (flags
& CborValidateMapKeysAreUnique
) == CborValidateMapKeysAreUnique
)
492 return CborErrorMapKeysNotUnique
;
497 previous_end
= it
->ptr
;
500 /* map: that was the key, so get the value */
501 err
= validate_value(it
, flags
, recursionLeft
);
508 static CborError
validate_value(CborValue
*it
, uint32_t flags
, int recursionLeft
) {
510 CborType type
= cbor_value_get_type(it
);
512 if (cbor_value_is_length_known(it
)) {
513 err
= validate_number(it
, type
, flags
);
517 if (flags
& CborValidateNoIndeterminateLength
)
518 return CborErrorUnknownLength
;
526 err
= cbor_value_enter_container(it
, &recursed
);
528 err
= validate_container(&recursed
, type
, flags
, recursionLeft
- 1);
530 it
->ptr
= recursed
.ptr
;
533 err
= cbor_value_leave_container(it
, &recursed
);
539 case CborIntegerType
: {
541 err
= cbor_value_get_raw_integer(it
, &val
);
542 cbor_assert(err
== CborNoError
); /* can't fail */
547 case CborByteStringType
:
548 case CborTextStringType
: {
552 err
= _cbor_value_prepare_string_iteration(it
);
557 err
= validate_number(it
, type
, flags
);
561 err
= _cbor_value_get_string_chunk(it
, &ptr
, &n
, it
);
567 if (type
== CborTextStringType
&& flags
& CborValidateUtf8
) {
568 err
= validate_utf8_string(ptr
, n
);
579 err
= cbor_value_get_tag(it
, &tag
);
580 cbor_assert(err
== CborNoError
); /* can't fail */
582 err
= cbor_value_advance_fixed(it
);
585 err
= validate_tag(it
, tag
, flags
, recursionLeft
- 1);
592 case CborSimpleType
: {
594 err
= cbor_value_get_simple_type(it
, &simple_type
);
595 cbor_assert(err
== CborNoError
); /* can't fail */
596 err
= validate_simple_type(simple_type
, flags
);
603 case CborBooleanType
:
606 case CborUndefinedType
:
607 if (flags
& CborValidateNoUndefined
)
608 return CborErrorExcludedType
;
611 case CborHalfFloatType
:
613 case CborDoubleType
: {
614 #ifdef CBOR_NO_FLOATING_POINT
615 return CborErrorUnsupportedType
;
617 err
= validate_floating_point(it
, type
, flags
);
621 #endif /* !CBOR_NO_FLOATING_POINT */
624 case CborInvalidType
:
625 return CborErrorUnknownType
;
628 err
= cbor_value_advance_fixed(it
);
633 * Performs a full validation, controlled by the \a flags options, of the CBOR
634 * stream pointed by \a it and returns the error it found. If no error was
635 * found, it returns CborNoError and the application can iterate over the items
636 * with certainty that no errors will appear during parsing.
638 * If \a flags is CborValidateBasic, the result should be the same as
639 * cbor_value_validate_basic().
641 * This function has the same timing and memory requirements as
642 * cbor_value_advance() and cbor_value_validate_basic().
644 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
646 CborError
cbor_value_validate(const CborValue
*it
, uint32_t flags
) {
647 CborValue value
= *it
;
648 CborError err
= validate_value(&value
, flags
, CBOR_PARSER_MAX_RECURSIONS
);
651 if (flags
& CborValidateCompleteData
&& it
->ptr
!= it
->parser
->end
)
652 return CborErrorGarbageAtEnd
;