From 4f5df557a94989e01cfcfeffc17e3531a146f493 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Thu, 19 Mar 2026 11:09:22 +0000 Subject: [PATCH 1/6] Replace t_cose and QCBOR with Rust COSE lib --- 3rdparty/internal/QCBOR/CMakeLists.txt | 99 - 3rdparty/internal/QCBOR/LICENSE | 37 - 3rdparty/internal/QCBOR/Makefile | 106 - 3rdparty/internal/QCBOR/README.md | 561 -- 3rdparty/internal/QCBOR/SECURITY.md | 27 - 3rdparty/internal/QCBOR/inc/UsefulBuf.h | 1 - 3rdparty/internal/QCBOR/inc/qcbor.h | 1 - 3rdparty/internal/QCBOR/inc/qcbor/UsefulBuf.h | 2559 ------ 3rdparty/internal/QCBOR/inc/qcbor/qcbor.h | 41 - .../internal/QCBOR/inc/qcbor/qcbor_common.h | 587 -- .../internal/QCBOR/inc/qcbor/qcbor_decode.h | 1708 ---- .../internal/QCBOR/inc/qcbor/qcbor_encode.h | 4386 ---------- .../internal/QCBOR/inc/qcbor/qcbor_private.h | 409 - .../QCBOR/inc/qcbor/qcbor_spiffy_decode.h | 3072 ------- 3rdparty/internal/QCBOR/src/UsefulBuf.c | 473 -- 3rdparty/internal/QCBOR/src/ieee754.c | 643 -- 3rdparty/internal/QCBOR/src/ieee754.h | 126 - 3rdparty/internal/QCBOR/src/qcbor_decode.c | 7340 ----------------- 3rdparty/internal/QCBOR/src/qcbor_encode.c | 1111 --- .../internal/QCBOR/src/qcbor_err_to_str.c | 92 - 3rdparty/internal/cose-openssl/.gitignore | 2 + 3rdparty/internal/cose-openssl/Cargo.toml | 18 + 3rdparty/internal/cose-openssl/src/cbor.rs | 616 ++ 3rdparty/internal/cose-openssl/src/cose.rs | 528 ++ 3rdparty/internal/cose-openssl/src/lib.rs | 12 + .../cose-openssl/src/ossl_wrappers.rs | 778 ++ 3rdparty/internal/cose-openssl/src/sign.rs | 57 + 3rdparty/internal/cose-openssl/src/verify.rs | 40 + .../internal/t_cose/.github/workflows/ci.yml | 101 - .../t_cose/.github/workflows/pages.yml | 33 - 3rdparty/internal/t_cose/.gitignore | 62 - 3rdparty/internal/t_cose/CMakeLists.txt | 136 - 3rdparty/internal/t_cose/CONTRIBUTING.md | 180 - 3rdparty/internal/t_cose/LICENSE | 29 - 3rdparty/internal/t_cose/Makefile.ossl | 142 - 3rdparty/internal/t_cose/Makefile.psa | 144 - 3rdparty/internal/t_cose/Makefile.test | 91 - 3rdparty/internal/t_cose/README.md | 317 - 3rdparty/internal/t_cose/SECURITY.md | 27 - .../internal/t_cose/cmake/FindMbedTLS.cmake | 108 - .../internal/t_cose/cmake/FindQCBOR.cmake | 81 - .../crypto_adapters/b_con_hash/sha256.c | 161 - .../crypto_adapters/b_con_hash/sha256.h | 34 - .../crypto_adapters/t_cose_openssl_crypto.c | 966 --- .../crypto_adapters/t_cose_psa_crypto.c | 423 - .../crypto_adapters/t_cose_test_crypto.c | 225 - .../examples/t_cose_basic_example_ossl.c | 733 -- .../examples/t_cose_basic_example_psa.c | 605 -- .../internal/t_cose/inc/t_cose/q_useful_buf.h | 162 - .../t_cose/inc/t_cose/t_cose_common.h | 466 -- .../t_cose/inc/t_cose/t_cose_sign1_sign.h | 718 -- .../t_cose/inc/t_cose/t_cose_sign1_verify.h | 629 -- 3rdparty/internal/t_cose/main.c | 54 - 3rdparty/internal/t_cose/mainpage.dox | 18 - 3rdparty/internal/t_cose/src/t_cose_crypto.h | 710 -- .../internal/t_cose/src/t_cose_parameters.c | 506 -- .../internal/t_cose/src/t_cose_parameters.h | 115 - .../t_cose/src/t_cose_short_circuit.c | 130 - .../t_cose/src/t_cose_short_circuit.h | 100 - .../internal/t_cose/src/t_cose_sign1_sign.c | 614 -- .../internal/t_cose/src/t_cose_sign1_verify.c | 512 -- .../t_cose/src/t_cose_standard_constants.h | 451 - 3rdparty/internal/t_cose/src/t_cose_util.c | 288 - 3rdparty/internal/t_cose/src/t_cose_util.h | 200 - 3rdparty/internal/t_cose/t-cose-logo.png | Bin 68555 -> 0 bytes .../t_cose/t_cose.xcodeproj/project.pbxproj | 1028 --- 3rdparty/internal/t_cose/test/keys/README.txt | 15 - .../internal/t_cose/test/keys/prime256v1.pem | 8 - .../internal/t_cose/test/keys/secp384r1.pem | 9 - .../internal/t_cose/test/keys/secp521r1.pem | 10 - 3rdparty/internal/t_cose/test/run_tests.c | 319 - 3rdparty/internal/t_cose/test/run_tests.h | 69 - .../test/t_cose_make_openssl_test_key.c | 188 - .../t_cose/test/t_cose_make_psa_test_key.c | 217 - .../t_cose/test/t_cose_make_test_messages.c | 658 -- .../t_cose/test/t_cose_make_test_messages.h | 153 - .../t_cose/test/t_cose_make_test_pub_key.h | 41 - .../t_cose/test/t_cose_rsa_test_key.h | 123 - .../t_cose/test/t_cose_sign_verify_test.c | 976 --- .../t_cose/test/t_cose_sign_verify_test.h | 67 - 3rdparty/internal/t_cose/test/t_cose_test.c | 1662 ---- 3rdparty/internal/t_cose/test/t_cose_test.h | 158 - CHANGELOG.md | 1 + CMakeLists.txt | 22 +- cgmanifest.json | 20 - cmake/cose_openssl.cmake | 26 + cmake/crypto.cmake | 11 +- cmake/qcbor.cmake | 26 - cmake/t_cose.cmake | 34 - include/ccf/crypto/cose_verifier.h | 5 + src/cose/cose_rs/Cargo.lock | 93 + src/cose/cose_rs/Cargo.toml | 14 + src/cose/cose_rs/rust-toolchain.toml | 2 + src/cose/cose_rs/src/lib.rs | 253 + src/cose/cose_rs_ffi.h | 208 + src/cose/test/cose_ffi_test.cpp | 402 + src/crypto/cbor.cpp | 7 + src/crypto/openssl/cose_sign.cpp | 200 - src/crypto/openssl/cose_sign.h | 30 - src/crypto/openssl/cose_verifier.cpp | 172 +- src/crypto/openssl/cose_verifier.h | 5 + src/crypto/openssl/public_key.h | 9 + src/crypto/test/cbor.cpp | 27 + src/crypto/test/cose.cpp | 205 +- src/crypto/test/crypto.cpp | 140 - src/endpoints/authentication/cose_auth.cpp | 66 +- src/node/cose_common.h | 1 - src/node/history.h | 60 +- src/node/quote.cpp | 19 +- src/service/internal_tables_access.h | 60 +- 110 files changed, 3436 insertions(+), 40084 deletions(-) delete mode 100644 3rdparty/internal/QCBOR/CMakeLists.txt delete mode 100644 3rdparty/internal/QCBOR/LICENSE delete mode 100644 3rdparty/internal/QCBOR/Makefile delete mode 100644 3rdparty/internal/QCBOR/README.md delete mode 100644 3rdparty/internal/QCBOR/SECURITY.md delete mode 100644 3rdparty/internal/QCBOR/inc/UsefulBuf.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/UsefulBuf.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor_common.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor_decode.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor_encode.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor_private.h delete mode 100644 3rdparty/internal/QCBOR/inc/qcbor/qcbor_spiffy_decode.h delete mode 100644 3rdparty/internal/QCBOR/src/UsefulBuf.c delete mode 100644 3rdparty/internal/QCBOR/src/ieee754.c delete mode 100644 3rdparty/internal/QCBOR/src/ieee754.h delete mode 100644 3rdparty/internal/QCBOR/src/qcbor_decode.c delete mode 100644 3rdparty/internal/QCBOR/src/qcbor_encode.c delete mode 100644 3rdparty/internal/QCBOR/src/qcbor_err_to_str.c create mode 100644 3rdparty/internal/cose-openssl/.gitignore create mode 100644 3rdparty/internal/cose-openssl/Cargo.toml create mode 100644 3rdparty/internal/cose-openssl/src/cbor.rs create mode 100644 3rdparty/internal/cose-openssl/src/cose.rs create mode 100644 3rdparty/internal/cose-openssl/src/lib.rs create mode 100644 3rdparty/internal/cose-openssl/src/ossl_wrappers.rs create mode 100644 3rdparty/internal/cose-openssl/src/sign.rs create mode 100644 3rdparty/internal/cose-openssl/src/verify.rs delete mode 100644 3rdparty/internal/t_cose/.github/workflows/ci.yml delete mode 100644 3rdparty/internal/t_cose/.github/workflows/pages.yml delete mode 100644 3rdparty/internal/t_cose/.gitignore delete mode 100644 3rdparty/internal/t_cose/CMakeLists.txt delete mode 100644 3rdparty/internal/t_cose/CONTRIBUTING.md delete mode 100644 3rdparty/internal/t_cose/LICENSE delete mode 100644 3rdparty/internal/t_cose/Makefile.ossl delete mode 100644 3rdparty/internal/t_cose/Makefile.psa delete mode 100644 3rdparty/internal/t_cose/Makefile.test delete mode 100644 3rdparty/internal/t_cose/README.md delete mode 100644 3rdparty/internal/t_cose/SECURITY.md delete mode 100644 3rdparty/internal/t_cose/cmake/FindMbedTLS.cmake delete mode 100644 3rdparty/internal/t_cose/cmake/FindQCBOR.cmake delete mode 100644 3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.c delete mode 100644 3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.h delete mode 100644 3rdparty/internal/t_cose/crypto_adapters/t_cose_openssl_crypto.c delete mode 100644 3rdparty/internal/t_cose/crypto_adapters/t_cose_psa_crypto.c delete mode 100644 3rdparty/internal/t_cose/crypto_adapters/t_cose_test_crypto.c delete mode 100644 3rdparty/internal/t_cose/examples/t_cose_basic_example_ossl.c delete mode 100644 3rdparty/internal/t_cose/examples/t_cose_basic_example_psa.c delete mode 100644 3rdparty/internal/t_cose/inc/t_cose/q_useful_buf.h delete mode 100644 3rdparty/internal/t_cose/inc/t_cose/t_cose_common.h delete mode 100644 3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_sign.h delete mode 100644 3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_verify.h delete mode 100644 3rdparty/internal/t_cose/main.c delete mode 100644 3rdparty/internal/t_cose/mainpage.dox delete mode 100644 3rdparty/internal/t_cose/src/t_cose_crypto.h delete mode 100644 3rdparty/internal/t_cose/src/t_cose_parameters.c delete mode 100644 3rdparty/internal/t_cose/src/t_cose_parameters.h delete mode 100644 3rdparty/internal/t_cose/src/t_cose_short_circuit.c delete mode 100644 3rdparty/internal/t_cose/src/t_cose_short_circuit.h delete mode 100644 3rdparty/internal/t_cose/src/t_cose_sign1_sign.c delete mode 100644 3rdparty/internal/t_cose/src/t_cose_sign1_verify.c delete mode 100644 3rdparty/internal/t_cose/src/t_cose_standard_constants.h delete mode 100644 3rdparty/internal/t_cose/src/t_cose_util.c delete mode 100644 3rdparty/internal/t_cose/src/t_cose_util.h delete mode 100644 3rdparty/internal/t_cose/t-cose-logo.png delete mode 100644 3rdparty/internal/t_cose/t_cose.xcodeproj/project.pbxproj delete mode 100644 3rdparty/internal/t_cose/test/keys/README.txt delete mode 100644 3rdparty/internal/t_cose/test/keys/prime256v1.pem delete mode 100644 3rdparty/internal/t_cose/test/keys/secp384r1.pem delete mode 100644 3rdparty/internal/t_cose/test/keys/secp521r1.pem delete mode 100644 3rdparty/internal/t_cose/test/run_tests.c delete mode 100644 3rdparty/internal/t_cose/test/run_tests.h delete mode 100644 3rdparty/internal/t_cose/test/t_cose_make_openssl_test_key.c delete mode 100644 3rdparty/internal/t_cose/test/t_cose_make_psa_test_key.c delete mode 100644 3rdparty/internal/t_cose/test/t_cose_make_test_messages.c delete mode 100644 3rdparty/internal/t_cose/test/t_cose_make_test_messages.h delete mode 100644 3rdparty/internal/t_cose/test/t_cose_make_test_pub_key.h delete mode 100644 3rdparty/internal/t_cose/test/t_cose_rsa_test_key.h delete mode 100644 3rdparty/internal/t_cose/test/t_cose_sign_verify_test.c delete mode 100644 3rdparty/internal/t_cose/test/t_cose_sign_verify_test.h delete mode 100644 3rdparty/internal/t_cose/test/t_cose_test.c delete mode 100644 3rdparty/internal/t_cose/test/t_cose_test.h create mode 100644 cmake/cose_openssl.cmake delete mode 100644 cmake/qcbor.cmake delete mode 100644 cmake/t_cose.cmake create mode 100644 src/cose/cose_rs/Cargo.lock create mode 100644 src/cose/cose_rs/Cargo.toml create mode 100644 src/cose/cose_rs/rust-toolchain.toml create mode 100644 src/cose/cose_rs/src/lib.rs create mode 100644 src/cose/cose_rs_ffi.h create mode 100644 src/cose/test/cose_ffi_test.cpp delete mode 100644 src/crypto/openssl/cose_sign.cpp delete mode 100644 src/crypto/openssl/cose_sign.h diff --git a/3rdparty/internal/QCBOR/CMakeLists.txt b/3rdparty/internal/QCBOR/CMakeLists.txt deleted file mode 100644 index 3537c27c23fd..000000000000 --- a/3rdparty/internal/QCBOR/CMakeLists.txt +++ /dev/null @@ -1,99 +0,0 @@ -#------------------------------------------------------------------------------- -# Copyright (c) 2022-2023, Arm Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# See BSD-3-Clause license in README.md -#------------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.15) - -project(qcbor - DESCRIPTION "QCBOR" - LANGUAGES C - VERSION 1.5.2 -) - -set(BUILD_QCBOR_TEST "OFF" CACHE STRING "Build QCBOR test suite [OFF, LIB, APP]") -set(BUILD_QCBOR_WARN OFF CACHE BOOL "Compile with the warning flags used in the QCBOR release process") -# BUILD_SHARED_LIBS is a built-in global CMake flag -# The shared library is not made by default because of platform -# variability For example MacOS and Linux behave differently and some -# IoT OS's don't support them at all. -set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries instead of static ones") - -# Configuration: -# Floating-point support (see README.md for more information) -set(QCBOR_OPT_DISABLE_FLOAT_HW_USE OFF CACHE BOOL "Eliminate dependency on FP hardware and FP instructions") -set(QCBOR_OPT_DISABLE_FLOAT_PREFERRED OFF CACHE BOOL "Eliminate support for half-precision and CBOR preferred serialization") -set(QCBOR_OPT_DISABLE_FLOAT_ALL OFF CACHE BOOL "Eliminate floating-point support completely") - -if (BUILD_QCBOR_WARN) - # Compile options applying to all targets in current directory and below - add_compile_options(-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual) -endif() - -add_library(qcbor) - -target_sources(qcbor - PRIVATE - src/ieee754.c - src/qcbor_decode.c - src/qcbor_encode.c - src/qcbor_err_to_str.c - src/UsefulBuf.c -) - -target_include_directories(qcbor - PUBLIC - inc - PRIVATE - src -) - -target_compile_definitions(qcbor - PRIVATE - $<$:QCBOR_DISABLE_FLOAT_HW_USE> - $<$:QCBOR_DISABLE_PREFERRED_FLOAT> - $<$:USEFULBUF_DISABLE_ALL_FLOAT> -) - -if (BUILD_SHARED_LIBS) - target_compile_options(qcbor PRIVATE -Os -fPIC) -endif() - -# The math library is needed for floating-point support. -# To avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE -if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - # Using GCC - target_link_libraries(qcbor - PRIVATE - $<$>:m> - ) -endif() - -set(HEADERS - inc/qcbor/qcbor.h - inc/qcbor/qcbor_common.h - inc/qcbor/qcbor_private.h - inc/qcbor/qcbor_encode.h - inc/qcbor/qcbor_decode.h - inc/qcbor/qcbor_spiffy_decode.h - inc/qcbor/UsefulBuf.h -) -set_target_properties( - qcbor PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - PUBLIC_HEADER "${HEADERS}" -) -include(GNUInstallDirs) -install( - TARGETS qcbor - PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/qcbor" -) - -if (NOT BUILD_QCBOR_TEST STREQUAL "OFF") - enable_testing() - add_subdirectory(test) -endif() diff --git a/3rdparty/internal/QCBOR/LICENSE b/3rdparty/internal/QCBOR/LICENSE deleted file mode 100644 index 6dc01570d647..000000000000 --- a/3rdparty/internal/QCBOR/LICENSE +++ /dev/null @@ -1,37 +0,0 @@ -QCBOR is available under what is essentially the 3-Clause BSD License. - -Files created inside Qualcomm and open-sourced through CAF (The Code -Aurora Forum) have a slightly modified 3-Clause BSD License. The -modification additionally disclaims NON-INFRINGEMENT. - -Files created after release to CAF use the standard 3-Clause BSD -License with no modification. These files have the SPDX license -identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. - - -BSD 3-Clause License - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3rdparty/internal/QCBOR/Makefile b/3rdparty/internal/QCBOR/Makefile deleted file mode 100644 index defcb720d08b..000000000000 --- a/3rdparty/internal/QCBOR/Makefile +++ /dev/null @@ -1,106 +0,0 @@ -# Makefile -- UNIX-style make for qcbor as a lib and command line test -# -# Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# See BSD-3-Clause license in README.md -# - - -# The math library is needed for floating-point support. To -# avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE -LIBS=-lm - - -# The QCBOR makefile uses a minimum of compiler flags so that it will -# work out-of-the-box with a wide variety of compilers. For example, -# some compilers error out on some of the warnings flags gcc supports. -# The $(CMD_LINE) variable allows passing in extra flags. This is -# used on the stringent build script that is in -# https://github.com/laurencelundblade/qdv. This script is used -# before pushes to master (though not yet through an automated build -# process). See "warn:" below. -CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC - - -QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o src/qcbor_err_to_str.o - -TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o \ - test/qcbor_decode_tests.o test/run_tests.o \ - test/float_tests.o test/half_to_double_from_rfc7049.o example.o ub-example.o - -.PHONY: all so install uninstall clean warn - -all: qcbortest libqcbor.a - -so: libqcbor.so - -qcbortest: libqcbor.a $(TEST_OBJ) cmd_line_main.o - $(CC) -o $@ $^ libqcbor.a $(LIBS) - -libqcbor.a: $(QCBOR_OBJ) - ar -r $@ $^ - -# run "make warn" as a handy way to compile with the warning flags -# used in the QCBOR release process. See CFLAGS above. -warn: - make CMD_LINE="$(CMD_LINE) -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" - - -# The shared library is not made by default because of platform -# variability For example MacOS and Linux behave differently and some -# IoT OS's don't support them at all. -libqcbor.so: $(QCBOR_OBJ) - $(CC) -shared $^ $(CFLAGS) -o $@ - -PUBLIC_INTERFACE=inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_spiffy_decode.h - -src/UsefulBuf.o: inc/qcbor/UsefulBuf.h -src/qcbor_decode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_spiffy_decode.h src/ieee754.h -src/qcbor_encode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h src/ieee754.h -src/iee754.o: src/ieee754.h -src/qcbor_err_to_str.o: inc/qcbor/qcbor_common.h - -example.o: $(PUBLIC_INTERFACE) -ub-example.o: $(PUBLIC_INTERFACE) - -test/run_tests.o: test/UsefulBuf_Tests.h test/float_tests.h test/run_tests.h test/qcbor_encode_tests.h test/qcbor_decode_tests.h inc/qcbor/qcbor_private.h -test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor/UsefulBuf.h -test/qcbor_encode_tests.o: test/qcbor_encode_tests.h $(PUBLIC_INTERFACE) -test/qcbor_decode_tests.o: test/qcbor_decode_tests.h $(PUBLIC_INTERFACE) -test/float_tests.o: test/float_tests.h test/half_to_double_from_rfc7049.h $(PUBLIC_INTERFACE) -test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h - -cmd_line_main.o: test/run_tests.h $(PUBLIC_INTERFACE) - - -ifeq ($(PREFIX),) - PREFIX := /usr/local -endif - -install: libqcbor.a $(PUBLIC_INTERFACE) - install -d $(DESTDIR)$(PREFIX)/lib/ - install -m 644 libqcbor.a $(DESTDIR)$(PREFIX)/lib/ - install -d $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor_private.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor_common.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor_decode.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor_spiffy_decode.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/qcbor_encode.h $(DESTDIR)$(PREFIX)/include/qcbor - install -m 644 inc/qcbor/UsefulBuf.h $(DESTDIR)$(PREFIX)/include/qcbor - -install_so: libqcbor.so - install -m 755 libqcbor.so $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1.0.0 - ln -sf libqcbor.so.1 $(DESTDIR)$(PREFIX)/lib/libqcbor.so - ln -sf libqcbor.so.1.0.0 $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1 - -uninstall: libqcbor.a $(PUBLIC_INTERFACE) - $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/* - $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/ - $(RM) $(addprefix $(DESTDIR)$(PREFIX)/lib/, \ - libqcbor.a libqcbor.so libqcbor.so.1 libqcbor.so.1.0.0) - -clean: - rm -f $(QCBOR_OBJ) $(TEST_OBJ) libqcbor.a cmd_line_main.o libqcbor.a libqcbor.so qcbormin qcbortest diff --git a/3rdparty/internal/QCBOR/README.md b/3rdparty/internal/QCBOR/README.md deleted file mode 100644 index a1cc4c574eda..000000000000 --- a/3rdparty/internal/QCBOR/README.md +++ /dev/null @@ -1,561 +0,0 @@ -![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true) - -**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that -implements these RFCs: - -* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything -except sorting of encoded maps) -* [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard. -Replaced by RFC 8949. -* [RFC8742](https://tools.ietf.org/html/rfc8742) CBOR Sequences -* [RFC8943](https://tools.ietf.org/html/rfc8943) CBOR Dates - -## QCBOR v2 alpha release - -Alpha releases of QCBOR 2.0 are available [here](https://github.com/laurencelundblade/QCBOR/tree/dev). -It includes: - -* Better tag handling -* Map sorting -* Modes for CDE and Preferred Serialization -* dCBOR support -* Better big number support - -## QCBOR Characteristics - -**Implemented in C with minimal dependency** – Dependent only - on C99, , , and making - it highly portable. and are used too, but their - use can disabled. No #ifdefs or compiler options need to be set for - QCBOR to run correctly. - -**Focused on C / native data representation** – Careful conversion of - CBOR data types in to C data types, handling over and - underflow, strict typing and such so the caller doesn't have to - worry so much about this and so code using QCBOR passes static - analyzers easier. Simpler code because there is no support for - encoding/decoding to/from JSON, pretty printing, diagnostic - notation... Only encoding from native C representations and decoding - to native C representations is supported. - -**Small simple memory model** – Malloc is not needed. The encode - context is 176 bytes, decode context is 312 bytes and the - description of decoded data item is 56 bytes. Stack use is light and - there is no recursion. The caller supplies the memory to hold the - encoded CBOR and encode/decode contexts so caller has full control - of memory usage making it good for embedded implementations that - have to run in small fixed memory. - -**Easy decoding of maps** – The "spiffy decode" functions allow - fetching map items directly by label. Detection of duplicate map - items is automatically performed. This makes decoding of complex - protocols much simpler, say when compared to TinyCBOR. - -**Supports most of RFC 8949** – With some size limits, all data types - and formats in the specification are supported. Map sorting is main - CBOR feature that is not supported. The same decoding API supports - both definite and indefinite-length map and array decoding. Decoding - indefinite length strings is supported but requires a string - allocator be set up. Encoding of indefinite length strings is - planned, but not yet supported. - -**Extensible and general** – Provides a way to handle data types that - are not directly supported. - -**Secure coding style** – Uses a construct called UsefulBuf as a - discipline for very safe coding and handling of binary data. - -**Small code size** – In the smallest configuration the object - code is less than 4KB on 64-bit x86 CPUs. The design is such that - object code for QCBOR APIs not used is not referenced. - -**Clear documented public interface** – The public interface is - separated from the implementation. It can be put to use without - reading the source. - -**Comprehensive test suite** – Easy to verify on a new platform or OS - with the test suite. The test suite dependencies are minimal and the - same as the library's. - -## Documentation - -Full API documentation is at https://www.securitytheory.com/qcbor-docs/ - - -## Spiffy Decode - -These are functions to decode particular data types. They are an -alternative to and built on top of QCBORDecode_GetNext(). They do type -checking and in some cases sophisticated type conversion. - -Spiffy decode supports easier map and array decoding. A map can be -descended into with QCBORDecode_EnterMap(). When a map has been -entered, members can be retrieved by label. Detection of duplicate -map labels, an error, is automatically performed. - -An internal error state is maintained. This simplifies the decode -implementation as an error check is only needed at the end of the -decode, rather than on every function. - -An outcome is that decoding implementations are simple and involve -many fewer lines of code. They also tend to parallel the encoding -implementations as seen in the following example. - - /* Encode */ - QCBOREncode_Init(&EncodeCtx, Buffer); - QCBOREncode_OpenMap(&EncodeCtx); - QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pE->Manufacturer); - QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pE->uDisplacement); - QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pE->uHorsePower); - QCBOREncode_CloseMap(&EncodeCtx); - uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine); - - /* Decode */ - QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterMap(&DecodeCtx); - QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer)); - QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement)); - QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower)); - QCBORDecode_ExitMap(&DecodeCtx); - uErr = QCBORDecode_Finish(&DecodeCtx); - -The spiffy decode functions will handle definite and indefinite length -maps and arrays without the caller having to do anything. This -includes mixed definite and indefinte maps and arrays. (Some work -remains to support map searching with indefinite length strings.) - -## Comparison to TinyCBOR - -TinyCBOR is a popular widely used implementation. Like QCBOR, -it is a solid, well-maintained commercial quality implementation. This -section is for folks trying to understand the difference in -the approach between QCBOR and TinyCBOR. - -TinyCBOR's API is more minimalist and closer to the CBOR -encoding mechanics than QCBOR's. QCBOR's API is at a somewhat higher -level of abstraction. - -QCBOR really does implement just about everything described in -RFC 8949. The main part missing is sorting of maps when encoding. -TinyCBOR implements a smaller part of the standard. - -No detailed code size comparison has been made, but in a spot check -that encodes and decodes a single integer shows QCBOR about 25% -larger. QCBOR encoding is actually smaller, but QCBOR decoding is -larger. This includes the code to call the library, which is about the -same for both libraries, and the code linked from the libraries. QCBOR -is a bit more powerful, so you get value for the extra code brought -in, especially when decoding more complex protocols. - -QCBOR tracks encoding and decoding errors internally so the caller -doesn't have to check the return code of every call to an encode or -decode function. In many cases the error check is only needed as the -last step or an encode or decode. TinyCBOR requires an error check on -each call. - -QCBOR provides a substantial feature that allows searching for data -items in a map by label. It works for integer and text string labels -(and at some point byte-string labels). This includes detection of -items with duplicate labels. This makes the code for decoding CBOR -simpler, similar to the encoding code and easier to read. TinyCBOR -supports search by string, but no integer, nor duplicate detection. - -QCBOR provides explicit support many of the registered CBOR tags. For -example, QCBOR supports big numbers and decimal fractions including -their conversion to floats, uint64_t and such. - -Generally, QCBOR supports safe conversion of most CBOR number formats -into number formats supported in C. For example, a data item can be -fetched and converted to a C uint64_t whether the input CBOR is an -unsigned 64-bit integer, signed 64-bit integer, floating-point number, -big number, decimal fraction or a big float. The conversion is -performed with full proper error detection of overflow and underflow. - -QCBOR has a special feature for decoding byte-string wrapped CBOR. It -treats this similar to entering an array with one item. This is -particularly use for CBOR protocols like COSE that make use of -byte-string wrapping. The implementation of these protocols is -simpler and uses less memory. - -QCBOR's test suite is written in the same portable C that QCBOR is -where TinyCBOR requires Qt for its test. QCBOR's test suite is -designed to be able to run on small embedded devices the same as -QCBOR. - -## Code Status - -The official current release is version 1.5.3. Changes over the last few -years have been only minor bug fixes, minor feature additions and -documentation improvements. QCBOR 1.x is highly stable. - -Work on some larger feature additions is ongoing in "dev" branch. -This includes more explicit support for preferred serialization and -CDE (CBOR Deterministic Encoding). It will eventually be release as -QCBOR 2.x. - -QCBOR was originally developed by Qualcomm. It was [open sourced -through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a -permissive Linux license, September 2018 (thanks Qualcomm!). - -## Building - -There is a simple makefile for the UNIX style command line binary that -compiles everything to run the tests. CMake is also available, please read -the "Building with CMake" section for more information. - -These eleven files, the contents of the src and inc directories, make -up the entire implementation. - -* inc - * UsefulBuf.h - * qcbor_private.h - * qcbor_common.h - * qcbor_encode.h - * qcbor_decode.h - * qcbor_spiffy_decode.h -* src - * UsefulBuf.c - * qcbor_encode.c - * qcbor_decode.c - * ieee754.h - * ieee754.c - -For most use cases you should just be able to add them to your -project. Hopefully the easy portability of this implementation makes -this work straight away, whatever your development environment is. - -The test directory includes the tests that are nearly as portable as -the main implementation. If your development environment doesn't -support UNIX style command line and make, you should be able to make a -simple project and add the test files to it. Then just call -RunTests() to invoke them all. - -While this code will run fine without configuration, there are several -C pre processor macros that can be #defined in order to: - - * use a more efficient implementation - * to reduce code size - * to improve performance (a little) - * remove features to reduce code size - -See the comment sections on "Configuration" in inc/UsefulBuf.h and -the pre processor defines that start with QCBOR_DISABLE_XXX. - -### Building with CMake - -CMake can also be used to build QCBOR and the test application. Having the root -`CMakeLists.txt` file, QCBOR can be easily integrated with your project's -existing CMake environment. The result of the build process is a static library, -to build a shared library instead you must add the -`-DBUILD_SHARED_LIBS=ON` option at the CMake configuration step. -The tests can be built into a simple command line application to run them as it -was mentioned before; or it can be built as a library to be integrated with your -development environment. -The `BUILD_QCBOR_TEST` CMake option can be used for building the tests, it can -have three values: `APP`, `LIB` or `OFF` (default, test are not included in the -build). - -Building the QCBOR library: - -```bash -cd -# Configuring the project and generating a native build system -cmake -S . -B -# Building the project -cmake --build -``` - -Building and running the QCBOR test app: -```bash -cd -# Configuring the project and generating a native build system -cmake -S . -B -DBUILD_QCBOR_TEST=APP -# Building the project -cmake --build -# Running the test app -./test/qcbortest -``` - -To enable all the compiler warnings that are used in the QCBOR release process -you can use the `BUILD_QCBOR_WARN` option at the CMake configuration step: -```bash -cmake -S . -B -DBUILD_QCBOR_WARN=ON -``` - -### Floating Point Support & Configuration - -By default, all QCBOR floating-point features are enabled: - -* Encoding and decoding of basic float types, single and double-precision -* Encoding and decoding of half-precision with conversion to/from single - and double-precision -* Preferred serialization of floating-point -* Floating point dates -* Methods that can convert big numbers, decimal fractions and other numbers - to/from floating-point - -If full floating-point is not needed, the following #defines can be -used to reduce object code size and dependency. - -See discussion in qcbor_encode.h for other details. - -#### #define QCBOR_DISABLE_FLOAT_HW_USE - -This removes dependency on: - -* Floating-point hardware and floating-point instructions -* `` and `` -* The math library (libm, -lm) - -For most limited environments, this removes enough floating-point -dependencies to be able to compile and run QCBOR. - -Note that this does not remove use of the types double and float from -QCBOR, but it limits QCBOR's use of them to converting the encoded -byte stream to them and copying them. Converting and copying them -usually don't require any hardware, libraries or includes. The C -compiler takes care of it on its own. - -QCBOR uses its own implementation of half-precision float-pointing -that doesn't depend on math libraries. It uses masks and shifts -instead. Thus, even with this define, half-precision encoding and -decoding works. - -When this is defined, the QCBOR functionality lost is minimal and only -for decoding: - -* Decoding floating-point format dates are not handled -* There is no conversion between floats and integers when decoding. For - example, QCBORDecode_GetUInt64ConvertAll() will be unable to convert - to and from float-point. -* Floats will be unconverted to double when decoding. - -No interfaces are disabled or removed with this define. If input that -requires floating-point conversion or functions are called that -request floating-point conversion, an error code like -`QCBOR_ERR_HW_FLOAT_DISABLED` will be returned. - -This saves only a small amount of object code. The primary purpose for -defining this is to remove dependency on floating point hardware and -libraries. - -#### #define QCBOR_DISABLE_PREFERRED_FLOAT - -This eliminates support for half-precision -and CBOR preferred serialization by disabling -QCBOR's shift and mask based implementation of -half-precision floating-point. - -With this defined, single and double-precision floating-point -numbers can still be encoded and decoded. Conversion -of floating-point to and from integers, big numbers and -such is also supported. Floating-point dates are still -supported. - -The primary reason to define this is to save object code. -Roughly 900 bytes are saved, though about half of this -can be saved just by not calling any functions that -encode floating-point numbers. - -#### #define USEFULBUF_DISABLE_ALL_FLOAT - -This eliminates floating point support completely (along with related function -headers). This is useful if the compiler options deny the usage of floating -point operations completely, and the usage soft floating point ABI is not -possible. - -#### Compiler options - -Compilers support a number of options that control -which float-point related code is generated. For example, -it is usually possible to give options to the compiler to avoid all -floating-point hardware and instructions, to use software -and replacement libraries instead. These are usually -bigger and slower, but these options may still be useful -in getting QCBOR to run in some environments in -combination with `QCBOR_DISABLE_FLOAT_HW_USE`. -In particular, `-mfloat-abi=soft`, disables use of - hardware instructions for the float and double - types in C for some architectures. - -#### CMake options - -If you are using CMake, it can also be used to configure the floating-point -support. These options can be enabled by adding them to the CMake configuration -step and setting their value to 'ON' (True). The following table shows the -available options and the associated #defines. - - | CMake option | #define | - |-----------------------------------|-------------------------------| - | QCBOR_OPT_DISABLE_FLOAT_HW_USE | QCBOR_DISABLE_FLOAT_HW_USE | - | QCBOR_OPT_DISABLE_FLOAT_PREFERRED | QCBOR_DISABLE_PREFERRED_FLOAT | - | QCBOR_OPT_DISABLE_FLOAT_ALL | USEFULBUF_DISABLE_ALL_FLOAT | - -## Code Size - -These are approximate sizes on a 64-bit x86 CPU with the -Os optimization. -All QCBOR_DISABLE_XXX are set and compiler stack frame checking is disabled -for smallest but not for largest. Smallest is the library functions for a -protocol with strings, integers, arrays, maps and Booleans, but not floats -and standard tag types. - - | | smallest | largest | - |---------------|----------|---------| - | encode only | 850 | 2200 | - | decode only | 1550 | 13300 | - | combined | 2500 | 15500 | - - From the table above, one can see that the amount of code pulled in - from the QCBOR library varies a lot, ranging from 1KB to 15KB. The - main factor is the number of QCBOR functions called and - which ones they are. QCBOR minimizes internal - interdependency so only code necessary for the called functions is - brought in. - - Encoding is simpler and smaller. An encode-only implementation may - bring in only 1KB of code. - - Encoding of floating-point brings in a little more code as does - encoding of tagged types and encoding of bstr wrapping. - - Basic decoding using QCBORDecode_GetNext() brings in 3KB. - - Use of the supplied MemPool by calling QCBORDecode_SetMemPool() to - setup to decode indefinite-length strings adds 0.5KB. - - Basic use of spiffy decode to brings in about 3KB. Using more spiffy - decode functions, such as those for tagged types bstr wrapping brings - in more code. - - Finally, use of all of the integer conversion functions will bring in - about 5KB, though you can use the simpler ones like - QCBORDecode_GetInt64() without bringing in very much code. - - In addition to using fewer QCBOR functions, the following are some - ways to make the code smaller. - - The gcc compiler output is usually smaller than llvm because stack - guards are off by default (be sure you actually have gcc and not llvm - installed to be invoked by the gcc command). You can also turn off - stack gaurds with llvm. It is safe to turn off stack gaurds with this - code because Usefulbuf provides similar defenses and this code was - carefully written to be defensive. - - If QCBOR is installed as a shared library, then of course only one - copy of the code is in memory no matter how many applications use it. - -### Disabling Features - -Here's the list of all features that can be disabled to save object -code. The amount saved is an approximation. - - | #define | Saves | - | ----------------------------------------| ------| - | QCBOR_DISABLE_ENCODE_USAGE_GUARDS | 150 | - | QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS | 400 | - | QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS | 200 | - | QCBOR_DISABLE_UNCOMMON_TAGS | 100 | - | QCBOR_DISABLE_EXP_AND_MANTISSA | 400 | - | QCBOR_DISABLE_PREFERRED_FLOAT | 900 | - | QCBOR_DISABLE_FLOAT_HW_USE | 50 | - | QCBOR_DISABLE_TAGS | 400 | - | QCBOR_DISABLE_NON_INTEGER_LABELS | 140 | - | USEFULBUF_DISABLE_ALL_FLOAT | 950 | - -QCBOR_DISABLE_ENCODE_USAGE_GUARDS affects encoding only. It doesn't -disable any encoding features, just some error checking. Disable it -when you are confident that an encoding implementation is complete and -correct. - -Indefinite lengths are a feature of CBOR that makes encoding simpler -and the decoding more complex. They allow the encoder to not have to -know the length of a string, map or array when they start encoding -it. Their main use is when encoding has to be done on a very -constrained device. Conversely when decoding on a very constrained -device, it is good to prohibit use of indefinite lengths so the -decoder can be smaller. - -The QCBOR decode API processes both definite and indefinite lengths -with the same API, except to decode indefinite-length strings a -storage allocator must be configured. - -To reduce the size of the decoder define -QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS particularly if you are not -configuring a storage allocator. - -Further reduction can be by defining -QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS which will result in an error -when an indefinite-length map or array arrives for decoding. - -QCBOR_DISABLE_UNCOMMON_TAGS disables the decoding of explicit tags for -base 64, regex, UUID and MIME data. This just disables the automatic -recognition of these from a major type 6 tag. - -QCBOR_DISABLE_EXP_AND_MANTISSA disables the decoding of decimal -fractions and big floats. - -QCBOR_DISABLE_TAGS disables all decoding of CBOR tags. If the input has -a single tag, the error is unrecoverable so it is suitable only for protocols that -have no tags. "Borrowed" tag content formats (e.g. an epoch-based date -without the tag number), can still be processed. - -QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't -fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error. -This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and -QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based -protocols to use only small integers as labels. - -See the discussion above on floating-point. - - ### Size of spiffy decode - - When creating a decode implementation, there is a choice of whether - or not to use spiffy decode features or to just use - QCBORDecode_GetNext(). - - The implementation using spiffy decode will be simpler resulting in - the calling code being smaller, but the amount of code brought in - from the QCBOR library will be larger. Basic use of spiffy decode - brings in about 2KB of object code. If object code size is not a - concern, then it is probably better to use spiffy decode because it - is less work, there is less complexity and less testing to worry - about. - - If code size is a concern, then use of QCBORDecode_GetNext() will - probably result in smaller overall code size for simpler CBOR - protocols. However, if the CBOR protocol is complex then use of - spiffy decode may reduce overall code size. An example of a complex - protocol is one that involves decoding a lot of maps or maps that - have many data items in them. The overall code may be smaller - because the general purpose spiffy decode map processor is the one - used for all the maps. - - -## Other Software Using QCBOR - -* [t_cose](https://github.com/laurencelundblade/t_cose) implements enough of -[COSE, RFC 8152](https://tools.ietf.org/html/rfc8152) to support -[CBOR Web Token (CWT)](https://tools.ietf.org/html/rfc8392) and -[Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-06). -Specifically it supports signing and verification of the COSE_Sign1 message. - -* [ctoken](https://github.com/laurencelundblade/ctoken) is an implementation of -EAT and CWT. - -## Credits -* Ganesh Kanike for porting to QSEE -* Mark Bapst for sponsorship and release as open source by Qualcomm -* Sachin Sharma for release through CAF -* Tamas Ban for porting to TF-M and 32-bit ARM -* Michael Eckel for Makefile improvements -* Jan Jongboom for indefinite length encoding -* Peter Uiterwijk for error strings and other -* Michael Richarson for CI set up and fixing some compiler warnings -* Máté Tóth-Pál for float-point disabling and other -* Dave Thaler for portability to Windows - - -### Copyright for this README - -Copyright (c) 2018-2025, Laurence Lundblade. All rights reserved. -Copyright (c) 2021-2023, Arm Limited. All rights reserved. diff --git a/3rdparty/internal/QCBOR/SECURITY.md b/3rdparty/internal/QCBOR/SECURITY.md deleted file mode 100644 index a2badc305701..000000000000 --- a/3rdparty/internal/QCBOR/SECURITY.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -Please report security vulnerabilities by sending email to lgl@island-resort.com. -Please include "QCBOR SECURITY" in the subject line. - -In most cases the vulnerability should not be reported by filing an issue in GitHub as this -will publically disclose the issue before a fix is available. - -Laurence Lundblade maintains this code and will respond in a day or two with an initial -evaluation. - -Security fixes will be prioritized over other work. - -Vulnerabilities will be fixed promptly, but some may be more complex than others -and take longer. If the fix is quick, it will usually be turned around in a -few days. - -## Availability of Fixes - -When the fix has been created, it will be privately verified with the party that reported it. -Only after the fix has been verified and the reporter has had a chance to integrate the fix, -will it be made available as a public commit in GitHub. - -If the reporter doesn't respond or can't integrate the fix, it will be made public after 30 days. - diff --git a/3rdparty/internal/QCBOR/inc/UsefulBuf.h b/3rdparty/internal/QCBOR/inc/UsefulBuf.h deleted file mode 100644 index f14084e8b8bf..000000000000 --- a/3rdparty/internal/QCBOR/inc/UsefulBuf.h +++ /dev/null @@ -1 +0,0 @@ -#include "qcbor/UsefulBuf.h" diff --git a/3rdparty/internal/QCBOR/inc/qcbor.h b/3rdparty/internal/QCBOR/inc/qcbor.h deleted file mode 100644 index e5b23e608901..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor.h +++ /dev/null @@ -1 +0,0 @@ -#include "qcbor/qcbor.h" diff --git a/3rdparty/internal/QCBOR/inc/qcbor/UsefulBuf.h b/3rdparty/internal/QCBOR/inc/qcbor/UsefulBuf.h deleted file mode 100644 index 3e567c03d815..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/UsefulBuf.h +++ /dev/null @@ -1,2559 +0,0 @@ -/* ========================================================================= - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2024, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - -/*============================================================================ - FILE: UsefulBuf.h - - DESCRIPTION: General purpose input and output buffers - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- -------------------------------------------------- - 08/14/2024 llundblade Add UsefulOutBuf_RetrieveOutputStorage(). - 08/13/2024 llundblade Add UsefulInputBuf_RetrieveUndecodedInput(). - 08/08/2024 llundblade Add UsefulOutBuf_SubString(). - 10/05/2024 llundblade Add Xxx_OffsetToPointer. - 19/12/2022 llundblade Document that adding empty data is allowed. - 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf. - 9/21/2021 llundbla Clarify UsefulOutBuf size calculation mode - 8/8/2021 dthaler/llundbla Work with C++ without compiler extensions - 5/11/2021 llundblade Improve comments and comment formatting. - 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual - 2/17/2021 llundblade Add method to go from a pointer to an offset. - 1/25/2020 llundblade Add some casts so static anlyzers don't complain. - 5/21/2019 llundblade #define configs for efficient endianness handling. - 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL(). - 3/23/2019 llundblade Big documentation & style update. No interface - change. - 3/6/2019 llundblade Add UsefulBuf_IsValue() - 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len - 12/13/2018 llundblade Documentation improvements - 09/18/2018 llundblade Cleaner distinction between UsefulBuf and - UsefulBufC. - 02/02/18 llundbla Full support for integers in and out; fix pointer - alignment bug. Incompatible change: integers - in/out are now in network byte order. - 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find - 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected - comparison for < or > for unequal length buffers. - Added UsefulBuf_Set() function. - 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst - 11/13/16 llundbla Initial Version. - - =============================================================================*/ - -#ifndef _UsefulBuf_h -#define _UsefulBuf_h - - -/* - * Endianness Configuration - * - * This code is written so it will work correctly on big- and - * little-endian CPUs without configuration or any auto-detection of - * endianness. All code here will run correctly regardless of the - * endianness of the CPU it is running on. - * - * There are four C preprocessor macros that can be set with #define - * to explicitly configure endianness handling. Setting them can - * reduce code size a little and improve efficiency a little. - * - * Note that most of QCBOR is unaffected by this configuration. Its - * endianness handling is integrated with the code that handles - * alignment and preferred serialization. This configuration does - * affect QCBOR's (planned) implementation of integer arrays (tagged - * arrays) and use of the functions here to serialize or deserialize - * integers and floating-point values. - * - * Following is the recipe for configuring the endianness-related - * #defines. - * - * The first option is to not define anything. This will work fine - * with all CPUs, OS's and compilers. The code for encoding integers - * may be a little larger and slower. - * - * If your CPU is big-endian then define - * USEFULBUF_CONFIG_BIG_ENDIAN. This will give the most efficient code - * for big-endian CPUs. It will be small and efficient because there - * will be no byte swapping. - * - * Try defining USEFULBUF_CONFIG_HTON. This will work on most CPUs, - * OS's and compilers, but not all. On big-endian CPUs this should - * give the most efficient code, the same as - * USEFULBUF_CONFIG_BIG_ENDIAN does. On little-endian CPUs it should - * call the system-defined byte swapping method which is presumably - * implemented efficiently. In some cases, this will be a dedicated - * byte swap instruction like Intel's bswap. - * - * If USEFULBUF_CONFIG_HTON works and you know your CPU is - * little-endian, it is also good to define - * USEFULBUF_CONFIG_LITTLE_ENDIAN. - * - * if USEFULBUF_CONFIG_HTON doesn't work and you know your system is - * little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and - * USEFULBUF_CONFIG_BSWAP. This should call the most efficient - * system-defined byte swap method. However, note - * https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps - * this is fixed now. Often hton() and ntoh() will call the built-in - * __builtin_bswapXX()() function, so this size issue could affect - * USEFULBUF_CONFIG_HTON. - * - * Last, run the tests. They must all pass. - * - * These #define config options affect the inline implementation of - * UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They - * also affect the 16-, 32-bit, float and double versions of these - * functions. Since they are inline, the size effect is not in the - * UsefulBuf object code, but in the calling code. - * - * Summary: - * USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian. - * USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian. - * USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to - * handle big and little-endian with system option. - * USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN, - * use __builtin_bswapXX(). - * - * It is possible to run this code in environments where using floating point is - * not allowed. Defining USEFULBUF_DISABLE_ALL_FLOAT will disable all the code - * that is related to handling floating point types, along with related - * interfaces. This makes it possible to compile the code with the compile - * option -mgeneral-regs-only. - */ - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) -#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN" -#endif - - -#include /* for uint8_t, uint16_t.... */ -#include /* for strlen, memcpy, memmove, memset */ -#include /* for size_t */ - - -#ifdef USEFULBUF_CONFIG_HTON -#include /* for htons, htonl, htonll, ntohs... */ -#endif - -#ifdef __cplusplus -extern "C" { -#if 0 -} /* Keep editor indention formatting happy */ -#endif -#endif - -/** - * @file UsefulBuf.h - * - * The goal of this code is to make buffer and pointer manipulation - * easier and safer when working with binary data. - * - * The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf - * structures are used to represent buffers rather than ad hoc - * pointers and lengths. - * - * With these it is possible to write code that does little or no - * direct pointer manipulation for copying and formatting data. For - * example, the QCBOR encoder was written using these and has less - * pointer manipulation. - * - * While it is true that object code using these functions will be a - * little larger and slower than a white-knuckle clever use of - * pointers might be, but not by that much or enough to have an effect - * for most use cases. For security-oriented code this is highly - * worthwhile. Clarity, simplicity, reviewability and are more - * important. - * - * There are some extra sanity and double checks in this code to help - * catch coding errors and simple memory corruption. They are helpful, - * but not a substitute for proper code review, input validation and - * such. - * - * This code consists of a lot of inline functions and a few that are - * not. It should not generate very much object code, especially with - * the optimizer turned up to @c -Os or @c -O3. - */ - - -/** - * @ref UsefulBufC and @ref UsefulBuf are simple data structures to - * hold a pointer and length for binary data. In C99 this data - * structure can be passed on the stack making a lot of code cleaner - * than carrying around a pointer and length as two parameters. - * - * This is also conducive to secure coding practice as the length is - * always carried with the pointer and the convention for handling a - * pointer and a length is clear. - * - * While it might be possible to write buffer and pointer code more - * efficiently in some use cases, the thought is that unless there is - * an extreme need for performance (e.g., you are building a - * gigabit-per-second IP router), it is probably better to have - * cleaner code you can be most certain about the security of. - * - * The non-const @ref UsefulBuf is usually used to refer an empty - * buffer to be filled in. The length is the size of the buffer. - * - * The const @ref UsefulBufC is usually used to refer to some data - * that has been filled in. The length is amount of valid data pointed - * to. - * - * A common use mode is to pass a @ref UsefulBuf to a function, the - * function puts some data in it, then the function returns a @ref - * UsefulBufC refering to the data. The @ref UsefulBuf is a non-const - * "in" parameter and the @ref UsefulBufC is a const "out" parameter - * so the constness stays correct. There is no single "in,out" - * parameter (if there was, it would have to be non-const). Note that - * the pointer returned in the @ref UsefulBufC usually ends up being - * the same pointer passed in as a @ref UsefulBuf, though this is not - * striclty required. - * - * A @ref UsefulBuf is null, it has no value, when @c ptr in it is - * @c NULL. - * - * There are functions and macros for the following: - * - Initializing - * - Create initialized const @ref UsefulBufC from compiler literals - * - Create initialized const @ref UsefulBufC from NULL-terminated string - * - Make an empty @ref UsefulBuf on the stack - * - Checking whether a @ref UsefulBuf is null, empty or both - * - Copying, copying with offset, copying head or tail - * - Comparing and finding substrings - * - * See also @ref UsefulOutBuf. It is a richer structure that has both - * the size of the valid data and the size of the buffer. - * - * @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so - * it can go on the stack and be a function parameter or return value. - * - * Another way to look at it is this. C has the NULL-terminated string - * as a means for handling text strings, but no means or convention - * for binary strings. Other languages do have such means, Rust, an - * efficient compiled language, for example. - * - * @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on - * his birthday. Eeyore's balloon fits beautifully, "it goes in and - * out like anything". - */ -typedef struct q_useful_buf_c { - const void *ptr; - size_t len; -} UsefulBufC; - - -/** - * This non-const @ref UsefulBuf is typically used for some allocated - * memory that is to be filled in. The @c len is the amount of memory, - * not the length of the valid data in the buffer. - */ -typedef struct q_useful_buf { - void *ptr; - size_t len; -} UsefulBuf; - - -/** - * A null @ref UsefulBufC is one that has no value in the same way a - * @c NULL pointer has no value. A @ref UsefulBufC is @c NULL when - * the @c ptr field is @c NULL. It doesn't matter what @c len is. See - * UsefulBuf_IsEmpty() for the distinction between null and empty. - */ -/* - * NULLUsefulBufC and few other macros have to be - * definied differently in C than C++ because there - * is no common construct for a literal structure. - * - * In C compound literals are used. - * - * In C++ list initalization is used. This only works - * in C++11 and later. - * - * Note that some popular C++ compilers can handle compound - * literals with on-by-default extensions, however - * this code aims for full correctness with strict - * compilers so they are not used. - */ -#ifdef __cplusplus -#define NULLUsefulBufC {NULL, 0} -#else -#define NULLUsefulBufC ((UsefulBufC) {NULL, 0}) -#endif - -/** - * A null @ref UsefulBuf is one that has no memory associated the same - * way @c NULL points to nothing. It does not matter what @c len is. - **/ -#ifdef __cplusplus -#define NULLUsefulBuf {NULL, 0} -#else -#define NULLUsefulBuf ((UsefulBuf) {NULL, 0}) -#endif - - -/** - * @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not. - * - * @param[in] UB The UsefulBuf to check. - * - * @return 1 if it is @ref NULLUsefulBuf, 0 if not. - */ -static inline int UsefulBuf_IsNULL(UsefulBuf UB); - - -/** - * @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not. - * - * @param[in] UB The @ref UsefulBufC to check. - * - * @return 1 if it is @c NULLUsefulBufC, 0 if not. - */ -static inline int UsefulBuf_IsNULLC(UsefulBufC UB); - - -/** - * @brief Check if a @ref UsefulBuf is empty or not. - * - * @param[in] UB The @ref UsefulBuf to check. - * - * @return 1 if it is empty, 0 if not. - * - * An "empty" @ref UsefulBuf is one that has a value and can be - * considered to be set, but that value is of zero length. It is - * empty when @c len is zero. It doesn't matter what the @c ptr is. - * - * Many uses will not need to clearly distinguish a @c NULL @ref - * UsefulBuf from an empty one and can have the @c ptr @c NULL and the - * @c len 0. However if a use of @ref UsefulBuf needs to make a - * distinction then @c ptr should not be @c NULL when the @ref - * UsefulBuf is considered empty, but not @c NULL. - */ -static inline int UsefulBuf_IsEmpty(UsefulBuf UB); - - -/** - * @brief Check if a @ref UsefulBufC is empty or not. - * - * @param[in] UB The @ref UsefulBufC to check. - * - * @return 1 if it is empty, 0 if not. - */ -static inline int UsefulBuf_IsEmptyC(UsefulBufC UB); - - -/** - * @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty. - * - * @param[in] UB The @ref UsefulBuf to check. - * - * @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not. - */ -static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB); - - -/** - * @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty. - * - * @param[in] UB The @ref UsefulBufC to check. - * - * @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not. - */ -static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB); - - -/** - * @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC. - * - * @param[in] UB The @ref UsefulBuf to convert. - * - * @return A @ref UsefulBufC struct. - */ -static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB); - - -/** - * @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf. - * - * @param[in] UBC The @ref UsefulBuf to convert. - * - * @return A non-const @ref UsefulBuf struct. - * - * Use of this is not necessary for the intended use mode of @ref - * UsefulBufC and @ref UsefulBuf. In that mode, the @ref UsefulBuf is - * created to describe a buffer that has not had any data put in - * it. Then the data is put in it. Then a @ref UsefulBufC is create - * to describe the part with the data in it. This goes from non-const - * to const, so this function is not needed. - * - * If the -Wcast-qual warning is enabled, this function can be used to - * avoid that warning. - */ -static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC); - - -/** - * Convert a literal string to a @ref UsefulBufC. - * - * @c szString must be a literal string that @c sizeof() works on. - * This is better for literal strings than UsefulBuf_FromSZ() because - * it generates less code. It will not work on non-literal strings. - * - * The terminating \0 (NULL) is NOT included in the length! - */ -#ifdef __cplusplus -#define UsefulBuf_FROM_SZ_LITERAL(szString) {(szString), sizeof(szString)-1} -#else -#define UsefulBuf_FROM_SZ_LITERAL(szString) \ - ((UsefulBufC) {(szString), sizeof(szString)-1}) -#endif - - -/** - * Convert a literal byte array to a @ref UsefulBufC. - * - * @c pBytes must be a literal string that @c sizeof() works on. It - * will not work on non-literal arrays. - */ -#ifdef __cplusplus -#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) {(pBytes), sizeof(pBytes)} -#else -#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \ - ((UsefulBufC) {(pBytes), sizeof(pBytes)}) -#endif - -/** - * Make an automatic variable named @c name of type @ref UsefulBuf and - * point it to a stack variable of the given @c size. - */ -#define UsefulBuf_MAKE_STACK_UB(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} - - -/** - * Make a byte array in to a @ref UsefulBuf. This is usually used on - * stack variables or static variables. Also see @ref - * UsefulBuf_MAKE_STACK_UB. - */ -#ifdef __cplusplus -#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) {(pBytes), sizeof(pBytes)} -#else -#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \ - ((UsefulBuf) {(pBytes), sizeof(pBytes)}) -#endif - - -/** - * @brief Convert a NULL-terminated string to a @ref UsefulBufC. - * - * @param[in] szString The string to convert. - * - * @return A @ref UsefulBufC struct. - * - * @c UsefulBufC.ptr points to the string so its lifetime must be - * maintained. - * - * The terminating \0 (NULL) is NOT included in the length. - */ -static inline UsefulBufC UsefulBuf_FromSZ(const char *szString); - - -/** - * @brief Copy one @ref UsefulBuf into another at an offset. - * - * @param[in] Dest Destination buffer to copy into. - * @param[in] uOffset The byte offset in @c Dest at which to copy to. - * @param[in] Src The bytes to copy. - * - * @return Pointer and length of the copy or @ref NULLUsefulBufC. - * - * This fails and returns @ref NULLUsefulBufC if @c offset is beyond the - * size of @c Dest. - * - * This fails and returns @ref NULLUsefulBufC if the @c Src length - * plus @c uOffset is greater than the length of @c Dest. - * - * The results are undefined if @c Dest and @c Src overlap. - * - * This assumes that there is valid data in @c Dest up to @c - * uOffset. The @ref UsefulBufC returned starts at the beginning of @c - * Dest and goes to @c Src.len @c + @c uOffset. - */ -UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src); - - -/** - * @brief Copy one @ref UsefulBuf into another. - * - * @param[in] Dest The destination buffer to copy into. - * @param[out] Src The source to copy from. - * - * @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC - * on failure. - * - * This fails if @c Src.len is greater than @c Dest.len. - * - * Note that like @c memcpy(), the pointers are not checked and this - * will crash rather than return @ref NULLUsefulBufC if they are @c - * NULL or invalid. - * - * The results are undefined if @c Dest and @c Src overlap. - */ -static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src); - - -/** - * @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0. - * - * @param[in] pDest The destination buffer to copy into. - * @param[in] value The value to set the bytes to. - * - * Note that like @c memset(), the pointer in @c pDest is not checked - * and this will crash if @c NULL or invalid. - */ -static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value); - - -/** - * @brief Copy a pointer into a @ref UsefulBuf. - * - * @param[in,out] Dest The destination buffer to copy into. - * @param[in] ptr The source to copy from. - * @param[in] uLen Length of the source; amount to copy. - * - * @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC - * on failure. - * - * This fails and returns @ref NULLUsefulBufC if @c uLen is greater - * than @c pDest->len. - * - * Note that like @c memcpy(), the pointers are not checked and this - * will crash, rather than return 1 if they are @c NULL or invalid. - */ -static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, - const void *ptr, - size_t uLen); - - -/** - * @brief Returns a truncation of a @ref UsefulBufC. - * - * @param[in] UB The buffer to get the head of. - * @param[in] uAmount The number of bytes in the head. - * - * @return A @ref UsefulBufC that is the head of UB. - */ -static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount); - - -/** - * @brief Returns bytes from the end of a @ref UsefulBufC. - * - * @param[in] UB The buffer to get the tail of. - * @param[in] uAmount The offset from the start where the tail is to begin. - * - * @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC - * if @c uAmount is greater than the length of the @ref UsefulBufC. - * - * If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will - * be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length - * of the tail. - */ -static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount); - - -/** - * @brief Compare one @ref UsefulBufC to another. - * - * @param[in] UB1 The first buffer to compare. - * @param[in] UB2 The second buffer to compare. - * - * @return 0, positive or negative value. - * - * Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is - * less than @c UB2 if it is shorter or the first byte that is not the - * same is less. - * - * Returns 0 if the inputs are the same. - * - * Returns a positive value if @c UB2 is less than @c UB1. - * - * All that is of significance is that the result is positive, negative - * or 0. (This doesn't return the difference between the first - * non-matching byte like @c memcmp() ). - */ -int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2); - - -/** - * @brief Find first byte that is not a particular byte value. - * - * @param[in] UB The destination buffer for byte comparison. - * @param[in] uValue The byte value to compare to. - * - * @return Offset of first byte that isn't @c uValue or - * @c SIZE_MAX if all bytes are @c uValue. - * - * Note that unlike most comparison functions, 0 - * does not indicate a successful comparison, so the - * test for match is: - * - * UsefulBuf_IsValue(...) == SIZE_MAX - * - * If @c UB is null or empty, there is no match - * and 0 is returned. - */ -size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue); - - -/** - * @brief Find one @ref UsefulBufC in another. - * - * @param[in] BytesToSearch Buffer to search through. - * @param[in] BytesToFind Buffer with bytes to be found. - * - * @return Position of found bytes or @c SIZE_MAX if not found. - */ -size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); - - -/** - * @brief Convert a pointer to an offset with bounds checking. - * - * @param[in] UB A UsefulBuf. - * @param[in] p Pointer to convert to offset. - * - * @return SIZE_MAX if @c p is out of range, the byte offset if not. -*/ -static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p); - - -/** - * @brief Convert an offset to a pointer with bounds checking. - * - * @param[in] UB A UsefulBuf. - * @param[in] uOffset Offset in @c pUInBuf. - * - * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. - */ -static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset); - - -#ifndef USEFULBUF_DISABLE_DEPRECATED -/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */ -#define SZLiteralToUsefulBufC(szString) UsefulBuf_FROM_SZ_LITERAL(szString) - -/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */ -#define MakeUsefulBufOnStack(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} - -/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */ -#define ByteArrayLiteralToUsefulBufC(pBytes) \ - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) - -/** Deprecated function; use UsefulBuf_Unconst() instead */ -static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) -{ - UsefulBuf UB; - - /* See UsefulBuf_Unconst() implementation for comment */ - UB.ptr = (void *)(uintptr_t)UBC.ptr; - - UB.len = UBC.len; - - return UB; -} -#endif /* USEFULBUF_DISABLE_DEPRECATED */ - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Copy a @c float to a @c uint32_t. - * - * @param[in] f Float value to copy. - * - * @return A @c uint32_t with the float bits. - * - * Convenience function to avoid type punning, compiler warnings and - * such. The optimizer usually reduces this to a simple assignment. This - * is a crusty corner of C. - */ -static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f); - - -/** - * @brief Copy a @c double to a @c uint64_t. - * - * @param[in] d Double value to copy. - * - * @return A @c uint64_t with the double bits. - * - * Convenience function to avoid type punning, compiler warnings and - * such. The optimizer usually reduces this to a simple assignment. This - * is a crusty corner of C. - */ -static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d); - - -/** - * @brief Copy a @c uint32_t to a @c float. - * - * @param[in] u32 Integer value to copy. - * - * @return The value as a @c float. - * - * Convenience function to avoid type punning, compiler warnings and - * such. The optimizer usually reduces this to a simple assignment. This - * is a crusty corner of C. - */ -static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32); - - -/** - * @brief Copy a @c uint64_t to a @c double. - * - * @param[in] u64 Integer value to copy. - * - * @return The value as a @c double. - * - * Convenience function to avoid type punning, compiler warnings and - * such. The optimizer usually reduces this to a simple assignment. This - * is a crusty corner of C. - */ -static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - - - -/** - * UsefulOutBuf is a structure and functions (an object) for - * serializing data into a buffer to encode for a network protocol or - * write data to a file. - * - * The main idea is that all the pointer manipulation is performed by - * @ref UsefulOutBuf functions so the caller doesn't have to do any - * pointer manipulation. The pointer manipulation is centralized. - * This code has been reviewed and written carefully so it - * spares the caller of much of this work and results in safer code - * with less effort. - * - * The @ref UsefulOutBuf methods that add data to the output buffer - * always check the length and will never write off the end of the - * output buffer. If an attempt to add data that will not fit is made, - * an internal error flag will be set and further attempts to add data - * will not do anything. - * - * There is no way to ever write off the end of that buffer when - * calling the @c UsefulOutBuf_AddXxx() and - * @c UsefulOutBuf_InsertXxx() functions. - * - * The functions to add data do not report success of failure. The - * caller only needs to check for an error in the final call, either - * UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to get the - * result. This makes the calling code cleaner. - * - * There is a utility function to get the error status anytime along - * the way for a special circumstance. There are functions to see how - * much room is left and see if some data will fit too, but their use - * is generally unnecessary. - * - * The general call flow is: - * - * - Initialize by calling @ref UsefulOutBuf_Init(). The output - * buffer given to it can be from the heap, stack or - * otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience - * macro that makes a buffer on the stack and initializes it. - * - * - Call methods like UsefulOutBuf_InsertString(), - * UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf() - * to output data. The append calls add data to the end of the - * valid data. The insert calls take a position argument. - * - * - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see - * there were no errors and to get the serialized output bytes. - * - * @ref UsefulOutBuf can be used in a mode to calculate the size of - * what would be output without actually outputting anything. This is - * useful to calculate the size of a buffer that is to be allocated to - * hold the output. See @ref SizeCalculateUsefulBuf. - * - * Methods like UsefulOutBuf_InsertUint64() always output in network - * byte order (big endian). - * - * The possible errors are: - * - * - The @ref UsefulOutBuf was not initialized or was corrupted. - * - * - An attempt was made to add data that will not fit. - * - * - An attempt was made to insert data at a position beyond the end of - * the buffer. - * - * - An attempt was made to insert data at a position beyond the valid - * data in the buffer. - * - * Some inexpensive simple sanity checks are performed before every - * data addition to guard against use of an uninitialized or corrupted - * UsefulOutBuf. - * - * @ref UsefulOutBuf has been used to create a CBOR encoder. The CBOR - * encoder has almost no pointer manipulation in it, is easier to - * read, and easier to review. - * - * A @ref UsefulOutBuf is small and can go on the stack: - * - 32 bytes (27 bytes plus alignment padding) on a 64-bit CPU - * - 16 bytes (15 bytes plus alignment padding) on a 32-bit CPU - */ -typedef struct useful_out_buf { - /* PRIVATE DATA STRUCTURE */ - UsefulBuf UB; /* Memory that is being output to */ - size_t data_len; /* length of the valid data, the insertion point */ - uint16_t magic; /* Used to detect corruption and lack - * of initialization */ - uint8_t err; -} UsefulOutBuf; - - -/** - * This is a @ref UsefulBuf value that can be passed to - * UsefulOutBuf_Init() to have it calculate the size of the output - * buffer needed. Pass this for @c Storage, call all the append and - * insert functions normally, then call UsefulOutBuf_OutUBuf(). The - * returned @ref UsefulBufC has the size. - * - * As one can see, this is just a NULL pointer and very large size. - * The NULL pointer tells UsefulOutputBuf to not copy any data. - */ -#ifdef __cplusplus -#define SizeCalculateUsefulBuf {NULL, SIZE_MAX} -#else -#define SizeCalculateUsefulBuf ((UsefulBuf) {NULL, SIZE_MAX}) -#endif - - -/** - * @brief Initialize and supply the actual output buffer. - * - * @param[out] pUOutBuf The @ref UsefulOutBuf to initialize. - * @param[in] Storage Buffer to output into. - * - * This initializes the @ref UsefulOutBuf with storage, sets the - * current position to the beginning of the buffer and clears the - * error state. - * - * See @ref SizeCalculateUsefulBuf for instructions on how to - * initialize a @ref UsefulOutBuf to calculate the size that would be - * output without actually outputting. - * - * This must be called before the @ref UsefulOutBuf is used. - */ -void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage); - - -/** - * Convenience macro to make a @ref UsefulOutBuf on the stack and - * initialize it with a stack buffer of the given size. The variable - * will be named @c name. - */ -#define UsefulOutBuf_MakeOnStack(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulOutBuf name;\ - UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)}); - - -/** - * @brief Reset a @ref UsefulOutBuf for re use. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf - * - * This sets the amount of data in the output buffer to none and - * clears the error state. - * - * The output buffer is still the same one and size as from the - * UsefulOutBuf_Init() call. - * - * This doesn't zero the data, just resets to 0 bytes of valid data. - */ -static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Returns position of end of data in the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return position of end of data. - * - * On a freshly initialized @ref UsefulOutBuf with no data added, this - * will return 0. After 10 bytes have been added, it will return 10 - * and so on. - * - * Generally, there is no need to call this for most uses of @ref - * UsefulOutBuf. - */ -static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Returns whether any data has been added to the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return 1 if output position is at start, 0 if not. - */ -static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Inserts bytes into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] NewData The bytes to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * @c NewData is the pointer and length for the bytes to be added to - * the output buffer. There must be room in the output buffer for all - * of @c NewData or an error will occur. - * - * The insertion point must be between 0 and the current valid - * data. If not, an error will occur. Appending data to the output - * buffer is achieved by inserting at the end of the valid data. This - * can be retrieved by calling UsefulOutBuf_GetEndPosition(). - * - * When insertion is performed, the bytes between the insertion point - * and the end of data previously added to the output buffer are slid - * to the right to make room for the new data. - * - * Overlapping buffers are OK. @c NewData can point to data in the - * output buffer. - * - * NewData.len may be 0 in which case nothing will be inserted. - * - * If an error occurs, an error state is set in the @ref - * UsefulOutBuf. No error is returned. All subsequent attempts to add - * data will do nothing. - * - * The intended use is that all additions are made without checking - * for an error. The error will be taken into account when - * UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC. - * UsefulOutBuf_GetError() can also be called to check for an error. - */ -void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf, - UsefulBufC NewData, - size_t uPos); - - -/** - * @brief Insert a data buffer into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] pBytes Pointer to the bytes to insert - * @param[in] uLen Length of the bytes to insert - * @param[in] uPos Index in output buffer at which to insert - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - * the difference being a pointer and length is passed in rather than an - * @ref UsefulBufC. - */ -static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf, - const void *pBytes, - size_t uLen, - size_t uPos); - - -/** - * @brief Insert a NULL-terminated string into the UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] szString NULL-terminated string to insert. - * @param[in] uPos Index in output buffer at which to insert. - */ -static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf, - const char *szString, - size_t uPos); - - -/** - * @brief Insert a byte into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the UsefulOutBuf. - * @param[in] byte Bytes to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being a single byte is to be inserted. - */ -static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf, - uint8_t byte, - size_t uPos); - - -/** - * @brief Insert a 16-bit integer into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger16 Integer to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being a two-byte integer is to be inserted. - * - * The integer will be inserted in network byte order (big endian). - */ -static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf, - uint16_t uInteger16, - size_t uPos); - - -/** - * @brief Insert a 32-bit integer into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger32 Integer to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being a four-byte integer is to be inserted. - * - * The integer will be inserted in network byte order (big endian). - */ -static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf, - uint32_t uInteger32, - size_t uPos); - - -/** - * @brief Insert a 64-bit integer into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger64 Integer to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being an eight-byte integer is to be inserted. - * - * The integer will be inserted in network byte order (big endian). - */ -static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf, - uint64_t uInteger64, - size_t uPos); - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Insert a @c float into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] f @c float to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being a @c float is to be inserted. - * - * The @c float will be inserted in network byte order (big endian). - */ -static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf, - float f, - size_t uPos); - - -/** - * @brief Insert a @c double into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] d @c double to insert. - * @param[in] uPos Index in output buffer at which to insert. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This is the same - * with the difference being a @c double is to be inserted. - * - * The @c double will be inserted in network byte order (big endian). - */ -static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf, - double d, - size_t uPos); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -/** - * @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] NewData The @ref UsefulBuf with the bytes to append. - * - * See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - * with the insertion point at the end of the valid data. - */ -static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf, - UsefulBufC NewData); - - -/** - * @brief Append bytes to the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] pBytes Pointer to bytes to append. - * @param[in] uLen Length of @c pBytes to append. - * - * See UsefulOutBuf_InsertData() for details. This does the same with - * the insertion point at the end of the valid data. - */ -static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf, - const void *pBytes, - size_t uLen); - - -/** - * @brief Append a NULL-terminated string to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] szString NULL-terminated string to append. - */ -static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf, - const char *szString); - - -/** - * @brief Append a byte to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] byte Bytes to append. - * - * See UsefulOutBuf_InsertByte() for details. This does the same - * with the insertion point at the end of the valid data. - */ -static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf, - uint8_t byte); - - -/** - * @brief Append an integer to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger16 Integer to append. - * - * See UsefulOutBuf_InsertUint16() for details. This does the same - * with the insertion point at the end of the valid data. - * - * The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf, - uint16_t uInteger16); - - -/** - * @brief Append an integer to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger32 Integer to append. - * - * See UsefulOutBuf_InsertUint32() for details. This does the same - * with the insertion point at the end of the valid data. - * - * The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf, - uint32_t uInteger32); - - -/** - * @brief Append an integer to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uInteger64 Integer to append. - * - * See UsefulOutBuf_InsertUint64() for details. This does the same - * with the insertion point at the end of the valid data. - * - * The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf, - uint64_t uInteger64); - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Append a @c float to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] f @c float to append. - * - * See UsefulOutBuf_InsertFloat() for details. This does the same with - * the insertion point at the end of the valid data. - * - * The float will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf, - float f); - - -/** - * @brief Append a @c double to the @ref UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] d @c double to append. - * - * See UsefulOutBuf_InsertDouble() for details. This does the same - * with the insertion point at the end of the valid data. - * - * The double will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf, - double d); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -/** - * @brief Returns the current error status. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return 0 if all OK, 1 on error. - * - * This returns the error status since a call to either - * UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once a @ref UsefulOutBuf - * goes into the error state, it will stay until one of those - * functions is called. - * - * Possible error conditions are: - * - bytes to be inserted will not fit - * - insertion point is out of buffer or past valid data - * - current position is off end of buffer (probably corrupted or uninitialized) - * - detect corruption / uninitialized by bad magic number - */ -static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Returns number of bytes unused used in the output buffer. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return Number of unused bytes or zero. - * - * Because of the error handling strategy and checks in - * UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use - * this. - */ -static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf); - - -/** - *@brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf - * @param[in] uLen Number of bytes for which to check - * - * @return 1 if @c uLen bytes will fit, 0 if not. - * - * Because of the error handling strategy and checks in - * UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use - * this. - */ -static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen); - - - /** - * @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf - * - * @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL. - * - * Giving a @c NULL output buffer to UsefulOutBuf_Init() is used when - * just calculating the length of the encoded data. - */ -static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Returns pointer and length of the output buffer not yet used. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return pointer and length of output buffer not used. - * - * This is an escape that allows the caller to write directly - * to the output buffer without any checks. This doesn't - * change the output buffer or state. It just returns a pointer - * and length of the bytes remaining. - * - * This is useful to avoid having the bytes to be added all - * in a contiguous buffer. Its use can save memory. A good - * example is in the COSE encrypt implementation where - * the output of the symmetric cipher can go directly - * into the output buffer, rather than having to go into - * an intermediate buffer. - * - * See UsefulOutBuf_Advance() which is used to tell - * UsefulOutBuf how much was written. - * - * Warning: this bypasses the buffer safety provided by - * UsefulOutBuf! - */ -static inline UsefulBuf -UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Advance the amount output assuming it was written by the caller. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uAmount The amount to advance. - * - * This advances the position in the output buffer - * by @c uAmount. This assumes that the - * caller has written @c uAmount to the pointer obtained - * with UsefulOutBuf_GetOutPlace(). - * - * Warning: this bypasses the buffer safety provided by - * UsefulOutBuf! - */ -void -UsefulOutBuf_Advance(UsefulOutBuf *pUOutBuf, size_t uAmount); - - -/** - * @brief Returns the resulting valid data in a UsefulOutBuf - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * - * @return The valid data in @ref UsefulOutBuf or - * @ref NULLUsefulBufC if there was an error adding data. - * - * The storage for the returned data is the @c Storage parameter - * passed to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut(). - * - * This can be called anytime and many times to get intermediate - * results. It doesn't change the data or reset the current position, - * so further data can be added. - */ -UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf); - - -/** - * @brief Copies the valid data into a supplied buffer - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[out] Dest The destination buffer to copy into. - * - * @return Pointer and length of copied data or @c NULLUsefulBufC - * if it will not fit in the @c Dest buffer or the error - * state was entered. - * - * This is the same as UsefulOutBuf_OutUBuf() except it copies the - * data to @c Dest. - */ -UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest); - - -/** - * @brief Return a substring of the output data. - * - * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. - * @param[in] uStart Offset of start of substring. - * @param[in] uLen Length of substring. - * - * This is the same as UsefulOutBuf_OutUBuf(), but returns a - * substring. @c NULLUsefulBufC is returned if the requested substring - * is off the end of the output bytes or if in error state. - */ -UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pUOutBuf, - const size_t uStart, - const size_t uLen); - - -/** - * @brief Retrieve the storage buffer passed in to UsefulOutBuf_Init(). - * - * @param[in] pUOutBuf The encoding context. - * - * @return The output storage buffer passed to UsefulOutBuf_Init(). - * - * This doesn't give any information about how much has been encoded - * or the error state. It just returns the exact @ref UsefulOutBuf given - * to UsefulOutBuf_Init(). - */ -static UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pUOutBuf); - - - -/** - * @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf. It is - * for parsing data received. Initialize it with the data from the - * network. Then use the functions like UsefulInputBuf_GetBytes() to - * get data chunks of various types. A position cursor is maintained - * internally. - * - * As long as the functions here are used, there will never be any - * reference off the end of the given buffer (except - * UsefulInputBuf_SetBufferLength()). This is true even if they are - * called incorrectly, an attempt is made to seek off the end of the - * buffer or such. This makes it easier to write safe and correct - * code. For example, the QCBOR decoder implementation is safer and - * easier to review through its use of @ref UsefulInputBuf. - * - * @ref UsefulInputBuf maintains an internal error state. The - * intended use is fetching data chunks without any error checks until - * the end. If there was any error, such as an attempt to fetch data - * off the end, the error state is entered and no further data will be - * returned. In the error state the @c UsefulInputBuf_GetXxxx() - * functions return 0, or @c NULL or @ref NULLUsefulBufC. As long as - * null is not dereferenced, the error check can be put off until the - * end, simplifying the calling code. - * - * The integer and float parsing expects network byte order (big - * endian). Network byte order is what is used by TCP/IP, CBOR and - * most internet protocols. - * - * Lots of inline functions are used to keep code size down. The - * optimizer, particularly with the @c -Os or @c -O3, also reduces - * code size a lot. The only non-inline code is - * UsefulInputBuf_GetBytes(). It is less than 100 bytes so use of - * @ref UsefulInputBuf doesn't add much code for all the messy - * hard-to-get right issues with parsing binary protocols in C that it - * solves. - * - * The parse context size is: - * - 64-bit machine: 16 + 8 + 2 + 1 (+ 5 bytes padding to align) = 32 bytes - * - 32-bit machine: 8 + 4 + 2 + 1 (+ 1 byte padding to align) = 16 bytes - */ -typedef struct useful_input_buf { - /* PRIVATE DATA STRUCTURE */ - UsefulBufC UB; /* Data being parsed */ - size_t cursor; /* Current offset in data being parse */ - uint16_t magic; /* Check for corrupted or uninitialized UsefulInputBuf */ - uint8_t err; /* Set request goes off end or magic number is bad */ -} UsefulInputBuf; - -#define UIB_MAGIC (0xB00F) - - -/** - * @brief Initialize the @ref UsefulInputBuf structure before use. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] UB The data to parse. - */ -static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB); - - -/** - * @brief Returns current position in input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return Integer position of the cursor. - * - * The position that the next bytes will be returned from. - */ -static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf); - - -/** - * @brief Sets the current position in input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uPos Position to set to. - * - * If the position is off the end of the input buffer, the error state - * is entered. - * - * Seeking to a valid position in the buffer will not reset the error - * state. Only re-initialization will do that. - */ -static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos); - - -/** - * @brief Returns the number of bytes from the cursor to the end of the buffer, - * the unconsumed bytes. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return Number of bytes unconsumed or 0 on error. - * - * Returns 0 if the cursor is invalid or corruption of the - * @ref UsefulInputBuf structure is detected. - */ -static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf); - - -/** - * @brief Check if there are unconsumed bytes. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uLen Number of bytes to check availability for. - * - * @return 1 if @c uLen bytes are available after the cursor, and 0 if not. - */ -static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen); - - -/** - * @brief Convert a pointer to an offset with bounds checking. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] p Pointer to convert to offset. - * - * @return SIZE_MAX if @c p is out of range, the byte offset if not. - */ -static size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p); - - -/** - * @brief Convert an offset to a pointer with bounds checking. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uOffset Offset in @c pUInBuf. - * - * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. - */ -static const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset); - - -/** - * @brief Get pointer to bytes out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uNum Number of bytes to get. - * - * @return Pointer to bytes. - * - * This consumes @c uNum bytes from the input buffer. This returns a - * pointer to the start of the @c uNum bytes. - * - * If there are not @c uNum bytes in the input buffer, @c NULL will be - * returned and the error state is entered. - * - * This advances the position cursor by @c uNum bytes. - */ -const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum); - - -/** - * @brief Get @ref UsefulBuf out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uNum Number of bytes to get. - * - * @return A @ref UsefulBufC with ptr and length of bytes consumed. - * - * This consumes @c uNum bytes from the input buffer and returns the - * pointer and length for them as a @ref UsefulBufC. The length - * returned will always be @c uNum. The position cursor is advanced by - * @c uNum bytes. - * - * If there are not @c uNum bytes in the input buffer, @ref - * NULLUsefulBufC will be returned and the error state is entered. - */ -static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum); - - -/** - * @brief Get a byte out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The byte. - * - * This consumes 1 byte from the input buffer, returns it and advances - * the position cursor by 1. - * - * If there is not 1 byte in the buffer, 0 will be returned for the - * byte and the error state is entered. To know if the 0 returned was - * in error or the real value, the error state must be checked. If - * possible, put this off until all values are retrieved to have - * smaller and simpler code, but if not possible - * UsefulInputBuf_GetError() can be called. Also, in the error state - * UsefulInputBuf_GetBytes() returns @c NULL *or the @c ptr from - * UsefulInputBuf_GetUsefulBuf() is @c NULL. - */ -static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf); - - -/** - * @brief Get a @c uint16_t out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The @c uint16_t. - * - * See UsefulInputBuf_GetByte(). This works the same, except it returns - * a @c uint16_t and two bytes are consumed. - * - * The input bytes are interpreted in network order (big endian). - */ -static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf); - - -/** - * @brief Get a @c uint32_t out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The @c uint32_t. - * - * See UsefulInputBuf_GetByte(). This works the same, except it - * returns a @c uint32_t and four bytes are consumed. - * - * The input bytes are interpreted in network order (big endian). - */ -static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf); - - -/** - * @brief Get a @c uint64_t out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The uint64_t. - * - * See UsefulInputBuf_GetByte(). This works the same, except it returns - * a @c uint64_t and eight bytes are consumed. - * - * The input bytes are interpreted in network order (big endian). - */ -static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf); - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Get a float out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The float. - * - * See UsefulInputBuf_GetByte(). This works the same, except it - * returns a float and four bytes are consumed. - * - * The input bytes are interpreted in network order (big endian). - */ -static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf); - - -/** - * @brief Get a double out of the input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The double. - * - * See UsefulInputBuf_GetByte(). This works the same, except it - * returns a double and eight bytes are consumed. - * - * The input bytes are interpreted in network order (big endian). - */ -static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -/** - * @brief Get the error status. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return 0 if not in the error state, 1 if in the error state. - * - * This returns whether the @ref UsefulInputBuf is in the - * error state or not. - * - * The error state is entered for one of these reasons: - * - Attempt to fetch data past the end of the buffer - * - Attempt to seek to a position past the end of the buffer - * - Attempt to get data from an uninitialized or corrupt instance - * of @ref UsefulInputBuf - * - * Once in the error state, it can only be cleared by calling - * UsefulInputBuf_Init(). - * - * For many use cases, it is possible to only call this once after all - * the @c UsefulInputBuf_GetXxxx() calls have been made. This is - * possible if no reference to the data returned are needed before the - * error state is checked. - * - * In some cases UsefulInputBuf_GetUsefulBuf() or - * UsefulInputBuf_GetBytes() can stand in for this because they return - * @c NULL if the error state has been entered. (The others can't stand - * in because they don't return a clearly distinct error value.) - */ -static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf); - - -/** - * @brief Gets the input buffer length. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The length of the input buffer. - * - * This returns the length of the input buffer set by - * UsefulInputBuf_Init() or UsefulInputBuf_SetBufferLength(). - */ -static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf); - - -/** - * @brief Alters the input buffer length (use with caution). - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * @param[in] uNewLen The new length of the input buffer. - * - * This alters the internal remembered length of the input buffer set - * when UsefulInputBuf_Init() was called. - * - * The new length given here should always be equal to or less than - * the length given when UsefulInputBuf_Init() was called. Making it - * larger allows @ref UsefulInputBuf to run off the input buffer. - * - * The typical use is to set a length shorter than that when - * initialized to constrain parsing. If - * UsefulInputBuf_GetBufferLength() was called before this, then the - * original length can be restored with another call to this. - * - * This should be used with caution. It is the only - * @ref UsefulInputBuf method that can violate the safety of input - * buffer parsing. - */ -static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen); - - -/** - * @brief Retrieve the undecoded input buffer. - * - * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. - * - * @return The input that was given to UsefulInputBuf_Init(). - * - * A simple convenience method, should it be useful to get the original input back. - */ -static UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pUInBuf); - - -/*---------------------------------------------------------- - Inline implementations. - */ -static inline int UsefulBuf_IsNULL(UsefulBuf UB) -{ - return !UB.ptr; -} - - -static inline int UsefulBuf_IsNULLC(UsefulBufC UB) -{ - return !UB.ptr; -} - - -static inline int UsefulBuf_IsEmpty(UsefulBuf UB) -{ - return !UB.len; -} - - -static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) -{ - return !UB.len; -} - - -static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) -{ - return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB); -} - - -static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) -{ - return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB); -} - - -static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB) -{ - UsefulBufC UBC; - UBC.ptr = UB.ptr; - UBC.len = UB.len; - - return UBC; -} - -static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC) -{ - UsefulBuf UB; - - /* -Wcast-qual is a good warning flag to use in general. This is - * the one place in UsefulBuf where it needs to be quieted. - */ - UB.ptr = (void *)(uintptr_t)UBC.ptr; - - UB.len = UBC.len; - - return UB; -} - - -static inline UsefulBufC UsefulBuf_FromSZ(const char *szString) -{ - UsefulBufC UBC; - UBC.ptr = szString; - UBC.len = strlen(szString); - return UBC; -} - - -static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) -{ - return UsefulBuf_CopyOffset(Dest, 0, Src); -} - - -static inline UsefulBufC UsefulBuf_Set(UsefulBuf Dest, uint8_t value) -{ - memset(Dest.ptr, value, Dest.len); - - UsefulBufC UBC; - UBC.ptr = Dest.ptr; - UBC.len = Dest.len; - - return UBC; -} - - -static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len) -{ - UsefulBufC UBC; - UBC.ptr = ptr; - UBC.len = len; - return UsefulBuf_Copy(Dest, UBC); -} - - -static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount) -{ - if(uAmount > UB.len) { - return NULLUsefulBufC; - } - UsefulBufC UBC; - - UBC.ptr = UB.ptr; - UBC.len = uAmount; - - return UBC; -} - - -static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount) -{ - UsefulBufC ReturnValue; - - if(uAmount > UB.len) { - ReturnValue = NULLUsefulBufC; - } else if(UB.ptr == NULL) { - ReturnValue.ptr = NULL; - ReturnValue.len = UB.len - uAmount; - } else { - ReturnValue.ptr = (const uint8_t *)UB.ptr + uAmount; - ReturnValue.len = UB.len - uAmount; - } - - return ReturnValue; -} - - -static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p) -{ - if(UB.ptr == NULL) { - return SIZE_MAX; - } - - if(p < UB.ptr) { - /* given pointer is before start of buffer */ - return SIZE_MAX; - } - - /* Cast to size_t (from ptrdiff_t) is OK because of check above */ - const size_t uOffset = (size_t)((const uint8_t *)p - (const uint8_t *)UB.ptr); - - if(uOffset >= UB.len) { - /* given pointer is off the end of the buffer */ - return SIZE_MAX; - } - - return uOffset; -} - - -static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset) -{ - if(UsefulBuf_IsNULLC(UB) || uOffset >= UB.len) { - return NULL; - } - - return (const uint8_t *)UB.ptr + uOffset; -} - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) -{ - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; -} - -static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d) -{ - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; -} - -static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64) -{ - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; -} - -static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32) -{ - float f; - memcpy(&f, &u32, sizeof(uint32_t)); - return f; -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - - - -static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe) -{ - pMe->data_len = 0; - pMe->err = 0; -} - - -static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe) -{ - return pMe->data_len; -} - - -static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe) -{ - return 0 == pMe->data_len; -} - - -static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe, - const void *pBytes, - size_t uLen, - size_t uPos) -{ - UsefulBufC Data = {pBytes, uLen}; - UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos); -} - - -static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe, - const char *szString, - size_t uPos) -{ - UsefulBufC UBC; - UBC.ptr = szString; - UBC.len = strlen(szString); - - UsefulOutBuf_InsertUsefulBuf(pMe, UBC, uPos); -} - - -static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me, - uint8_t byte, - size_t uPos) -{ - UsefulOutBuf_InsertData(me, &byte, 1, uPos); -} - - -static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, - uint16_t uInteger16, - size_t uPos) -{ - /* See UsefulOutBuf_InsertUint64() for comments on this code */ - - const void *pBytes; - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - pBytes = &uInteger16; - -#elif defined(USEFULBUF_CONFIG_HTON) - uint16_t uTmp = htons(uInteger16); - pBytes = &uTmp; - -#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP) - uint16_t uTmp = __builtin_bswap16(uInteger16); - pBytes = &uTmp; - -#else - uint8_t aTmp[2]; - - aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8); - aTmp[1] = (uint8_t)(uInteger16 & 0xff); - - pBytes = aTmp; -#endif - - UsefulOutBuf_InsertData(me, pBytes, 2, uPos); -} - - -static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe, - uint32_t uInteger32, - size_t uPos) -{ - /* See UsefulOutBuf_InsertUint64() for comments on this code */ - - const void *pBytes; - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - pBytes = &uInteger32; - -#elif defined(USEFULBUF_CONFIG_HTON) - uint32_t uTmp = htonl(uInteger32); - pBytes = &uTmp; - -#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP) - uint32_t uTmp = __builtin_bswap32(uInteger32); - - pBytes = &uTmp; - -#else - uint8_t aTmp[4]; - - aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24); - aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16); - aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8); - aTmp[3] = (uint8_t)(uInteger32 & 0xff); - - pBytes = aTmp; -#endif - - UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos); -} - -static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe, - uint64_t uInteger64, - size_t uPos) -{ - const void *pBytes; - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - /* We have been told explicitly we are running on a big-endian - * machine. Network byte order is big endian, so just copy. There - * is no issue with alignment here because uInteger64 is always - * aligned (and it doesn't matter if pBytes is aligned). - */ - pBytes = &uInteger64; - -#elif defined(USEFULBUF_CONFIG_HTON) - /* Use system function to handle big- and little-endian. This works - * on both big- and little-endian machines, but hton() is not - * always available or in a standard place so it is not used by - * default. With some compilers and CPUs the code for this is very - * compact through use of a special swap instruction and on - * big-endian machines hton() will reduce to nothing. - */ - uint64_t uTmp = htonll(uInteger64); - - pBytes = &uTmp; - -#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP) - /* Use built-in function for byte swapping. This usually compiles - * to an efficient special byte swap instruction. Unlike hton() it - * does not do this conditionally on the CPU endianness, so this - * code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN - */ - uint64_t uTmp = __builtin_bswap64(uInteger64); - - pBytes = &uTmp; - -#else - /* Default which works on every CPU with no dependency on anything - * from the CPU, compiler, libraries or OS. This always works, but - * it is usually a little larger and slower than hton(). - */ - uint8_t aTmp[8]; - - aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56); - aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48); - aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40); - aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32); - aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24); - aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16); - aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8); - aTmp[7] = (uint8_t)(uInteger64 & 0xff); - - pBytes = aTmp; -#endif - - /* Do the insert */ - UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos); -} - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe, - float f, - size_t uPos) -{ - UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos); -} - - -static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe, - double d, - size_t uPos) -{ - UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos); -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe, - UsefulBufC NewData) -{ - /* An append is just a insert at the end */ - UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe)); -} - - -static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe, - const void *pBytes, - size_t uLen) -{ - UsefulBufC Data = {pBytes, uLen}; - UsefulOutBuf_AppendUsefulBuf(pMe, Data); -} - - -static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe, - const char *szString) -{ - UsefulBufC UBC; - UBC.ptr = szString; - UBC.len = strlen(szString); - - UsefulOutBuf_AppendUsefulBuf(pMe, UBC); -} - - -static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe, - uint8_t byte) -{ - UsefulOutBuf_AppendData(pMe, &byte, 1); -} - - -static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe, - uint16_t uInteger16) -{ - UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe)); -} - -static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe, - uint32_t uInteger32) -{ - UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe)); -} - - -static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe, - uint64_t uInteger64) -{ - UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe)); -} - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe, - float f) -{ - UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe)); -} - - -static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe, - double d) -{ - UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe)); -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe) -{ - return pMe->err; -} - - -static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe) -{ - return pMe->UB.len - pMe->data_len; -} - - -static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen) -{ - return uLen <= UsefulOutBuf_RoomLeft(pMe); -} - - -static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe) -{ - return pMe->UB.ptr == NULL; -} - - -static inline UsefulBuf UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf) -{ - UsefulBuf R; - - R.len = UsefulOutBuf_RoomLeft(pUOutBuf); - if(R.len > 0 && pUOutBuf->UB.ptr != NULL) { - R.ptr = (uint8_t *)pUOutBuf->UB.ptr + pUOutBuf->data_len; - } else { - R.ptr = NULL; - } - - return R; -} - - -static inline UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pMe) -{ - return pMe->UB; -} - - - - -static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB) -{ - pMe->cursor = 0; - pMe->err = 0; - pMe->magic = UIB_MAGIC; - pMe->UB = UB; -} - -static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe) -{ - return pMe->cursor; -} - - -static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pMe) -{ - return pMe->UB.len; -} - - -static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos) -{ - if(uPos > pMe->UB.len) { - pMe->err = 1; - } else { - pMe->cursor = uPos; - } -} - - -static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe) -{ - /* Code Reviewers: THIS FUNCTION DOES POINTER MATH */ - - /* Magic number is messed up. Either the structure got overwritten - * or was never initialized. - */ - if(pMe->magic != UIB_MAGIC) { - return 0; - } - - /* The cursor is off the end of the input buffer given. - * Presuming there are no bugs in this code, this should never happen. - * If it is so, the struct was corrupted. The check is retained as - * as a defense in case there is a bug in this code or the struct is - * corrupted by an attacker or accidentally. - */ - if(pMe->cursor > pMe->UB.len) { - return 0; - } - - /* subtraction can't go negative because of check above */ - return pMe->UB.len - pMe->cursor; -} - - -static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen) -{ - return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0; -} - - -static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p) -{ - return UsefulBuf_PointerToOffset(pUInBuf->UB, p); -} - - -static inline const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset) - { - return UsefulBuf_OffsetToPointer(pUInBuf->UB, uOffset); - } - - -static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum) -{ - const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum); - if(!pResult) { - return NULLUsefulBufC; - } else { - UsefulBufC UBC; - UBC.ptr = pResult; - UBC.len = uNum; - return UBC; - } -} - - -static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe) -{ - const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t)); - - /* The ternary operator is subject to integer promotion, because - * the operands are smaller than int, so cast back to uint8_t is - * needed to be completely explicit about types (for static - * analyzers). - */ - return (uint8_t)(pResult ? *(const uint8_t *)pResult : 0); -} - -static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t)); - - if(!pResult) { - return 0; - } - - /* See UsefulInputBuf_GetUint64() for comments on this code */ -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP) - uint16_t uTmp; - memcpy(&uTmp, pResult, sizeof(uint16_t)); - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - return uTmp; - -#elif defined(USEFULBUF_CONFIG_HTON) - return ntohs(uTmp); - -#else - return __builtin_bswap16(uTmp); - -#endif - -#else - - /* The operations here are subject to integer promotion because the - * operands are smaller than int. They will be promoted to unsigned - * int for the shift and addition. The cast back to uint16_t is is - * needed to be completely explicit about types (for static - * analyzers). - */ - return (uint16_t)((pResult[0] << 8) + pResult[1]); - -#endif -} - - -static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t)); - - if(!pResult) { - return 0; - } - - /* See UsefulInputBuf_GetUint64() for comments on this code */ -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP) - uint32_t uTmp; - memcpy(&uTmp, pResult, sizeof(uint32_t)); - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - return uTmp; - -#elif defined(USEFULBUF_CONFIG_HTON) - return ntohl(uTmp); - -#else - return __builtin_bswap32(uTmp); - -#endif - -#else - return ((uint32_t)pResult[0]<<24) + - ((uint32_t)pResult[1]<<16) + - ((uint32_t)pResult[2]<<8) + - (uint32_t)pResult[3]; -#endif -} - - -static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t)); - - if(!pResult) { - return 0; - } - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP) - /* pResult will probably not be aligned. This memcpy() moves the - * bytes into a temp variable safely for CPUs that can or can't do - * unaligned memory access. Many compilers will optimize the - * memcpy() into a simple move instruction. - */ - uint64_t uTmp; - memcpy(&uTmp, pResult, sizeof(uint64_t)); - -#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) - /* We have been told expliclity this is a big-endian CPU. Since - * network byte order is big-endian, there is nothing to do. - */ - - return uTmp; - -#elif defined(USEFULBUF_CONFIG_HTON) - /* We have been told to use ntoh(), the system function to handle - * big- and little-endian. This works on both big- and - * little-endian machines, but ntoh() is not always available or in - * a standard place so it is not used by default. On some CPUs the - * code for this is very compact through use of a special swap - * instruction. - */ - - return ntohll(uTmp); - -#else - /* Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and - * USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON). - * __builtin_bswap64() and friends are not conditional on CPU - * endianness so this must only be used on little-endian machines. - */ - - return __builtin_bswap64(uTmp); - - -#endif - -#else - /* This is the default code that works on every CPU and every - * endianness with no dependency on ntoh(). This works on CPUs - * that either allow or do not allow unaligned access. It will - * always work, but usually is a little less efficient than ntoh(). - */ - - return ((uint64_t)pResult[0]<<56) + - ((uint64_t)pResult[1]<<48) + - ((uint64_t)pResult[2]<<40) + - ((uint64_t)pResult[3]<<32) + - ((uint64_t)pResult[4]<<24) + - ((uint64_t)pResult[5]<<16) + - ((uint64_t)pResult[6]<<8) + - (uint64_t)pResult[7]; -#endif -} - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe) -{ - uint32_t uResult = UsefulInputBuf_GetUint32(pMe); - - return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0; -} - - -static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe) -{ - uint64_t uResult = UsefulInputBuf_GetUint64(pMe); - - return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0; -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe) -{ - return pMe->err; -} - - -static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uNewLen) -{ - pMe->UB.len = uNewLen; -} - -static inline UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pMe) -{ - return pMe->UB; -} - - -#ifdef __cplusplus -} -#endif - -#endif /* _UsefulBuf_h */ - - diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor.h deleted file mode 100644 index 7b8096b3d540..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor.h +++ /dev/null @@ -1,41 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2020, Laurence Lundblade. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ - -/** - * @file qcbor.h - * - * Backwards compatibility for includers of qcbor.h (which has been split - * into four include files). - */ - -#include "qcbor_encode.h" -#include "qcbor_decode.h" diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_common.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor_common.h deleted file mode 100644 index a9515c8763da..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_common.h +++ /dev/null @@ -1,587 +0,0 @@ -/* ========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2025, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ -#ifndef qcbor_common_h -#define qcbor_common_h - -#ifdef __cplusplus -extern "C" { -#if 0 -} // Keep editor indention formatting happy -#endif -#endif - - -/** - * @file qcbor_common.h - * - * Constant values for types, error codes and such that are common to - * encoding and decoding. - */ - - -/** - * Semantic versioning for QCBOR x.y.z from 1.3.0 on - * - * Note: - * - QCBOR 1.2 is indicated by the #define QCBOR_1_2 - * - QCBOR 1.1 is indicated by the #define QCBOR_1_1 - * - QCBOR 1.0 is indicated by the absence of all the above - */ -#define QCBOR_VERSION_MAJOR 1 -#define QCBOR_VERSION_MINOR 5 -#define QCBOR_VERSION_PATCH 3 - - -/** - * This define indicates a version of QCBOR that supports spiffy - * decode, the decode functions found in qcbor_spiffy_decode.h. - * - * Versions of QCBOR that support spiffy decode are backwards - * compatible with previous versions, but there are a few minor - * exceptions such as some aspects of tag handling that are - * different. This define can be used to handle these variances. - */ -#define QCBOR_SPIFFY_DECODE - - - -/* Standard CBOR Major type for positive integers of various lengths. */ -#define CBOR_MAJOR_TYPE_POSITIVE_INT 0 - -/* Standard CBOR Major type for negative integer of various lengths. */ -#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1 - -/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */ -#define CBOR_MAJOR_TYPE_BYTE_STRING 2 - -/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8 - * with no encoding and no NULL termination. */ -#define CBOR_MAJOR_TYPE_TEXT_STRING 3 - -/* Standard CBOR Major type for an ordered array of other CBOR data items. */ -#define CBOR_MAJOR_TYPE_ARRAY 4 - -/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The - * first item in the pair is the "label" (key, name or identfier) and the second - * item is the value. */ -#define CBOR_MAJOR_TYPE_MAP 5 - -/* Standard CBOR major type for a tag number. This creates a CBOR "tag" that - * is the tag number and a data item that follows as the tag content. - * - * Note that this was called an optional tag in RFC 7049, but there's - * not really anything optional about it. It was misleading. It is - * renamed in RFC 8949. - */ -#define CBOR_MAJOR_TYPE_TAG 6 -#define CBOR_MAJOR_TYPE_OPTIONAL 6 - -/* Standard CBOR simple types like float, the values true, false, null... */ -#define CBOR_MAJOR_TYPE_SIMPLE 7 - - - - -/* - * Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These - * are types defined in RFC 8949 and some additional ones - * in the IANA CBOR tags registry. - */ -/** See QCBOREncode_AddTDateString(). */ -#define CBOR_TAG_DATE_STRING 0 -/** See QCBOREncode_AddTDateEpoch(). */ -#define CBOR_TAG_DATE_EPOCH 1 -/** See QCBOREncode_AddTPositiveBignum(). */ -#define CBOR_TAG_POS_BIGNUM 2 -/** See QCBOREncode_AddTNegativeBignum(). */ -#define CBOR_TAG_NEG_BIGNUM 3 -/** CBOR tag for a two-element array representing a fraction with a - * mantissa and base-10 scaling factor. See - * QCBOREncode_AddTDecimalFraction() and @ref expAndMantissa. */ -#define CBOR_TAG_DECIMAL_FRACTION 4 -/** CBOR tag for a two-element array representing a fraction with a - * mantissa and base-2 scaling factor. See QCBOREncode_AddTBigFloat() - * and @ref expAndMantissa. */ -#define CBOR_TAG_BIGFLOAT 5 -/** Not Decoded by QCBOR. Tag for COSE format encryption with no - * recipient identification. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided - * for this tag. */ -#define CBOR_TAG_COSE_ENCRYPT0 16 -#define CBOR_TAG_COSE_ENCRYPTO 16 -/** Not Decoded by QCBOR. Tag for COSE format MAC'd data with no - * recipient identification. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this - * tag. */ -#define CBOR_TAG_COSE_MAC0 17 -/** Tag for COSE format single signature signing. No API is provided - * for this tag. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). */ -#define CBOR_TAG_COSE_SIGN1 18 -/** A hint that the following byte string should be encoded in - * Base64URL when converting to JSON or similar text-based - * representations. Call @c - * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to - * QCBOREncode_AddBytes(). */ -#define CBOR_TAG_ENC_AS_B64URL 21 -/** A hint that the following byte string should be encoded in Base64 - * when converting to JSON or similar text-based - * representations. Call @c - * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to - * QCBOREncode_AddBytes(). */ -#define CBOR_TAG_ENC_AS_B64 22 -/** A hint that the following byte string should be encoded in base-16 - * format per [RFC 4648] - * (https://www.rfc-editor.org/rfc/rfc4648.html) when converting to - * JSON or similar text-based representations. Essentially, Base-16 - * encoding is the standard case- insensitive hex encoding and may be - * referred to as "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) - * before the call to QCBOREncode_AddBytes(). */ -#define CBOR_TAG_ENC_AS_B16 23 -/** See QCBORDecode_EnterBstrWrapped()). */ -#define CBOR_TAG_CBOR 24 -/** See QCBOREncode_AddTURI(). */ -#define CBOR_TAG_URI 32 -/** See QCBOREncode_AddTB64URLText(). */ -#define CBOR_TAG_B64URL 33 -/** See QCBOREncode_AddB64Text(). */ -#define CBOR_TAG_B64 34 -/** See QCBOREncode_AddTRegex(). */ -#define CBOR_TAG_REGEX 35 -/** See QCBOREncode_AddMIMEData(). */ -#define CBOR_TAG_MIME 36 -/** See QCBOREncode_AddTBinaryUUID(). */ -#define CBOR_TAG_BIN_UUID 37 -/** The data is a CBOR Web Token per [RFC 8392] - * (https://www.rfc-editor.org/rfc/rfc8392.html). No API is provided for this - * tag. */ -#define CBOR_TAG_CWT 61 -/** Tag for COSE format encryption. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this - * tag. */ -#define CBOR_TAG_CBOR_SEQUENCE 63 -/** Not Decoded by QCBOR. Tag for COSE format encrypt. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this - * tag. */ -#define CBOR_TAG_COSE_ENCRYPT 96 -#define CBOR_TAG_ENCRYPT 96 -/** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this - tag. */ -#define CBOR_TAG_COSE_MAC 97 -#define CBOR_TAG_MAC 97 -/** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this - tag. */ -#define CBOR_TAG_COSE_SIGN 98 -#define CBOR_TAG_SIGN 98 -/** Tag for date counted by days from Jan 1 1970 per [RFC 8943] - * (https://www.rfc-editor.org/rfc/rfc8943.html). See - * QCBOREncode_AddTDaysEpoch(). */ -#define CBOR_TAG_DAYS_EPOCH 100 -/** Not Decoded by QCBOR. World geographic coordinates. See ISO 6709, [RFC 5870] - * (https://www.rfc-editor.org/rfc/rfc5870.html) and WGS-84. No API is - * provided for this tag. */ -#define CBOR_TAG_GEO_COORD 103 -/** Binary MIME.*/ -#define CBOR_TAG_BINARY_MIME 257 -/** Tag for date string without time or time zone per [RFC 8943] - * (https://www.rfc-editor.org/rfc/rfc8943.html). See - * QCBOREncode_AddTDaysString(). */ -#define CBOR_TAG_DAYS_STRING 1004 -/** The magic number, self-described CBOR. No API is provided for this - * tag. */ -#define CBOR_TAG_CBOR_MAGIC 55799 - -/** The 16-bit invalid tag from the CBOR tags registry */ -#define CBOR_TAG_INVALID16 0xffff -/** The 32-bit invalid tag from the CBOR tags registry */ -#define CBOR_TAG_INVALID32 0xffffffff -/** The 64-bit invalid tag from the CBOR tags registry */ -#define CBOR_TAG_INVALID64 0xffffffffffffffff - - - - -/** - * Error codes returned by QCBOR Encoder-Decoder. - * - * They are grouped to keep the code size of - * QCBORDecode_IsNotWellFormedError() and - * QCBORDecode_IsUnrecoverableError() minimal. - * - * 1..19: Encode errors - * 20..: Decode errors - * 20-39: QCBORDecode_IsNotWellFormedError() - * 30..59: QCBORDecode_IsUnrecoverableError() - * 60..: Other decode errors - * - * Error renumbering may occur in the future when new error codes are - * added for new QCBOR features. - */ -typedef enum { - /** The encode or decode completed correctly. */ - QCBOR_SUCCESS = 0, - - /** The buffer provided for the encoded output when doing encoding - * was too small and the encoded output will not fit. */ - QCBOR_ERR_BUFFER_TOO_SMALL = 1, - - /** During encoding, an attempt to create simple value between 24 - * and 31. */ - QCBOR_ERR_ENCODE_UNSUPPORTED = 2, - - /** During encoding, the length of the encoded CBOR exceeded - * @ref QCBOR_MAX_ARRAY_OFFSET, which is slightly less than - * @c UINT32_MAX. */ - QCBOR_ERR_BUFFER_TOO_LARGE = 3, - - /** During encoding, the array or map nesting was deeper than this - * implementation can handle. Note that in the interest of code - * size and memory use, QCBOR has a hard limit on array - * nesting. The limit is defined as the constant - * @ref QCBOR_MAX_ARRAY_NESTING. */ - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 4, - - /** During encoding, @c QCBOREncode_CloseXxx() called for a - * different type than is currently open. */ - QCBOR_ERR_CLOSE_MISMATCH = 5, - - /** During encoding, the array or map had too many items in it. The - * limits are @ref QCBOR_MAX_ITEMS_IN_ARRAY and - * @ref QCBOR_MAX_ITEMS_IN_MAP. */ - QCBOR_ERR_ARRAY_TOO_LONG = 6, - - /** During encoding, more arrays or maps were closed than - * opened. This is a coding error on the part of the caller of the - * encoder. */ - QCBOR_ERR_TOO_MANY_CLOSES = 7, - - /** During encoding, the number of array or map opens was not - * matched by the number of closes. Also occurs with opened byte - * strings that are not closed. */ - QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 8, - - /** During encoding, opening a byte string while a byte string is - * open is not allowed. */ - QCBOR_ERR_OPEN_BYTE_STRING = 9, - - /** Trying to cancel a byte string wrapping after items have been - * added to it. */ - QCBOR_ERR_CANNOT_CANCEL = 10, - -#define QCBOR_START_OF_NOT_WELL_FORMED_ERRORS 20 - - /** During decoding, the CBOR is not well-formed because a simple - * value between 0 and 31 is encoded in a two-byte integer rather - * than one. */ - QCBOR_ERR_BAD_TYPE_7 = 20, - - /** During decoding, returned by QCBORDecode_Finish() if all the - * inputs bytes have not been consumed. This is considered not - * well-formed. */ - QCBOR_ERR_EXTRA_BYTES = 21, - - /** During decoding, some CBOR construct was encountered that this - * decoder doesn't support, primarily this is the reserved - * additional info values, 28 through 30. The CBOR is not - * well-formed. - */ - QCBOR_ERR_UNSUPPORTED = 22, - - /** During decoding, the an array or map was not fully consumed. - * Returned by QCBORDecode_Finish(). The CBOR is not - * well-formed. */ - QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED = 23, - - /** During decoding, an integer type is encoded with a bad length - * (that of an indefinite length string). The CBOR is not-well - * formed. */ - QCBOR_ERR_BAD_INT = 24, - -#define QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS 30 - - /** During decoding, one of the chunks in an indefinite-length - * string is not of the type of the start of the string. The CBOR - * is not well-formed. This error makes no further decoding - * possible. */ - QCBOR_ERR_INDEFINITE_STRING_CHUNK = 30, - - /** During decoding, hit the end of the given data to decode. For - * example, a byte string of 100 bytes was expected, but the end - * of the input was hit before finding those 100 bytes. Corrupted - * CBOR input will often result in this error. See also - * @ref QCBOR_ERR_NO_MORE_ITEMS. The CBOR is not well-formed. - * This error makes no further decoding possible. */ - QCBOR_ERR_HIT_END = 31, - - /** During decoding, a break occurred outside an indefinite-length - * item. The CBOR is not well-formed. This error makes no further - * decoding possible. */ - QCBOR_ERR_BAD_BREAK = 32, - -#define QCBOR_END_OF_NOT_WELL_FORMED_ERRORS 39 - - /** During decoding, the input is too large. It is greater than - * QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. - * This error makes no further decoding possible. */ - QCBOR_ERR_INPUT_TOO_LARGE = 40, - - /** During decoding, the array or map nesting was deeper than this - * implementation can handle. Note that in the interest of code - * size and memory use, QCBOR has a hard limit on array - * nesting. The limit is defined as the constant - * @ref QCBOR_MAX_ARRAY_NESTING. This error makes no further - * decoding possible. */ - QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP = 41, - - /** During decoding, the array or map had too many items in it. - * This limit is @ref QCBOR_MAX_ITEMS_IN_ARRAY (65,534) for - * arrays and @ref QCBOR_MAX_ITEMS_IN_MAP (32,767) for maps. This - * error makes no further decoding possible. */ - QCBOR_ERR_ARRAY_DECODE_TOO_LONG = 42, - - /** When decoding, a string's size is greater than what a size_t - * can hold less 4. In all but some very strange situations this - * is because of corrupt input CBOR and should be treated as - * such. The strange situation is a CPU with a very small size_t - * (e.g., a 16-bit CPU) and a large string (e.g., > 65KB). This - * error makes no further decoding possible. */ - QCBOR_ERR_STRING_TOO_LONG = 43, - - /** Something is wrong with a decimal fraction or bigfloat such as - * it not consisting of an array with two integers. This error - * makes no further decoding possible. */ - QCBOR_ERR_BAD_EXP_AND_MANTISSA = 44, - - /** Unable to decode an indefinite-length string because no string - * allocator was configured. See QCBORDecode_SetMemPool() or - * QCBORDecode_SetUpAllocator(). This error makes no further - * decoding possible.*/ - QCBOR_ERR_NO_STRING_ALLOCATOR = 45, - - /** Error allocating memory for a string, usually out of memory. - * This primarily occurs decoding indefinite-length strings. This - * error makes no further decoding possible. */ - QCBOR_ERR_STRING_ALLOCATE = 46, - - /** During decoding, the type of the label for a map entry is not - * one that can be handled in the current decoding mode. Typically - * this is because a label is not an integer or a string. This is - * an implementation limit. */ - QCBOR_ERR_MAP_LABEL_TYPE = 47, - - /** When the built-in tag decoding encounters an unexpected type, - * this error is returned. This error is unrecoverable because the - * built-in tag decoding doesn't try to consume the unexpected - * type. In previous versions of QCBOR this was considered a - * recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going - * back further, RFC 7049 use the name "optional tags". That name - * is no longer used because "optional" was causing confusion. */ - QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT = 48, - QCBOR_ERR_BAD_TAG_CONTENT = 48, - QCBOR_ERR_BAD_OPT_TAG = 48, - - /** Indefinite length string handling is disabled and there is an - * indefinite length string in the input CBOR. */ - QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED = 49, - - /** Indefinite length arrays and maps handling are disabled and - * there is an indefinite length map or array in the input - * CBOR. */ - QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED = 50, - - /** All decoding of tags (major type 6) has been disabled and a tag - * occurred in the decode input. */ - QCBOR_ERR_TAGS_DISABLED = 51, - -#define QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS 59 - - /** More than @ref QCBOR_MAX_TAGS_PER_ITEM tags encountered for a - * CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this - * implementation. During decoding, too many tags in the - * caller-configured tag list, or not enough space in - * @ref QCBORTagListOut. This error makes no further decoding - * possible. */ - QCBOR_ERR_TOO_MANY_TAGS = 60, - - /** When decoding for a specific type, the type was not expected. */ - QCBOR_ERR_UNEXPECTED_TYPE = 61, - - /** Duplicate label detected in a map. */ - QCBOR_ERR_DUPLICATE_LABEL = 62, - - /** During decoding, the buffer given to QCBORDecode_SetMemPool() - * is either too small, smaller than - * @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than - * UINT32_MAX. */ - QCBOR_ERR_MEM_POOL_SIZE = 63, - - /** During decoding, an integer smaller than INT64_MIN was received - * (CBOR can represent integers smaller than INT64_MIN, but C - * cannot). */ - QCBOR_ERR_INT_OVERFLOW = 64, - - /** During decoding, a date greater than +- 292 billion years from - * Jan 1 1970 encountered during parsing. This is an - * implementation limit. */ - QCBOR_ERR_DATE_OVERFLOW = 65, - - /** During decoding, @c QCBORDecode_ExitXxx() was called for a - * different type than @c QCBORDecode_EnterXxx(). */ - QCBOR_ERR_EXIT_MISMATCH = 66, - - /** All well-formed data items have been consumed and there are no - * more. If parsing a CBOR stream this indicates the non-error end - * of the stream. If not parsing a CBOR stream/sequence, this - * probably indicates that some data items expected are not - * present. See also @ref QCBOR_ERR_HIT_END. */ - QCBOR_ERR_NO_MORE_ITEMS = 67, - - /** When finding an item by label, an item with the requested label - * was not found. */ - QCBOR_ERR_LABEL_NOT_FOUND = 68, - - /** Number conversion failed because of sign. For example a - * negative int64_t can't be converted to a uint64_t */ - QCBOR_ERR_NUMBER_SIGN_CONVERSION = 69, - - /** When converting a decoded number, the value is too large or too - * small for the conversion target. */ - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW = 70, - - /** Trying to get an item by label when a map has not been - * entered. */ - QCBOR_ERR_MAP_NOT_ENTERED = 71, - - /** A callback indicates processing should not continue for some - * non-CBOR reason. */ - QCBOR_ERR_CALLBACK_FAIL = 72, - - /** This error code is deprecated. Instead, - * @ref QCBOR_ERR_HALF_PRECISION_DISABLED, - * @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED - * is returned depending on the specific floating-point functionality - * that is disabled and the type of floating-point input. */ - QCBOR_ERR_FLOAT_DATE_DISABLED = 73, - - /** Support for half-precision float decoding is disabled. */ - QCBOR_ERR_HALF_PRECISION_DISABLED = 74, - - /** Use of floating-point HW is disabled. This affects all type - * conversions to and from double and float types. */ - QCBOR_ERR_HW_FLOAT_DISABLED = 75, - - /** Unable to complete operation because a floating-point value - * that is a NaN (not a number), that is too large, too small, - * infinity or -infinity was encountered in encoded CBOR. Usually - * this because conversion of the float-point value was being - * attempted. */ - QCBOR_ERR_FLOAT_EXCEPTION = 76, - - /** Floating point support is completely turned off, - * encoding/decoding floating point numbers is not possible. */ - QCBOR_ERR_ALL_FLOAT_DISABLED = 77, - - /** Like @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT, but recoverable. - * If an implementation decodes a tag and can and does consume the - * whole tag contents when it is not the correct tag content, this - * error can be returned. None of the built-in tag decoders do this - * (to save object code). */ - QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78, - - /** QCBORDecode_EnterBstrWrapped() cannot be used on - * indefinite-length strings because they exist in memory pool for - * a @ref QCBORStringAllocate. */ - QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 79, - - /** A range of error codes that can be made use of by the - * caller. QCBOR internally does nothing with these except notice - * that they are not QCBOR_SUCCESS. See QCBORDecode_SetError(). */ - QCBOR_ERR_FIRST_USER_DEFINED = 128, - - /** See @ref QCBOR_ERR_FIRST_USER_DEFINED */ - QCBOR_ERR_LAST_USER_DEFINED = 255 - - /* This is stored in uint8_t; never add values > 255 */ -} QCBORError; - - -/** - * @brief Get string describing an error code. - * - * @param[in] uErr The error code. - * - * @return NULL-terminated string describing error or "Unidentified - * error" if the error is not known. - * - * This is not thread-safe because it uses a static buffer - * for formatting, but this is only a diagnostic and the only - * consequence is the wrong description. - */ -const char * -qcbor_err_to_str(QCBORError uErr); - - - - -/** - * The maximum nesting of arrays and maps when encoding or - * decoding. The error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be - * returned on encoding or @ref QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on - * decoding if it is exceeded. Do not increase this over 255. - */ -#define QCBOR_MAX_ARRAY_NESTING 15 - - -/** - * The maximum number of items in a single array when encoding or - * decoding. See also @ref QCBOR_MAX_ITEMS_IN_MAP. - */ -#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) /* -1 is because the - * value UINT16_MAX is - * used to indicate - * indefinite-length. - */ -/** - * The maximum number of items in a single map when encoding or - * decoding. See also @ref QCBOR_MAX_ITEMS_IN_ARRAY. - */ -#define QCBOR_MAX_ITEMS_IN_MAP (QCBOR_MAX_ITEMS_IN_ARRAY/2) - - -#ifdef __cplusplus -} -#endif - -#endif /* qcbor_common_h */ diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_decode.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor_decode.h deleted file mode 100644 index 0dd9265767c9..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_decode.h +++ /dev/null @@ -1,1708 +0,0 @@ -/* =========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2025, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - - -#ifndef qcbor_decode_h -#define qcbor_decode_h - - -#include "qcbor/qcbor_common.h" -#include "qcbor/qcbor_private.h" -#include - - -#ifdef __cplusplus -extern "C" { -#if 0 -} /* Keep editor indention formatting happy */ -#endif -#endif - - -/** - * @file qcbor_decode.h - * - * @anchor BasicDecode - * # QCBOR Basic Decode - * - * This section discusses decoding assuming familiarity with the - * general description of this encoder-decoder in section @ref - * Overview. - * - * Encoded CBOR has a tree structure where the leaf nodes are - * non-aggregate types like integers and strings and the intermediate - * nodes are either arrays or maps. Fundamentally, CBOR decoding is a - * pre-order traversal of this tree with CBOR sequences a minor - * exception. Calling QCBORDecode_GetNext() repeatedly will perform - * this. QCBOR maintains an internal traversal cursor. It is possible - * to decode any CBOR by only calling QCBORDecode_GetNext(), though - * this doesn't take advantage of many QCBOR features. - * - * QCBORDecode_GetNext() returns a 56 byte structure called - * @ref QCBORItem that describes the decoded item including: - * - The data itself, integer, string, floating-point number... - * - The label if present - * - Unprocessed tags - * - Nesting level - * - Allocation type (primarily of interest for indefinite length strings) - * - * For strings, this structure contains a pointer and length back into - * the original data. - * - * Most of the tags that QCBOR supports directly are decoded into a - * representation in @ref QCBORItem. - * - * A string allocator must be used when decoding indefinite length - * strings. See QCBORDecode_SetMemPool() or - * QCBORDecode_SetUpAllocator(). @ref QCBORItem indicates if a string - * was allocated with the string allocator. - * - * This pre-order traversal gives natural decoding of arrays where the - * array members are taken in order. Maps can be decoded this way too, - * but the @ref SpiffyDecode APIs that allow searching maps by label - * are often more convenient. - * - * @anchor Decode-Errors-Overview - * # Decode Errors Overview - * - * The simplest way to handle decoding errors is to make use of the - * internal error tracking. The only error code check necessary is - * at the end when QCBORDecode_Finish() is called. To do this: - * - * - Use QCBORDecode_VGetNext(), QCBORDecode_VPeekNext() - * and any or all of the functions in qcbor_spiffy_decode.h. Don't use - * QCBORDecode_GetNext() or QCBORDecode_PeekNext(). - * - Call QCBORDecode_Finish() and check its return code. - * - Do not reference any decoded data until after - * QCBORDecode_Finish() returns success. - * - * Once an encoding error has been encountered, the error state is - * entered and further decoding function calls will do nothing. It is - * safe to continue calling decoding functions after an error. No - * error checking is necessary making the code to decode a protocol - * simpler. The two exceptions are QCBORDecode_GetNext() and - * QCBORDecode_PeekNext() which will try to decode even if the decoder - * is in the error state. Use QCBORDecode_VGetNext() and - * QCBORDecode_VPeekNext() instead. - * - * While some protocols are simple enough to be decoded this way, many - * aren’t because the data items earlier in the protocol determine how - * later data items are to be decoded. In that case it is necessary to - * call QCBORDecode_GetError() to know the earlier items were - * successfully decoded before examining their value or type. - * - * The internal decode error state can be reset by reinitializing the - * decoder or calling QCBORDecode_GetAndResetError(). Code calling - * QCBOR may take advantage of the internal error state to halt - * futher decoding and propagate errors it detects using - * QCBORDecode_SetError(). - * - * It is only useful to reset the error state by calling - * QCBORDecode_GetAndResetError() on recoverable errors. Examples of - * recoverable errors are a map entry not being found or integer - * overflow or underflow during conversion. Examples of unrecoverable - * errors are hitting the end of the input and array or map nesting - * beyond the limits of the implementation. See - * QCBORDecode_IsUnrecoverableError().Trying to reset and decode after - * an unrecoverable error will usually just lead to another error. - * - * It is possible to use QCBORDecode_GetNext() and - * QCBORDecode_PeekNext() to decode an entire protocol. However, that is - * usually more work, more code and less convenient than using spiffy - * decode functions. - * - * It is also possible to mix the use of QCBORDecode_GetNext() with - * QCBORDecode_VGetNext() and the spiffy decode functions, but - * QCBORDecode_GetError() must be called and return QCBOR_SUCCESS before - * QCBORDecode_GetNext() is called. - * - * The effect of a decoding error on the traversal cursor position - * varies by the decoding method called. It is unaffected by spiffy - * decode methods that get items by map label. - * QCBORDecode_GetInt64InMapN() is an example of this. The traversal - * cursor will be advanced by most other decode methods even when - * there is a decode error, often leaving it in an indeterminate - * position. If it is necessary to continue to decoding after an - * error, QCBORDecode_Rewind() can be used to reset it to a known-good - * position. - * - * When using spiffy decode methods to get an item by label from a map - * the whole map is internally traversed including nested arrays and - * maps. If there is any unrecoverable error during that traversal, - * the retrieval by label will fail. The unrecoverable error will be - * returned even if it is not because the item being sought is in - * error. Recoverable errors will be ignored unless they are on the - * item being sought, in which case the unrecoverable error will be - * returned. Unrecoverable errors are those indicated by - * QCBORDecode_IsUnrecoverableError(). - * - * @anchor Disabilng-Tag-Decoding - * # Disabilng Tag Decoding - * - * If QCBOR_DISABLE_TAGS is defined, all code for decoding tags will - * be omitted reducing the core decoder, QCBORDecode_VGetNext(), by - * about 400 bytes. If a tag number is encountered in the decoder - * input the unrecoverable error @ref QCBOR_ERR_TAGS_DISABLED will be - * returned. No input with tags can be decoded. - * - * Decode functions like QCBORDecode_GetEpochDate() and - * QCBORDecode_GetDecimalFraction() that can decode the tag content - * even if the tag number is absent are still available. Typically - * they won't be linked in because of dead stripping. The - * @c uTagRequirement parameter has no effect, but if it is - * @ref QCBOR_TAG_REQUIREMENT_TAG, @ref QCBOR_ERR_TAGS_DISABLED - * will be set. - */ - -/** - * The decode mode options. - */ -typedef enum { - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_NORMAL = 0, - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1, - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2 - /* This is stored in uint8_t in places; never add values > 255 */ -} QCBORDecodeMode; - -/** - * The maximum size of input to the decoder. Slightly less than - * @c UINT32_MAX to make room for some special indicator values. - */ -#define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2) - -/** - * The maximum number of tags that may occur on an individual nested - * item. Typically 4. - */ -#define QCBOR_MAX_TAGS_PER_ITEM QCBOR_MAX_TAGS_PER_ITEM1 - - - -/* Do not renumber these. Code depends on some of these values. */ -/** The data type is unknown, unset or invalid. */ -#define QCBOR_TYPE_NONE 0 - -/** Never used in QCBORItem. Used by functions that match QCBOR types. */ -#define QCBOR_TYPE_ANY 1 - -/** Type for an integer that decoded either between @c INT64_MIN and - * @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member - * @c val.int64. */ -#define QCBOR_TYPE_INT64 2 - -/** Type for an integer that decoded to a more than @c INT64_MAX and - * @c UINT64_MAX. Data is in member @c val.uint64. */ -#define QCBOR_TYPE_UINT64 3 - -/** Type for an array. See comments on @c val.uCount. */ -#define QCBOR_TYPE_ARRAY 4 - -/** Type for a map. See comments on @c val.uCount. */ -#define QCBOR_TYPE_MAP 5 - -/** Type for a buffer full of bytes. Data is in @c val.string. */ -#define QCBOR_TYPE_BYTE_STRING 6 - -/** Type for a UTF-8 string. It is not NULL-terminated. See - * QCBOREncode_AddText() for a discussion of line endings in CBOR. Data - * is in @c val.string. */ -#define QCBOR_TYPE_TEXT_STRING 7 - -/** Type for a positive big number. Data is in @c val.bignum, a - * pointer and a length. */ -#define QCBOR_TYPE_POSBIGNUM 9 - -/** Type for a negative big number. Data is in @c val.bignum, a - * pointer and a length. */ -#define QCBOR_TYPE_NEGBIGNUM 10 - -/** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date - * string, possibly with time zone. Data is in @c val.string . Note this - * was previously in @c val.dateString, however this is the same as - * val.string being the same type in same union. val.dateString will - * be deprecated.. */ -#define QCBOR_TYPE_DATE_STRING 11 - -/** Type for integer seconds since Jan 1970 + floating-point - * fraction. Data is in @c val.epochDate */ -#define QCBOR_TYPE_DATE_EPOCH 12 - -/** The CBOR major type "simple" has a small integer value indicating - * what it is. The standard CBOR simples are true, false, null, undef - * (values 20-23) and float-point numbers (values 25-27). The values - * 0-19 and 32-255 are unassigned and may be used if registered with - * in the IANA Simple Values Registry. If these unassigned simple - * values occur in the input they will be decoded as this. The value - * is in @c val.uSimple. */ -#define QCBOR_TYPE_UKNOWN_SIMPLE 13 - -/** A decimal fraction made of decimal exponent and integer mantissa. - * See @ref expAndMantissa and QCBOREncode_AddTDecimalFraction(). */ -#define QCBOR_TYPE_DECIMAL_FRACTION 14 - -/** A decimal fraction made of decimal exponent and positive big - * number mantissa. See @ref expAndMantissa and - * QCBOREncode_AddTDecimalFractionBigNum(). */ -#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15 - -/** A decimal fraction made of decimal exponent and negative big - * number mantissa. See @ref expAndMantissa and - * QCBOREncode_AddTDecimalFractionBigNum(). */ -#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16 - -/** A floating-point number made of base-2 exponent and integer - * mantissa. See @ref expAndMantissa and - * QCBOREncode_AddTBigFloat(). */ -#define QCBOR_TYPE_BIGFLOAT 17 - -/** A floating-point number made of base-2 exponent and positive big - * number mantissa. See @ref expAndMantissa and - * QCBOREncode_AddTBigFloatBigNum(). */ -#define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18 - -/** A floating-point number made of base-2 exponent and negative big - * number mantissa. See @ref expAndMantissa and - * QCBOREncode_AddTBigFloatBigNum(). */ -#define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19 - -/** Type for the simple value false. */ -#define QCBOR_TYPE_FALSE 20 - -/** Type for the simple value true. */ -#define QCBOR_TYPE_TRUE 21 - -/** Type for the simple value null. */ -#define QCBOR_TYPE_NULL 22 - -/** Type for the simple value undef. */ -#define QCBOR_TYPE_UNDEF 23 - -/** Type for a floating-point number. Data is in @c val.fnum. */ -#define QCBOR_TYPE_FLOAT 26 - -/** Type for a double floating-point number. Data is in @c val.dfnum. */ -#define QCBOR_TYPE_DOUBLE 27 - -#define QCBOR_TYPE_BREAK 31 /* Used internally; never returned */ - -/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is - * being traversed as an array. See QCBORDecode_Init() */ -#define QCBOR_TYPE_MAP_AS_ARRAY 32 - -/** Encoded CBOR that is wrapped in a byte string. Often used when the - * CBOR is to be hashed for signing or HMAC. See also @ref - * QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in @c val.string. */ -#define QBCOR_TYPE_WRAPPED_CBOR 36 - -/** A URI as defined in RFC 3986. Data is in @c val.string. */ -#define QCBOR_TYPE_URI 44 - -/** Text is base64 URL encoded in RFC 4648. The base64 encoding is - * NOT removed. Data is in @c val.string. */ -#define QCBOR_TYPE_BASE64URL 45 - -/** Text is base64 encoded in RFC 4648. The base64 encoding is NOT - * removed. Data is in @c val.string. */ -#define QCBOR_TYPE_BASE64 46 - -/** PERL-compatible regular expression. Data is in @c val.string. */ -#define QCBOR_TYPE_REGEX 47 - -/** Non-binary MIME per RFC 2045. See also @ref - * QCBOR_TYPE_BINARY_MIME. Data is in @c val.string. */ -#define QCBOR_TYPE_MIME 48 - -/** Binary UUID per RFC 4122. Data is in @c val.string. */ -#define QCBOR_TYPE_UUID 49 - -/** A CBOR sequence per RFC 8742. See also @ ref - * QBCOR_TYPE_WRAPPED_CBOR. Data is in @c val.string. */ -#define QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE 75 - -/** Binary MIME per RFC 2045. See also @ref QCBOR_TYPE_MIME. Data is - * in @c val.string. */ -#define QCBOR_TYPE_BINARY_MIME 76 - -/** Type for [RFC 8943](https://tools.ietf.org/html/rfc8943) date - * string, a date with no time or time zone info. Data is in - * @c val.string */ -#define QCBOR_TYPE_DAYS_STRING 77 - -/** Type for integer days since Jan 1 1970 described in - * [RFC 8943](https://tools.ietf.org/html/rfc8943). Data is in - * @c val.epochDays */ -#define QCBOR_TYPE_DAYS_EPOCH 78 - -#define QCBOR_TYPE_TAG 254 /* Used internally; never returned */ - -#define QCBOR_TYPE_OPTTAG QCBOR_TYPE_TAG /* Depricated. See QCBOR_TYPE_TAG */ - - - -/** - * The largest value in @c utags that is unmapped and can be used without - * mapping it through QCBORDecode_GetNthTag(). - */ -#define QCBOR_LAST_UNMAPPED_TAG (CBOR_TAG_INVALID16 - QCBOR_NUM_MAPPED_TAGS - 1) - - -/** - * @anchor expAndMantissa - * - * This holds the value for big floats and decimal fractions, as an - * exponent and mantissa. For big floats the base for exponentiation - * is 2. For decimal fractions it is 10. Whether an instance is a big - * float or decimal fraction is known by context, usually by @c uDataType - * in @ref QCBORItem which might be @ref QCBOR_TYPE_DECIMAL_FRACTION, - * @ref QCBOR_TYPE_BIGFLOAT, ... - * - * The mantissa may be an @c int64_t or a big number. This is again - * determined by context, usually @c uDataType in @ref QCBORItem which - * might be @ref QCBOR_TYPE_DECIMAL_FRACTION, - * @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, ... The sign of the - * big number also comes from the context - * (@ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - * @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,...). - * - * @c bigNum is big endian or network byte order. The most significant - * byte is first. - * - * When @c Mantissa is @c int64_t, it represents the true value of the - * mantissa with the offset of 1 for CBOR negative values - * applied. When it is a negative big number - * (@ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM or - * @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM), the offset of 1 has NOT been - * applied (doing so requires somewhat complex big number arithmetic - * and may increase the length of the big number). To get the correct - * value @c bigNum must be incremented by one before use. - * - * Also see QCBOREncode_AddTDecimalFraction(), - * QCBOREncode_AddTBigFloat(), QCBOREncode_AddTDecimalFractionBigNum() - * and QCBOREncode_AddTBigFloatBigNum(). - */ -typedef struct { - int64_t nExponent; - union { - int64_t nInt; - UsefulBufC bigNum; - } Mantissa; -} QCBORExpAndMantissa; - - -/** - * This holds a decoded data item. It is returned by the - * QCBORDecode_GetNext(), the principle decoding function. - * It holds the type, value, label, tags and other details - * of the decoded data item. - * - * This is typically 56 bytes on 64-bit CPUs and 52 bytes on 32-bit - * CPUs (the CPU and the system's ABI determine this size). - */ -typedef struct _QCBORItem { - /** Tells what element of the @c val union to use. One of @ref - * QCBOR_TYPE_INT64, @ref QCBOR_TYPE_ARRAY, ...*/ - uint8_t uDataType; - - /** Tells what element of the @c label union to use. One of - * @ref QCBOR_TYPE_INT64, @ref QCBOR_TYPE_BYTE_STRING, ...*/ - uint8_t uLabelType; - - /** Holds the nesting depth for arrays and map. 0 is the top level - * with no arrays or maps entered. */ - uint8_t uNestingLevel; - - /** Holds the nesting level of the next item after this one. If - * less than @c uNestingLevel, this item was the last one in an - * arry or map and it closed out at least one nesting level. */ - uint8_t uNextNestLevel; - - /** 1 if a @c val that is a string is allocated with string - * allocator, 0 if not. Always 0 unless an allocator has been set - * up by calling QCBORDecode_SetMemPool() or - * QCBORDecode_SetUpAllocator(). */ - uint8_t uDataAlloc; - - /** 1 if a @c label that is a string is allocated with string - * allocator, 0 if not. Always 0 unless an allocator has been set - * up by calling QCBORDecode_SetMemPool() or - * QCBORDecode_SetUpAllocator(). */ - uint8_t uLabelAlloc; - - /** The union holding the item's value. Select union member based - * on @c uDataType. */ - union { - /** The value for @c uDataType @ref QCBOR_TYPE_INT64. */ - int64_t int64; - /** The value for @c uDataType @ref QCBOR_TYPE_UINT64. */ - uint64_t uint64; - /** The value for @c uDataType @ref QCBOR_TYPE_BYTE_STRING and - * @ref QCBOR_TYPE_TEXT_STRING. Also - * for many tags whose content is a string such @ref QCBOR_TYPE_DAYS_STRING - * and @ref QCBOR_TYPE_URI. */ - UsefulBufC string; - /** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref - * QCBOR_TYPE_MAP, the number of items in the array or map. It - * is @c UINT16_MAX when decoding indefinite-lengths maps and - * arrays. Detection of the end of a map or array is best done - * with @c uNestLevel and @c uNextNestLevel so as to work for - * both definite and indefinite length maps and arrays. */ - uint16_t uCount; -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */ - double dfnum; - /** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */ - float fnum; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH, the - * number of seconds after or before Jan 1, 1970. This has a - * range of 500 billion years. Floating-point dates are - * converted to this integer + fractional value. If the input - * value is beyond the 500 billion-year range (e.g., +/i - * infinity, large floating point values, NaN) - * @ref QCBOR_ERR_DATE_OVERFLOW will be returned. If the input - * is floating-point and QCBOR has been compiled with - * floating-point disabled, one of the various floating-point - * disabled errors will be returned. */ - struct { - int64_t nSeconds; -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - double fSecondsFraction; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - } epochDate; - - /** The value for @c uDataType @ref QCBOR_TYPE_DAYS_EPOCH -- the - * number of days before or after Jan 1, 1970. */ - int64_t epochDays; - /** No longer used. Was the value for @ref QCBOR_TYPE_DATE_STRING, - * but now that value is in @c string. This will be removed in QCBOR 2.0. */ - UsefulBufC dateString; - /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and - * @ref QCBOR_TYPE_NEGBIGNUM. */ - UsefulBufC bigNum; - /** See @ref QCBOR_TYPE_UKNOWN_SIMPLE */ - uint8_t uSimple; -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - QCBORExpAndMantissa expAndMantissa; -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - uint64_t uTagV; /* Used internally during decoding */ - - } val; - - /** Union holding the different label types selected based on @c uLabelType */ - union { - /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */ - int64_t int64; -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */ - uint64_t uint64; - /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and - * @ref QCBOR_TYPE_TEXT_STRING */ - UsefulBufC string; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - } label; - -#ifndef QCBOR_DISABLE_TAGS - /** - * The tags numbers for which the item is the tag content. Tags - * nest, so index 0 in the array is the tag on the data item - * itself, index 1 is the tag that applies to the tag in index - * 0. The end of the list is indicated by @ref CBOR_TAG_INVALID16 - * - * Tag nesting is uncommon and rarely deep. This implementation - * only allows nesting to a depth of @ref QCBOR_MAX_TAGS_PER_ITEM, - * usually 4. - * - * Tag numbers in the array below and equal to @ref - * QCBOR_LAST_UNMAPPED_TAG are unmapped and can be used - * directly. Tag numbers above this must be translated through - * QCBORDecode_GetNthTag(). - * - * See also the large number of functions like - * QCBORDecode_GetEpochDate() and QCBORDecode_GetBignum() in - * qcbor_spiffy_decode.h for a way to decode tagged types without - * having to reference this array. Also see @ref Tags-Overview. - */ - uint16_t uTags[QCBOR_MAX_TAGS_PER_ITEM]; -#endif - -} QCBORItem; - -/** - * An array or map's length is indefinite when it has this value. - */ -#define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX - - - - -/** - * @brief Prototype for the implementation of a string allocator. - * - * @param[in] pAllocateCxt Pointer to context for the particular - * allocator implementation. Its contents - * depend on how a particular string allocator - * works. Typically, it will contain a pointer - * to the memory pool and some booking keeping - * data. - * - * @param[in] pOldMem Points to some memory previously allocated - * that is either to be freed or to be - * reallocated to be larger. It is @c NULL for - * new allocations and when called as the - * destructor. - * - * @param[in] uNewSize Size of memory to be allocated or new size - * for a chunk being reallocated. Zero when - * called to free memory or when called as the - * destructor. - * - * @return Either the allocated buffer is returned, or - * @ref NULLUsefulBufC. @ref NULLUsefulBufC is returned on a - * failed allocation and in the two cases where there is - * nothing to return. - * - * This function must be implemented for a custom string - * allocator. See QCBORDecode_SetUpAllocator(). - * - * This is not needed if the built-in string allocator available - * through QCBORDecode_SetMemPool() is used. - * - * After being set up by a call to QCBORDecode_SetUpAllocator(), - * this is called back in four modes: - * - * - allocate: @c uNewSize is the amount to allocate. @c pOldMem is - * @c NULL. - * - * - free: @c uNewSize is 0. @c pOldMem points to the memory to be - * freed. When the decoder calls this, it will always be for the most - * recent block that was either allocated or reallocated. - * - * - reallocate: @c pOldMem is the block to reallocate. @c uNewSize is - * its new size. When the decoder calls this, it will always be for the - * most recent block that was either allocated or reallocated. - * - * - destruct: @c pOldMem is @c NULL and @c uNewSize is 0. This is - * called when the decoding is complete by - * QCBORDecode_Finish(). Usually, the strings allocated by a string - * allocator are in use after the decoding is completed so this - * usually will not free those strings. Many string allocators will - * not need to do anything in this mode. - * - * The strings allocated by this will have @c uDataAlloc set to true - * in the @ref QCBORItem when they are returned. The user of the - * strings will have to free them. How they free them, depends on the - * design of the string allocator. - */ -typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, - void *pOldMem, - size_t uNewSize); - - -/** - * For the built-in string allocator available via - * QCBORDecode_SetMemPool(), this is the size overhead needed - * internally. The amount of memory available for decoded strings is - * the size of the buffer given to QCBORDecode_SetMemPool() less this - * amount. - * - * This doesn't apply to custom string allocators, only to the one - * available via QCBORDecode_SetMemPool(). - */ -#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8 - - - - -/** - * QCBORDecodeContext holds the context for decoding CBOR. It is - * about 300 bytes, so it can go on the stack. The contents are - * opaque, and the caller should not access any internal items. A - * context may be re-used serially as long as it is re initialized. - */ -typedef struct _QCBORDecodeContext QCBORDecodeContext; - - -/** - * Initialize the CBOR decoder context. - * - * @param[in] pCtx The context to initialize. - * @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded. - * @param[in] nMode See below and @ref QCBORDecodeMode. - * - * Initialize context for a pre-order traversal of the encoded CBOR - * tree. - * - * Most CBOR decoding can be completed by calling this function to - * start and QCBORDecode_GetNext() in a loop. - * - * If indefinite-length strings are to be decoded, then - * QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be - * called to set up a string allocator. - * - * Three decoding modes are supported. In normal mode, @ref - * QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers - * are accepted as map labels. If a label is other than these, the - * error @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by - * QCBORDecode_GetNext(). - * - * In strings-only mode, @ref QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only - * text strings are accepted for map labels. This lines up with CBOR - * that converts to JSON. The error @ref QCBOR_ERR_MAP_LABEL_TYPE is - * returned by QCBORDecode_GetNext() if anything but a text string - * label is encountered. - * - * In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special - * arrays. They will be returned with special @c uDataType @ref - * QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be - * double what it would be for a normal map because the labels are - * also counted. This mode is useful for decoding CBOR that has labels - * that are not integers or text strings, but the caller must manage - * much of the map decoding. - */ -void -QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); - - -/** - * @brief Set up the MemPool string allocator for indefinite-length strings. - * - * @param[in] pCtx The decode context. - * @param[in] MemPool The pointer and length of the memory pool. - * @param[in] bAllStrings If true, all strings, even of definite - * length, will be allocated with the string - * allocator. - * - * @return Error if the MemPool was greater than @c UINT32_MAX - * or less than @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE. - * - * Indefinite-length strings (text and byte) cannot be decoded unless - * there is a string allocator configured. MemPool is a simple - * built-in string allocator that allocates bytes from a memory pool - * handed to it by calling this function. The memory pool is just a - * pointer and length for some block of memory that is to be used for - * string allocation. It can come from the stack, heap or other. - * - * The memory pool must be @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE plus - * space for all the strings allocated. There is no overhead per - * string allocated. A conservative way to size this buffer is to make - * it the same size as the CBOR being decoded plus @ref - * QCBOR_DECODE_MIN_MEM_POOL_SIZE. - * - * This memory pool is used for all indefinite-length strings that are - * text strings or byte strings, including strings used as labels. - * - * The pointers to strings in @ref QCBORItem will point into the - * memory pool set here. They do not need to be individually - * freed. Just discard the buffer when they are no longer needed. - * - * If @c bAllStrings is set, then the size will be the overhead plus - * the space to hold **all** strings, definite and indefinite-length, - * value or label. The advantage of this is that after the decode is - * complete, the original memory holding the encoded CBOR does not - * need to remain valid. - * - * This simple allocator is not hard linked to the QCBOR decoder. - * Assuming dead-stripping of unused symbols is being performed, this - * simple allocator will not be linked in unless - * QCBORDecode_SetMemPool() is called. - * - * See also QCBORDecode_SetUpAllocator() to set up a custom allocator - * if this one isn't sufficient. - */ -QCBORError -QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, - UsefulBuf MemPool, - bool bAllStrings); - - -/** - * @brief Sets up a custom string allocator for indefinite-length strings - * - * @param[in] pCtx The decoder context to set up an - * allocator for. - * @param[in] pfAllocateFunction Pointer to function that will be - * called by QCBOR for allocations and - * frees. - * @param[in] pAllocateContext Context passed to @c - * pfAllocateFunction. - * @param[in] bAllStrings If true, all strings, even of definite - * length, will be allocated with the - * string allocator. - * - * Indefinite-length strings (text and byte) cannot be decoded unless - * a string allocator is configured. QCBORDecode_SetUpAllocator() - * allows the caller to configure an external string allocator - * implementation if the internal string allocator is - * unsuitable. See QCBORDecode_SetMemPool() to configure the internal - * allocator. - * - * The string allocator configured here is a custom one designed - * and implemented by the caller. See @ref QCBORStringAllocate for - * the requirements for a string allocator implementation. - * - * A malloc-based string external allocator can be obtained by calling - * @c QCBORDecode_MakeMallocStringAllocator(). It will return a - * function and pointer that can be given here as @c pAllocatorFunction - * and @c pAllocatorContext. It uses standard @c malloc() so @c free() - * must be called on all strings marked by @c uDataAlloc @c == @c 1 or - * @c uLabelAlloc @c == @c 1 in @ref QCBORItem. Note this is in a - * separate GitHub repository. - */ -void -QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings); - - -/** - * @brief Get the next item (integer, byte string, array...) in the - * preorder traversal of the CBOR tree. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem The decoded CBOR item. - * - * @c pDecodedItem is filled from the decoded item. Generally, the - * following data is returned in the structure: - * - * - @c uDataType which indicates which member of the @c val union the - * data is in. This decoder figures out the type based on the CBOR - * major type, the CBOR "additionalInfo", the CBOR optional tags and - * the value of the integer. - * - * - The value of the item, which might be an integer, a pointer and a - * length, the count of items in an array, a floating-point number or - * other. - * - * - The nesting level for maps and arrays. - * - * - The label for an item in a map, which may be a text or byte string - * or an integer. - * - * - The unprocessed tag numbers for which the item is the tag content. - * - * See @ref QCBORItem for all the details about what is returned. - * - * This function handles arrays and maps. When an array or map is - * first encountered a @ref QCBORItem will be returned with major type - * @ref QCBOR_TYPE_ARRAY or @ref QCBOR_TYPE_MAP. @c - * QCBORItem.val.uNestLevel gives the nesting level of the opening of - * the array or map. When the next item is fetched, it will be the - * first one in the array or map and its @c QCBORItem.val.uNestLevel - * will be one more than that of the opening of the array or map. - * - * Nesting level 0 is the top-most nesting level. The first item - * decoded always has nesting level 0. A map or array at the top level - * has nesting level 0 and the members of the array or map have - * nesting level 1. - * - * Here is an example of how the nesting level is reported for a CBOR - * sequence with no arrays or maps at all. - * - * @code - * Data Item Nesting Level - * integer 0 - * byte string 0 - * @endcode - * - * Here is an example of how the nesting level is reported for a CBOR - * sequence with a simple array and some top-level items. - * - * @code - * Data Item Nesting Level - * integer 0 - * array with 2 items 0 - * byte string 1 - * byte string 1 - * integer 0 - * @endcode - * - * Here's a more complex example that is not a CBOR sequence - * - * @code - * Data Item Nesting Level - * map with 4 items 0 - * text string 1 - * array with 3 integers 1 - * integer 2 - * integer 2 - * integer 2 - * text string 1 - * byte string 1 - * @endcode - * - * In @ref QCBORItem, @c uNextNestLevel is the nesting level for the - * next call to QCBORDecode_VGetNext(). It indicates if any maps or - * arrays were closed out during the processing of the just-fetched - * @ref QCBORItem. This processing includes a look-ahead for any - * breaks that close out indefinite-length arrays or maps. This value - * is needed to be able to understand the hierarchical structure. If - * @c uNextNestLevel is not equal to @c uNestLevel the end of the - * current map or array has been encountered. This works for both - * definite and indefinite-length arrays so it is the best way to find the - * end of a map or array. Alternatively, for definite-length arrays, - * @c QCBORItem.val.uCount contains the number of items in the - * array. For indefinite-length arrays, @c QCBORItem.val.uCount - * is @c UINT16_MAX. - * - * All tags defined in RFC 8949 are automatically fully decoded. There - * are QCBOR_TYPES and members in @ref QCBORItem for them. For - * example, the tag 9 will show up in the @ref QCBORItem as type - * @ref QCBOR_TYPE_POSBIGNUM with the value in - * @c QCBORItem.val.bignum. There is also support for - * some of the tags in the IANA tag registry. - * - * Most tags with a CBOR_TAG_XXX define in qcbor_common.h like @ref - * CBOR_TAG_DATE_STRING are automaticlly decoded by QCBOR. Those that - * are defined but not decoded are so noted. - * - * Tags that are not decoded by QCBOR will be identified and recorded - * in @ref QCBORItem. Use QCBORDecode_GetNthTag() to get them. Only - * @ref QCBOR_MAX_TAGS_PER_ITEM tags are recorded per item and an - * error is returned if there are more than that. - * - * Previous versions of QCBOR handled tags in a more complex way using - * QCBORDecode_SetCallerConfiguredTagList() and - * QCBORDecode_GetNextWithTags(). This version is largely compatible, but - * imposes the limit of @ref QCBOR_MAX_TAGS_PER_ITEM tags per item. - * - * See @ref Tags-Overview for a description of how to go about - * creating custom tags. - * - * This tag decoding design is to be open-ended and flexible to be - * able to handle newly defined tags, while using very little memory, - * in particular keeping @ref QCBORItem as small as possible. - * - * See [Decode Error Overview](#Decode-Errors-Overview). - * - * If a decoding error occurs or previously occured, @c uDataType and - * @c uLabelType will be set to @ref QCBOR_TYPE_NONE. If there is no - * need to know the specific error, it is sufficient to check for @ref - * QCBOR_TYPE_NONE. - * - * Errors fall in several categories: - * - * - Not well-formed errors are those where there is something - * syntactically and fundamentally wrong with the CBOR being - * decoded. Decoding should stop completely. - * - * - Invalid CBOR is well-formed, but still not correct. It is - * probably best to stop decoding, but not necessary. - * - * - This implementation has some size limits. They should rarely be - * encountered. If they are it may because something is wrong with - * the CBOR, for example an array size is incorrect. - * - * - There are a few CBOR constructs that are not handled without some - * extra configuration. These are indefinite length strings and maps - * with labels that are not strings or integers. See - * QCBORDecode_Init(). Also, the QCBOR library may have been - * compiled with some features disabled to reduce code size and this - * can result in some errors. - * - * - Resource exhaustion. This only occurs when a string allocator is - * configured to handle indefinite-length strings as other than - * that, this implementation does no dynamic memory allocation. - * - * | Error | Description | - * | ---- | ---- | - * | __Not well-formed errors__ || - * | @ref QCBOR_ERR_HIT_END | Partial data item; need more input bytes to complete decoding | - * | @ref QCBOR_ERR_UNSUPPORTED | Input contains CBOR with reserved additional info values | - * | @ref QCBOR_ERR_BAD_TYPE_7 | Simple value encoded as two-byte integer rather than one | - * | @ref QCBOR_ERR_BAD_BREAK | Break occured outside an indefinite-length map or such | - * | @ref QCBOR_ERR_BAD_INT | Length of integer is bad | - * | @ref QCBOR_ERR_INDEFINITE_STRING_CHUNK | One of the chunks in indefinite-length string is the wrong type | - * | __Invalid CBOR__ || - * | @ref QCBOR_ERR_NO_MORE_ITEMS | Need more input data items to decode | - * | @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA | The structure of a big float or big number is invalid | - * | @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT | The content of a tag is of the wrong type | - * | __Implementation Limits__ || - * | @ref QCBOR_ERR_INT_OVERFLOW | Input integer smaller than INT64_MIN | - * | @ref QCBOR_ERR_ARRAY_DECODE_TOO_LONG | Array or map has more elements than can be handled | - * | @ref QCBOR_ERR_DATE_OVERFLOW | Date larger than can be handled | - * | @ref QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP | Nesting deeper than can be handled | - * | @ref QCBOR_ERR_STRING_TOO_LONG | Encountered a string longer than size_t can hold less 4 bytes | - * | @ref QCBOR_ERR_TOO_MANY_TAGS | Tag nesting deeper than limit, typically 4 | - * | __Configuration errors__ || - * | @ref QCBOR_ERR_NO_STRING_ALLOCATOR | Encountered indefinite-length string with no allocator configured | - * | @ref QCBOR_ERR_MAP_LABEL_TYPE | A map label that is not a string on an integer | - * | @ref QCBOR_ERR_HALF_PRECISION_DISABLED | Half-precision input, but disabled in QCBOR library | - * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Indefinite-length input, but disabled in QCBOR library | - * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Indefinite-length input, but disabled in QCBOR library | - * | @ref QCBOR_ERR_ALL_FLOAT_DISABLED | Library compiled with floating-point support turned off. | - * | __Resource exhaustion errors__ || - * | @ref QCBOR_ERR_STRING_ALLOCATE | The string allocator is unable to allocate more memory | - */ -void -QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - * @brief Preorder traversal like QCBORDecode_VGetNext() without use - * of internal error state. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem The decoded CBOR item. - * - * @return See error table of decoding errors set by QCBORDecode_VGetNext(). - * - * This is the same as QCBORDecode_VGetNext() except it - * doesn't set the internal decoding error and will attempt to decode - * even if the decoder is in the error state. - */ -QCBORError -QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - * @brief Get the next item, fully consuming it if it is a map or array. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem The decoded CBOR item. - * - * @c pItem returned is the same as QCBORDecode_VGetNext(). If the - * item is an array or map, the entire contents of the array or map - * will be consumed leaving the cursor after the array or map. - * - * If an array or map is being consumed by this, an error will occur - * if any of the items in the array or map are in error. - * - * If the item is a tag the contents of which is an array or map, like - * a big float, @c pItem will identify it as such and the contents - * will be consumed, but the validity of the tag won't be checked - * other than for being well-formed. - * - * In order to go back to decode the contents of an array or map - * consumed by this, the decoder must be rewound using - * QCBORDecode_Rewind(). - */ -void -QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - * @brief Get the next data item without consuming it. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem The decoded CBOR item. - * - * This is the same as QCBORDecode_VGetNext() but does not consume the - * data item. This only looks ahead one item. Calling it repeatedly - * will just return the same item over and over. - * - * This uses about 200 bytes of stack, far more than anything else - * here in qcbor_decode.h because it saves a copy of most of the - * decode context temporarily. - * - * This is useful for looking ahead to determine the type of a data - * item to know which type-specific spiffy decode function to call or - * decoding protocols where the types of later data items - * depending on type of earlier ones. - * - * The error must be retrieved with QCBORDecode_GetError() and checked - * to know the peek was successful before referencing the contents of - * @c pDecodedItem. - */ -void -QCBORDecode_VPeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - * @brief Get the next data item without consuming it without use - * of internal error state. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem The decoded CBOR item. - * - * This is the same as QCBORDecode_VPeekNext() except it doesn't set - * the internal decoding error and will attempt to decode even if the - * decoder is in the error state. - */ -QCBORError -QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - * @brief Get the current traversal cursort offset in the input CBOR. - * - * @param[in] pCtx The decoder context. - * - * @returns The traversal cursor offset or @c UINT32_MAX. - - * The position returned is always the start of the next item that - * would be next decoded with QCBORDecode_VGetNext(). The cursor - * returned may be at the end of the input in which case the next call - * to QCBORDecode_VGetNext() will result in the @ref - * QCBOR_ERR_NO_MORE_ITEMS. See also QCBORDecode_AtEnd(). - * - * If the decoder is in error state from previous decoding, - * @c UINT32_MAX is returned. - * - * When decoding map items, the position returned is always of the - * label, never the value. - * - * For indefinite-length arrays and maps, the break byte is consumed - * when the last item in the array or map is consumed so the cursor is - * at the next item to be decoded as expected. - * - * There are some special rules for the traversal cursor when fetching - * map items by label. See the description of @ref SpiffyDecode. - * - * When traversal is bounded because an array or map has been entered - * (e.g., QCBORDecode_EnterMap()) and all items in the array or map - * have been consumed, the position returned will be of the item - * outside of the array or map. The array or map must be exited before - * QCBORDecode_VGetNext() will decode it. - * - * In many cases the position returned will be in the middle of - * an array or map. It will not be possible to start decoding at - * that location with another instance of the decoder and go to - * the end. It is not valid CBOR. If the input is a CBOR sequence - * and the position is not in the moddle of an array or map - * then it is possible to decode to the end. - * - * There is no corresponding seek method because it is too complicated - * to restore the internal decoder state that tracks nesting. - */ -static uint32_t -QCBORDecode_Tell(QCBORDecodeContext *pCtx); - - -/** - * @brief Tell whether cursor is at end of the input. - * - * @param[in] pCtx The decoder context. - * - * @returns Error code possibly indicating end of input. - * - * This returns the same as QCBORDecode_GetError() except that @ref - * QCBOR_ERR_NO_MORE_ITEMS is returned if the travseral cursor is at - * the end of the CBOR input bytes (not the end of an entered array or - * map). - */ -QCBORError -QCBORDecode_EndCheck(QCBORDecodeContext *pCtx); - - -/** - * @brief Returns the tag numbers for an item. - * - * @param[in] pCtx The decoder context. - * @param[in] pItem The CBOR item to get the tag for. - * @param[in] uIndex The index of the tag to get. - * - * @returns The nth tag number or CBOR_TAG_INVALID64. - * - * When QCBOR decodes an item that is a tag, it will fully decode tags - * it is able to. Tags that it is unable to process are put in a list - * in the QCBORItem. - * - * Tags nest. Here the tag with index 0 has the data item as its content. The - * tag with index 1 has the tag at index 0 has its content and so forth. - * - * Deep tag nesting is rare so this implementation imposes a limit of - * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref - * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this - * implementation, not of CBOR. (To be able to handle deeper - * nesting, the constant can be increased and the library - * recompiled. It will use more memory). - * - * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. - * - * To reduce memory used by a QCBORItem, tag numbers larger than - * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be - * accessed with this function rather than directly. - * - * This returns @ref CBOR_TAG_INVALID64 if any error occurred when - * getting the item. This is also returned if there are no tags on the - * item or no tag at @c uIndex. - */ -uint64_t -QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); - - -/** - * @brief Returns the tag numbers for last-decoded item. - * - * @param[in] pCtx The decoder context. - * @param[in] uIndex The index of the tag to get. - * - * @returns The nth tag number or CBOR_TAG_INVALID64. - * - * This returns tags of the most recently decoded item. See - * QCBORDecode_GetNthTag(). This is particularly of use for spiffy - * decode functions that don't return a @ref QCBORItem. - * - * This does not work for QCBORDecode_GetNext(), - * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or - * QCBORDecode_VGetNextConsume() but these all return a - * @ref QCBORItem, so it is not necessary. - * - * If a decoding error is set, then this returns CBOR_TAG_INVALID64. - */ -uint64_t -QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); - - -/** - * @brief Check that a decode completed successfully. - * - * @param[in] pCtx The context to check. - * - * @returns The internal tracked decode error or @ref QCBOR_SUCCESS. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * This should always be called at the end of a decode to determine if - * it completed successfully. For some protocols, checking the return - * value here may be the only error check necessary. - * - * This returns the internal tracked error if the decoder is in the - * error state, the same one returned by QCBORDecode_GetError(). This - * performs final checks at the end of the decode, and may also return - * @ref QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN - * or @ref QCBOR_ERR_EXTRA_BYTES. - * - * This calls the destructor for the string allocator, if one is in - * use. Because of this, It can't be called multiple times like - * QCBORDecode_PartialFinish(). - * - * Some CBOR protocols use a CBOR sequence defined in [RFC 8742] - * (https://tools.ietf.org/html/rfc8742). A CBOR sequence typically - * doesn't start out with a map or an array. The end of the CBOR is - * determined in some other way, perhaps by external framing, or by - * the occurrence of some particular CBOR data item or such. The - * buffer given to decode must start out with valid CBOR, but it can - * have extra bytes at the end that are not CBOR or CBOR that is to be - * ignored. - * - * QCBORDecode_Finish() should still be called when decoding CBOR - * sequences to check that the input decoded was well-formed. If the - * input was well-formed and there are extra bytes at the end @ref - * QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a - * successful decode. See also QCBORDecode_PartialFinish(). - */ -QCBORError -QCBORDecode_Finish(QCBORDecodeContext *pCtx); - - -/** - * @brief Return number of bytes consumed so far. - * - * @param[in] pCtx The context to check. - * @param[out] puConsumed The number of bytes consumed so far. - * May be @c NULL. - * - * @returns The same as QCBORDecode_Finish(); - * - * This is primarily for partially decoding CBOR sequences. It is the - * same as QCBORDecode_Finish() except it returns the number of bytes - * consumed and doesn't call the destructor for the string allocator - * (See @ref QCBORDecode_SetMemPool()). - * - * When this is called before all input bytes are consumed, @ref - * QCBOR_ERR_EXTRA_BYTES will be returned as QCBORDecode_Finish() - * does. For typical use of this, that particular error is disregarded. - * - * Decoding with the same @ref QCBORDecodeContext can continue after - * calling this and this may be called many times. - * - * Another way to resume decoding is to call QCBORDecode_Init() with the - * bytes not decoded, but this only works on CBOR sequences when the - * decoding stopped with no open arrays, maps or byte strings. - */ -QCBORError -QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed); - - -/** - * @brief Retrieve the undecoded input buffer. - * - * @param[in] pCtx The decode context. - * - * @return The input that was given to QCBORDecode_Init(). - * - * A simple convenience method, should it be useful to get the original input back. - */ -static UsefulBufC -QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pCtx); - - -/** - * @brief Get the decoding error. - * - * @param[in] pCtx The decoder context. - * @return The decoding error. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * The returns the tracked internal error code. All decoding functions - * set the internal error except QCBORDecode_GetNext() and - * QCBORDecode_PeekNext(). - * - * For many protocols it is only necessary to check the return code - * from QCBORDecode_Finish() at the end of all the decoding. It is - * unnecessary to call this. - * - * For some protocols, the decoding sequence depends on the types, - * values or labels of data items. If so, this must be called before - * using decoded values to know the decode was a success and the - * type, value and label is valid. - * - * Some errors, like integer conversion overflow, date string format - * may not affect the flow of a protocol. The protocol decoder may - * wish to proceed even if they occur. In that case - * QCBORDecode_GetAndResetError() may be called after these data items - * are fetched. - */ -static QCBORError -QCBORDecode_GetError(QCBORDecodeContext *pCtx); - - -/** - * @brief Get and reset the decoding error. - * - * @param[in] pCtx The decoder context. - * @returns The decoding error. - * - * This returns the same as QCBORDecode_GetError() and also resets the - * error state to @ref QCBOR_SUCCESS. - */ -static QCBORError -QCBORDecode_GetAndResetError(QCBORDecodeContext *pCtx); - - -/** - * @brief Whether an error indicates non-well-formed CBOR. - * - * @param[in] uErr The QCBOR error code. - * @return @c true if the error code indicates non-well-formed CBOR. - */ -static bool -QCBORDecode_IsNotWellFormedError(QCBORError uErr); - - -/** - * @brief Whether a decoding error is recoverable. - * - * @param[in] uErr The QCBOR error code. - * @return @c true if the error code indicates and uncrecoverable error. - * - * When an error is unrecoverable, no further decoding of the input is - * possible. CBOR is a compact format with almost no redundancy so - * errors like incorrect lengths or array counts are - * unrecoverable. Unrecoverable errors also occur when implementation - * limits such as the limit on array and map nesting are encountered. - * When the built-in decoding of a tag like an epoch date encounters - * an error such as a data item of an unexpected type, this is also an - * unrecoverable error because the internal decoding doesn't try to - * decode everything in the tag. - * - * The unrecoverable errors are a range of the errors in - * @ref QCBORError. - */ -static bool -QCBORDecode_IsUnrecoverableError(QCBORError uErr); - - -/** - * @brief Manually set error condition, or set user-defined error. - * - * @param[in] pCtx The decoder context. - * @param[in] uError The error code to set. - * - * Once set, none of the QCBORDecode methods will do anything and the - * error code set will stay until cleared with - * QCBORDecode_GetAndResetError(). A user-defined error can be set - * deep in some decoding layers to short-circuit further decoding - * and propagate up. - * - * When the error condition is set, QCBORDecode_VGetNext() will always - * return an item with data and label type as @ref QCBOR_TYPE_NONE. - * - * The main intent of this is to set a user-defined error code in the - * range of @ref QCBOR_ERR_FIRST_USER_DEFINED to - * @ref QCBOR_ERR_LAST_USER_DEFINED, but it is OK to set QCBOR-defined - * error codes too. - */ -static void -QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError); - - - - -/** - * @brief Convert int64_t to smaller integers safely. - * - * @param [in] src An @c int64_t. - * @param [out] dest A smaller sized integer to convert to. - * - * @return 0 on success -1 if not - * - * When decoding an integer, the CBOR decoder will return the value as - * an int64_t unless the integer is in the range of @c INT64_MAX and - * @c UINT64_MAX. That is, unless the value is so large that it can only be - * represented as a @c uint64_t, it will be an @c int64_t. - * - * CBOR itself doesn't size the individual integers it carries at - * all. The only limits it puts on the major integer types is that they - * are 8 bytes or less in length. Then encoders like this one use the - * smallest number of 1, 2, 4 or 8 bytes to represent the integer based - * on its value. There is thus no notion that one data item in CBOR is - * a 1-byte integer and another is a 4-byte integer. - * - * The interface to this CBOR encoder only uses 64-bit integers. Some - * CBOR protocols or implementations of CBOR protocols may not want to - * work with something smaller than a 64-bit integer. Perhaps an array - * of 1,000 integers needs to be sent and none has a value larger than - * 50,000 and are represented as @c uint16_t. - * - * The sending / encoding side is easy. Integers are temporarily widened - * to 64-bits as a parameter passing through QCBOREncode_AddInt64() and - * encoded in the smallest way possible for their value, possibly in - * less than an @c uint16_t. - * - * On the decoding side the integers will be returned at @c int64_t even if - * they are small and were represented by only 1 or 2 bytes in the - * encoded CBOR. The functions here will convert integers to a small - * representation with an overflow check. - * - * (The decoder could have support 8 different integer types and - * represented the integer with the smallest type automatically, but - * this would have made the decoder more complex and code calling the - * decoder more complex in most use cases. In most use cases on 64-bit - * machines it is no burden to carry around even small integers as - * 64-bit values). - */ -static inline int -QCBOR_Int64ToInt32(int64_t src, int32_t *dest) -{ - if(src > INT32_MAX || src < INT32_MIN) { - return -1; - } else { - *dest = (int32_t) src; - } - return 0; -} - -static inline int -QCBOR_Int64ToInt16(int64_t src, int16_t *dest) -{ - if(src > INT16_MAX || src < INT16_MIN) { - return -1; - } else { - *dest = (int16_t) src; - } - return 0; -} - -static inline int -QCBOR_Int64ToInt8(int64_t src, int8_t *dest) -{ - if(src > INT8_MAX || src < INT8_MIN) { - return -1; - } else { - *dest = (int8_t) src; - } - return 0; -} - -static inline int -QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) -{ - if(src > UINT32_MAX || src < 0) { - return -1; - } else { - *dest = (uint32_t) src; - } - return 0; -} - -/** - * https://github.com/laurencelundblade/QCBOR/pull/243 - * For backwards compatibility - */ -#define QCBOR_Int64UToInt16 QCBOR_Int64ToUInt16 - -static inline int -QCBOR_Int64ToUInt16(int64_t src, uint16_t *dest) -{ - if(src > UINT16_MAX || src < 0) { - return -1; - } else { - *dest = (uint16_t) src; - } - return 0; -} - -static inline int -QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) -{ - if(src > UINT8_MAX || src < 0) { - return -1; - } else { - *dest = (uint8_t) src; - } - return 0; -} - -static inline int -QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) -{ - if(src < 0) { - return -1; - } else { - *dest = (uint64_t) src; - } - return 0; -} - - - - -/* ========================================================================= * - * BEGINNING OF DEPRECATED FUNCTIONS * - * * - * There is no plan to remove these in future versions. * - * They just have been replaced by something better. * - * ========================================================================= */ - -/** - * Deprecated -- Tag handling has been revised and this is no longer - * used. See QCBORDecode_GetNthTag() for new tag handling. - */ -typedef struct { - uint8_t uNumTags; - const uint64_t *puTags; -} QCBORTagListIn; - - -/** - * Deprecated -- this is retained only for backwards compatibility. - * Use QCBORDecode_GetNthTag() instead. - * - * This is for QCBORDecode_GetNextWithTags() to be able to return the - * full list of tags on an item. - * - * On input, @c puTags points to a buffer to be filled in and - * uNumAllocated is the number of @c uint64_t values in the buffer. - * - * On output the buffer contains the tags for the item. @c uNumUsed - * tells how many there are. - */ -typedef struct { - uint8_t uNumUsed; - uint8_t uNumAllocated; - uint64_t *puTags; -} QCBORTagListOut; - - -/** - * @brief Deprecated -- Configure list of caller-selected tags to be recognized. - * - * @param[in] pCtx The decode context. - * @param[out] pTagList Structure holding the list of tags to configure. - * - * Tag handling has been revised and it is no longer ncessary to use - * this. See QCBORDecode_GetNthTag(). - */ -void -QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, - const QCBORTagListIn *pTagList); - - -/** - * @brief Deprecated -- Determine if a CBOR item is a particular tag. - * - * @param[in] pCtx The decoder context. - * @param[in] pItem The CBOR item to check. - * @param[in] uTag The tag to check, one of @c CBOR_TAG_XXX, - * for example, @ref CBOR_TAG_DATE_STRING. - * - * @return true if it was tagged, false if not. - * - * See QCBORDecode_GetNext() for the main description of tag - * handling. For tags that are not fully decoded a bit corresponding - * to the tag is set in in @c uTagBits in the @ref QCBORItem. The - * particular bit depends on an internal mapping table. This function - * checks for set bits against the mapping table. - * - * Typically, a protocol implementation just wants to know if a - * particular tag is present. That is what this provides. To get the - * full list of tags on a data item, see - * QCBORDecode_GetNextWithTags(). - * - * Also see QCBORDecode_SetCallerConfiguredTagList() for the means to - * add new tags to the internal list so they can be checked for with - * this function. - */ -bool -QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, - const QCBORItem *pItem, - uint64_t uTag); - - -/** - * @brief Deprecated -- Gets the next item including full list of tags for item. - * - * @param[in] pCtx The decoder context. - * @param[out] pDecodedItem Holds the CBOR item just decoded. - * @param[in,out] pTagList On input array to put tags in; on output - * the tags on this item. See - * @ref QCBORTagListOut. - * - * @return See return values for QCBORDecode_GetNext(). - * - * @retval QCBOR_ERR_TOO_MANY_TAGS The size of @c pTagList is too small. - * - * This is retained for backwards compatibility. It is replaced by - * QCBORDecode_GetNthTag() which also returns all the tags that have - * been decoded. - * - * This is not backwards compatibile in two ways. First, it is limited - * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was - * unlimited. Second, it will not inlucde the tags that QCBOR decodes - * internally. - * - * This works the same as QCBORDecode_GetNext() except that it also - * returns the list of tags for the data item in @c pTagList. - * - * The 0th tag returned here is the one furthest from the data - * item. This is opposite the order for QCBORDecode_GetNthTag(). - * - * CBOR has no upper bound or limit on the number of tags that can be - * associated with a data item but in practice the number of tags on - * an item will usually be small. This will return @ref - * QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is too small to - * hold all the tags for the item. - */ -QCBORError -QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, - QCBORItem *pDecodedItem, - QCBORTagListOut *pTagList); - - -/* ========================================================================= * - * END OF DEPRECATED FUNCTIONS * - * ========================================================================= */ - - - - -/* ========================================================================= * - * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * - * ========================================================================= */ - -static inline uint32_t -QCBORDecode_Tell(QCBORDecodeContext *pMe) -{ - if(pMe->uLastError) { - return UINT32_MAX; - } - - /* Cast is safe because decoder input size is restricted. */ - return (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf)); -} - -static inline UsefulBufC -QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pMe) -{ - return UsefulInputBuf_RetrieveUndecodedInput(&(pMe->InBuf)); -} - -static inline QCBORError -QCBORDecode_GetError(QCBORDecodeContext *pMe) -{ - return (QCBORError)pMe->uLastError; -} - -static inline QCBORError -QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe) -{ - const QCBORError uReturn = (QCBORError)pMe->uLastError; - pMe->uLastError = QCBOR_SUCCESS; - return uReturn; -} - -static inline bool -QCBORDecode_IsNotWellFormedError(const QCBORError uErr) -{ - if(uErr >= QCBOR_START_OF_NOT_WELL_FORMED_ERRORS && - uErr <= QCBOR_END_OF_NOT_WELL_FORMED_ERRORS) { - return true; - } else { - return false; - } -} - -static inline bool -QCBORDecode_IsUnrecoverableError(const QCBORError uErr) -{ - if(uErr >= QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS && - uErr <= QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS) { - return true; - } else { - return false; - } -} - - -static inline void -QCBORDecode_SetError(QCBORDecodeContext *pMe, QCBORError uError) -{ - pMe->uLastError = (uint8_t)uError; -} - -/* ======================================================================== * - * END OF PRIVATE INLINE IMPLEMENTATION * - * ======================================================================== */ - - -/* A few cross checks on size constants and special value lengths */ -#if QCBOR_MAP_OFFSET_CACHE_INVALID < QCBOR_MAX_DECODE_INPUT_SIZE -#error QCBOR_MAP_OFFSET_CACHE_INVALID is too large -#endif - -#if QCBOR_NON_BOUNDED_OFFSET < QCBOR_MAX_DECODE_INPUT_SIZE -#error QCBOR_NON_BOUNDED_OFFSET is too large -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* qcbor_decode_h */ diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_encode.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor_encode.h deleted file mode 100644 index c25d7112f075..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_encode.h +++ /dev/null @@ -1,4386 +0,0 @@ -/* =========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2025, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - - -#ifndef qcbor_encode_h -#define qcbor_encode_h - - -#include "qcbor/qcbor_common.h" -#include "qcbor/qcbor_private.h" -#include - - -#ifdef __cplusplus -extern "C" { -#if 0 -} // Keep editor indention formatting happy -#endif -#endif - - -/** - * @file qcbor_encode.h - * - * @anchor Overview - * - * # QCBOR Overview - * - * This implements CBOR -- Concise Binary Object Representation as - * defined in [RFC 8949] (https://www.rfc-editor.org/rfc/rfc8949.html). - * More information is at http://cbor.io. This is a near-complete - * implementation of the specification. [RFC 8742] - * (https://www.rfc-editor.org/rfc/rfc8742.html) CBOR Sequences is - * also supported. Limitations are listed further down. - * - * See @ref Encoding for general discussion on encoding, - * @ref BasicDecode for general discussion on the basic decode features - * and @ref SpiffyDecode for general discussion on the easier-to-use - * decoder functions. - * - * CBOR is intentionally designed to be translatable to JSON, but not - * all CBOR can convert to JSON. See RFC 8949 for more info on how to - * construct CBOR that is the most JSON friendly. - * - * The memory model for encoding and decoding is that encoded CBOR must - * be in a contiguous buffer in memory. During encoding the caller must - * supply an output buffer and if the encoding would go off the end of - * the buffer an error is returned. During decoding the caller supplies - * the encoded CBOR in a contiguous buffer and the decoder returns - * pointers and lengths into that buffer for strings. - * - * This implementation does not require malloc. All data structures - * passed in/out of the APIs can fit on the stack. - * - * Decoding of indefinite-length strings is a special case that requires - * a "string allocator" to allocate memory into which the segments of - * the string are coalesced. Without this, decoding will error out if an - * indefinite-length string is encountered (indefinite-length maps and - * arrays do not require the string allocator). A simple string - * allocator called MemPool is built-in and will work if supplied with a - * block of memory to allocate. The string allocator can optionally use - * malloc() or some other custom scheme. - * - * Here are some terms and definitions: - * - * - "Item", "Data Item": An integer or string or such. The basic "thing" that - * CBOR is about. An array is an item itself that contains some items. - * - * - "Array": An ordered sequence of items, the same as JSON. - * - * - "Map": A collection of label/value pairs. Each pair is a data - * item. A JSON "object" is the same as a CBOR "map". - * - * - "Label": The data item in a pair in a map that names or identifies - * the pair, not the value. This implementation refers to it as a - * "label". JSON refers to it as the "name". The CBOR RFC refers to it - * this as a "key". This implementation chooses label instead because - * key is too easily confused with a cryptographic key. The COSE - * standard, which uses CBOR, has also chosen to use the term "label" - * rather than "key" for this same reason. - * - * - "Key": See "Label" above. - * - * - "Tag": A data item that is an explicitly labeled new data - * type made up of the tagging integer and the tag content. - * See @ref Tags-Overview and @ref Tag-Usage. - * - * - "Initial Byte": The first byte of an encoded item. Encoding and - * decoding of this byte is taken care of by the implementation. - * - * - "Additional Info": In addition to the major type, all data items - * have some other info. This is usually the length of the data but can - * be several other things. Encoding and decoding of this is taken care - * of by the implementation. - * - * CBOR has two mechanisms for tagging and labeling the data values like - * integers and strings. For example, an integer that represents - * someone's birthday in epoch seconds since Jan 1, 1970 could be - * encoded like this: - * - * - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64), - * the primitive positive integer. - * - * - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer - * represents a date in the form of the number of seconds since Jan 1, - * 1970. - * - * - Last it has a string "label" like "BirthDate" indicating the - * meaning of the data. - * - * The encoded binary looks like this: - * - * a1 # Map of 1 item - * 69 # Indicates text string of 9 bytes - * 426972746844617465 # The text "BirthDate" - * c1 # Tags next integer as epoch date - * 1a # Indicates a 4-byte integer - * 580d4172 # unsigned integer date 1477263730 - * - * Implementors using this API will primarily work with - * labels. Generally, tags are only needed for making up new data - * types. This implementation covers most of the data types defined in - * the RFC using tags. It also, allows for the use of custom tags if - * necessary. - * - * This implementation explicitly supports labels that are text strings - * and integers. Text strings translate nicely into JSON objects and are - * very readable. Integer labels are much less readable but can be very - * compact. If they are in the range of 0 to 23, they take up only one - * byte. - * - * CBOR allows a label to be any type of data including an array or a - * map. It is possible to use this API to construct and parse such - * labels, but it is not explicitly supported. - * - * @anchor Encoding - * - * ## Encoding - * - * A common encoding usage mode is to invoke the encoding twice. First - * with the output buffer as @ref SizeCalculateUsefulBuf to compute the - * length of the needed output buffer. The correct sized output buffer - * is allocated. The encoder is invoked a second time with the allocated - * output buffer. - * - * The double invocation is not required if the maximum output buffer - * size can be predicted. This is usually possible for simple CBOR - * structures. - * - * If a buffer too small to hold the encoded output is given, the error - * @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be - * written off the end of the output buffer no matter which functions - * here are called or what parameters are passed to them. - * - * The encoding error handling is simple. The only possible errors are - * trying to encode structures that are too large or too complex. There - * are no internal malloc calls so there will be no failures for out of - * memory. The error state is tracked internally, so there is no need - * to check for errors when encoding. Only the return code from - * QCBOREncode_Finish() need be checked as once an error happens, the - * encoder goes into an error state and calls to it to add more data - * will do nothing. An error check is not needed after every data item - * is added. - * - * Encoding generally proceeds by calling QCBOREncode_Init(), calling - * lots of @c QCBOREncode_AddXxx() functions and calling - * QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx() - * functions for various data types. The input buffers need only to be - * valid during the @c QCBOREncode_AddXxx() calls as the data is copied - * into the output buffer. - * - * There are three `Add` functions for each data type. The first / main - * one for the type is for adding the data item to an array. The second - * one's name ends in `ToMap`, is used for adding data items to maps and - * takes a string argument that is its label in the map. The third one - * ends in `ToMapN`, is also used for adding data items to maps, and - * takes an integer argument that is its label in the map. - * - * The simplest aggregate type is an array, which is a simple ordered - * set of items without labels the same as JSON arrays. Call - * QCBOREncode_OpenArray() to open a new array, then various @c - * QCBOREncode_AddXxx() functions to put items in the array and then - * QCBOREncode_CloseArray(). Nesting to the limit @ref - * QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by - * closes or an encoding error will be returned. - * - * The other aggregate type is a map which does use labels. The `Add` - * functions that end in `ToMap` and `ToMapN` are convenient ways to add - * labeled data items to a map. You can also call any type of `Add` - * function once to add a label of any type and then call any type of - * `Add` again to add its value. - * - * Note that when you nest arrays or maps in a map, the nested array or - * map has a label. - * - * Many CBOR-based protocols start with an array or map. This makes - * them self-delimiting. No external length or end marker is needed to - * know the end. It is also possible not start this way, in which case - * this it is usually called a CBOR sequence which is described in - * [RFC 8742] (https://www.rfc-editor.org/rfc/rfc8742.html). This - * encoder supports either just by whether the first item added is an - * array, map or other. - * - * If QCBOR is compiled with QCBOR_DISABLE_ENCODE_USAGE_GUARDS defined, - * the errors QCBOR_ERR_CLOSE_MISMATCH, QCBOR_ERR_ARRAY_TOO_LONG, - * QCBOR_ERR_TOO_MANY_CLOSES, QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, and - * QCBOR_ERR_ENCODE_UNSUPPORTED will never be returned. It is up to the - * caller to make sure that opened maps, arrays and byte-string wrapping - * is closed correctly and that QCBOREncode_AddType7() is called - * correctly. With this defined, it is easier to make a mistake when - * authoring the encoding of a protocol that will output not well formed - * CBOR, but as long as the calling code is correct, it is safe to - * disable these checks. Bounds checking that prevents security issues - * in the code is still enforced. This define reduces the size of - * encoding object code by about 150 bytes. - * - * @anchor Tags-Overview - * - * ## Tags Overview - * - * Any CBOR data item can be made into a tag to add semantics, define a - * new data type or such. Some tags are fully standardized and some are - * just registered. Others are not registered and used in a proprietary - * way. - * - * Encoding and decoding of many of the registered tags is fully - * implemented by QCBOR. It is also possible to encode and decode tags - * that are not directly supported. For many use cases the built-in tag - * support should be adequate. - * - * For example, the registered epoch date tag is supported in encoding - * by QCBOREncode_AddTDateEpoch() and in decoding by @ref - * QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref - * QCBORItem. This is typical of the built-in tag support. There is an - * API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded. - * - * Tags are registered in the [IANA CBOR Tags Registry] - * (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There - * are roughly three options to create a new tag. First, a public - * specification can be created and the new tag registered with IANA. - * This is the most formal. Second, the new tag can be registered with - * IANA with just a short description rather than a full specification. - * These tags must be greater than 256. Third, a tag can be used without - * any IANA registration, though the registry should be checked to see - * that the new value doesn't collide with one that is registered. The - * value of these tags must be 256 or larger. - * - * See also @ref CBORTags and @ref Tag-Usage - * - * The encoding side of tags not built-in is handled by - * QCBOREncode_AddTag() and is relatively simple. Tag decoding is more - * complex and mainly handled by QCBORDecode_GetNext(). Decoding of the - * structure of tagged data not built-in (if there is any) has to be - * implemented by the caller. - * - * @anchor Floating-Point - * - * ## Floating-Point - * - * By default QCBOR fully supports IEEE 754 floating-point: - * - Encode/decode of double, single and half-precision - * - CBOR preferred serialization of floating-point - * - Floating-point epoch dates - * - * For the most part, the type double is used in the interface for - * floating-point values. In the default configuration, all decoded - * floating-point values are returned as a double. - * - * With CBOR preferred serialization, the encoder outputs the smallest - * representation of the double or float that preserves precision. Zero, - * NaN and infinity are always output as a half-precision, each taking - * just 2 bytes. This reduces the number of bytes needed to encode - * double and single-precision, especially if zero, NaN and infinity are - * frequently used. - * - * To avoid use of preferred serialization in the standard configuration - * when encoding, use QCBOREncode_AddDoubleNoPreferred() or - * QCBOREncode_AddFloatNoPreferred(). - * - * This implementation of preferred floating-point serialization and - * half-precision does not depend on the CPU having floating-point HW or - * the compiler bringing in a (sometimes large) library to compensate - * for lack of CPU support. This implementation uses shifts and masks - * rather than floating-point functions. - * - * To reduce overall object code by about 900 bytes, define - * QCBOR_DISABLE_PREFERRED_FLOAT. This will eliminate all support for - * preferred serialization and half-precision. An error will be returned - * when attempting to decode half-precision. A float will always be - * encoded and decoded as 32-bits and a double will always be encoded - * and decoded as 64 bits. - * - * Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all - * the float-point encoding object code can be avoided by never calling - * any functions that encode double or float. Just not calling - * floating-point functions will reduce object code by about 500 bytes. - * - * On CPUs that have no floating-point hardware, - * QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is - * not, then the compiler will bring in possibly large software - * libraries to compensate. Defining QCBOR_DISABLE_FLOAT_HW_USE reduces - * object code size on CPUs with floating-point hardware by a tiny - * amount and eliminates the need for - * - * When QCBOR_DISABLE_FLOAT_HW_USE is defined, trying to decoding - * floating-point dates will give error - * @ref QCBOR_ERR_FLOAT_DATE_DISABLED and decoded single-precision - * numbers will be returned as @ref QCBOR_TYPE_FLOAT instead of - * converting them to double as usual. - * - * If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - * are defined, then the only thing QCBOR can do is encode/decode a C - * float type as 32-bits and a C double type as 64-bits. Floating-point - * epoch dates will be unsupported. - * - * If USEFULBUF_DISABLE_ALL_FLOAT is defined, then floating point - * support is completely disabled. Decoding functions return - * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is - * encountered during decoding. Functions that are encoding floating - * point values are not available. - * - * @anchor Limitations - * - * ## Limitations - * - * Summary limitations: - * - The entire encoded CBOR must fit into contiguous memory. - * - Max size of encoded CBOR data is a few bytes less than - * @c UINT32_MAX (4GB). - * - Max array / map nesting level when encoding or decoding is - * @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15). - * - Max items in an array or map when encoding or decoding is - * @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). - * - Does not directly support labels in maps other than text strings & integers. - * - Does not directly support integer labels beyond whats fits in @c int64_t - * or @c uint64_t. - * - Epoch dates limited to @c INT64_MAX (+/- 292 billion years). - * - Exponents for bigfloats and decimal integers are limited to whats fits in - * @c int64_t. - * - Tags on labels are ignored during decoding. - * - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4). - * - Works only on 32- and 64-bit CPUs. - * - QCBORDecode_EnterBstrWrapped() doesn't work on indefinite-length strings. - * - Numeric reduction of big numbers to integers for preferred - * serialization is not performed. - * - * The public interface uses @c size_t for all lengths. Internally the - * implementation uses 32-bit lengths by design to use less memory and - * fit structures on the stack. This limits the encoded CBOR it can - * work with to size @c UINT32_MAX (4GB). - * - * This implementation requires two's compliment integers. While - * C doesn't require two's compliment, does. Other - * parts of this implementation may also require two's compliment. - */ - - -/** - * The size of the buffer to be passed to QCBOREncode_EncodeHead(). It - * is one byte larger than sizeof(uint64_t) + 1, the actual maximum - * size of the head of a CBOR data item because - * QCBOREncode_EncodeHead() needs one extra byte to work. - */ -#define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2) - - -/** - * Output the full CBOR tag. See @ref CBORTags, @ref Tag-Usage and - * @ref Tags-Overview. - */ -#define QCBOR_ENCODE_AS_TAG 0 - -/** - * Output only the 'borrowed' content format for the relevant tag. - * See @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. - */ -#define QCBOR_ENCODE_AS_BORROWED 1 - - -/** - * QCBOREncodeContext is the data type that holds context for all the - * encoding functions. It is less than 200 bytes, so it can go on the - * stack. The contents are opaque, and the caller should not access - * internal members. A context may be re used serially as long as it is - * re initialized. - */ -typedef struct _QCBOREncodeContext QCBOREncodeContext; - - -/** - * Initialize the encoder. - * - * @param[in,out] pCtx The encoder context to initialize. - * @param[in] Storage The buffer into which the encoded result - * will be written. - * - * Call this once at the start of an encoding of some CBOR. Then call - * the many functions like QCBOREncode_AddInt64() and - * QCBOREncode_AddText() to add the different data items. Finally, - * call QCBOREncode_Finish() to get the pointer and length of the - * encoded result. - * - * The primary purpose of this function is to give the pointer and - * length of the output buffer into which the encoded CBOR will be - * written. This is done with a @ref UsefulBuf structure, which is - * just a pointer and length (it is equivalent to two parameters, one - * a pointer and one a length, but a little prettier). - * - * The output buffer can be allocated any way (malloc, stack, - * static). It is just some memory that QCBOR writes to. The length - * must be the length of the allocated buffer. QCBOR will never write - * past that length, but might write up to that length. If the buffer - * is too small, encoding will go into an error state and not write - * anything further. - * - * If allocating on the stack the convenience macro - * UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required. - * - * Since there is no reallocation or such, the output buffer must be - * correctly sized when passed in here. It is OK, but wasteful if it - * is too large. One way to pick the size is to figure out the maximum - * size that will ever be needed and hard code a buffer of that size. - * - * Another way to do it is to have QCBOR calculate it for you. To do - * this, pass @ref SizeCalculateUsefulBuf for @c Storage. Then call - * all the functions to add the CBOR exactly as if encoding for - * real. Finally, call QCBOREncode_FinishGetSize(). Once the length - * is obtained, allocate a buffer of that size, call - * QCBOREncode_Init() again with the real buffer. Call all the add - * functions again and finally, QCBOREncode_Finish() to obtain the - * final result. This uses twice the CPU time, but that is usually not - * an issue. - * - * See QCBOREncode_Finish() for how the pointer and length for the - * encoded CBOR is returned. - * - * For practical purposes QCBOR can't output encoded CBOR larger than - * @c UINT32_MAX (4GB) even on 64-bit CPUs because the internal - * offsets used to track the start of an array/map are 32 bits to - * reduce the size of the encoding context. - * - * A @ref QCBOREncodeContext can be reused over and over as long as - * QCBOREncode_Init() is called before each use. - */ -void -QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); - - -/** - * @brief Add a signed 64-bit integer to the encoded output. - * - * @param[in] pCtx The encoding context to add the integer to. - * @param[in] nNum The integer to add. - * - * The integer will be encoded and added to the CBOR output. - * - * This function figures out the size and the sign and encodes in the - * correct minimal CBOR. Specifically, it will select CBOR major type - * 0 or 1 based on sign and will encode to 1, 2, 4 or 8 bytes - * depending on the value of the integer. Values less than 24 - * effectively encode to one byte because they are encoded in with the - * CBOR major type. This is a neat and efficient characteristic of - * CBOR that can be taken advantage of when designing CBOR-based - * protocols. If integers like tags can be kept between -23 and 23 - * they will be encoded in one byte including the major type. - * - * If you pass a smaller integer, like @c int16_t or a small value, - * like 100, the encoding will still be CBOR's most compact that can - * represent the value. For example, CBOR always encodes the value 0 - * as one byte, 0x00. The representation as 0x00 includes - * identification of the type as an integer too as the major type for - * an integer is 0. See [RFC 8949 Appendix A] - * (https://www.rfc-editor.org/rfc/rfc8949.html#section-appendix.a) - * for more examples of CBOR encoding. This compact encoding is - * preferred serialization CBOR as per [RFC 8949 section 4.1] - * (https://www.rfc-editor.org/rfc/rfc8949.html#section-4.1) - * - * There are no functions to add @c int16_t or @c int32_t because they - * are not necessary because this always encodes to the smallest - * number of bytes based on the value. - * - * If the encoding context is in an error state, this will do - * nothing. If an error occurs when adding this integer, the internal - * error flag will be set, and the error will be returned when - * QCBOREncode_Finish() is called. - * - * See also QCBOREncode_AddUInt64(). - */ -void -QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); - -static void -QCBOREncode_AddInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); - -static void -QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nNum); - - -/** - * @brief Add an unsigned 64-bit integer to the encoded output. - * - * @param[in] pCtx The encoding context to add the integer to. - * @param[in] uNum The integer to add. - * - * The integer will be encoded and added to the CBOR output. - * - * The only reason so use this function is for integers larger than - * @c INT64_MAX and smaller than @c UINT64_MAX. Otherwise - * QCBOREncode_AddInt64() will work fine. - * - * Error handling is the same as for QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); - -static void -QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); - -static void -QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum); - - -/** - * @brief Add a UTF-8 text string to the encoded output. - * - * @param[in] pCtx The encoding context to add the text to. - * @param[in] Text Pointer and length of text to add. - * - * The text passed in must be unencoded UTF-8 according to - * [RFC 3629] (https://www.rfc-editor.org/rfc/rfc3629.html). There is - * no NULL termination. The text is added as CBOR major type 3. - * - * If called with @c nBytesLen equal to 0, an empty string will be - * added. When @c nBytesLen is 0, @c pBytes may be @c NULL. - * - * Note that the restriction of the buffer length to a @c uint32_t is - * entirely intentional as this encoder is not capable of encoding - * lengths greater. This limit to 4GB for a text string should not be - * a problem. - * - * Text lines in Internet protocols (on the wire) are delimited by - * either a CRLF or just an LF. Officially many protocols specify - * CRLF, but implementations often work with either. CBOR type 3 text - * can be either line ending, even a mixture of both. - * - * Operating systems usually have a line end convention. Windows uses - * CRLF. Linux and MacOS use LF. Some applications on a given OS may - * work with either and some may not. - * - * The majority of use cases and CBOR protocols using type 3 text will - * work with either line ending. However, some use cases or protocols - * may not work with either in which case translation to and/or from - * the local line end convention, typically that of the OS, is - * necessary. - * - * QCBOR does no line ending translation for type 3 text when encoding - * and decoding. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); - -static void -QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - -static void -QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); - - -/** - * @brief Add a UTF-8 text string to the encoded output. - * - * @param[in] pCtx The encoding context to add the text to. - * @param[in] szString Null-terminated text to add. - * - * This works the same as QCBOREncode_AddText(). - */ -static void -QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); - -static void -QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - -static void -QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Add a double-precision floating-point number to the encoded output. - * - * @param[in] pCtx The encoding context to add the double to. - * @param[in] dNum The double-precision number to add. - * - * This encodes and outputs a double-precision floating-point - * number. CBOR major type 7 is used. - * - * This implements preferred serialization, selectively encoding the - * double-precision floating-point number as either double-precision, - * single-precision or half-precision. Infinity, NaN and zero are - * always encoded as half-precision. If no precision will be lost in - * the conversion to half-precision, then it will be converted and - * encoded. If not and no precision will be lost in conversion to - * single-precision, then it will be converted and encoded. If not, - * then no conversion is performed, and it encoded as a - * double-precision. - * - * Half-precision floating-point numbers take up two bytes, half that - * of single-precision, one quarter of double-precision. Preferred - * serialization can therefore reduce message size down to one quarter - * of the original if most of the values are zero, infinity or NaN. - * - * When decoded, QCBOR returns these values as double-precision even - * if they were encoded as single or half-precision. - * - * It is possible to disable preferred serialization when compiling - * QCBOR. In that case, this operates the same as - * QCBOREncode_AddDoubleNoPreferred(). - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat() - * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. - */ -static void -QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); - -static void -QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -static void -QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); - - -/** - * @brief Add a single-precision floating-point number to the encoded output. - * - * @param[in] pCtx The encoding context to add the single to. - * @param[in] fNum The single-precision number to add. - * - * This is identical to QCBOREncode_AddDouble() except the input is - * single-precision. The preferred serialization output will be either - * single-precision or half-precision. - * - * See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(), - * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. - */ -static void -QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum); - -static void -QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); - -static void -QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum); - - -/** - * @brief Add a double-precision floating-point number without preferred encoding. - * - * @param[in] pCtx The encoding context to add the double to. - * @param[in] dNum The double-precision number to add. - * - * This always outputs the number as a 64-bit double-precision. - * Preferred serialization is not used. - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - * QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. - */ -static void -QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum); - -static void -QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -static void -QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); - - -/** - * @brief Add a single-precision floating-point number without preferred encoding. - * - * @param[in] pCtx The encoding context to add the double to. - * @param[in] fNum The single-precision number to add. - * - * This always outputs the number as a 32-bit single-precision. - * Preferred serialization is not used. - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - * QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point. - */ -static void -QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum); - -static void -QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); - -static void -QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum); -#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ - - -/** - * @brief Add a tag number. - * - * @param[in] pCtx The encoding context to add the tag to. - * @param[in] uTag The tag to add - * - * This outputs a CBOR major type 6 item that tags the next data item - * that is output usually to indicate it is some new data type. - * - * For many of the common standard tags, a function to encode data - * using it is provided and this is not needed. For example, - * QCBOREncode_AddTDateEpoch() already exists to output integers - * representing dates with the right tag. - * - * The tag is applied to the next data item added to the encoded - * output. That data item that is to be tagged can be of any major - * CBOR type. Any number of tags can be added to a data item by - * calling this multiple times before the data item is added. - * - * See @ref Tags-Overview for discussion of creating new non-standard - * tags. See QCBORDecode_GetNext() for discussion of decoding custom - * tags. - */ -static void -QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag); - - -/** - * @brief Add an epoch-based date. - * - * @param[in] pCtx The encoding context to add the date to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] nDate Number of seconds since 1970-01-01T00:00Z - * in UTC time. - * - * As per RFC 8949 this is similar to UNIX/Linux/POSIX dates. This is - * the most compact way to specify a date and time in CBOR. Note that - * this is always UTC and does not include the time zone. Use - * QCBOREncode_AddDateString() if you want to include the time zone. - * - * The preferred integer serialization rules apply here so the date will be - * encoded in a minimal number of bytes. Until about the year 2106 - * these dates will encode in 6 bytes -- one byte for the tag, one - * byte for the type and 4 bytes for the integer. After that it will - * encode to 10 bytes. - * - * Negative values are supported for dates before 1970. - * - * If you care about leap-seconds and that level of accuracy, make sure - * the system you are running this code on does it correctly. This code - * just takes the value passed in. - * - * This implementation cannot encode fractional seconds using float or - * double even though that is allowed by CBOR, but you can encode them - * if you want to by calling QCBOREncode_AddTag() and QCBOREncode_AddDouble(). - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddTDaysEpoch(). - */ -static void -QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nDate); - -static void -QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nDate); - -static void -QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nDate); - - - - - -/** - * @brief Add an epoch-based day-count date. - * - * @param[in] pCtx The encoding context to add the date to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] nDays Number of days before or after 1970-01-0. - * - * This date format is described in - * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html). - * - * The preferred integer serialization rules apply here so the date - * will be encoded in a minimal number of bytes. Until about the year - * 2149 these dates will encode in 4 bytes -- one byte for the tag, - * one byte for the type and 2 bytes for the integer. - * - * See also QCBOREncode_AddTDateEpoch(). - */ -static void -QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nDays); - -static void -QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nDays); - -static void -QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nDays); - - - - -/** - * @brief Add a byte string to the encoded output. - * - * @param[in] pCtx The encoding context to add the bytes to. - * @param[in] Bytes Pointer and length of the input data. - * - * Simply adds the bytes to the encoded output as CBOR major type 2. - * - * If called with @c Bytes.len equal to 0, an empty string will be - * added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -static void -QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -static void -QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - - -/** - * @brief Set up to write a byte string value directly to encoded output. - * - * @param[in] pCtx The encoding context to add the bytes to. - * @param[out] pPlace Pointer and length of place to write byte string value. - * - * QCBOREncode_AddBytes() is the normal way to encode a byte string. - * This is for special cases and by passes some of the pointer safety. - * - * The purpose of this is to output the bytes that make up a byte - * string value directly to the QCBOR output buffer so you don't need - * to have a copy of it in memory. This is particularly useful if the - * byte string is large, for example, the encrypted payload of a - * COSE_Encrypt message. The payload encryption algorithm can output - * directly to the encoded CBOR buffer, perhaps by making it the - * output buffer for some function (e.g. symmetric encryption) or by - * multiple writes. - * - * The pointer in @c pPlace is where to start writing. Writing is just - * copying bytes to the location by the pointer in @c pPlace. Writing - * past the length in @c pPlace will be writing off the end of the - * output buffer. - * - * If there is no room in the output buffer @ref NULLUsefulBuf will be - * returned and there is no need to call QCBOREncode_CloseBytes(). - * - * The byte string must be closed by calling QCBOREncode_CloseBytes(). - * - * Warning: this bypasses some of the usual checks provided by QCBOR - * against writing off the end of the encoded output buffer. - */ -void -QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace); - -static void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBuf *pPlace); - -static void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBuf *pPlace); - - -/** - * @brief Close out a byte string written directly to encoded output. - * - * @param[in] pCtx The encoding context to add the bytes to. - * @param[out] uAmount The number of bytes written, the length of the - * byte string. - * - * This closes out a call to QCBOREncode_OpenBytes(). This inserts a - * CBOR header at the front of the byte string value to make it a - * well-formed byte string. - * - * If there was no call to QCBOREncode_OpenBytes() then @ref - * QCBOR_ERR_TOO_MANY_CLOSES is set. - */ -void -QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount); - - -/** - * @brief Add a binary UUID to the encoded output. - * - * @param[in] pCtx The encoding context to add the UUID to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] Bytes Pointer and length of the binary UUID. - * - * A binary UUID as defined in [RFC 4122] - * (https://www.rfc-editor.org/rfc/rfc4122.html) is added to the - * output. - * - * It is output as CBOR major type 2, a binary string, with tag @ref - * CBOR_TAG_BIN_UUID indicating the binary string is a UUID. - */ -static void -QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void -QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void -QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -/** - * @brief Add a positive big number to the encoded output. - * - * @param[in] pCtx The encoding context. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] BigNumber Pointer and length of the big number. - * - * @c BigNumber makes up an aribtrary precision integer in - * network/big-endian byte order. The first byte is the most - * significant. - * - * It is encoded as CBOR major type 2, a binary string, possibly with - * tag @ref CBOR_TAG_POS_BIGNUM. See [RFC 8949 section 3.4.3] - * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No - * processing, such as removal of leading zeros, is perfomed. - * - * RFC 8949 preferred serialization requires big numbers that - * will fit in integers be encoded as integers. That is NOT - * performed. - */ -static void -QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - -static void -QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - -static void -QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - - -/** - * @brief Add a negative big number to the encoded output. - * - * @param[in] pCtx The encoding context. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] BigNumber Pointer and length of the big number. - * - * @c BigNumber makes up an aribtrary precision integer in - * network/big-endian byte order. The first byte is the most - * significant. - * - * It is encoded as CBOR major type 2, a binary string, possibly with - * tag @ref CBOR_TAG_NEG_BIGNUM. See [RFC 8949 section 3.4.3] - * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No - * processing, such as removal of leading zeros or the required offset - * of 1 for negative values, is perfomed. - * - * RFC 8949 preferred serialization requires big numbers that - * will fit in integers be encoded as integers. That is NOT - * performed. - */ -static void -QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - -static void -QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - -static void -QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC BigNumber); - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - * @brief Add a decimal fraction to the encoded output. - * - * @param[in] pCtx Encoding context to add the decimal fraction to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] nMantissa The mantissa. - * @param[in] nBase10Exponent The exponent. - * - * The value is @c nMantissa * 10 ^ @c nBase10Exponent. - * - * A decimal fraction is good for exact representation of some values - * that can't be represented exactly with standard C (IEEE 754) - * floating-point numbers. Much larger and much smaller numbers can - * also be represented than floating-point because of the larger - * number of bits in the exponent. - * - * The decimal fraction is conveyed as two integers, a mantissa and a - * base-10 scaling factor. - * - * For example, 273.15 is represented by the two integers 27315 and -2. - * - * The exponent and mantissa have the range from @c INT64_MIN to - * @c INT64_MAX for both encoding and decoding (CBOR allows - * @c -UINT64_MAX to @c UINT64_MAX, but this implementation doesn't - * support this range to reduce code size and interface complexity a - * little). - * - * Preferred serialization is used when the mantissa or exponent are - * integers, thus they will be encoded in the smallest number of bytes. - * - * See also QCBOREncode_AddTDecimalFractionBigNum() for a decimal - * fraction with arbitrarily large precision and - * QCBOREncode_AddTBigFloat(). - * - * There is no representation of positive or negative infinity or NaN - * (Not a Number). Use QCBOREncode_AddDouble() to encode them. - * - * See @ref expAndMantissa for decoded representation. - */ -static void -QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void -QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void -QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - - -/** - * @brief Add a decimal fraction with a big number mantissa to the encoded output. - * - * @param[in] pCtx Encoding context to add the decimal fraction to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] Mantissa The mantissa. - * @param[in] bIsNegative false if mantissa is positive, true if negative. - * @param[in] nBase10Exponent The exponent. - * - * This is the same as QCBOREncode_AddTDecimalFraction() except the - * mantissa is a big number (See QCBOREncode_AddTPositiveBignum()) - * allowing for arbitrarily large precision. - * - * RFC 8949 preferred serialization requires reduction of big numbers - * that can fit into integers be encoded as integers, not big numbers. - * This implementation does NOT do that. - * - * See @ref expAndMantissa for decoded representation. - */ -static void -QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void -QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void -QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/** - * @brief Add a big floating-point number to the encoded output. - * - * @param[in] pCtx The encoding context to add the bigfloat to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] nMantissa The mantissa. - * @param[in] nBase2Exponent The exponent. - * - * The value is @c nMantissa * 2 ^ @c nBase2Exponent. - * - * "Bigfloats", as CBOR terms them, are similar to IEEE floating-point - * numbers in having a mantissa and base-2 exponent, but they are not - * supported by hardware or encoded the same. They explicitly use two - * CBOR-encoded integers to convey the mantissa and exponent, each of - * which can be 8, 16, 32 or 64 bits. With both the mantissa and - * exponent 64 bits they can express more precision and a larger range - * than an IEEE double floating-point number. See - * QCBOREncode_AddTBigFloatBigNum() for even more precision. - * - * For example, 1.5 would be represented by a mantissa of 3 and an - * exponent of -1. - * - * The exponent and mantissa have the range from @c INT64_MIN to - * @c INT64_MAX for both encoding and decoding (CBOR allows @c - * -UINT64_MAX to @c UINT64_MAX, but this implementation doesn't - * support this range to reduce code size and interface complexity a - * little). - * - * Preferred serialization is used when the mantissa or exponent are - * integers, thus they will be encoded in the smallest number of bytes. - * - * This can also be used to represent floating-point numbers in - * environments that don't support IEEE 754. - * - * See @ref expAndMantissa for decoded representation. - */ -static void -QCBOREncode_AddTBigFloat(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void -QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void -QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - - -/** - * @brief Add a big floating-point number with a big number mantissa to - * the encoded output. - * - * @param[in] pCtx The encoding context to add the bigfloat to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] Mantissa The mantissa. - * @param[in] bIsNegative false if mantissa is positive, true if negative. - * @param[in] nBase2Exponent The exponent. - * - * This is the same as QCBOREncode_AddTBigFloat() except the mantissa - * is a big number (See QCBOREncode_AddTPositiveBignum()) allowing for - * arbitrary precision. - * - * RFC 8949 preferred serialization requires reduction of big numbers - * that can fit into integers be encoded as integers, not big numbers. - * This implementation does NOT do that. - * - * See @ref expAndMantissa for decoded representation. - */ -static void -QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void -QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void -QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - - -/** - * @brief Add a text URI to the encoded output. - * - * @param[in] pCtx The encoding context to add the URI to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] URI Pointer and length of the URI. - * - * The format of URI must be per [RFC 3986] - * (https://www.rfc-editor.org/rfc/rfc3986.html). - * - * It is output as CBOR major type 3, a text string, with tag @ref - * CBOR_TAG_URI indicating the text string is a URI. - * - * A URI in a NULL-terminated string, @c szURI, can be easily added with - * this code: - * - * QCBOREncode_AddTURI(pCtx, QCBOR_ENCODE_AS_TAG, UsefulBuf_FromSZ(szURI)); - */ -static void -QCBOREncode_AddTURI(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void -QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void -QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - - -/** - * @brief Add Base64-encoded text to encoded output. - * - * @param[in] pCtx The encoding context to add the base-64 text to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] B64Text Pointer and length of the base-64 encoded text. - * - * The text content is Base64 encoded data per [RFC 4648] - * (https://www.rfc-editor.org/rfc/rfc4648.html). - * - * It is output as CBOR major type 3, a text string, with tag @ref - * CBOR_TAG_B64 indicating the text string is Base64 encoded. - */ -static void -QCBOREncode_AddTB64Text(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void -QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void -QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -/** - * @brief Add base64url encoded data to encoded output. - * - * @param[in] pCtx The encoding context to add the base64url to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] B64Text Pointer and length of the base64url encoded text. - * - * The text content is base64URL encoded text as per - * [RFC 4648] (https://www.rfc-editor.org/rfc/rfc4648.html). - * - * It is output as CBOR major type 3, a text string, with tag - * @ref CBOR_TAG_B64URL indicating the text string is a Base64url - * encoded. - */ -static void -QCBOREncode_AddTB64URLText(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void -QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void -QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -/** - * @brief Add Perl Compatible Regular Expression. - * - * @param[in] pCtx Encoding context to add the regular expression to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] Regex Pointer and length of the regular expression. - * - * The text content is Perl Compatible Regular - * Expressions (PCRE) / JavaScript syntax [ECMA262]. - * - * It is output as CBOR major type 3, a text string, with tag @ref - * CBOR_TAG_REGEX indicating the text string is a regular expression. - */ -static void -QCBOREncode_AddTRegex(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void -QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void -QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - - -/** - * @brief MIME encoded data to the encoded output. - * - * @param[in] pCtx The encoding context to add the MIME data to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] MIMEData Pointer and length of the MIME data. - * - * The text content is in MIME format per [RFC 2045] - * (https://www.rfc-editor.org/rfc/rfc2045.html) including the headers. - * - * It is output as CBOR major type 2, a binary string, with tag - * @ref CBOR_TAG_BINARY_MIME indicating the string is MIME data. This - * outputs tag 257, not tag 36, as it can carry any type of MIME - * binary, 7-bit, 8-bit, quoted-printable and base64 where tag 36 - * cannot. - * - * Previous versions of QCBOR, those before spiffy decode, output tag - * 36. Decoding supports both tag 36 and 257. (if the old behavior - * with tag 36 is needed, copy the inline functions below and change - * the tag number). - * - * See also QCBORDecode_GetMIMEMessage() and - * @ref QCBOR_TYPE_BINARY_MIME. - * - * This does no translation of line endings. See QCBOREncode_AddText() - * for a discussion of line endings in CBOR. - */ -static void -QCBOREncode_AddTMIMEData(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void -QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void -QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - - -/** - * @brief Add an RFC 3339 date string - * - * @param[in] pCtx The encoding context to add the date to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] szDate Null-terminated string with date to add. - * - * The string szDate should be in the form of - * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html) as defined - * by section 3.3 in [RFC 4287] (https://www.rfc-editor.org/rfc/rfc4287.html). - * This is as described in section 3.4.1 in [RFC 8949] - * (https://www.rfc-editor.org/rfc/rfc8949.html#section3.1.4). - * - * Note that this function doesn't validate the format of the date - * string at all. If you add an incorrect format date string, the - * generated CBOR will be incorrect and the receiver may not be able - * to handle it. - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddTDayString(). - */ -static void -QCBOREncode_AddTDateString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); - -static void -QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); - -static void -QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); - - -/** - * @brief Add a date-only string. - * - * @param[in] pCtx The encoding context to add the date to. - * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - * @ref QCBOR_ENCODE_AS_BORROWED. - * @param[in] szDate Null-terminated string with date to add. - * - * This date format is described in - * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html), but that mainly - * references RFC 3339. The string szDate must be in the forrm - * specified the ABNF for a full-date in - * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html). Examples of this - * are "1985-04-12" and "1937-01-01". The time and the time zone are - * never included. - * - * Note that this function doesn't validate the format of the date - * string at all. If you add an incorrect format date string, the - * generated CBOR will be incorrect and the receiver may not be able - * to handle it. - * - * Error handling is the same as QCBOREncode_AddInt64(). - * - * See also QCBOREncode_AddTDateString(). - */ -static void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); - -static void -QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); - -static void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); - - -/** - * @brief Add a standard Boolean. - * - * @param[in] pCtx The encoding context to add the Boolean to. - * @param[in] b true or false from @c . - * - * Adds a Boolean value as CBOR major type 7. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); - -static void -QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, bool b); - -static void -QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); - - -/** - * @brief Add a NULL to the encoded output. - * - * @param[in] pCtx The encoding context to add the NULL to. - * - * Adds the NULL value as CBOR major type 7. - * - * This NULL doesn't have any special meaning in CBOR such as a - * terminating value for a string or an empty value. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - -static void -QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - * @brief Add an "undef" to the encoded output. - * - * @param[in] pCtx The encoding context to add the "undef" to. - * - * Adds the undef value as CBOR major type 7. - * - * Note that this value will not translate to JSON. - * - * "undef" doesn't have any special meaning in CBOR such as a - * terminating value for a string or an empty value. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static void -QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - -static void -QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - * @brief Add a simple value. - * - * @param[in] pCtx The encode context. - * @param[in] uNum The simple value. - * - * QCBOREncode_AddBool(), QCBOREncode_AddUndef() and - * QCBOREncode_AddNull() are preferred to this for the simple values - * defined in RFC 8949, but this can be used for them too. - * - * The main purpose of this is to add simple values beyond those in - * defined RFC 8949. Note that simple values must be registered with - * IANA. Those in the range of 0 to 19 must be standardized. Those in - * the range of 32 to 255 do not require a standard, but must be - * publically specified. There is no range of values for proprietary - * use. See - * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml - */ -static void -QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, const uint8_t uNum); - -static void -QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - const uint8_t uSimple); - -static void -QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, - const int64_t nLabel, - const uint8_t uSimple); - - -/** - * @brief Indicates that the next items added are in an array. - * - * @param[in] pCtx The encoding context to open the array in. - * - * Arrays are the basic CBOR aggregate or structure type. Call this - * function to start or open an array. Then call the various - * @c QCBOREncode_AddXxx() functions to add the items that go into the - * array. Then call QCBOREncode_CloseArray() when all items have been - * added. The data items in the array can be of any type and can be of - * mixed types. - * - * Nesting of arrays and maps is allowed and supported just by calling - * QCBOREncode_OpenArray() again before calling - * QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this - * implementation does in order to keep it smaller and simpler. The - * limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of - * times this can be called without calling - * QCBOREncode_CloseArray(). QCBOREncode_Finish() will return - * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this - * function just sets an error state and returns no value when this - * occurs. - * - * If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to - * a single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be - * returned when QCBOREncode_Finish() is called. - * - * An array itself must have a label if it is being added to a map. - * Note that array elements do not have labels (but map elements do). - * - * An array itself may be tagged by calling QCBOREncode_AddTag() - * before this call. - */ -static void -QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - -static void -QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - * @brief Close an open array. - * - * @param[in] pCtx The encoding context to close the array in. - * - * The closes an array opened by QCBOREncode_OpenArray(). It reduces - * nesting level by one. All arrays (and maps) must be closed before - * calling QCBOREncode_Finish(). - * - * When an error occurs as a result of this call, the encoder records - * the error and enters the error state. The error will be returned - * when QCBOREncode_Finish() is called. - * - * If this has been called more times than QCBOREncode_OpenArray(), then - * @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish() - * is called. - * - * If this is called and it is not an array that is currently open, - * @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when - * QCBOREncode_Finish() is called. - */ -static void -QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); - - - - -/** - * @brief Indicates that the next items added are in a map. - * - * @param[in] pCtx The encoding context to open the map in. - * - * See QCBOREncode_OpenArray() for more information, particularly - * error handling. - * - * CBOR maps are an aggregate type where each item in the map consists - * of a label and a value. They are similar to JSON objects. - * - * The value can be any CBOR type including another map. - * - * The label can also be any CBOR type, but in practice they are - * typically, integers as this gives the most compact output. They - * might also be text strings which gives readability and translation - * to JSON. - * - * Every @c QCBOREncode_AddXxx() call has one version that ends with - * @c InMap for adding items to maps with string labels and one that - * ends with @c InMapN that is for adding with integer labels. - * - * RFC 8949 uses the term "key" instead of "label". - * - * If you wish to use map labels that are neither integer labels nor - * text strings, then just call the QCBOREncode_AddXxx() function - * explicitly to add the label. Then call it again to add the value. - * - * See the [RFC 8949] (https://www.rfc-editor.org/rfc/rfc8949.html) - * for a lot more information on creating maps. - */ -static void -QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - -static void -QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - * @brief Close an open map. - * - * @param[in] pCtx The encoding context to close the map in. - * - * This closes a map opened by QCBOREncode_OpenMap(). It reduces - * nesting level by one. - * - * When an error occurs as a result of this call, the encoder records - * the error and enters the error state. The error will be returned - * when QCBOREncode_Finish() is called. - * - * If this has been called more times than QCBOREncode_OpenMap(), then - * @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when - * QCBOREncode_Finish() is called. - * - * If this is called and it is not a map that is currently open, - * @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when - * QCBOREncode_Finish() is called. - */ -static void -QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); - - -/** - * @brief Indicates that the next items added are in an indefinite length array. - * - * @param[in] pCtx The encoding context to open the array in. - * - * This is the same as QCBOREncode_OpenArray() except the array is - * indefinite length. - * - * This must be closed with QCBOREncode_CloseArrayIndefiniteLength(). - */ -static void -QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel); - -static void -QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, - int64_t nLabel); - - -/** - * @brief Close an open indefinite length array. - * - * @param[in] pCtx The encoding context to close the array in. - * - * This is the same as QCBOREncode_CloseArray(), but the open array - * that is being close must be of indefinite length. - */ -static void -QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx); - - -/** - * @brief Indicates that the next items added are in an indefinite length map. - * - * @param[in] pCtx The encoding context to open the map in. - * - * This is the same as QCBOREncode_OpenMap() except the array is - * indefinite length. - * - * This must be closed with QCBOREncode_CloseMapIndefiniteLength(). - */ -static void -QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel); - -static void -QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, - int64_t nLabel); - - - - -/** - * @brief Close an open indefinite length map. - * - * @param[in] pCtx The encoding context to close the map in. - * - * This is the same as QCBOREncode_CloseMap(), but the open map that - * is being close must be of indefinite length. - */ -static void -QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx); - - - - -/** - * @brief Indicate start of encoded CBOR to be wrapped in a bstr. - * - * @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in. - * - * All added encoded items between this call and a call to - * QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will - * appear in the final output as a byte string. That byte string will - * contain encoded CBOR. This increases nesting level by one. - * - * The typical use case is for encoded CBOR that is to be - * cryptographically hashed, as part of a [RFC 9052, COSE] - * (https://www.rfc-editor.org/rfc/rfc9052.html) implementation. The - * wrapping byte string is taken as input by the hash function (which - * is why it is returned by QCBOREncode_CloseBstrWrap2()). It is also - * easy to recover on decoding with standard CBOR decoders. - * - * Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() - * avoids having to encode the items first in one buffer (e.g., the - * COSE payload) and then add that buffer as a bstr to another - * encoding (e.g. the COSE to-be-signed bytes, the @c Sig_structure) - * potentially halving the memory needed. - * - * CBOR by nature must be decoded item by item in order from the - * start. By wrapping some CBOR in a byte string, the decoding of - * that wrapped CBOR can be skipped. This is another use of wrapping, - * perhaps because the CBOR is large and deeply nested. Perhaps APIs - * for handling one defined CBOR message that is being embedded in - * another only take input as a byte string. Perhaps the desire is to - * be able to decode the out layer even in the wrapped has errors. - */ -static void -QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); - -static void -QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - -static void -QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - * @brief Close a wrapping bstr. - * - * @param[in] pCtx The encoding context to close of bstr wrapping in. - * @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr - * as well as the bytes in @c pWrappedCBOR. - * @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes. - * - * The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces - * nesting level by one. - * - * A pointer and length of the enclosed encoded CBOR is returned in @c - * *pWrappedCBOR if it is not @c NULL. The main purpose of this is so - * this data can be hashed (e.g., with SHA-256) as part of a - * [RFC 9052, COSE] (https://www.rfc-editor.org/rfc/rfc9052.html) - * implementation. **WARNING**, this pointer and length should be used - * right away before any other calls to @c QCBOREncode_CloseXxx() as - * they will move data around and the pointer and length will no - * longer be to the correct encoded CBOR. - * - * When an error occurs as a result of this call, the encoder records - * the error and enters the error state. The error will be returned - * when QCBOREncode_Finish() is called. - * - * If this has been called more times than QCBOREncode_BstrWrap(), - * then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when - * QCBOREncode_Finish() is called. - * - * If this is called and it is not a wrapping bstr that is currently - * open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when - * QCBOREncode_Finish() is called. - * - * QCBOREncode_CloseBstrWrap() is a deprecated version of this function - * that is equivalent to the call with @c bIncludeCBORHead @c true. - */ -void -QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR); - -static void -QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); - - -/** - * @brief Cancel byte string wrapping. - * - * @param[in] pCtx The encoding context. - * - * This cancels QCBOREncode_BstrWrap() making the encoding as if it - * were never called. - * - * WARNING: This does not work on QCBOREncode_BstrWrapInMapSZ() - * or QCBOREncode_BstrWrapInMapN() and there is no error detection - * of an attempt at their use. - * - * This only works if nothing has been added into the wrapped byte - * string. If something has been added, this sets the error - * @ref QCBOR_ERR_CANNOT_CANCEL. - */ -void -QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pCtx); - - -/** - * @brief Add some already-encoded CBOR bytes. - * - * @param[in] pCtx The encoding context to add the already-encode CBOR to. - * @param[in] Encoded The already-encoded CBOR to add to the context. - * - * The encoded CBOR being added must be fully conforming CBOR. It must - * be complete with no arrays or maps that are incomplete. it is OK for the - * raw CBOR added here to have indefinite lengths. - * - * The raw CBOR added here is not checked in anyway. If it is not - * conforming or has open arrays or such, the final encoded CBOR - * will probably be wrong or not what was intended. - * - * If the encoded CBOR being added here contains multiple items, they - * must be enclosed in a map or array. At the top level the raw - * CBOR must be a single data item. - */ -void -QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); - -static void -QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); - -static void -QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); - - -/** - * @brief Get the encoded result. - * - * @param[in] pCtx The context to finish encoding with. - * @param[out] pEncodedCBOR Structure in which the pointer and length of - * the encoded CBOR is returned. - * - * @retval QCBOR_SUCCESS Encoded CBOR is returned. - * - * @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error - * - * @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error - * - * @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error - * - * @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size - * - * @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size - * - * @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit - * - * @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit - * - * On success, the pointer and length of the encoded CBOR are returned - * in @c *pEncodedCBOR. The pointer is the same pointer that was passed - * in to QCBOREncode_Init(). Note that it is not const when passed to - * QCBOREncode_Init(), but it is const when returned here. The length - * will be smaller than or equal to the length passed in when - * QCBOREncode_Init() as this is the length of the actual result, not - * the size of the buffer it was written to. - * - * If a @c NULL was passed for @c Storage.ptr when QCBOREncode_Init() - * was called, @c NULL will be returned here, but the length will be - * that of the CBOR that would have been encoded. - * - * Encoding errors primarily manifest here as most other encoding function - * do no return an error. They just set the error state in the encode - * context after which no encoding function does anything. - * - * Three types of errors manifest here. The first type are nesting - * errors where the number of @c QCBOREncode_OpenXxx() calls do not - * match the number @c QCBOREncode_CloseXxx() calls. The solution is to - * fix the calling code. - * - * The second type of error is because the buffer given is either too - * small or too large. The remedy is to give a correctly sized buffer. - * - * The third type are due to limits in this implementation. - * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by - * encoding the CBOR in two (or more) phases and adding the CBOR from - * the first phase to the second with @c QCBOREncode_AddEncoded(). - * - * If an error is returned, the buffer may have partially encoded - * incorrect CBOR in it and it should not be used. Likewise, the length - * may be incorrect and should not be used. - * - * Note that the error could have occurred in one of the many - * @c QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was - * called. This error handling reduces the CBOR implementation size - * but makes debugging harder. - * - * This may be called multiple times. It will always return the - * same. It can also be interleaved with calls to - * QCBOREncode_FinishGetSize(). See QCBOREncode_SubString() for a - * means to get the thus-far-encoded CBOR. - * - * QCBOREncode_GetErrorState() can be called to get the current - * error state in order to abort encoding early as an optimization, but - * calling it is is never required. - */ -QCBORError -QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); - - -/** - * @brief Get the encoded CBOR and error status. - * - * @param[in] pCtx The context to finish encoding with. - * @param[out] uEncodedLen The length of the encoded or potentially - * encoded CBOR in bytes. - * - * @return The same errors as QCBOREncode_Finish(). - * - * This functions the same as QCBOREncode_Finish(), but only returns the - * size of the encoded output. - */ -QCBORError -QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); - - -/** - * @brief Indicate whether the output storage buffer is NULL. - * - * @param[in] pCtx The encoding context. - * - * @return 1 if the output buffer is @c NULL. - * - * As described in QCBOREncode_Init(), @c Storage.ptr may be give as @c NULL - * for output size calculation. This returns 1 when that is the true, and 0 if not. - */ -static int -QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx); - - -/** - * @brief Retrieve the storage buffer passed in to QCBOREncode_Init(). - * - * @param[in] pCtx The encoding context. - * - * @return The output storage buffer passed to QCBOREncode_Init(). - * - * This doesn't give any information about how much has been encoded - * or the error state. It just returns the exact @ref UsefulOutBuf given - * to QCBOREncode_Init(). - */ -static UsefulBuf -QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pCtx); - - -/** - * @brief Get the encoding error state. - * - * @param[in] pCtx The encoding context. - * - * @return One of @ref QCBORError. See return values from - * QCBOREncode_Finish() - * - * Normally encoding errors need only be handled at the end of - * encoding when QCBOREncode_Finish() is called. This can be called to - * get the error result before finish should there be a need to halt - * encoding before QCBOREncode_Finish() is called. - */ -static QCBORError -QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx); - - -/** - * @brief Returns current end of encoded data. - * - * @param[in] pCtx The encoding context. - * - * @return Byte offset of end of encoded data. - * - * The purpose of this is to enable cryptographic hashing over a - * subpart of thus far CBOR-encoded data. Then perhaps a signature - * over the hashed CBOR is added to the encoded output. There is - * nothing specific to hashing or signing in this, so this can be used - * for other too. - * - * Call this to get the offset of the start of the encoded - * to-be-hashed CBOR items, then call QCBOREncode_SubString(). - * QCBOREncode_Tell() can also be called twice, first to get the - * offset of the start and second for the offset of the end. Those - * offsets can be applied to the output storage buffer. - * - * This will return successfully even if the encoder is in the error - * state. - * - * WARNING: All definite-length arrays and maps opened before the - * first call to QCBOREncode_Tell() must not be closed until the - * substring is obtained and processed. Similarly, every - * definite-length array or map opened after the first call to - * QCBOREncode_Tell() must be closed before the substring is obtained - * and processed. The same applies for opened byte strings. There is - * no detection of these errors. This occurs because QCBOR goes back - * and inserts the lengths of definite-length arrays and maps when - * they are closed. This insertion will make the offsets incorrect. - */ -static size_t -QCBOREncode_Tell(QCBOREncodeContext *pCtx); - - -/** - * @brief Get a substring of encoded CBOR for cryptographic hash - * - * @param[in] pCtx The encoding context. - * @param[in] uStart The start offset of substring. - * - * @return Pointer and length of of substring. - * - * @c uStart is obtained by calling QCBOREncode_Tell() before encoding - * the first item in the substring. Then encode some data items. Then - * call this. The substring returned contains the encoded data items. - * - * The substring may have deeply nested arrays and maps as long as any - * opened after the call to QCBOREncode_Tell() are closed before this - * is called. - * - * This will return @c NULLUsefulBufC if the encoder is in the error - * state or if @c uStart is beyond the end of the thus-far encoded - * data items. - * - * If @c uStart is 0, all the thus-far-encoded CBOR will be returned. - * Unlike QCBOREncode_Finish(), this will succeed even if some arrays - * and maps are not closed. - * - * See important usage WARNING in QCBOREncode_Tell() - */ -UsefulBufC -QCBOREncode_SubString(QCBOREncodeContext *pCtx, const size_t uStart); - - -/** - * @brief Encode the head of a CBOR data item. - * - * @param Buffer Buffer to output the encoded head to; must be - * @ref QCBOR_HEAD_BUFFER_SIZE bytes in size. - * @param uMajorType One of CBOR_MAJOR_TYPE_XX. - * @param uMinLen The minimum number of bytes to encode uNumber. Almost - * always this is 0 to use preferred - * serialization. If this is 4, then even the - * values 0xffff and smaller will be encoded in 4 - * bytes. This is used primarily when encoding a - * float or double put into uNumber as the leading - * zero bytes for them must be encoded. - * @param uNumber The numeric argument part of the CBOR head. - * @return Pointer and length of the encoded head or - * @ref NULLUsefulBufC if the output buffer is too small. - * - * Callers do not to need to call this for normal CBOR encoding. Note - * that it doesn't even take a @ref QCBOREncodeContext argument. - * - * This encodes the major type and argument part of a data item. The - * argument is an integer that is usually either the value or the length - * of the data item. - * - * This is exposed in the public interface to allow hashing of some CBOR - * data types, bstr in particular, a chunk at a time so the full CBOR - * doesn't have to be encoded in a contiguous buffer. - * - * For example, if you have a 100,000 byte binary blob in a buffer that - * needs to be bstr encoded and then hashed. You could allocate a - * 100,010 byte buffer and encode it normally. Alternatively, you can - * encode the head in a 10 byte buffer with this function, hash that and - * then hash the 100,000 bytes using the same hash context. - */ -UsefulBufC -QCBOREncode_EncodeHead(UsefulBuf Buffer, - uint8_t uMajorType, - uint8_t uMinLen, - uint64_t uNumber); - - - - -/* ========================================================================= * - * BEGINNING OF DEPRECATED FUNCTIONS * - * * - * There is no plan to remove these in future versions. * - * They just have been replaced by something better. * - * ========================================================================= */ - -/* Use QCBOREncode_AddInt64ToMapSZ() instead */ -static void -QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); - -/* Use QCBOREncode_AddUInt64ToMapSZ() instead */ -static void -QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); - -/* Use QCBOREncode_AddTextToMapSZ() instead */ -static void -QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - -/* Use QCBOREncode_AddSZStringToMapSZ() instead */ -static void -QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/* Use QCBOREncode_AddDoubleToMapSZ() instead */ -static void -QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -/* Use QCBOREncode_AddFloatToMapSZ() instead */ -static void -QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); - -/* Use QCBOREncode_AddDoubleNoPreferredToMapSZ() instead */ -static void -QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -/* Use QCBOREncode_AddFloatNoPreferredToMapSZ() instead */ -static void -QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ - -/* Use QCBOREncode_AddTDateEpoch() instead */ -static void -QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t nDate); - -/* Use QCBOREncode_AddTDateEpochToMapSZ() instead */ -static void -QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nDate); - -/* Use QCBOREncode_AddTDateEpochToMapN() instead */ -static void -QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nDate); - -/* Use QCBOREncode_AddBytesToMapSZ() instead */ -static void -QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -/* Use QCBOREncode_AddTBinaryUUID() instead */ -static void -QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -/* Use QCBOREncode_AddTBinaryUUIDToMapSZ() instead */ -static void -QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -/* Use QCBOREncode_AddTBinaryUUIDToMapN() instead */ -static void -QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - -/* Use QCBOREncode_AddTPositiveBignum() instead */ -static void -QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); - -/* QCBOREncode_AddTPositiveBignumToMapSZ() instead */ -static void -QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC BigNumber); - -/* Use QCBOREncode_AddTPositiveBignumToMapN() instead */ -static void -QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC BigNumber); - -/* Use QCBOREncode_AddTNegativeBignum() instead */ -static void -QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); - -/* Use QCBOREncode_AddTNegativeBignumToMapSZ() instead */ -static void -QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC BigNumber); - -/* Use QCBOREncode_AddTNegativeBignumToMapN() instead */ -static void -QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC BigNumber); - - -#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA - -/* Use QCBOREncode_AddTDecimalFraction() instead */ -static void -QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTDecimalFractionToMapSZ() instead */ -static void -QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nMantissa, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTDecimalFractionToMapN() instead */ -static void -QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTDecimalFractionBigNum() instead */ -static void -QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTDecimalFractionBigNumToMapSZ() instead */ -static void -QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTDecimalFractionBigNumToMapN() instead */ -static void -QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/* Use QCBOREncode_AddTBigFloat() instead */ -static void -QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase2Exponent); - -/* Use QCBOREncode_AddTBigFloatToMapSZ() instead */ -static void -QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nMantissa, - int64_t nBase2Exponent); - -/* Use QCBOREncode_AddTBigFloatToMapN() instead */ -static void -QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase2Exponent); - -/* Use QCBOREncode_AddTBigFloatBigNum() instead */ -static void -QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -/* Use QCBOREncode_AddTBigFloatBigNumToMapSZ() instead */ -static void -QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -/* Use QCBOREncode_AddTBigFloatBigNumToMapN() instead */ -static void -QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); -#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */ - -/* Use QCBOREncode_AddTURI() instead */ -static void -QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI); - -/* Use QCBOREncode_AddTURIToMapSZ() instead */ -static void -QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI); - -/* Use QCBOREncode_AddTURIToMapN() instead */ -static void -QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI); - -/* Use QCBOREncode_AddTB64Text() instead */ -static void -QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - -/* Use QCBOREncode_AddTB64TextToMapSZ() instead */ -static void -QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); - -/* Use QCBOREncode_AddTB64TextToMapN() instead */ -static void -QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); - -/* Use QCBOREncode_AddTB64URLText() instead */ -static void -QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - -/* Use QCBOREncode_AddTB64URLTextToMapSZ() instead */ -static void -QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC B64Text); - -/* Use QCBOREncode_AddTB64URLTextToMapN() instead */ -static void -QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC B64Text); - -/* Use QCBOREncode_AddTRegex() instead */ -static void -QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex); - -/* Use QCBOREncode_AddTRegexToMapSZ() instead */ -static void -QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Regex); - -/* Use QCBOREncode_AddTRegexToMapN() instead */ -static void -QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Regex); - -/* Use QCBOREncode_AddTMIMEData() instead */ -static void -QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData); - -/* Use QCBOREncode_AddTMIMEDataToMapSZ() instead */ -static void -QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC MIMEData); - -/* Use QCBOREncode_AddTMIMEDataToMapN() instead */ -static void -QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC MIMEData); - -/* Use QCBOREncode_AddTDateString() instead */ -static void -QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate); - -/* Use QCBOREncode_AddTDateStringToMapSZ() instead */ -static void -QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - const char *szDate); - -/* Use QCBOREncode_AddTDateStringToMapN instead */ -static void -QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - const char *szDate); - -/* Use QCBOREncode_AddBoolToMapSZ() instead */ -static void -QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); - -/* Use QCBOREncode_AddNULLToMapSZ() instead */ -static void -QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -/* Use QCBOREncode_AddUndefToMapSZ() instead */ -static void -QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -/* Use QCBOREncode_AddSimpleToMapSZ instead */ -static void -QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - const uint8_t uSimple); - -/* Use QCBOREncode_OpenArrayInMapSZ() instead */ -static void -QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -/* Use QCBOREncode_OpenMapInMapSZ() instead */ -static void -QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -/* Use QCBOREncode_OpenArrayIndefiniteLengthInMapSZ() instead */ -static void -QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, - const char *szLabel); - -/* Use QCBOREncode_OpenMapIndefiniteLengthInMapSZ() instead */ -static void -QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, - const char *szLabel); - -/* Use QCBOREncode_BstrWrapInMapSZ() instead */ -static void -QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -/* Use QCBOREncode_AddEncodedToMapSZ() instead */ -static void -QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); - - -/* ========================================================================= * - * END OF DEPRECATED FUNCTIONS * - * ========================================================================= */ - - - - - -/* ========================================================================= * - * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * - * ========================================================================= */ - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, - const uint8_t uMajorType, - const uint64_t uArgument, - const uint8_t uMinLen); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pCtx, - uint8_t uMajorType, - UsefulBufC Bytes); - - -/* Semi-private function for adding a double with preferred encoding. See qcbor_encode.c */ -void -QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum); - - -/* Semi-private function for adding a float with preferred encoding. See qcbor_encode.c */ -void -QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pCtx, - uint8_t uMajorType); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, - uint8_t uMajorType); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pCtx, - uint8_t uMajorType); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, - uint8_t uMajorType); - - -/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ -void -QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pCtx, - uint64_t uTag, - UsefulBufC BigNumMantissa, - bool bBigNumIsNegative, - int64_t nMantissa, - int64_t nExponent); - - -/** - * @brief Semi-private method to add simple items and floating-point. - * - * @param[in] pMe The encoding context. - * @param[in] uMinLen Minimum encoding size for uNum. Usually 0. - * @param[in] uArgument The value to add. - * - * This is used to add simple types like true and false and float-point - * values, both of which are type 7. - * - * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), - * QCBOREncode_AddUndef() QCBOREncode_AddDouble() instead of this. - * - * Error handling is the same as QCBOREncode_AddInt64(). - */ -static inline void -QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe, - const uint8_t uMinLen, - const uint64_t uArgument) -{ - QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uArgument, uMinLen); -} - - -/** - * @brief Semi-private method to add only the type and length of a byte string. - * - * @param[in] pCtx The context to initialize. - * @param[in] Bytes Pointer and length of the input data. - * - * This will be removed in QCBOR 2.0. It was never a public function. - * - * This is the same as QCBOREncode_AddBytes() except it only adds the - * CBOR encoding for the type and the length. It doesn't actually add - * the bytes. You can't actually produce correct CBOR with this and - * the rest of this API. It is only used for a special case where the - * valid CBOR is created manually by putting this type and length in - * and then adding the actual bytes. In particular, when only a hash - * of the encoded CBOR is needed, where the type and header are hashed - * separately and then the bytes is hashed. This makes it possible to - * implement COSE Sign1 with only one copy of the payload in the - * output buffer, rather than two, roughly cutting memory use in half. - * - * This is only used for this odd case, but this is a supported - * tested function for QCBOR 1.0. - * - * See also QCBOREncode_EncodeHead(). - */ -static void -QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, - UsefulBufC Bytes); - -static void -QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Bytes); - -static void -QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Bytes); - - -/* Forward declaration */ -static void -QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString); - - - - -static inline void -QCBOREncode_AddInt64ToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const int64_t nNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddInt64(pMe, nNum); -} - -static inline void -QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t nNum) -{ - QCBOREncode_AddInt64ToMapSZ(pMe, szLabel, nNum); -} - -static inline void -QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const int64_t nNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddInt64(pMe, nNum); -} - - -static inline void -QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue) -{ - QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0); -} - - -static inline void -QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint64_t uNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddUInt64(pMe, uNum); -} - -static inline void -QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, uint64_t uNum) -{ - QCBOREncode_AddUInt64ToMapSZ(pMe, szLabel, uNum); -} - -static inline void -QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint64_t uNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddUInt64(pMe, uNum); -} - - -static inline void -QCBOREncode_AddText(QCBOREncodeContext *pMe, const UsefulBufC Text) -{ - QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text); -} - -static inline void -QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Text) -{ - QCBOREncode_AddText(pMe, UsefulBuf_FromSZ(szLabel)); - QCBOREncode_AddText(pMe, Text); -} - -static inline void -QCBOREncode_AddTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Text) -{ - QCBOREncode_AddTextToMapSZ(pMe, szLabel, Text); -} - -static inline void -QCBOREncode_AddTextToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Text) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddText(pMe, Text); -} - - -inline static void -QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString) -{ - QCBOREncode_AddText(pMe, UsefulBuf_FromSZ(szString)); -} - -static inline void -QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const char *szString) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddSZString(pMe, szString); -} - -static inline void -QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szString) -{ - QCBOREncode_AddSZStringToMapSZ(pMe, szLabel, szString); -} - -static inline void -QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const char *szString) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddSZString(pMe, szString); -} - - -static inline void -QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag) -{ - QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0); -} - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - -static inline void -QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum) -{ - QCBOREncode_Private_AddType7(pMe, - sizeof(uint64_t), - UsefulBufUtil_CopyDoubleToUint64(dNum)); -} - -static inline void -QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum) -{ - QCBOREncode_Private_AddType7(pMe, - sizeof(uint32_t), - UsefulBufUtil_CopyFloatToUint32(fNum)); -} - - -static inline void -QCBOREncode_AddDouble(QCBOREncodeContext *pMe, const double dNum) -{ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - QCBOREncode_Private_AddPreferredDouble(pMe, dNum); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddDoubleNoPreferred(pMe, dNum); -#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ -} - -static inline void -QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const double dNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddDouble(pMe, dNum); -} - -static inline void -QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) -{ - QCBOREncode_AddDoubleToMapSZ(pMe, szLabel, dNum); -} - -static inline void -QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const double dNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddDouble(pMe, dNum); -} - - -static inline void -QCBOREncode_AddFloat(QCBOREncodeContext *pMe, const float fNum) -{ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - QCBOREncode_Private_AddPreferredFloat(pMe, fNum); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddFloatNoPreferred(pMe, fNum); -#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ -} - -static inline void -QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const float dNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddFloat(pMe, dNum); -} - -static inline void -QCBOREncode_AddFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) -{ - QCBOREncode_AddFloatToMapSZ(pMe, szLabel, fNum); -} - -static inline void -QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const float fNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddFloat(pMe, fNum); -} - -static inline void -QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const double dNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddDoubleNoPreferred(pMe, dNum); -} - -static inline void -QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) -{ - QCBOREncode_AddDoubleNoPreferredToMapSZ(pMe, szLabel, dNum); -} - -static inline void -QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const double dNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddDoubleNoPreferred(pMe, dNum); -} - -static inline void -QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const float dNum) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddFloatNoPreferred(pMe, dNum); -} - -static inline void -QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) -{ - QCBOREncode_AddFloatNoPreferredToMapSZ(pMe, szLabel, fNum); -} - -static inline void -QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const float dNum) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddFloatNoPreferred(pMe, dNum); -} -#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ - - - - - -static inline void -QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, - const uint8_t uTag, - const int64_t nDate) -{ - if(uTag == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_EPOCH); - } - QCBOREncode_AddInt64(pMe, nDate); -} - -static inline void -QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTag, - const int64_t nDate) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); -} - -static inline void -QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTag, - const int64_t nDate) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); -} - -static inline void -QCBOREncode_AddDateEpoch(QCBOREncodeContext *pMe, - const int64_t nDate) -{ - QCBOREncode_AddTDateEpoch(pMe, QCBOR_ENCODE_AS_TAG, nDate); -} - -static inline void -QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const int64_t nDate) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddDateEpoch(pMe, nDate); -} - -static inline void -QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const int64_t nDate) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddDateEpoch(pMe, nDate); -} - - -static inline void -QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, - const uint8_t uTag, - const int64_t nDays) -{ - if(uTag == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_EPOCH); - } - QCBOREncode_AddInt64(pMe, nDays); -} - -static inline void -QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTag, - const int64_t nDays) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); -} - -static inline void -QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTag, - const int64_t nDays) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); -} - - -static inline void -QCBOREncode_AddBytes(QCBOREncodeContext *pMe, - const UsefulBufC Bytes) -{ - QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); -} - -static inline void -QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddBytes(pMe, Bytes); -} - -static inline void -QCBOREncode_AddBytesToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddBytesToMapSZ(pMe, szLabel, Bytes); -} - -static inline void -QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddBytes(pMe, Bytes); -} - -static inline void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - UsefulBuf *pPlace) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_OpenBytes(pMe, pPlace); -} - -static inline void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - UsefulBuf *pPlace) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_OpenBytes(pMe, pPlace); -} - - -static inline void -QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes) -{ - QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes.len, 0); -} - - -static inline void -QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddBytesLenOnly(pMe, Bytes); -} - -static inline void -QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddBytesLenOnly(pMe, Bytes); -} - - -static inline void -QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_BIN_UUID); - } - QCBOREncode_AddBytes(pMe, Bytes); -} - -static inline void -QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pMe, const UsefulBufC Bytes) -{ - QCBOREncode_AddTBinaryUUID(pMe, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTBinaryUUIDToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTBinaryUUIDToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - Bytes); -} - - -static inline void -QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_POS_BIGNUM); - } - QCBOREncode_AddBytes(pMe, Bytes); -} - -static inline void -QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) -{ - QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTPositiveBignumToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - Bytes); -} - -static inline void -QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTPositiveBignumToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - Bytes); -} - - -static inline void -QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM); - } - QCBOREncode_AddBytes(pMe, Bytes); -} - -static inline void -QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) -{ - QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTNegativeBignumToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - Bytes); -} - -static inline void -QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTNegativeBignumToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - Bytes); -} - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - -static inline void -QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - uint64_t uTag; - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - uTag = CBOR_TAG_DECIMAL_FRACTION; - } else { - uTag = CBOR_TAG_INVALID64; - } - QCBOREncode_Private_AddExpMantissa(pMe, - uTag, - NULLUsefulBufC, - false, - nMantissa, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFraction(pMe, - uTagRequirement, - nMantissa, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFraction(pMe, - uTagRequirement, - nMantissa, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pMe, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddTDecimalFraction(pMe, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddTDecimalFractionToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const int64_t nMantissa, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddTDecimalFractionToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase10Exponent); -} - - - -static inline void -QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase10Exponent) -{ - uint64_t uTag; - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - uTag = CBOR_TAG_DECIMAL_FRACTION; - } else { - uTag = CBOR_TAG_INVALID64; - } - QCBOREncode_Private_AddExpMantissa(pMe, - uTag, - Mantissa, - bIsNegative, - 0, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, - uTagRequirement, - Mantissa, - bIsNegative, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, - uTagRequirement, - Mantissa, - bIsNegative, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pMe, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddTDecimalFractionBigNum(pMe, - QCBOR_ENCODE_AS_TAG, - Mantissa, - bIsNegative, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase10Exponent) -{ - QCBOREncode_AddTDecimalFractionBigNumToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - Mantissa, - bIsNegative, - nBase10Exponent); -} - -static inline void -QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTDecimalFractionBigNumToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - Mantissa, - bIsNegative, - nBase2Exponent); -} - - - - - -static inline void -QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - uint64_t uTag; - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - uTag = CBOR_TAG_BIGFLOAT; - } else { - uTag = CBOR_TAG_INVALID64; - } - QCBOREncode_Private_AddExpMantissa(pMe, - uTag, - NULLUsefulBufC, - false, - nMantissa, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); -} - -static inline void -QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); -} - -static inline void -QCBOREncode_AddBigFloat(QCBOREncodeContext *pMe, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloat(pMe, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloatToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const int64_t nMantissa, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloatToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - nMantissa, - nBase2Exponent); -} - - - -static inline void -QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - uint64_t uTag; - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - uTag = CBOR_TAG_BIGFLOAT; - } else { - uTag = CBOR_TAG_INVALID64; - } - QCBOREncode_Private_AddExpMantissa(pMe, - uTag, - Mantissa, - bIsNegative, - 0, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, - uTagRequirement, - Mantissa, - bIsNegative, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, - uTagRequirement, - Mantissa, - bIsNegative, - nBase2Exponent); -} - - -static inline void -QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pMe, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloatBigNum(pMe, - QCBOR_ENCODE_AS_TAG, - Mantissa, bIsNegative, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - Mantissa, - bIsNegative, - nBase2Exponent); -} - -static inline void -QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Mantissa, - const bool bIsNegative, - const int64_t nBase2Exponent) -{ - QCBOREncode_AddTBigFloatBigNumToMapN(pMe, - nLabel, - QCBOR_ENCODE_AS_TAG, - Mantissa, - bIsNegative, - nBase2Exponent); -} -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - - -static inline void -QCBOREncode_AddTURI(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC URI) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_URI); - } - QCBOREncode_AddText(pMe, URI); -} - -static inline void -QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC URI) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTURI(pMe, uTagRequirement, URI); -} - -static inline void -QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC URI) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTURI(pMe, uTagRequirement, URI); -} - -static inline void -QCBOREncode_AddURI(QCBOREncodeContext *pMe, const UsefulBufC URI) -{ - QCBOREncode_AddTURI(pMe, QCBOR_ENCODE_AS_TAG, URI); -} - -static inline void -QCBOREncode_AddURIToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC URI) -{ - QCBOREncode_AddTURIToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, URI); -} - -static inline void -QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC URI) -{ - QCBOREncode_AddTURIToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, URI); -} - - - -static inline void -QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_B64); - } - QCBOREncode_AddText(pMe, B64Text); -} - -static inline void -QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); -} - -static inline void -QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); -} - -static inline void -QCBOREncode_AddB64Text(QCBOREncodeContext *pMe, const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64Text(pMe, QCBOR_ENCODE_AS_TAG, B64Text); -} - -static inline void -QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64TextToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, B64Text); -} - -static inline void -QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64TextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); -} - - - -static inline void -QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_B64URL); - } - QCBOREncode_AddText(pMe, B64Text); -} - -static inline void -QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); -} - -static inline void -QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC B64Text) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); -} - -static inline void -QCBOREncode_AddB64URLText(QCBOREncodeContext *pMe, const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64URLText(pMe, QCBOR_ENCODE_AS_TAG, B64Text); -} - -static inline void -QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64URLTextToMapSZ(pMe, - szLabel, - QCBOR_ENCODE_AS_TAG, - B64Text); -} - -static inline void -QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC B64Text) -{ - QCBOREncode_AddTB64URLTextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); -} - - - -static inline void -QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_REGEX); - } - QCBOREncode_AddText(pMe, Bytes); -} - -static inline void -QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); -} - -static inline void -QCBOREncode_AddRegex(QCBOREncodeContext *pMe, const UsefulBufC Bytes) -{ - QCBOREncode_AddTRegex(pMe, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddRegexToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTRegexToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); -} - -static inline void -QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Bytes) -{ - QCBOREncode_AddTRegexToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); - -} - - -static inline void -QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBufC MIMEData) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_BINARY_MIME); - } - QCBOREncode_AddBytes(pMe, MIMEData); -} - -static inline void -QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBufC MIMEData) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); -} - -static inline void -QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBufC MIMEData) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); -} - -static inline void -QCBOREncode_AddMIMEData(QCBOREncodeContext *pMe, UsefulBufC MIMEData) -{ - QCBOREncode_AddTMIMEData(pMe, QCBOR_ENCODE_AS_TAG, MIMEData); -} - -static inline void -QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC MIMEData) -{ - QCBOREncode_AddTMIMEDataToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, MIMEData); -} - -static inline void -QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC MIMEData) -{ - QCBOREncode_AddTMIMEDataToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, MIMEData); -} - - -static inline void -QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const char *szDate) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_STRING); - } - QCBOREncode_AddSZString(pMe, szDate); -} - -static inline void -QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const char *szDate) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDateString(pMe, uTagRequirement, szDate); -} - -static inline void -QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const char *szDate) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDateString(pMe, uTagRequirement, szDate); -} - -static inline void -QCBOREncode_AddDateString(QCBOREncodeContext *pMe, const char *szDate) -{ - QCBOREncode_AddTDateString(pMe, QCBOR_ENCODE_AS_TAG, szDate); -} - -static inline void -QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const char *szDate) -{ - QCBOREncode_AddTDateStringToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, szDate); -} - -static inline void -QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const char *szDate) -{ - QCBOREncode_AddTDateStringToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, szDate); -} - - -static inline void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, - const uint8_t uTagRequirement, - const char *szDate) -{ - if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { - QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_STRING); - } - QCBOREncode_AddSZString(pMe, szDate); -} - -static inline void -QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const char *szDate) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDaysString(pMe, uTagRequirement, szDate); -} - -static inline void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const char *szDate) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDaysString(pMe, uTagRequirement, szDate); -} - - -static inline void -QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint8_t uNum) -{ - /* This check often is optimized out because uNum is known at compile time. */ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) { - pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED; - return; - } -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - QCBOREncode_Private_AddType7(pMe, 0, uNum); -} - -static inline void -QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uSimple) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddSimple(pMe, uSimple); -} - -static inline void -QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe, - const char *szLabel, - const uint8_t uSimple) -{ - QCBOREncode_AddSimpleToMapSZ(pMe, szLabel, uSimple); -} - -static inline void -QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const uint8_t uSimple) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddSimple(pMe, uSimple); -} - - -static inline void -QCBOREncode_AddBool(QCBOREncodeContext *pMe, const bool b) -{ - uint8_t uSimple = CBOR_SIMPLEV_FALSE; - if(b) { - uSimple = CBOR_SIMPLEV_TRUE; - } - QCBOREncode_AddSimple(pMe, uSimple); -} - -static inline void -QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, const bool b) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddBool(pMe, b); -} - -static inline void -QCBOREncode_AddBoolToMap(QCBOREncodeContext *pMe, const char *szLabel, bool b) -{ - QCBOREncode_AddBoolToMapSZ(pMe, szLabel, b); -} - -static inline void -QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pMe, const int64_t nLabel, const bool b) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddBool(pMe, b); -} - - -static inline void -QCBOREncode_AddNULL(QCBOREncodeContext *pMe) -{ - QCBOREncode_AddSimple(pMe, CBOR_SIMPLEV_NULL); -} - -static inline void -QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddNULL(pMe); -} - -static inline void -QCBOREncode_AddNULLToMap(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddNULLToMapSZ(pMe, szLabel); -} - -static inline void -QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddNULL(pMe); -} - - -static inline void -QCBOREncode_AddUndef(QCBOREncodeContext *pMe) -{ - QCBOREncode_AddSimple(pMe, CBOR_SIMPLEV_UNDEF); -} - -static inline void -QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddUndef(pMe); -} - -static inline void -QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddUndefToMapSZ(pCtx, szLabel); -} - -static inline void -QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddUndef(pMe); -} - - -static inline void -QCBOREncode_OpenArray(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); -} - -static inline void -QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_OpenArray(pMe); -} - -static inline void -QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_OpenArrayInMapSZ(pMe, szLabel); -} - - -static inline void -QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_OpenArray(pMe); -} - -static inline void -QCBOREncode_CloseArray(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); -} - - -static inline void -QCBOREncode_OpenMap(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); -} - -static inline void -QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_OpenMap(pMe); -} - -static inline void -QCBOREncode_OpenMapInMap(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_OpenMapInMapSZ(pMe, szLabel); -} - -static inline void -QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_OpenMap(pMe); -} - -static inline void -QCBOREncode_CloseMap(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); -} - -static inline void -QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); -} - -static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, - const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_OpenArrayIndefiniteLength(pMe); -} - -static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pMe, - const char *szLabel) -{ - QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(pMe, szLabel); -} - -static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, - const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_OpenArrayIndefiniteLength(pMe); -} - -static inline void -QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); -} - - -static inline void -QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); -} - -static inline void -QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, - const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_OpenMapIndefiniteLength(pMe); -} - -static inline void -QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pMe, - const char *szLabel) -{ - QCBOREncode_OpenMapIndefiniteLengthInMapSZ(pMe, szLabel); -} - -static inline void -QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, - const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_OpenMapIndefiniteLength(pMe); -} - -static inline void -QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); -} - - -static inline void -QCBOREncode_BstrWrap(QCBOREncodeContext *pMe) -{ - QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_BYTE_STRING); -} - -static inline void -QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_BstrWrap(pMe); -} - -static inline void -QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pMe, const char *szLabel) -{ - QCBOREncode_BstrWrapInMapSZ(pMe, szLabel); -} - -static inline void -QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_BstrWrap(pMe); -} - -static inline void -QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pMe, UsefulBufC *pWrappedCBOR) -{ - QCBOREncode_CloseBstrWrap2(pMe, true, pWrappedCBOR); -} - - - -static inline void -QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pMe, - const char *szLabel, - const UsefulBufC Encoded) -{ - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddEncoded(pMe, Encoded); -} - -static inline void -QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Encoded) -{ - QCBOREncode_AddEncodedToMapSZ(pMe, szLabel, Encoded); -} - -static inline void -QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pMe, - const int64_t nLabel, - const UsefulBufC Encoded) -{ - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddEncoded(pMe, Encoded); -} - - -static inline int -QCBOREncode_IsBufferNULL(QCBOREncodeContext *pMe) -{ - return UsefulOutBuf_IsBufferNULL(&(pMe->OutBuf)); -} - - -static inline UsefulBuf -QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pMe) -{ - return UsefulOutBuf_RetrieveOutputStorage(&(pMe->OutBuf)); -} - - -static inline QCBORError -QCBOREncode_GetErrorState(QCBOREncodeContext *pMe) -{ - if(UsefulOutBuf_GetError(&(pMe->OutBuf))) { - /* Items didn't fit in the buffer. This check catches this - * condition for all the appends and inserts so checks aren't - * needed when the appends and inserts are performed. And of - * course UsefulBuf will never overrun the input buffer given to - * it. No complex analysis of the error handling in this file is - * needed to know that is true. Just read the UsefulBuf code. - */ - pMe->uError = QCBOR_ERR_BUFFER_TOO_SMALL; - /* QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is - * OK. Once the caller fixes this, they'll be unmasked. - */ - } - - return (QCBORError)pMe->uError; -} - - -static inline size_t -QCBOREncode_Tell(QCBOREncodeContext *pMe) -{ - return UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); -} - -/* ======================================================================== * - * END OF PRIVATE INLINE IMPLEMENTATION * - * ======================================================================== */ - -#ifdef __cplusplus -} -#endif - -#endif /* qcbor_encode_h */ diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_private.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor_private.h deleted file mode 100644 index a061809cc508..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_private.h +++ /dev/null @@ -1,409 +0,0 @@ -/* ========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2024, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - - -#ifndef qcbor_private_h -#define qcbor_private_h - - -#include -#include "UsefulBuf.h" -#include "qcbor/qcbor_common.h" - - -#ifdef __cplusplus -extern "C" { -#if 0 -} // Keep editor indention formatting happy -#endif -#endif - - -/* This was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, - * but this is inconsistent with all the other QCBOR_DISABLE_ - * #defines, so the name was changed and this was added for backwards - * compatibility - */ -#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -#define QCBOR_DISABLE_EXP_AND_MANTISSA -#endif - -/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define - * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - */ -#ifdef USEFULBUF_DISABLE_ALL_FLOAT -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -#define QCBOR_DISABLE_FLOAT_HW_USE -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT -#define QCBOR_DISABLE_PREFERRED_FLOAT -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - -/* - * Convenience macro for selecting the proper return value in case floating - * point feature(s) are disabled. - * - * The macros: - * - * FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should - * result error, and all other cases should return - * 'x'. - * - * The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all - * floating point is disabled. - * - * FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float - * results in error, and all other cases should - * return 'x'. - * FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating - * point results in error, and all other cases - * should return 'x'. - * FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled - * preferred float or disabling - * hardware floating point results in - * error, and all other cases should - * return 'x'. - */ -#ifdef USEFULBUF_DISABLE_ALL_FLOAT - #define FLOAT_ERR_CODE_NO_FLOAT(x) QCBOR_ERR_ALL_FLOAT_DISABLED - #define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_ALL_FLOAT_DISABLED - #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED - #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED -#else /* USEFULBUF_DISABLE_ALL_FLOAT*/ - #define FLOAT_ERR_CODE_NO_FLOAT(x) x - #ifdef QCBOR_DISABLE_PREFERRED_FLOAT - #define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_HALF_PRECISION_DISABLED - #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HALF_PRECISION_DISABLED - #else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - #define FLOAT_ERR_CODE_NO_HALF_PREC(x) x - #ifdef QCBOR_DISABLE_FLOAT_HW_USE - #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED - #else - #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) x - #endif - #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ - #ifdef QCBOR_DISABLE_FLOAT_HW_USE - #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED - #else /* QCBOR_DISABLE_FLOAT_HW_USE */ - #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) x - #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#endif /*USEFULBUF_DISABLE_ALL_FLOAT*/ - - -/* - * These are special values for the AdditionalInfo bits that are part of - * the first byte. Mostly they encode the length of the data item. - */ -#define LEN_IS_ONE_BYTE 24 -#define LEN_IS_TWO_BYTES 25 -#define LEN_IS_FOUR_BYTES 26 -#define LEN_IS_EIGHT_BYTES 27 -#define ADDINFO_RESERVED1 28 -#define ADDINFO_RESERVED2 29 -#define ADDINFO_RESERVED3 30 -#define LEN_IS_INDEFINITE 31 - - -/* - * 24 is a special number for CBOR. Integers and lengths - * less than it are encoded in the same byte as the major type. - */ -#define CBOR_TWENTY_FOUR 24 - - -/* - * Values for the 5 bits for items of major type 7 - */ -#define CBOR_SIMPLEV_FALSE 20 -#define CBOR_SIMPLEV_TRUE 21 -#define CBOR_SIMPLEV_NULL 22 -#define CBOR_SIMPLEV_UNDEF 23 -#define CBOR_SIMPLEV_ONEBYTE 24 -#define HALF_PREC_FLOAT 25 -#define SINGLE_PREC_FLOAT 26 -#define DOUBLE_PREC_FLOAT 27 -#define CBOR_SIMPLE_BREAK 31 -#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE -#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK - - -/* The largest offset to the start of an array or map. It is slightly - * less than UINT32_MAX so the error condition can be tested on 32-bit - * machines. UINT32_MAX comes from uStart in QCBORTrackNesting being - * a uin32_t. - * - * This will cause trouble on a machine where size_t is less than 32-bits. - */ -#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) - - -/* The number of tags that are 16-bit or larger that can be handled - * in a decode. - */ -#define QCBOR_NUM_MAPPED_TAGS 4 - -/* The number of tags (of any size) recorded for an individual item. */ -#define QCBOR_MAX_TAGS_PER_ITEM1 4 - - - - -/* - * PRIVATE DATA STRUCTURE - * - * Holds the data for tracking array and map nesting during - * encoding. Pairs up with the Nesting_xxx functions to make an - * "object" to handle nesting encoding. - * - * uStart is a uint32_t instead of a size_t to keep the size of this - * struct down so it can be on the stack without any concern. It - * would be about double if size_t was used instead. - * - * Size approximation (varies with CPU/compiler): - * 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes - * 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes - */ -typedef struct __QCBORTrackNesting { - /* PRIVATE DATA STRUCTURE */ - struct { - /* See QCBOREncode_OpenMapOrArray() for details on how this works */ - uint32_t uStart; /* uStart is the position where the array starts */ - uint16_t uCount; /* Number of items in the arrary or map; counts items - * in a map, not pairs of items */ - uint8_t uMajorType; /* Indicates if item is a map or an array */ - } pArrays[QCBOR_MAX_ARRAY_NESTING+1], /* stored state for nesting levels */ - *pCurrentNesting; /* the current nesting level */ -} QCBORTrackNesting; - - -/* - * PRIVATE DATA STRUCTURE - * - * Context / data object for encoding some CBOR. Used by all encode - * functions to form a public "object" that does the job of encdoing. - * - * Size approximation (varies with CPU/compiler): - * 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes - * 32-bit machine: 15 + 1 + 132 = 148 bytes - */ -struct _QCBOREncodeContext { - /* PRIVATE DATA STRUCTURE */ - UsefulOutBuf OutBuf; /* Pointer to output buffer, its length and - * position in it. */ - uint8_t uError; /* Error state, always from QCBORError enum */ - QCBORTrackNesting nesting; /* Keep track of array and map nesting */ -}; - - -/* - * PRIVATE DATA STRUCTURE - * - * Holds the data for array and map nesting for decoding work. This - * structure and the DecodeNesting_Xxx() functions in qcbor_decode.c - * form an "object" that does the work for arrays and maps. All access - * to this structure is through DecodeNesting_Xxx() functions. - * - * 64-bit machine size - * 128 = 16 * 8 for the two unions - * 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment - * 16 = 16 bytes for two pointers - * 208 TOTAL - * - * 32-bit machine size is 200 bytes - */ -typedef struct __QCBORDecodeNesting { - /* PRIVATE DATA STRUCTURE */ - struct nesting_decode_level { - /* - * This keeps tracking info for each nesting level. There are two - * main types of levels: - * 1) Byte count tracking. This is for the top level input CBOR - * which might be a single item or a CBOR sequence and byte - * string wrapped encoded CBOR. - * 2) Item count tracking. This is for maps and arrays. - * - * uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and - * QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY - * for 2). - * - * Item count tracking is either for definite or indefinite-length - * maps/arrays. For definite lengths, the total count and items - * unconsumed are tracked. For indefinite-length, uTotalCount is - * QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and - * there is no per-item count of members. For indefinite-length - * maps and arrays, uCountCursor is UINT16_MAX if not consumed - * and zero if it is consumed in the pre-order - * traversal. Additionally, if entered in bounded mode, - * uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate - * it is empty. - * - * This also records whether a level is bounded or not. All - * byte-count tracked levels (the top-level sequence and - * bstr-wrapped CBOR) are bounded implicitly. Maps and arrays - * may or may not be bounded. They are bounded if they were - * Entered() and not if they were traversed with GetNext(). They - * are marked as bounded by uStartOffset not being @c UINT32_MAX. - */ - /* - * If uLevelType can put in a separately indexed array, the - * union/struct will be 8 bytes rather than 9 and a lot of - * wasted padding for alignment will be saved. - */ - uint8_t uLevelType; - union { - struct { -#define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX -#define QCBOR_COUNT_INDICATES_ZERO_LENGTH UINT16_MAX-1 - uint16_t uCountTotal; - uint16_t uCountCursor; -#define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX - /* The start of the array or map in bounded mode so - * the input can be rewound for GetInMapXx() by label. */ - uint32_t uStartOffset; - } ma; /* for maps and arrays */ - struct { - /* The end of the input before the bstr was entered so that - * it can be restored when the bstr is exited. */ - uint32_t uSavedEndOffset; - /* The beginning of the bstr so that it can be rewound. */ - uint32_t uBstrStartOffset; - } bs; /* for top-level sequence and bstr-wrapped CBOR */ - } u; - } pLevels[QCBOR_MAX_ARRAY_NESTING+1], - *pCurrent, - *pCurrentBounded; - /* - * pCurrent is for item-by-item pre-order traversal. - * - * pCurrentBounded points to the current bounding level or is NULL - * if there isn't one. - * - * pCurrent must always be below pCurrentBounded as the pre-order - * traversal is always bounded by the bounding level. - * - * When a bounded level is entered, the pre-order traversal is set - * to the first item in the bounded level. When a bounded level is - * exited, the pre-order traversl is set to the next item after the - * map, array or bstr. This may be more than one level up, or even - * the end of the input CBOR. - */ -} QCBORDecodeNesting; - - -typedef struct { - /* PRIVATE DATA STRUCTURE */ - void *pAllocateCxt; - UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); -} QCBORInternalAllocator; - - -/* - * PRIVATE DATA STRUCTURE - * - * The decode context. This data structure plus the public - * QCBORDecode_xxx functions form an "object" that does CBOR decoding. - * - * Size approximation (varies with CPU/compiler): - * 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes - * 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes - */ -struct _QCBORDecodeContext { - /* PRIVATE DATA STRUCTURE */ - UsefulInputBuf InBuf; - - QCBORDecodeNesting nesting; - - /* If a string allocator is configured for indefinite-length - * strings, it is configured here. - */ - QCBORInternalAllocator StringAllocator; - - /* These are special for the internal MemPool allocator. They are - * not used otherwise. We tried packing these in the MemPool - * itself, but there are issues with memory alignment. - */ - uint32_t uMemPoolSize; - uint32_t uMemPoolFreeOffset; - - /* A cached offset to the end of the current map 0 if no value is - * cached. - */ -#define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX - uint32_t uMapEndOffsetCache; - - uint8_t uDecodeMode; - uint8_t bStringAllocateAll; - uint8_t uLastError; /* QCBORError stuffed into a uint8_t */ - - /* See MapTagNumber() for description of how tags are mapped. */ - uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS]; - - uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1]; -}; - - -/* Used internally in the impementation here Must not conflict with - * any of the official CBOR types - */ -#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 -#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12 - - -/* Add this to types to indicate they are to be encoded as indefinite lengths */ -#define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80 -#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \ - CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER -#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN \ - CBOR_MAJOR_TYPE_MAP + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER -#define CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK \ - CBOR_MAJOR_TYPE_SIMPLE + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER - - -/* Value of QCBORItem.val.string.len when the string length is - * indefinite. Used temporarily in the implementation and never - * returned in the public interface. - */ -#define QCBOR_STRING_LENGTH_INDEFINITE SIZE_MAX - - -/* The number of elements in a C array of a particular type */ -#define C_ARRAY_COUNT(array, type) (sizeof(array)/sizeof(type)) - - -#ifdef __cplusplus -} -#endif - -#endif /* qcbor_private_h */ diff --git a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_spiffy_decode.h b/3rdparty/internal/QCBOR/inc/qcbor/qcbor_spiffy_decode.h deleted file mode 100644 index e5ad4cd762b5..000000000000 --- a/3rdparty/internal/QCBOR/inc/qcbor/qcbor_spiffy_decode.h +++ /dev/null @@ -1,3072 +0,0 @@ -/* ========================================================================== - * qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding. - * - * Copyright (c) 2020-2025, Laurence Lundblade. All rights reserved. - * Copyright (c) 2021, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in file named "LICENSE" - * - * Forked from qcbor_decode.h on 7/23/2020 - * ========================================================================== */ -#ifndef qcbor_spiffy_decode_h -#define qcbor_spiffy_decode_h - - -#include "qcbor/qcbor_decode.h" - - -#ifdef __cplusplus -extern "C" { -#if 0 -} // Keep editor indention formatting happy -#endif -#endif - - -/** - * @file qcbor_spiffy_decode.h - * - * @anchor SpiffyDecode - * # Spiffy Decode - * - * This section discusses spiffy decoding assuming familiarity with - * the general description of decoding in the - * @ref BasicDecode section. - * - * Spiffy decode is extra decode features over and above the @ref - * BasicDecode features that generally are easier to use, mirror the - * encoding functions better and can result in smaller code size for - * larger and more complex CBOR protocols. In particular, spiffy - * decode facilitates getting the next data item of a specific type, - * setting an error if it is not of that type. It facilitates - * explicitly entering and exiting arrays and maps. It facilates - * fetching items by label from a map including duplicate label - * detection. - * - * Encoded CBOR can be viewed to have a tree structure where the leaf - * nodes are non-aggregate types like integers and strings and the - * intermediate nodes are either arrays or maps. Fundamentally, all - * decoding is a pre-order traversal of the tree. Calling - * QCBORDecode_GetNext() repeatedly will perform this. - * - * This pre-order traversal gives natural decoding of arrays where the - * array members are taken in order, but does not give natural decoding - * of maps where access by label is usually preferred. Using the - * QCBORDecode_EnterMap() and QCBORDecode_GetXxxxInMapX() methods like - * QCBORDecode_GetInt64InMapN(), map items can be accessed by - * label. QCBORDecode_EnterMap() bounds decoding to a particular - * map. QCBORDecode_GetXxxxInMapX() methods allows decoding the item of - * a particular label in the particular map. This can be used with - * nested maps by using QCBORDecode_EnterMapFromMapX(). - * - * When QCBORDecode_EnterMap() is called, pre-order traversal - * continues to work. There is a cursor that is run over the tree with - * calls to QCBORDecode_GetNext(). Attempts to use - * QCBORDecode_GetNext() beyond the end of the map will give the - * @ref QCBOR_ERR_NO_MORE_ITEMS error. - * - * Use of the traversal cursor can be mixed with the fetching of items - * by label with some caveats. When a non-aggregate item like an - * integer or string is fetched by label, the traversal cursor is - * unaffected so the mixing can be done freely. When an aggregate - * item is entered by label (by QCBORDecode_EnterMapFromMapN() and - * similar), the traversal cursor is set to the item after the - * subordinate aggregate item when it is exited. This will not matter - * to many use cases. Use cases that mix can be sure to separate - * traversal by the cursor from fetching by label. - * QCBORDecode_Rewind() may be useful to reset the traversal cursor - * after fetching aggregate items by label. - * - * (This behavior was incorrectly documented in QCBOR 1.2 and prior - * which described aggregate and non-aggregate as behaving the same. - * Rather than changing to make aggregate and non-aggregate - * consistent, the behavior is retained and documented because 1) it - * is usable as is, 2) a change would bring backward compatibility - * issues, 3) the change would increase the decode context size and - * code size. In QCBOR 1.3 test cases were added to validate the - * behavior. No problems were uncovered.) - * - * QCBORDecode_EnterArray() can be used to narrow the traversal to the - * extent of the array. - * - * All the QCBORDecode_GetXxxxInMapX() methods support duplicate label - * detection and will result in an error if the map has duplicate - * labels. - * - * All the QCBORDecode_GetXxxxInMapX() methods are implemented by - * performing the pre-order traversal of the map to find the labeled - * item everytime it is called. It doesn't build up a hash table, a - * binary search tree or some other efficiently searchable structure - * internally. For small maps this is fine and for high-speed CPUs - * this is fine, but for large, perhaps deeply nested, maps on slow - * CPUs, it may have performance issues (these have not be - * quantified). One way ease this is to use - * QCBORDecode_GetItemsInMap() which allows decoding of a list of - * items expected in an map in one traveral. - * - * @anchor Tag-Usage - * ## Tag Usage - * - * Data types beyond the basic CBOR types of numbers, strings, maps and - * arrays are called tags. The main registry of these new types is in - * the IANA CBOR tags registry. These new types may be simple such a - * number that is to be interpreted as a date, or of moderate complexity - * such as defining a decimal fraction that is an array containing a - * mantissa and exponent, or complex such as format for signing and - * encryption. - * - * When a tag occurs in a protocol it is encoded as an integer tag - * number plus the content of the tag. - * - * The content format of a tag may also be "borrowed". For example, a - * protocol definition may say that a particular data item is an epoch - * date just like tag 1, but not actually tag 1. In practice the - * difference is the presence or absence of the integer tag number in - * the encoded CBOR. - * - * The decoding functions for these new types takes a tag requirement - * parameter to say whether the item is a tag, is just borrowing the - * content format and is not a tag, or whether either is OK. - * - * If the parameter indicates the item must be a tag (@ref - * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is - * set if it is not one of the expected tag types. To decode correctly - * the contents of the tag must also be of the correct type. For - * example, to decode an epoch date tag the content must be an integer - * or floating-point value. - * - * If the parameter indicates it should not be a tag - * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then - * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the - * encoded CBOR is not what is expected. In the example of an epoch - * date, the data type must be an integer or floating-point value. This - * is the case where the content format of a tag is borrowed. - * - * The parameter can also indicate that either a tag or no tag is - * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol - * design should however be clear and choose one or the other and not - * need this option. This is a way to implement "be liberal in what you - * accept", however these days that is less in favor. See - * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. - * - * Map searching works with indefinite length strings. A string - * allocator must be set up the same as for any handling of indefinite - * length strings. However, It currently over-allocates memory from the - * string pool and thus requires a much larger string pool than it - * should. The over-allocation happens every time a map is searched by - * label. (This may be corrected in the future). - */ - - - - -/** The data item must be a tag of the expected type. It is an error - * if it is not. For example when calling QCBORDecode_GetEpochDate(), - * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See - * @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_TAG 0 - -/** The data item must be of the type expected for content data type - * being fetched. It is an error if it is not. For example, when - * calling QCBORDecode_GetEpochDate() and it must not be an @ref - * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1 - -/** Either of the above two are allowed. This allows implementation of - * being liberal in what you receive, but it is better if CBOR-based - * protocols pick one and stick to and not required the reciever to - * take either. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2 - -/** Add this into the above value if other tags not processed by QCBOR - * are to be allowed to surround the data item. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80 - - - - -/** Conversion will proceed if the CBOR item to be decoded is an - * integer or either type 0 (unsigned) or type 1 (negative). */ -#define QCBOR_CONVERT_TYPE_XINT64 0x01 -/** Conversion will proceed if the CBOR item to be decoded is either - * double, single or half-precision floating-point (major type 7). */ -#define QCBOR_CONVERT_TYPE_FLOAT 0x02 -/** Conversion will proceed if the CBOR item to be decoded is a big - * number, positive or negative (tag 2 or tag 3). */ -#define QCBOR_CONVERT_TYPE_BIG_NUM 0x04 -/** Conversion will proceed if the CBOR item to be decoded is a - * decimal fraction (tag 4). */ -#define QCBOR_CONVERT_TYPE_DECIMAL_FRACTION 0x08 -/** Conversion will proceed if the CBOR item to be decoded is a big - * float (tag 5). */ -#define QCBOR_CONVERT_TYPE_BIGFLOAT 0x10 - - - - -/** - * @brief Decode next item into a signed 64-bit integer. - * - * @param[in] pCtx The decode context. - * @param[out] pnValue The returned 64-bit signed integer. - * - * The CBOR data item to decode must be a positive or negative integer - * (CBOR major type 0 or 1). If not @ref QCBOR_ERR_UNEXPECTED_TYPE is set. - * - * If the CBOR integer is either too large or too small to fit in an - * int64_t, the error @ref QCBOR_ERR_INT_OVERFLOW or - * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW is set. Note that type 0 - * unsigned integers can be larger than will fit in an int64_t and - * type 1 negative integers can be smaller than will fit in an - * int64_t. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_GetUInt64(), QCBORDecode_GetInt64Convert(), - * QCBORDecode_GetInt64ConvertAll() and QCBORDecode_GetDoubleConvert() - */ -static void -QCBORDecode_GetInt64(QCBORDecodeContext *pCtx, - int64_t *pnValue); - -static void -QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - int64_t *pnValue); - -static void -QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - int64_t *pnValue); - - -/** - * @brief Decode next item into a signed 64-bit integer with basic conversions. - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] pnValue The returned 64-bit signed integer. - * - * @c uConvertTypes controls what conversions this will perform and - * thus what CBOR types will be decoded. @c uConvertType is a bit map - * listing the conversions to be allowed. This function supports - * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - * conversions. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * If the CBOR data type can never be convered by this function or the - * conversion was not selected in @c uConversionTypes - * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. - * - * When converting floating-point values, the integer is rounded to - * the nearest integer using llround(). By default, floating-point - * suport is enabled for QCBOR. - * - * If floating-point HW use is disabled this will set - * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is - * encountered. If half-precision support is disabled, this will set - * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number - * is encountered. - * - * If floating-point usage is disabled this will set - * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is - * encountered. - * - * See also QCBORDecode_GetInt64ConvertAll() which will perform the - * same conversions as this and a lot more at the cost of adding more - * object code to your executable. - */ -static void -QCBORDecode_GetInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); - -static void -QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); - -static void -QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); - - -/** - * @brief Decode next item into a signed 64-bit integer with conversions. - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] pnValue The returned 64-bit signed integer. - * - * This is the same as QCBORDecode_GetInt64Convert() but additionally - * supports conversion from positive and negative bignums, decimal - * fractions and big floats, including decimal fractions and big floats - * that use bignums. The conversion types supported are - * @ref QCBOR_CONVERT_TYPE_XINT64, @ref QCBOR_CONVERT_TYPE_FLOAT, - * @ref QCBOR_CONVERT_TYPE_BIG_NUM, - * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and - * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * Note that most these types can support numbers much larger that can - * be represented by in a 64-bit integer, so - * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW may often be encountered. - * - * When converting bignums and decimal fractions, - * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be set if the result - * is below 1, unless the mantissa is zero, in which case the - * coversion is successful and the value of 0 is returned. - * - * See also QCBORDecode_GetInt64ConvertAll() which does some of these - * conversions, but links in much less object code. See also - * QCBORDecode_GetUInt64ConvertAll(). - * - * This relies on CBOR tags to identify big numbers, decimal fractions - * and big floats. It will not attempt to decode non-tag CBOR that might - * be one of these. (If QCBOR_DISABLE_TAGS is set, this is effectively - * the same as QCBORDecode_GetInt64Convert() because all the additional - * number types this decodes are tags). - */ -void -QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); - -void -QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); - -void -QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); - - -/** - * @brief Decode next item into an unsigned 64-bit integer. - * - * @param[in] pCtx The decode context. - * @param[out] puValue The returned 64-bit unsigned integer. - * - * This is the same as QCBORDecode_GetInt64(), but returns an unsigned integer - * and thus can only decode CBOR positive integers. - * @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION is set if the input is a negative - * integer. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_GetUInt64Convert() and QCBORDecode_GetUInt64ConvertAll(). - */ -static void -QCBORDecode_GetUInt64(QCBORDecodeContext *pCtx, - uint64_t *puValue); - -static void -QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint64_t *puValue); - -static void -QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint64_t *puValue); - - -/** - * @brief Decode next item as an unsigned 64-bit integer with basic conversions. - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] puValue The returned 64-bit unsigned integer. - * - * This is the same as QCBORDecode_GetInt64Convert(), but returns an - * unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - * if the value to be decoded is negatve. - * - * If floating-point HW use is disabled this will set - * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is - * encountered. If half-precision support is disabled, this will set - * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number - * is encountered. - * - * If floating-point usage is disabled this will set - * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is - * encountered. - * - * See also QCBORDecode_GetUInt64Convert() and - * QCBORDecode_GetUInt64ConvertAll(). - */ -static void -QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); - -static void -QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); - -static void -QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); - - -/** - * @brief Decode next item into an unsigned 64-bit integer with conversions - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] puValue The returned 64-bit unsigned integer. - * - * This is the same as QCBORDecode_GetInt64ConvertAll(), but returns - * an unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - * if the value to be decoded is negatve. - * - * See also QCBORDecode_GetUInt64() and QCBORDecode_GetUInt64Convert(). - */ -void -QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); - -void -QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); - -void -QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); - - - - -/** - * @brief Decode the next item as a byte string - * - * @param[in] pCtx The decode context. - * @param[out] pBytes The decoded byte string. - * - * The CBOR item to decode must be a byte string, CBOR type 2. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * If the CBOR item to decode is not a byte string, the - * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. - */ -static void -QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, - UsefulBufC *pBytes); - -static void -QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pBytes); - -static void -QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pBytes); - - -/** - * @brief Decode the next item as a text string. - * - * @param[in] pCtx The decode context. - * @param[out] pText The decoded byte string. - * - * The CBOR item to decode must be a text string, CBOR type 3. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * It the CBOR item to decode is not a text string, the - * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. - * - * This does no translation of line endings. See QCBOREncode_AddText() - * for a discussion of line endings in CBOR. - */ -static void -QCBORDecode_GetTextString(QCBORDecodeContext *pCtx, - UsefulBufC *pText); - -static void -QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pText); - -static void -QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pText); - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Decode next item into a double floating-point value. - * - * @param[in] pCtx The decode context. - * @param[out] pValue The returned floating-point value. - * - * The CBOR data item to decode must be a half-precision, - * single-precision or double-precision floating-point value. If not - * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. - * - * If floating-point HW use is disabled this will set - * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is - * encountered. If half-precision support is disabled, this will set - * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number - * is encountered. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_GetDoubleConvert() and - * QCBORDecode_GetDoubleConvertAll(). - */ -static void -QCBORDecode_GetDouble(QCBORDecodeContext *pCtx, - double *pValue); - -static void -QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - double *pdValue); - -static void -QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - double *pdValue); - - -/** - * @brief Decode next item into a double floating-point with basic conversion. - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] pdValue The returned floating-point value. - * - * This will decode CBOR integer and floating-point numbers, returning - * them as a double floating-point number. This function supports - - * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - * conversions. If the encoded CBOR is not one of the requested types - * or a type not supported by this function, @ref QCBOR_ERR_UNEXPECTED_TYPE - * is set. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * If floating-point HW use is disabled this will set - * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is - * encountered. If half-precision support is disabled, this will set - * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number is - * encountered. - * - * Positive and negative integers can always be converted to - * floating-point, so this will never error on CBOR major type 0 or 1. - * - * Note that a large 64-bit integer can have more precision (64 bits) - * than even a double floating-point (52 bits) value, so there is loss - * of precision in some conversions. - * - * See also QCBORDecode_GetDouble() and QCBORDecode_GetDoubleConvertAll(). - */ -static void -QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); - -static void -QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); - -static void -QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); - - -/** - * @brief Decode next item as a double floating-point value with conversion. - * - * @param[in] pCtx The decode context. - * @param[in] uConvertTypes The integer conversion options. - * @param[out] pdValue The returned floating-point value. - * - * This is the same as QCBORDecode_GetDoubleConvert() but supports - * many more conversions at the cost of linking in more object - * code. The conversion types supported are @ref QCBOR_CONVERT_TYPE_XINT64, - * @ref QCBOR_CONVERT_TYPE_FLOAT, @ref QCBOR_CONVERT_TYPE_BIG_NUM, - * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and - * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. - * - * Big numbers, decimal fractions and big floats that are too small or - * too large to be reprented as a double floating-point number will be - * returned as plus or minus zero or infinity rather than setting an - * under or overflow error. - * - * There is often loss of precision in the conversion. - * - * See also QCBORDecode_GetDoubleConvert() and QCBORDecode_GetDoubleConvert(). - */ -void -QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); - -void -QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); - -void -QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - - - -/** - * @brief Enter an array for decoding in bounded mode. - * - * @param[in] pCtx The decode context. - * @param[out] pItem The optionally returned QCBORItem that has the - * label and tags for the array. May be @c NULL (and - * usually is). - * - * This enters an array for decoding in bounded mode. The items in - * the array are decoded in order the same as when not in bounded mode, - * but the decoding will not proceed past the end or the array. - * - * The typical way to iterate over items in an array is to call - * QCBORDecode_VGetNext() until QCBORDecode_GetError() returns - * @ref QCBOR_ERR_NO_MORE_ITEMS. Other methods like QCBORDecode_GetInt64(), - * QCBORDecode_GetBignum() and such may also called until - * QCBORDecode_GetError() doesn't return QCBOR_SUCCESS. - * - * Another option is to get the array item count from - * @c pItem->val.uCount, but note that that will not work with - * indefinte-length arrays, where as QCBORDecode_GetError() will. - * - * Nested decoding of arrays may be handled by calling - * QCBORDecode_EnterArray() or by using QCBORDecode_VGetNext() to - * descend into and back out of the nested array. - * - * QCBORDecode_Rewind() can be called to restart decoding from the - * first item in the array. - * - * When all decoding in an array is complete, QCBORDecode_ExitArray() must - * be called. It is a decoding error to not have a corresponding call - * to QCBORDecode_ExitArray() for every call to QCBORDecode_EnterArray(). - * If not, @ref QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN will be returned when - * QCBORDecode_Finish() is called. - * - * After QCBORDecode_ExitArray() is called the traversal cusor is at - * the item right after the array. This is true whether or not all - * items in the array were consumed. QCBORDecode_ExitArray() can even - * be called right after QCBORDecode_EnterArray() as a way to skip - * over an array and all its contents. - * - * This works the same for definite and indefinite length arrays. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * If attempting to enter a data item that is not an array - * @ref QCBOR_ERR_UNEXPECTED_TYPE wil be set. - * - * Nested arrays and maps may be entered to a depth of - * @ref QCBOR_MAX_ARRAY_NESTING. - * - * See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap(), - * QCBORDecode_EnterBstrWrapped() and QCBORDecode_GetArray(). - */ -static void -QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem); - -void -QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t uLabel); - -void -QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel); - - -/** - * @brief Exit an array that has been enetered. - * - * @param[in] pCtx The decode context. - * - * An array must have been entered for this to succeed. - * - * The items in the array that was entered do not have to have been - * consumed for this to succeed. - * - * This sets the traversal cursor to the item after the - * array that was exited. - * - * This will result in an error if any item in the array is not well - * formed (since all items in the array must be decoded to find its - * end), or there are not enough items in the array. - */ -static void -QCBORDecode_ExitArray(QCBORDecodeContext *pCtx); - - - -/** - * @brief Get the encoded bytes that make up an array. - * - * @param[in] pCtx The decode context. - * @param[out] pItem Place to return the item. - * @param[out] pEncodedCBOR Place to return pointer and length of the array. - * - * The next item to decode must be an array. - * - * The encoded bytes of the array will be returned. They can be - * decoded by another decoder instance. - * - * @c pItem will have the label and tags for the array. It is filled - * in the same as if QCBORDecode_GetNext() were called on the array item. In - * particular, the array count will be filled in for definite-length - * arrays and set to @c UINT16_MAX for indefinite-length arrays. - * - * This works on both definite and indefinite length arrays (unless - * indefinite length array decoding has been disabled). - * - * The pointer returned is to the data item that opens the array. The - * length in bytes includes it and all the member data items. If the array - * occurs in another map and thus has a label, the label is not included - * in what is returned. - * - * If the array is preceeded by tags, those encoded tags are included - * in the encoded CBOR that is returned. - * - * QCBORDecode_GetArray() consumes the entire array and leaves the - * traversal cursor at the item after the array. - * QCBORDecode_GetArrayFromMapN() and QCBORDecode_GetArrayFromMapSZ() - * don't affect the traversal cursor. - * - * This traverses the whole array and every subordinate array or map in - * it. This is necessary to determine the length of the array. - * - * This will fail if any item in the array is not well-formed. - * - * This uses a few hundred bytes of stack, more than most methods. - * - * See also QCBORDecode_EnterArray(). - */ -static void -QCBORDecode_GetArray(QCBORDecodeContext *pCtx, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - -static void -QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - -static void -QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - -/** - * @brief Enter a map for decoding and searching. - * - * @param[in] pCtx The decode context. - * @param[out] pItem The optionally returned QCBORItem that has the - * label and tags for the map. May be @c NULL (and - * usually is). - * - * The next item in the CBOR input must be map or this sets an error. - * - * This puts the decoder in bounded mode which narrows decoding to the - * map entered and enables getting items by label. - * - * All items in the map must be well-formed to be able to search it by - * label because a full traversal is done for each search. If not, the - * search will retun an error for the item that is not well-formed. - * This will be the first non-well-formed item which may not be the - * item with the label that is the target of the search. - * - * Nested maps can be decoded like this by entering each map in turn. - * - * Call QCBORDecode_ExitMap() to exit the current map decoding - * level. When all map decoding layers are exited then bounded mode is - * fully exited. - * - * While in bounded mode, QCBORDecode_GetNext() works as usual on the - * map and the traversal cursor is maintained. It starts out - * at the first item in the map just entered. Attempts to get items - * off the end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS - * rather going to the next item after the map as it would when not in - * bounded mode. - * - * It is possible to mix use of the traversal cursor with the fetching - * of items in a map by label with the caveat that fetching - * non-aggregate items by label behaves differently from entering subordinate - * aggregate items by label. See dicussion in @ref SpiffyDecode. - * - * Exiting leaves the traversal cursor at the data item following the - * last entry in the map or at the end of the input CBOR if there - * nothing after the map. - * - * Entering and Exiting a map is a way to skip over an entire map and - * its contents. After QCBORDecode_ExitMap(), the traversal - * cursor will be at the first item after the map. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_EnterArray() and - * QCBORDecode_EnterBstrWrapped(). Entering and exiting any nested - * combination of maps, arrays and bstr-wrapped CBOR is supported up - * to the maximum of @ref QCBOR_MAX_ARRAY_NESTING. - * - * See also QCBORDecode_GetMap(). - */ -static void -QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem); - -void -QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel); - -void -QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel); - - -/** - * @brief Exit a map that has been enetered. - * - * @param[in] pCtx The decode context. - * - * A map must have been entered for this to succeed. - * - * The items in the map that was entered do not have to have been - * consumed for this to succeed. - * - * This sets the traversal cursor to the item after the map - * that was exited. - * - * This will result in an error if any item in the map is not well - * formed (since all items in the map must be decoded to find its - * end), or there are not enough items in the map. - */ -static void -QCBORDecode_ExitMap(QCBORDecodeContext *pCtx); - - -/** - * @brief Get the bytes that make up a map. - * - * @param[in] pCtx The decode context. - * @param[out] pItem Place to return the item. - * @param[out] pEncodedCBOR Place to return pointer and length of the map. - * - * The next item to decode must be a map. - * - * The encoded bytes of the map will be returned. They can be - * decoded by another decoder instance. - * - * @c pItem will have the label and tags for the array. It is filled - * in the same as if QCBORDecode_GetNext() were called on the map item. In - * particular, the map count will be filled in for definite-length - * maps and set to @c UINT16_MAX for indefinite-length maps. - * - * This works on both definite and indefinite length maps (unless - * indefinite length map decoding has been disabled). - * - * The pointer returned is to the data item that opens the map. The - * length in bytes includes it and all the member data items. If the map - * occurs in another map and thus has a label, the label is not included - * in what is returned. - * - * If the map is preceeded by tags, those encoded tags are included in - * the encoded CBOR that is returned. - * - * QCBORDecode_GetMap() consumes the entire array and leaves the - * traversal cursor at the item after the map. - * QCBORDecode_GetMapFromMapN() and QCBORDecode_GetMapFromMapSZ() - * don't affect the traversal cursor. - * - * This traverses the whole map and every subordinate array or map in - * it. This is necessary to determine the length of the map. The - * traversal cursor is left at the first item after the map. - * - * This will fail if any item in the map is not well-formed. - * - * This uses a few hundred bytes of stack, more than most methods. - * - * See also QCBORDecode_EnterMap(). - */ -static void -QCBORDecode_GetMap(QCBORDecodeContext *pCtx, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - -static void -QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - -static void -QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - -/** - * @brief Reset traversal cursor to start of map, array, byte-string - * wrapped CBOR or start of input. - * - * @param[in] pCtx The decode context. - * - * If an array, map or wrapping byte string has been entered this sets - * the traversal cursor to its beginning. If several arrays, maps or - * byte strings have been entered, this sets the traversal cursor to - * the beginning of the one most recently entered. - * - * If no map or array has been entered, this resets the traversal - * cursor to the beginning of the input CBOR. - * - * This also resets the error state. - */ -void -QCBORDecode_Rewind(QCBORDecodeContext *pCtx); - - -/** - * @brief Get an item in map by label and type. - * - * @param[in] pCtx The decode context. - * @param[in] nLabel The integer label. - * @param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX. - * @param[out] pItem The returned item. - * - * A map must have been entered to use this. If not - * @ref QCBOR_ERR_MAP_NOT_ENTERED is set. - * - * The map is searched for an item of the requested label and type. - * @ref QCBOR_TYPE_ANY can be given to search for the label without - * matching the type. - * - * This will always search the entire map. This will always perform - * duplicate label detection, setting @ref QCBOR_ERR_DUPLICATE_LABEL - * if there is more than one occurance of the label being searched - * for. - * - * Duplicate label detection is performed for the item being sought - * and only for the item being sought. - * - * This performs a full decode of every item in the map being - * searched which involves a full traversal of every item. For maps - * with little nesting, this is of little consequence, but may be of - * consequence for large deeply nested CBOR structures on slow CPUs. - * - * The position of the traversal cursor is not changed. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_GetItemsInMap() for error discussion. - */ -void -QCBORDecode_GetItemInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem); - -void -QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem); - - -/** - * @brief Get multiple labeled items from a CBOR map efficiently. - * - * @param[in] pCtx The decode context. - * @param[in,out] pItemList On input, the items to search for. On output, - * the returned items. - * - * @c pItemList is an array of items, terminated by an item with - * @c uLabelType == @ref QCBOR_TYPE_NONE. - * - * On input, each item in @c pItemList specifies: - * - A label to search for (@c uLabelType and @c label fields). - * - An expected CBOR type (@c uDataType). - * - To match any type regardless of its CBOR type, set @c uDataType to - * @ref QCBOR_TYPE_ANY. - * - * On output, each item in @c pItemList may contain a found item: - * - @c uDataType is the data type for found items or @ref QCBOR_TYPE_NONE - * if the label was not matched. - * - @c value is the value of the found item. - * - * This is CPU-efficient because the map is traversed only once, - * rather than scanning for each label individually. - * - * This function returns maps and arrays contained within the map, but - * does not provide a way to descend into or decode them. To process - * nested maps and arrays, use functions like - * QCBORDecode_EnterMapFromMapN(), QCBORDecode_EnterArrayFromMapN(), - * and similar. - * - * The cursor position in the decoder is preserved; it is not advanced - * by this function. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * This function may set the following errors: - * - * - @ref QCBOR_ERR_MAP_NOT_ENTERED --- called before entering a map - * with QCBORDecode_EnterMap() or similar. - * - * - @ref QCBOR_ERR_DUPLICATE_LABEL --- One of the labels being - * searched for is duplicated in the input CBOR. - * - * - @ref QCBOR_ERR_HIT_END --- and other well-formedness errors as - * per QCBORDecode_IsNotWellFormedError(). - * - * - @ref QCBOR_ERR_UNEXPECTED_TYPE --- The type of a found item does - * not match the expected @c uDataType. - * - * - @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP --- and other QCBOR implementation - * @ref Limitations errors. - * - * Because the entire map is traversed, these errors can occur on - * unrelated items—not just those being searched for. - * - * @sa QCBORDecode_GetItemInMapN(), QCBORDecode_GetItemInMapSZ() and - * QCBORDecode_GetItemsInMapWithCallback(). - */ -void -QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList); - - -/** - * @brief Per-item callback for map searching. - * - * @param[in] pCallbackCtx Pointer to the caller-defined context for the callback. - * @param[in] pItem The item from the map. - * - * The error set is intended for QCBOR errors, not general protocol - * decoding errors. If this sets other than @ref QCBOR_SUCCESS, the - * search will stop and the value it returns will be set in - * QCBORDecode_GetItemsInMapWithCallback(). The special error, - * @ref QCBOR_ERR_CALLBACK_FAIL, can be returned to indicate some - * protocol processing error that is not a CBOR error. The specific - * details of the protocol processing error can be returned the call - * back context. - */ -typedef QCBORError (*QCBORItemCallback)(void *pCallbackCtx, - const QCBORItem *pItem); - - -/** - * @brief Get a group of labeled items all at once from a map with a callback. - * - * @param[in] pCtx The decode context. - * @param[in,out] pItemList On input, the items to search for. On output, - * the returne *d items. - * @param[in,out] pCallbackCtx Pointer to a context structure for - * @ref QCBORItemCallback - * @param[in] pfCB Pointer to function of type - * @ref QCBORItemCallback that is called on - * unmatched items. - * - * This searchs a map like QCBORDecode_GetItemsInMap(), but calls a - * callback on items not matched rather than ignoring them. If @c - * pItemList is empty, the call back will be called on every item in the - * map. - * - * Like QCBORDecode_GetItemsInMap(), this only matches and calls back on - * the items at the top level of the map entered. Items in nested - * maps and arrays are skipped over and not candidate for matching or the - * callback. - * - * See QCBORItemCallback() for error handling. - */ -void -QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB); - - - - -/** - * @brief Decode the next item as a Boolean. - * - * @param[in] pCtx The decode context. - * @param[out] pbBool The decoded byte string. - * - * The CBOR item to decode must be either the CBOR simple value (CBOR - * type 7) @c true or @c false. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". If - * the CBOR item to decode is not true or false the @ref - * QCBOR_ERR_UNEXPECTED_TYPE error is set. -*/ -void -QCBORDecode_GetBool(QCBORDecodeContext *pCtx, bool *pbBool); - -void -QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - bool *pbBool); - -void -QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - bool *pbBool); - - -/** - * @brief Decode the next item as a null. - * - * @param[in] pCtx The decode context. - * - * The CBOR item to decode must be the CBOR simple value (CBOR type 7) - * @c null. The reason to call this is to see if an error is returned - * or not indicating whether the item is a CBOR null. If it is not - * then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. - */ -static void -QCBORDecode_GetNull(QCBORDecodeContext *pCtx); - -static void -QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void -QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - - -/** - * @brief Decode the next item as a CBOR "undefined" item. - * - * @param[in] pCtx The decode context. - * - * The CBOR item to decode must be the CBOR simple value (CBOR type 7) - * @c undefined. The reason to call this is to see if an error is - * returned or not indicating whether the item is a CBOR undefed - * item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is - * set. - */ -static void -QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx); - -static void -QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void -QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - - -/** - * @brief Decode the next item as a CBOR simple value. - * - * @param[in] pCtx The decode context. - * @param[out] puSimpleValue The simplle value returned. - * - * The purpose of this is to get a CBOR simple value other than a - * Boolean, NULL or "undefined", but this works on all simple - * values. See QCBOREncode_AddSimple() for more details on simple - * values in general. - * - * See QCBORDecode_GetBool(), QCBORDecode_GetNull(), - * QCBORDecode_GetUndefined() for the preferred way of getting those - * simple values. - */ -void -QCBORDecode_GetSimple(QCBORDecodeContext *pCtx, uint8_t *puSimpleValue); - -void -QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t *puSimpleValue); - -void -QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t *puSimpleValue); - - - - -/** - * @brief Decode the next item as a date string. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pDateString The decoded date. - * - * This decodes the standard CBOR date/time string tag, integer tag - * number of 0, or encoded CBOR that is not a tag, but borrows the - * date string content format. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and - * @ref QCBOR_TYPE_DATE_STRING. - */ -static void -QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - * @brief Decode the next item as a date-only string. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pDateString The decoded date. - * - * This decodes the CBOR date-only string tag, integer tag number of - * 1004, or encoded CBOR that is not a tag, but borrows the date-only - * string content format. An example of the format is "1985-04-12". - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and - * @ref QCBOR_TYPE_DAYS_STRING. - */ -static void -QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - * @brief Decode the next item as an epoch date. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnTime The decoded epoch date. - * - * This decodes the standard CBOR epoch date/time tag, integer tag - * number of 1. This will also decode any integer or floating-point - * number as an epoch date (a tag 1 epoch date is just an integer or - * floating-point number). - * - * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer - * will not fit in an @c int64_t. Note that an @c int64_t can - * represent a range of over 500 billion years with one second - * resolution. - * - * Floating-point dates are always returned as an @c int64_t. The - * fractional part is discarded. - * - * If the input is a floating-point date and the QCBOR library is - * compiled with some or all floating-point features disabled, the - * following errors will be set. If the input is half-precision and - * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED - * is set. This function needs hardware floating-point to convert the - * floating-point value to an integer so if HW floating point is - * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all - * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED - * is set. A previous version of this function would return - * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when - * floating-point decoding was disabled. - * - * Floating-point dates that are plus infinity, minus infinity or NaN - * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW - * error. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and - * @ref QCBOR_TYPE_DATE_EPOCH. -*/ -void -QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnTime); - -void -QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime); - -void -QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime); - - -/** - * @brief Decode the next item as an days-count epoch date. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnDays The decoded epoch date. - * - * This decodes the CBOR epoch date tag, integer tag number of 100, or - * encoded CBOR that is not a tag, but borrows the content format. The - * date is the number of days (not number of seconds) before or after - * Jan 1, 1970. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and - * @ref QCBOR_TYPE_DAYS_EPOCH. -*/ -void -QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnDays); - -void -QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - -void -QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - - - - -/** - * @brief Decode the next item as a big number. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pValue The returned big number. - * @param[out] pbIsNegative Is @c true if the big number is negative. This - * is only valid when @c uTagRequirement is - * @ref QCBOR_TAG_REQUIREMENT_TAG. - * - * This decodes a standard CBOR big number, integer tag number of 2 or - * 3, or encoded CBOR that is not a tag, but borrows the content - * format. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * The big number is in network byte order. The first byte in @c - * pValue is the most significant byte. There may be leading zeros. - * - * The negative value is computed as -1 - n, where n is the postive - * big number in @c pValue. There is no standard representation for - * big numbers, positive or negative in C, so this implementation - * leaves it up to the caller to apply this computation for negative - * big numbers. - * - * RFC 8949 preferred serialization requires that big numbers - * that fit into integers be encoded as integers. This function - * will error if the input CBOR is a type 0 or 1 integers. A - * future version of QCBOR fixes this, but in the mean time - * the application must handle this manually. - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * Determination of the sign of the big number depends on the tag - * requirement of the protocol using the big number. If the protocol - * requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign - * indication is in the protocol and @c pbIsNegative indicates the - * sign. If the protocol doesn't use a tag, @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - * then the protocol design must have some way of indicating the sign. - * - * See also QCBORDecode_GetInt64ConvertAll(), - * QCBORDecode_GetUInt64ConvertAll() and - * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - * - * See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM, - * QCBOREncode_AddTPositiveBignum(), QCBOREncode_AddTNegativeBignum(), - * @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM. - */ -void -QCBORDecode_GetBignum(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); - -void -QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); - -void -QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); - - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - * @brief Decode the next item as a decimal fraction. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnMantissa The mantissa. - * @param[out] pnExponent The base 10 exponent. - * - * This decodes a standard CBOR decimal fraction, integer tag number - * of 4, or encoded CBOR that is not a tag, but borrows the content - * format. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * The value of this is computed by: - * - * mantissa * ( 10 ** exponent ) - * - * In the encoded CBOR, the mantissa and exponent may be of CBOR type - * 0 (positive integer), type 1 (negative integer), type 2 tag 2 - * (positive big number) or type 2 tag 3 (negative big number). This - * implementation will attempt to convert all of these to an @c - * int64_t. If the value won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW - * or @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set. - * - * This implementation limits the exponent to between @c INT64_MIN and - * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to - * @c UINT64_MAX. - * - * Various format and type issues will result in - * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also QCBORDecode_GetInt64ConvertAll(), - * QCBORDecode_GetUInt64ConvertAll() and - * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - * - * See also @ref CBOR_TAG_DECIMAL_FRACTION, - * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - * and QCBORDecode_GetDecimalFractionBig(). - * - * If QCBOR_DISABLE_TAGS is set, the only input this will decode is an - * array of two integers. It will set an error if the the array is - * preceded by by a tag number or if the mantissa is a big number. - */ -void -QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void -QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void -QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - * @brief Decode the next item as a decimal fraction with a big number mantissa. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[in] MantissaBuffer The buffer in which to put the mantissa. - * @param[out] pMantissa The big num mantissa. - * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - * @param[out] pnExponent The base 10 exponent. - * - * This is the same as QCBORDecode_GetDecimalFraction() except the - * mantissa is returned as a big number. - * - * In the encoded CBOR, the mantissa may be a type 0 (positive - * integer), type 1 (negative integer), type 2 tag 2 (positive big - * number) or type 2 tag 3 (negative big number). This implementation - * will convert all these to a big number. The limit to this - * conversion is the size of @c MantissaBuffer. - * - * The mantissa returned does NOT have the offset - * of one applied when it is negative. To get the true value - * one must be added to @c *pMantissa (which requires - * some big number arithmetic and may increase the length - * of it by one). - * - * For QCBOR before v1.5, this function had a bug where - * by the negative mantissa sometimes had the offset of - * one applied, making this function somewhat usless for - * negative mantissas. Specifically if the to-be-decoded CBOR - * was a type 1 integer the offset was applied and when it - * was a tag 3, the offset was not applied. It is possible - * that a tag 3 could contain a value in the range of a type 1 - * integer. @ref QCBORExpAndMantissa is - * correct and can be used instead of this. - * - * See also QCBORDecode_GetInt64ConvertAll(), - * QCBORDecode_GetUInt64ConvertAll() and - * QCBORDecode_GetDoubleConvertAll() which can convert decimal - * fractions. - * - * See also @ref CBOR_TAG_DECIMAL_FRACTION, - * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - * and QCBORDecode_GetDecimalFraction(). - */ -void -QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void -QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pbMantissaIsNegative, - bool *pbIsNegative, - int64_t *pnExponent); - -void -QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - - -/** - * @brief Decode the next item as a big float. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnMantissa The mantissa. - * @param[out] pnExponent The base 2 exponent. - * - * This decodes a standard CBOR big float, integer tag number of 5, or - * encoded CBOR that is not a tag, but borrows the content format. - * - * This is the same as QCBORDecode_GetDecimalFraction() with the - * important distinction that the value is computed by: - * - * mantissa * ( 2 ** exponent ) - * - * If the mantissa is a tag that is a positive or negative big number, - * this will attempt to fit it into the int64_t that @c pnMantissa is - * and set an overflow error if it doesn't fit. - * - * See also QCBORDecode_GetInt64ConvertAll(), - * QCBORDecode_GetUInt64ConvertAll() and - * QCBORDecode_GetDoubleConvertAll() which can convert big floats. - * - * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), @ref - * QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig(). - */ -void -QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void -QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void -QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - * @brief Decode the next item as a big float with a big number mantissa. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[in] MantissaBuffer The buffer in which to put the mantissa. - * @param[out] pMantissa The big num mantissa. - * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - * @param[out] pnExponent The base 2 exponent. - * - * This is the same as QCBORDecode_GetDecimalFractionBig() with the - * important distinction that the value is computed by: - * - * mantissa * ( 2 ** exponent ) - * - * This has the same issue with negative mantissas as - * QCBORDecode_GetDecimalFractionBig(). - * - * See also QCBORDecode_GetInt64ConvertAll(), - * QCBORDecode_GetUInt64ConvertAll() and - * QCBORDecode_GetDoubleConvertAll() which can convert big floats. - * - * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), - * @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat(). - */ -void -QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void -QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void -QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); -#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */ - - - - -/** - * @brief Decode the next item as a URI. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pURI The decoded URI. - * - * This decodes a standard CBOR URI tag, integer tag number of 32, or - * encoded CBOR that is not a tag, that is a URI encoded in a text - * string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and - * @ref QCBOR_TYPE_URI. - */ -static void -QCBORDecode_GetURI(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void -QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void -QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - - -/** - * @brief Decode the next item as base64 encoded text. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pB64Text The decoded base64 text. - * - * This decodes a standard CBOR base64 tag, integer tag number of 34, - * or encoded CBOR that is not a tag, that is base64 encoded bytes - * encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * Note that this does not actually remove the base64 encoding. - * - * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and - * @ref QCBOR_TYPE_BASE64. - */ -static void -QCBORDecode_GetB64(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - * @brief Decode the next item as base64URL encoded text. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pB64Text The decoded base64 text. - * - * This decodes a standard CBOR base64url tag, integer tag number of - * 33, or encoded CBOR that is not a tag, that is base64url encoded - * bytes encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * Note that this does not actually remove the base64url encoding. - * - * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and - * @ref QCBOR_TYPE_BASE64URL. - */ -static void -QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - * @brief Decode the next item as a regular expression. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pRegex The decoded regular expression. - * - * This decodes a standard CBOR regex tag, integer tag number of 35, - * or encoded CBOR that is not a tag, that is a PERL-compatible - * regular expression encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and - * @ref QCBOR_TYPE_REGEX. - */ -static void -QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void -QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void -QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - - -/** - * @brief Decode the next item as a MIME message. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pMessage The decoded regular expression. - * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. - * - * This decodes the standard CBOR MIME and binary MIME tags, integer - * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that - * is a MIME message encoded in a text or binary string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * The MIME message itself is not parsed. - * - * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is - * @c true. The difference between the two is that tag 36 is utf8 and - * tag 257 is a byte string that can carry binary MIME. QCBOR - * processes them exactly the same. Possibly the difference can be - * ignored. NULL can be passed to have no value returned. - * - * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, - * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and - * @ref QCBOR_TYPE_BINARY_MIME. - * - * This does no translation of line endings. See QCBOREncode_AddText() - * for a discussion of line endings in CBOR. - */ -static void -QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -static void -QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - - -static void -QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -/** - * @brief Decode the next item as a UUID. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pUUID The decoded UUID - * - * This decodes a standard CBOR UUID tag, integer tag number of 37, or - * encoded CBOR that is not a tag, that is a UUID encoded in a byte - * string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and - * @ref QCBOR_TYPE_UUID. - */ -static void -QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -static void -QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -static void -QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - - - -/** - * @brief Decode some byte-string wrapped CBOR. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). - * - * This is for use on some CBOR that has been wrapped in a byte - * string. There are several ways that this can occur. - * - * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item - * and 63 a CBOR sequence. This implementation doesn't distinguish - * between the two (it would be more code and doesn't seem important). - * - * The @ref Tag-Usage discussion on the tag requirement applies here - * just the same as any other tag. - * - * In other cases, CBOR is wrapped in a byte string, but it is - * identified as CBOR by other means. The contents of a COSE payload - * are one example of that. They can be identified by the COSE content - * type, or they can be identified as CBOR indirectly by the protocol - * that uses COSE. for example, if a blob of CBOR is identified as a - * CWT, then the COSE payload is CBOR. To enter into CBOR of this - * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c - * uTagRequirement argument. - * - * Note that byte string wrapped CBOR can also be decoded by getting - * the byte string with QCBORDecode_GetItem() or - * QCBORDecode_GetByteString() and feeding it into another instance of - * QCBORDecode. Doing it with this function has the advantage of using - * less memory as another instance of QCBORDecode is not necessary. - * - * When the wrapped CBOR is entered with this function, the pre-order - * traversal and such are bounded to the wrapped - * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume - * processing CBOR outside the wrapped CBOR. - * - * This does not work on indefinite-length strings. The - * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set. - * - * If @c pBstr is not @c NULL the pointer and length of the wrapped - * CBOR will be returned. This is usually not needed, but sometimes - * useful, particularly in the case of verifying signed data like the - * COSE payload. This is usually the pointer and length of the data is - * that is hashed or MACed. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and - * QCBORDecode_EnterArray(). - */ -void -QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - -void -QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - -void -QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - - -/** - * @brief Exit some bstr-wrapped CBOR has been enetered. - * - * @param[in] pCtx The decode context. - * - * Bstr-wrapped CBOR must have been entered for this to succeed. - * - * The items in the wrapped CBOR that was entered do not have to have - * been consumed for this to succeed. - * - * The this sets the traversal cursor to the item after the - * byte string that was exited. - */ -void -QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); - - - - -/* ========================================================================= * - * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * - * ========================================================================= */ - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pCtx, - uint8_t uType, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pCtx, - uint8_t uType); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pValue, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); -#endif /* !USEFULBUF_DISABLE_ALL_FLOAT */ - -#define QCBOR_TAGSPEC_NUM_TYPES 4 -/* Semi-private data structure (which might change). - * - * See QCBOR_Private_CheckTagRequirement() which uses this to check the - * type of an item to be decoded as a tag or tag content. - * - * Improvement: Carefully understand what compilers do with this, - * particularly initialization and see if it can be optimized so there - * is less code and maybe so it can be smaller. - */ -typedef struct { - /* One of QCBOR_TAGSPEC_MATCH_xxx */ - uint8_t uTagRequirement; - /* The tagged type translated into QCBOR_TYPE_XXX. Used to match - * explicit tagging */ - uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES]; - /* The types of the content, which are used to match implicit - * tagging */ - uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES]; -} QCBOR_Private_TagSpec; - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pCtx, - QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pBstr); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pString); - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pString); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -QCBORError -QCBORDecode_Private_GetMIME(uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pMessage, - bool *pbIsTag257); - - - - - -static inline void -QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); -} - -static inline void -QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, - nLabel, - uConvertTypes, - puValue, - &Item); -} - -static inline void -QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - puValue, - &Item); -} - -static inline void -QCBORDecode_GetUInt64(QCBORDecodeContext *pMe, uint64_t *puValue) -{ - QCBORDecode_GetUInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, puValue); -} - -static inline void -QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - uint64_t *puValue) -{ - QCBORDecode_GetUInt64ConvertInMapN(pMe, - nLabel, - QCBOR_CONVERT_TYPE_XINT64, - puValue); -} - -static inline void -QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint64_t *puValue) -{ - QCBORDecode_GetUInt64ConvertInMapSZ(pMe, - szLabel, - QCBOR_CONVERT_TYPE_XINT64, - puValue); -} - - -static inline void -QCBORDecode_EnterMap(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP, pItem); -} - -static inline void -QCBORDecode_EnterArray(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY, pItem); -} - - -static inline void -QCBORDecode_ExitArray(QCBORDecodeContext *pMe) -{ - QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY); -} - -static inline void -QCBORDecode_ExitMap(QCBORDecodeContext *pMe) -{ - QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_MAP); -} - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx, - uint8_t uType, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx, - QCBORItem *pTarget, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - -static inline void -QCBORDecode_GetArray(QCBORDecodeContext *pMe, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_ARRAY, pItem, pEncodedCBOR); -} - - -static inline void -QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSearch[0].label.int64 = nLabel; - OneItemSearch[0].uDataType = QCBOR_TYPE_ARRAY; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSearch, pItem, pEncodedCBOR); -} - - -static inline void -QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSearch[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSearch[0].uDataType = QCBOR_TYPE_ARRAY; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSearch, pItem, pEncodedCBOR); -#else - (void)szLabel; - (void)pItem; - (void)pEncodedCBOR; - pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -} - -static inline void -QCBORDecode_GetMap(QCBORDecodeContext *pMe, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_MAP, pItem, pEncodedCBOR); -} - - -static inline void -QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSearch[0].label.int64 = nLabel; - OneItemSearch[0].uDataType = QCBOR_TYPE_MAP; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSearch, pItem, pEncodedCBOR); -} - - -static inline void -QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSearch[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSearch[0].uDataType = QCBOR_TYPE_MAP; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSearch, pItem, pEncodedCBOR); -#else - (void)szLabel; - (void)pItem; - (void)pEncodedCBOR; - pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -} - - - -static inline void -QCBORDecode_GetInt64Convert(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); -} - -static inline void -QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetInt64ConvertInMapN(pMe, - nLabel, - uConvertTypes, - pnValue, - &Item); -} - -static inline void -QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - pnValue, - &Item); -} - -static inline void -QCBORDecode_GetInt64(QCBORDecodeContext *pMe, int64_t *pnValue) -{ - QCBORDecode_GetInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, pnValue); -} - -static inline void -QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - int64_t *pnValue) -{ - QCBORDecode_GetInt64ConvertInMapN(pMe, - nLabel, - QCBOR_CONVERT_TYPE_XINT64, - pnValue); -} - -static inline void -QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - int64_t *pnValue) -{ - QCBORDecode_GetInt64ConvertInMapSZ(pMe, - szLabel, - QCBOR_CONVERT_TYPE_XINT64, - pnValue); -} - - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -static inline void -QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - double *pdValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); -} - -static inline void -QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetDoubleConvertInMapN(pMe, - nLabel, - uConvertTypes, - pdValue, - &Item); -} - -static inline void -QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - double *pdValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - pdValue, - &Item); -} - -static inline void -QCBORDecode_GetDouble(QCBORDecodeContext *pMe, double *pValue) -{ - QCBORDecode_GetDoubleConvert(pMe, QCBOR_CONVERT_TYPE_FLOAT, pValue); -} - -static inline void -QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - double *pdValue) -{ - QCBORDecode_GetDoubleConvertInMapN(pMe, - nLabel, - QCBOR_CONVERT_TYPE_FLOAT, - pdValue); -} - -static inline void -QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - double *pdValue) -{ - QCBORDecode_GetDoubleConvertInMapSZ(pMe, - szLabel, - QCBOR_CONVERT_TYPE_FLOAT, - pdValue); -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - - - - -static inline void -QCBORDecode_GetByteString(QCBORDecodeContext *pMe, UsefulBufC *pValue) -{ - // Complier should make this just a 64-bit integer parameter - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); -} - -static inline void -QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - UsefulBufC *pBstr) -{ - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr); -} - -static inline void -QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - UsefulBufC *pBstr) -{ - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr); -} - - -static inline void -QCBORDecode_GetTextString(QCBORDecodeContext *pMe, UsefulBufC *pValue) -{ - // Complier should make this just 64-bit integer parameter - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); -} - -static inline void -QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - UsefulBufC *pText) -{ - // This TagSpec only matches text strings; it also should optimize down - // to passing a 64-bit integer - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); -} - -static inline void -QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - UsefulBufC *pText) -{ - const QCBOR_Private_TagSpec TagSpec = - { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); -} - -static inline void -QCBORDecode_GetNull(QCBORDecodeContext *pMe) -{ - QCBORItem item; - - QCBORDecode_VGetNext(pMe, &item); - if(pMe->uLastError == QCBOR_SUCCESS && item.uDataType != QCBOR_TYPE_NULL) { - pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; - } -} - -static inline void -QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_NULL, &Item); -} - -static inline void -QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_NULL, &Item); -} - -static inline void -QCBORDecode_GetUndefined(QCBORDecodeContext *pMe) -{ - QCBORItem item; - - QCBORDecode_VGetNext(pMe, &item); - if(pMe->uLastError == QCBOR_SUCCESS && item.uDataType != QCBOR_TYPE_UNDEF) { - pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; - } -} - -static inline void -QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_UNDEF, &Item); -} - -static inline void -QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_UNDEF, &Item); -} - - - -static inline void -QCBORDecode_GetDateString(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pValue) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); -} - -static inline void -QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); -} - -static inline void -QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); -} - -static inline void -QCBORDecode_GetDaysString(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pValue) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); -} - -static inline void -QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); -} - -static inline void -QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); -} - - - -static inline void -QCBORDecode_GetURI(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); -} - -static inline void -QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); -} - -static inline void -QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); -} - - -static inline void -QCBORDecode_GetB64(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); -} - -static inline void -QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); -} - -static inline void -QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); -} - - -static inline void -QCBORDecode_GetB64URL(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); -} - -static inline void -QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); -} - -static inline void -QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); -} - - -static inline void -QCBORDecode_GetRegex(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pRegex); -} - -static inline void -QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex); -} - -static inline void -QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex); -} - - -static inline void -QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uError; - return; - } - - pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, - &Item, - pMessage, - pbIsTag257); -} - -static inline void -QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, - &Item, - pMessage, - pbIsTag257); - } -} - -static inline void -QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, - &Item, - pMessage, - pbIsTag257); - } -} - - -static inline void -QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); -} - -static inline void -QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); -} - -static inline void -QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); -} - -/* ======================================================================== * - * END OF PRIVATE INLINE IMPLEMENTATION * - * ======================================================================== */ - -#ifdef __cplusplus -} -#endif - -#endif /* qcbor_spiffy_decode_h */ diff --git a/3rdparty/internal/QCBOR/src/UsefulBuf.c b/3rdparty/internal/QCBOR/src/UsefulBuf.c deleted file mode 100644 index 4a7970f9e133..000000000000 --- a/3rdparty/internal/QCBOR/src/UsefulBuf.c +++ /dev/null @@ -1,473 +0,0 @@ -/* ========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2024, Laurence Lundblade. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - - - -/*============================================================================= - FILE: UsefulBuf.c - - DESCRIPTION: General purpose input and output buffers - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 08/08/2024 llundblade Add UsefulOutBuf_SubString(). - 21/05/2024 llundblade Comment formatting and some code tidiness. - 19/12/2022 llundblade Don't pass NULL to memmove when adding empty data. - 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf - 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual - 01/28/2020 llundblade Refine integer signedness to quiet static analysis. - 01/08/2020 llundblade Documentation corrections & improved code formatting. - 11/08/2019 llundblade Re check pointer math and update comments - 3/6/2019 llundblade Add UsefulBuf_IsValue() - 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off - the end of memory when the bytes to find is longer - than the bytes to search. - 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison - for < or > for unequal length buffers. Added - UsefulBuf_Set() function. - 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst - 11/13/16 llundbla Initial Version. - - ============================================================================*/ - -#include "UsefulBuf.h" - -/* used to catch use of uninitialized or corrupted UsefulOutBuf */ -#define USEFUL_OUT_BUF_MAGIC (0x0B0F) - - -/* - * Public function -- see UsefulBuf.h - */ -UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) -{ - /* Do this with subtraction so it doesn't give an erroneous - * result if uOffset + Src.len overflows. Right side is equivalent to - * uOffset + Src.len > Dest.len - */ - if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { - return NULLUsefulBufC; - } - - memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len); - - return (UsefulBufC){Dest.ptr, Src.len + uOffset}; -} - - -/* - * Public function -- see UsefulBuf.h - */ -int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) -{ - /* Use comparisons rather than subtracting lengths to - * return an int instead of a size_t - */ - if(UB1.len < UB2.len) { - return -1; - } else if (UB1.len > UB2.len) { - return 1; - } /* else UB1.len == UB2.len */ - - return memcmp(UB1.ptr, UB2.ptr, UB1.len); -} - - -/* - * Public function -- see UsefulBuf.h - */ -size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) -{ - if(UsefulBuf_IsNULLOrEmptyC(UB)) { - /* Not a match */ - return 0; - } - - const uint8_t * const pEnd = (const uint8_t *)UB.ptr + UB.len; - for(const uint8_t *p = UB.ptr; p < pEnd; p++) { - if(*p != uValue) { - /* Byte didn't match */ - /* Cast from signed to unsigned. Safe because the loop increments.*/ - return (size_t)(p - (const uint8_t *)UB.ptr); - } - } - - /* Success. All bytes matched */ - return SIZE_MAX; -} - - -/* - * Public function -- see UsefulBuf.h - */ -size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) -{ - if(BytesToSearch.len < BytesToFind.len) { - return SIZE_MAX; - } - - for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { - UsefulBufC SearchNext; - - SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos; - SearchNext.len = BytesToFind.len; - if(!UsefulBuf_Compare(SearchNext, BytesToFind)) { - return uPos; - } - } - - return SIZE_MAX; -} - - -/* - * Public function -- see UsefulBuf.h - * - * Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) -{ - pMe->magic = USEFUL_OUT_BUF_MAGIC; - UsefulOutBuf_Reset(pMe); - pMe->UB = Storage; - -#if 0 - /* This check is off by default. - * - * The following check fails on ThreadX - * - * Sanity check on the pointer and size to be sure we are not - * passed a buffer that goes off the end of the address space. - * Given this test, we know that all unsigned lengths less than - * me->size are valid and won't wrap in any pointer additions - * based off of pStorage in the rest of this code. - */ - const uintptr_t ptrM = UINTPTR_MAX - Storage.len; - if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */ - me->err = 1; -#endif -} - - - -/* - * Public function -- see UsefulBuf.h - * - * The core of UsefulOutBuf -- put some bytes in the buffer without writing off - * the end of it. - * - * Code Reviewers: THIS FUNCTION DOES POINTER MATH - * - * This function inserts the source buffer, NewData, into the destination - * buffer, me->UB.ptr. - * - * Destination is represented as: - * me->UB.ptr -- start of the buffer - * me->UB.len -- size of the buffer UB.ptr - * me->data_len -- length of value data in UB - * - * Source is data: - * NewData.ptr -- start of source buffer - * NewData.len -- length of source buffer - * - * Insertion point: - * uInsertionPos. - * - * Steps: - * - * 0. Corruption checks on UsefulOutBuf - * - * 1. Figure out if the new data will fit or not - * - * 2. Is insertion position in the range of valid data? - * - * 3. If insertion point is not at the end, slide data to the right of the - * insertion point to the right - * - * 4. Put the new data in at the insertion position. - * - */ -void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos) -{ - if(pMe->err) { - /* Already in error state. */ - return; - } - - /* 0. Sanity check the UsefulOutBuf structure - * A "counter measure". If magic number is not the right number it - * probably means pMe was not initialized or it was corrupted. Attackers - * can defeat this, but it is a hurdle and does good with very - * little code. - */ - if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { - pMe->err = 1; - return; /* Magic number is wrong due to uninitalization or corrption */ - } - - /* Make sure valid data is less than buffer size. This would only occur - * if there was corruption of me, but it is also part of the checks to - * be sure there is no pointer arithmatic under/overflow. - */ - if(pMe->data_len > pMe->UB.len) { /* Check #1 */ - pMe->err = 1; - /* Offset of valid data is off the end of the UsefulOutBuf due to - * uninitialization or corruption - */ - return; - } - - /* 1. Will it fit? - * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) - * Check #1 makes sure subtraction in RoomLeft will not wrap around - */ - if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */ - /* The new data will not fit into the the buffer. */ - pMe->err = 1; - return; - } - - /* 2. Check the Insertion Position - * This, with Check #1, also confirms that uInsertionPos <= me->data_len and - * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the - * address space. - */ - if(uInsertionPos > pMe->data_len) { /* Check #3 */ - /* Off the end of the valid data in the buffer. */ - pMe->err = 1; - return; - } - - /* 3. Slide existing data to the right */ - if (!UsefulOutBuf_IsBufferNULL(pMe)) { - uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */ - size_t uNumBytesToMove = pMe->data_len - uInsertionPos; /* PtrMath #2 */ - uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/ - - /* To know memmove won't go off end of destination, see PtrMath #4. - * Use memove because it handles overlapping buffers - */ - memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); - - /* 4. Put the new data in */ - uint8_t *pInsertionPoint = pSourceOfMove; - /* To know memmove won't go off end of destination, see PtrMath #5 */ - if(NewData.ptr != NULL) { - memmove(pInsertionPoint, NewData.ptr, NewData.len); - } - } - - pMe->data_len += NewData.len; -} - - -/* - * Rationale that describes why the above pointer math is safe - * - * PtrMath #1 will never wrap around over because - * Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap - * Check #1 makes sure me->data_len is less than me->UB.len - * Check #3 makes sure uInsertionPos is less than me->data_len - * - * PtrMath #2 will never wrap around under because - * Check #3 makes sure uInsertionPos is less than me->data_len - * - * PtrMath #3 will never wrap around over because - * PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len - * Check #2 that NewData.len will fit in the unused space left in me->UB - * - * PtrMath #4 will never wrap under because - * Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) - * Check #3 makes sure uInsertionPos is less than me->data_len - * Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) - * This algebraically rearranges to me->size > uInsertionPos + NewData.len - * - * PtrMath #5 will never wrap under because - * Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; - * Check #1 makes sure me->data_len is less than me->size - * Check #3 makes sure uInsertionPos is less than me->data_len - */ - - -/* - * Public function for advancing data length. See qcbor/UsefulBuf.h - */ -void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) -{ - /* This function is a trimmed down version of - * UsefulOutBuf_InsertUsefulBuf(). This could be combined with the - * code in UsefulOutBuf_InsertUsefulBuf(), but that would make - * UsefulOutBuf_InsertUsefulBuf() bigger and this will be very - * rarely used. - */ - - if(pMe->err) { - /* Already in error state. */ - return; - } - - /* 0. Sanity check the UsefulOutBuf structure - * - * A "counter measure". If magic number is not the right number it - * probably means me was not initialized or it was - * corrupted. Attackers can defeat this, but it is a hurdle and - * does good with very little code. - */ - if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { - pMe->err = 1; - return; /* Magic number is wrong due to uninitalization or corrption */ - } - - /* Make sure valid data is less than buffer size. This would only - * occur if there was corruption of me, but it is also part of the - * checks to be sure there is no pointer arithmatic - * under/overflow. - */ - if(pMe->data_len > pMe->UB.len) { /* Check #1 */ - pMe->err = 1; - /* Offset of valid data is off the end of the UsefulOutBuf due - * to uninitialization or corruption. - */ - return; - } - - /* 1. Will it fit? - * - * WillItFit() is the same as: NewData.len <= (me->UB.len - - * me->data_len) Check #1 makes sure subtraction in RoomLeft will - * not wrap around - */ - if(! UsefulOutBuf_WillItFit(pMe, uAmount)) { /* Check #2 */ - /* The new data will not fit into the the buffer. */ - pMe->err = 1; - return; - } - - pMe->data_len += uAmount; -} - - -/* - * Public function -- see UsefulBuf.h - */ -UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) -{ - if(pMe->err) { - return NULLUsefulBufC; - } - - if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { - pMe->err = 1; - return NULLUsefulBufC; - } - - return (UsefulBufC){pMe->UB.ptr, pMe->data_len}; -} - - -/* - * Public function -- see UsefulBuf.h - * - * Copy out the data accumulated in to the output buffer. - */ -UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) -{ - const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); - if(UsefulBuf_IsNULLC(Tmp)) { - return NULLUsefulBufC; - } - return UsefulBuf_Copy(pDest, Tmp); -} - - -/* - * Public function -- see UsefulBuf.h - * - * Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe, - const size_t uStart, - const size_t uLen) -{ - const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); - - if(UsefulBuf_IsNULLC(Tmp)) { - return NULLUsefulBufC; - } - - if(uStart > Tmp.len) { - return NULLUsefulBufC; - } - - if(Tmp.len - uStart < uLen) { - return NULLUsefulBufC; - } - - UsefulBufC SubString; - SubString.ptr = (const uint8_t *)Tmp.ptr + uStart; - SubString.len = uLen; - - return SubString; -} - - -/* - * Public function -- see UsefulBuf.h - * - * The core of UsefulInputBuf -- consume bytes without going off end of buffer. - * - * Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount) -{ - /* Already in error state. Do nothing. */ - if(pMe->err) { - return NULL; - } - - if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) { - /* Number of bytes asked for is more than available */ - pMe->err = 1; - return NULL; - } - - /* This is going to succeed */ - const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor; - /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */ - pMe->cursor += uAmount; - return result; -} diff --git a/3rdparty/internal/QCBOR/src/ieee754.c b/3rdparty/internal/QCBOR/src/ieee754.c deleted file mode 100644 index 17443680c1e2..000000000000 --- a/3rdparty/internal/QCBOR/src/ieee754.c +++ /dev/null @@ -1,643 +0,0 @@ -/* ========================================================================== - * ieee754.c -- floating-point conversion between half, double & single-precision - * - * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. - * Copyright (c) 2021, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in file named "LICENSE" - * - * Created on 7/23/18 - * ========================================================================== */ - -/* - * Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as - * QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h - */ -#include "qcbor/qcbor_common.h" - -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - -#include "ieee754.h" -#include /* For memcpy() */ - - -/* - * This code has long lines and is easier to read because of - * them. Some coding guidelines prefer 80 column lines (can they not - * afford big displays?). - * - * This code works solely using shifts and masks and thus has no - * dependency on any math libraries. It can even work if the CPU - * doesn't have any floating-point support, though that isn't the most - * useful thing to do. - * - * The memcpy() dependency is only for CopyFloatToUint32() and friends - * which only is needed to avoid type punning when converting the - * actual float bits to an unsigned value so the bit shifts and masks - * can work. - * - * The references used to write this code: - * - * IEEE 754-2008, particularly section 3.6 and 6.2.1 - * - * https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages - * - * https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values - * - * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules - * - * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be - * - * IEEE754_FloatToDouble(uint32_t uFloat) was created but is not - * needed. It can be retrieved from github history if needed. - */ - - - - -/* ----- Half Precsion ----------- */ -#define HALF_NUM_SIGNIFICAND_BITS (10) -#define HALF_NUM_EXPONENT_BITS (5) -#define HALF_NUM_SIGN_BITS (1) - -#define HALF_SIGNIFICAND_SHIFT (0) -#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS) -#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS) - -#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits -#define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent -#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // 0x8000 1 bit of sign -#define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200 - -/* Biased Biased Unbiased Use - * 0x00 0 -15 0 and subnormal - * 0x01 1 -14 Smallest normal exponent - * 0x1e 30 15 Largest normal exponent - * 0x1F 31 16 NaN and Infinity */ -#define HALF_EXPONENT_BIAS (15) -#define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased -#define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased -#define HALF_EXPONENT_ZERO (-HALF_EXPONENT_BIAS) // -15 Unbiased -#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased - - -/* ------ Single-Precision -------- */ -#define SINGLE_NUM_SIGNIFICAND_BITS (23) -#define SINGLE_NUM_EXPONENT_BITS (8) -#define SINGLE_NUM_SIGN_BITS (1) - -#define SINGLE_SIGNIFICAND_SHIFT (0) -#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS) -#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS) - -#define SINGLE_SIGNIFICAND_MASK (0x7fffffU) // The lower 23 bits -#define SINGLE_EXPONENT_MASK (0xffU << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent -#define SINGLE_SIGN_MASK (0x01U << SINGLE_SIGN_SHIFT) // 1 bit of sign -#define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1)) - -/* Biased Biased Unbiased Use - * 0x0000 0 -127 0 and subnormal - * 0x0001 1 -126 Smallest normal exponent - * 0x7f 127 0 1 - * 0xfe 254 127 Largest normal exponent - * 0xff 255 128 NaN and Infinity */ -#define SINGLE_EXPONENT_BIAS (127) -#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) -#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) -#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) -#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) - - -/* --------- Double-Precision ---------- */ -#define DOUBLE_NUM_SIGNIFICAND_BITS (52) -#define DOUBLE_NUM_EXPONENT_BITS (11) -#define DOUBLE_NUM_SIGN_BITS (1) - -#define DOUBLE_SIGNIFICAND_SHIFT (0) -#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS) -#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS) - -#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits -#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent -#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign -#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) - - -/* Biased Biased Unbiased Use - * 0x00000000 0 -1023 0 and subnormal - * 0x00000001 1 -1022 Smallest normal exponent - * 0x000007fe 2046 1023 Largest normal exponent - * 0x000007ff 2047 1024 NaN and Infinity */ -#define DOUBLE_EXPONENT_BIAS (1023) -#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) -#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) -#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) -#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) - - - - -/* - * Convenient functions to avoid type punning, compiler warnings and - * such. The optimizer reduces them to a simple assignment. This is a - * crusty corner of C. It shouldn't be this hard. - * - * These are also in UsefulBuf.h under a different name. They are copied - * here to avoid a dependency on UsefulBuf.h. There is no object code - * size impact because these always optimze down to a simple assignment. - */ -static inline uint32_t -CopyFloatToUint32(float f) -{ - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; -} - -static inline uint64_t -CopyDoubleToUint64(double d) -{ - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; -} - -static inline double -CopyUint64ToDouble(uint64_t u64) -{ - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; -} - -static inline float -CopyUint32ToSingle(uint32_t u32) -{ - float f; - memcpy(&f, &u32, sizeof(uint32_t)); - return f; -} - - - - -/** - * @brief Assemble sign, significand and exponent into single precision float. - * - * @param[in] uDoubleSign 0 if positive, 1 if negative - * @pararm[in] uDoubleSignificand Bits of the significand - * @param[in] nDoubleUnBiasedExponent Exponent - * - * This returns the bits for a single-precision float, a binary64 - * as specified in IEEE754. - */ -static double -IEEE754_AssembleDouble(uint64_t uDoubleSign, - uint64_t uDoubleSignificand, - int64_t nDoubleUnBiasedExponent) -{ - uint64_t uDoubleBiasedExponent; - - uDoubleBiasedExponent = (uint64_t)(nDoubleUnBiasedExponent + DOUBLE_EXPONENT_BIAS); - - return CopyUint64ToDouble(uDoubleSignificand | - (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | - (uDoubleSign << DOUBLE_SIGN_SHIFT)); -} - - -double -IEEE754_HalfToDouble(uint16_t uHalfPrecision) -{ - uint64_t uDoubleSignificand; - int64_t nDoubleUnBiasedExponent; - double dResult; - - /* Pull out the three parts of the half-precision float. Do all - * the work in 64 bits because that is what the end result is. It - * may give smaller code size and will keep static analyzers - * happier. - */ - const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; - const uint64_t uHalfBiasedExponent = (uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT; - const int64_t nHalfUnBiasedExponent = (int64_t)uHalfBiasedExponent - HALF_EXPONENT_BIAS; - const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; - - if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { - /* 0 or subnormal */ - if(uHalfSignificand) { - /* --- SUBNORMAL --- */ - /* A half-precision subnormal can always be converted to a - * normal double-precision float because the ranges line up. - * The exponent of a subnormal starts out at the min exponent - * for a normal. As the sub normal significand bits are - * shifted, left to normalize, the exponent is - * decremented. Shifting continues until fully normalized. - */ - nDoubleUnBiasedExponent = HALF_EXPONENT_MIN; - uDoubleSignificand = uHalfSignificand; - do { - uDoubleSignificand <<= 1; - nDoubleUnBiasedExponent--; - } while ((uDoubleSignificand & (1ULL << HALF_NUM_SIGNIFICAND_BITS)) == 0); - /* A normal has an implied 1 in the most significant - * position that a subnormal doesn't. */ - uDoubleSignificand -= 1ULL << HALF_NUM_SIGNIFICAND_BITS; - /* Must shift into place for a double significand */ - uDoubleSignificand <<= DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; - - dResult = IEEE754_AssembleDouble(uHalfSign, - uDoubleSignificand, - nDoubleUnBiasedExponent); - } else { - /* --- ZERO --- */ - dResult = IEEE754_AssembleDouble(uHalfSign, - 0, - DOUBLE_EXPONENT_ZERO); - } - } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { - /* NaN or Inifinity */ - if(uHalfSignificand) { - /* --- NaN --- */ - /* Half-precision payloads always fit into double precision - * payloads. They are shifted left the same as a normal - * number significand. - */ - uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - dResult = IEEE754_AssembleDouble(uHalfSign, - uDoubleSignificand, - DOUBLE_EXPONENT_INF_OR_NAN); - } else { - /* --- INFINITY --- */ - dResult = IEEE754_AssembleDouble(uHalfSign, - 0, - DOUBLE_EXPONENT_INF_OR_NAN); - } - } else { - /* --- NORMAL NUMBER --- */ - uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - dResult = IEEE754_AssembleDouble(uHalfSign, - uDoubleSignificand, - nHalfUnBiasedExponent); - } - - return dResult; -} - - -/** - * @brief Assemble sign, significand and exponent into single precision float. - * - * @param[in] uHalfSign 0 if positive, 1 if negative - * @pararm[in] uHalfSignificand Bits of the significand - * @param[in] nHalfUnBiasedExponent Exponent - * - * This returns the bits for a single-precision float, a binary32 as - * specified in IEEE754. It is returned as a uint64_t rather than a - * uint32_t or a float for convenience of usage. - */ -static uint32_t -IEEE754_AssembleHalf(uint32_t uHalfSign, - uint32_t uHalfSignificand, - int32_t nHalfUnBiasedExponent) -{ - uint32_t uHalfUnbiasedExponent; - - uHalfUnbiasedExponent = (uint32_t)(nHalfUnBiasedExponent + HALF_EXPONENT_BIAS); - - return uHalfSignificand | - (uHalfUnbiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); -} - - -/* Public function; see ieee754.h */ -IEEE754_union -IEEE754_SingleToHalf(float f) -{ - IEEE754_union result; - uint32_t uDroppedBits; - int32_t nExponentDifference; - int32_t nShiftAmount; - uint32_t uHalfSignificand; - - /* Pull the three parts out of the double-precision float Most work - * is done with uint32_t which helps avoid integer promotions and - * static analyzer complaints. - */ - const uint32_t uSingle = CopyFloatToUint32(f); - const uint32_t uSingleBiasedExponent = (uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT; - const int32_t nSingleUnbiasedExponent = (int32_t)uSingleBiasedExponent - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; - - if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { - if(uSingleSignificand == 0) { - /* --- IS ZERO --- */ - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_AssembleHalf(uSingleSign, - 0, - HALF_EXPONENT_ZERO); - } else { - /* --- IS SINGLE SUBNORMAL --- */ - /* The largest single subnormal is slightly less than the - * largest single normal which is 2^-149 or - * 2.2040517676619426e-38. The smallest half subnormal is - * 2^-14 or 5.9604644775390625E-8. There is no overlap so - * single subnormals can't be converted to halfs of any sort. - */ - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; - } - } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { - if(uSingleSignificand == 0) { - /* ---- IS INFINITY ---- */ - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_AssembleHalf(uSingleSign, 0, HALF_EXPONENT_INF_OR_NAN); - } else { - /* The NaN can only be converted if no payload bits are lost - * per RFC 8949 section 4.1 that defines Preferred - * Serializaton. Note that Deterministically Encode CBOR in - * section 4.2 allows for some variation of this rule, but at - * the moment this implementation is of Preferred - * Serialization, not CDE. As of December 2023, we are also - * expecting an update to CDE. This code may need to be - * updated for CDE. - */ - uDroppedBits = uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS); - if(uDroppedBits == 0) { - /* --- IS CONVERTABLE NAN --- */ - uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_AssembleHalf(uSingleSign, - uHalfSignificand, - HALF_EXPONENT_INF_OR_NAN); - - } else { - /* --- IS UNCONVERTABLE NAN --- */ - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; - } - } - } else { - /* ---- REGULAR NUMBER ---- */ - /* A regular single can be converted to a regular half if the - * single's exponent is in the smaller range of a half and if no - * precision is lost in the significand. - */ - if(nSingleUnbiasedExponent >= HALF_EXPONENT_MIN && - nSingleUnbiasedExponent <= HALF_EXPONENT_MAX && - (uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS)) == 0) { - uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - - /* --- CONVERT TO HALF NORMAL --- */ - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_AssembleHalf(uSingleSign, - uHalfSignificand, - nSingleUnbiasedExponent); - } else { - /* Unable to convert to a half normal. See if it can be - * converted to a half subnormal. To do that, the exponent - * must be in range and no precision can be lost in the - * signficand. - * - * This is more complicated because the number is not - * normalized. The signficand must be shifted proprotionally - * to the exponent and 1 must be added in. See - * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding - * - * Exponents -14 to -24 map to a shift of 0 to 10 of the - * significand. The largest value of a half subnormal has an - * exponent of -14. Subnormals are not normalized like - * normals meaning they lose precision as the numbers get - * smaller. Normals don't lose precision because the exponent - * allows all the bits of the significand to be significant. - */ - /* The exponent of the largest possible half-precision - * subnormal is HALF_EXPONENT_MIN (-14). Exponents larger - * than this are normal and handled above. We're going to - * shift the significand right by at least this amount. - */ - nExponentDifference = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN); - - /* In addition to the shift based on the exponent's value, - * the single significand has to be shifted right to fit into - * a half-precision significand */ - nShiftAmount = nExponentDifference + (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - - /* Must add 1 in to the possible significand because there is - * an implied 1 for normal values and not for subnormal - * values. See equations here: - * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding - */ - uHalfSignificand = (uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; - - /* If only zero bits get shifted out, this can be converted - * to subnormal */ - if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN && - nSingleUnbiasedExponent >= HALF_EXPONENT_MIN - HALF_NUM_SIGNIFICAND_BITS && - uHalfSignificand << nShiftAmount == uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) { - /* --- CONVERTABLE TO HALF SUBNORMAL --- */ - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_AssembleHalf(uSingleSign, - uHalfSignificand, - HALF_EXPONENT_ZERO); - } else { - /* --- DO NOT CONVERT --- */ - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; - } - } - } - - return result; -} - - -/** - * @brief Assemble sign, significand and exponent into single precision float. - * - * @param[in] uSingleSign 0 if positive, 1 if negative - * @pararm[in] uSingleSignificand Bits of the significand - * @param[in] nSingleUnBiasedExponent Exponent - * - * This returns the bits for a single-precision float, a binary32 as - * specified in IEEE754. It is returned as a uint64_t rather than a - * uint32_t or a float for convenience of usage. - */ -static uint64_t -IEEE754_AssembleSingle(uint64_t uSingleSign, - uint64_t uSingleSignificand, - int64_t nSingleUnBiasedExponent) -{ - uint64_t uSingleBiasedExponent; - - uSingleBiasedExponent = (uint64_t)(nSingleUnBiasedExponent + SINGLE_EXPONENT_BIAS); - - return uSingleSignificand | - (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) | - (uSingleSign << SINGLE_SIGN_SHIFT); -} - - -/** - * @brief Convert a double-precision float to single-precision. - * - * @param[in] d The value to convert. - * - * @returns Either unconverted value or value converted to single-precision. - * - * This always succeeds. If the value cannot be converted without the - * loss of precision, it is not converted. - * - * This handles all subnormals and NaN payloads. - */ -static IEEE754_union -IEEE754_DoubleToSingle(double d) -{ - IEEE754_union Result; - int64_t nExponentDifference; - int64_t nShiftAmount; - uint64_t uSingleSignificand; - uint64_t uDroppedBits; - - - /* Pull the three parts out of the double-precision float. Most - * work is done with uint64_t which helps avoid integer promotions - * and static analyzer complaints. - */ - const uint64_t uDouble = CopyDoubleToUint64(d); - const uint64_t uDoubleBiasedExponent = (uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT; - const int64_t nDoubleUnbiasedExponent = (int64_t)uDoubleBiasedExponent - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - - if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { - if(uDoubleSignificand == 0) { - /* --- IS ZERO --- */ - Result.uSize = IEEE754_UNION_IS_SINGLE; - Result.uValue = IEEE754_AssembleSingle(uDoubleSign, - 0, - SINGLE_EXPONENT_ZERO); - } else { - /* --- IS DOUBLE SUBNORMAL --- */ - /* The largest double subnormal is slightly less than the - * largest double normal which is 2^-1022 or - * 2.2250738585072014e-308. The smallest single subnormal - * is 2^-149 or 1.401298464324817e-45. There is no - * overlap so double subnormals can't be converted to - * singles of any sort. - */ - Result.uSize = IEEE754_UNION_IS_DOUBLE; - Result.uValue = uDouble; - } - } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - if(uDoubleSignificand == 0) { - /* ---- IS INFINITY ---- */ - Result.uSize = IEEE754_UNION_IS_SINGLE; - Result.uValue = IEEE754_AssembleSingle(uDoubleSign, - 0, - SINGLE_EXPONENT_INF_OR_NAN); - } else { - /* The NaN can only be converted if no payload bits are - * lost per RFC 8949 section 4.1 that defines Preferred - * Serializaton. Note that Deterministically Encode CBOR - * in section 4.2 allows for some variation of this rule, - * but at the moment this implementation is of Preferred - * Serialization, not CDE. As of December 2023, we are - * also expecting an update to CDE. This code may need to - * be updated for CDE. - */ - uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); - if(uDroppedBits == 0) { - /* --- IS CONVERTABLE NAN --- */ - uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); - Result.uSize = IEEE754_UNION_IS_SINGLE; - Result.uValue = IEEE754_AssembleSingle(uDoubleSign, - uSingleSignificand, - SINGLE_EXPONENT_INF_OR_NAN); - } else { - /* --- IS UNCONVERTABLE NAN --- */ - Result.uSize = IEEE754_UNION_IS_DOUBLE; - Result.uValue = uDouble; - } - } - } else { - /* ---- REGULAR NUMBER ---- */ - /* A regular double can be converted to a regular single if - * the double's exponent is in the smaller range of a single - * and if no precision is lost in the significand. - */ - uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); - if(nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN && - nDoubleUnbiasedExponent <= SINGLE_EXPONENT_MAX && - uDroppedBits == 0) { - /* --- IS CONVERTABLE TO SINGLE --- */ - uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); - Result.uSize = IEEE754_UNION_IS_SINGLE; - Result.uValue = IEEE754_AssembleSingle(uDoubleSign, - uSingleSignificand, - nDoubleUnbiasedExponent); - } else { - /* Unable to convert to a single normal. See if it can be - * converted to a single subnormal. To do that, the - * exponent must be in range and no precision can be lost - * in the signficand. - * - * This is more complicated because the number is not - * normalized. The signficand must be shifted - * proprotionally to the exponent and 1 must be added - * in. See - * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding - */ - nExponentDifference = -(nDoubleUnbiasedExponent - SINGLE_EXPONENT_MIN); - nShiftAmount = nExponentDifference + (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); - uSingleSignificand = (uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; - - if(nDoubleUnbiasedExponent < SINGLE_EXPONENT_MIN && - nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN - SINGLE_NUM_SIGNIFICAND_BITS && - uSingleSignificand << nShiftAmount == uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) { - /* --- IS CONVERTABLE TO SINGLE SUBNORMAL --- */ - Result.uSize = IEEE754_UNION_IS_SINGLE; - Result.uValue = IEEE754_AssembleSingle(uDoubleSign, - uSingleSignificand, - SINGLE_EXPONENT_ZERO); - } else { - /* --- CAN NOT BE CONVERTED --- */ - Result.uSize = IEEE754_UNION_IS_DOUBLE; - Result.uValue = uDouble; - } - } - } - - return Result; -} - - -/* Public function; see ieee754.h */ -IEEE754_union -IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision) -{ - IEEE754_union result; - - result = IEEE754_DoubleToSingle(d); - - if(result.uSize == IEEE754_UNION_IS_SINGLE && bAllowHalfPrecision) { - /* Cast to uint32_t is OK, because value was just successfully - * converted to single. */ - float uSingle = CopyUint32ToSingle((uint32_t)result.uValue); - result = IEEE754_SingleToHalf(uSingle); - } - - return result; -} - - -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - -int ieee754_dummy_place_holder; - -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ diff --git a/3rdparty/internal/QCBOR/src/ieee754.h b/3rdparty/internal/QCBOR/src/ieee754.h deleted file mode 100644 index 3013dc6fd547..000000000000 --- a/3rdparty/internal/QCBOR/src/ieee754.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ========================================================================== - * ieee754.h -- Conversion between half, double & single-precision floats - * - * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in file named "LICENSE" - * - * Created on 7/23/18 - * ========================================================================== */ - -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - -#ifndef ieee754_h -#define ieee754_h - -#include - - -/** @file ieee754.h - * - * This implements floating-point conversion between half, single and - * double precision floating-point numbers, in particular convesion to - * smaller representation (e.g., double to single) that does not lose - * precision for CBOR preferred serialization. - * - * This implementation works entirely with shifts and masks and does - * not require any floating-point HW or library. - * - * This conforms to IEEE 754-2008, but note that it doesn't specify - * conversions, just the encodings. - * - * This is complete, supporting +/- infinity, +/- zero, subnormals and - * NaN payloads. NaN payloads are converted to smaller by dropping the - * right most bits if they are zero and shifting to the right. If the - * rightmost bits are not zero the conversion is not performed. When - * converting from smaller to larger, the payload is shifted left and - * zero-padded. This is what is specified by CBOR preferred - * serialization and what modern HW conversion instructions do. CBOR - * CDE handling for NaN is not clearly specified, but upcoming - * documents may clarify this. - * - * There is no special handling of silent and quiet NaNs. It probably - * isn't necessary to transmit these special NaNs as there purpose is - * more for propgating errors up through some calculation. In many - * cases the handlng of the NaN payload will work for silent and quiet - * NaNs. - * - * A previous version of this was usable as a general library for - * conversion. This version is reduced to what is needed for CBOR. - */ - - -/** - * @brief Convert half-precision float to double-precision float. - * - * @param[in] uHalfPrecision Half-prevision number to convert. - * - * @returns double-presion value. - * - * This is a lossless conversion because every half-precision value - * can be represented as a double. There is no error condition. - * - * There is no half-precision type in C, so it is represented here as - * a @c uint16_t. The bits of @c uHalfPrecision are as described for - * half-precision by IEEE 754. - */ -double -IEEE754_HalfToDouble(uint16_t uHalfPrecision); - - -/** Holds a floating-point value that could be half, single or - * double-precision. The value is in a @c uint64_t that may be copied - * to a float or double. Simply casting uValue will usually work but - * may generate compiler or static analyzer warnings. Using - * UsefulBufUtil_CopyUint64ToDouble() or - * UsefulBufUtil_CopyUint32ToFloat() will not (and will not generate - * any extra code). - */ -typedef struct { - enum {IEEE754_UNION_IS_HALF = 2, - IEEE754_UNION_IS_SINGLE = 4, - IEEE754_UNION_IS_DOUBLE = 8, - } uSize; /* Size of uValue */ - uint64_t uValue; -} IEEE754_union; - - -/** - * @brief Convert a double to either single or half-precision. - * - * @param[in] d The value to convert. - * @param[in] bAllowHalfPrecision If true, convert to either half or - * single precision. - * - * @returns Unconverted value, or value converted to single or half-precision. - * - * This always succeeds. If the value cannot be converted without the - * loss of precision, it is not converted. - * - * This handles all subnormals and NaN payloads. - */ -IEEE754_union -IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision); - - -/** - * @brief Convert a single-precision float to half-precision. - * - * @param[in] f The value to convert. - * - * @returns Either unconverted value or value converted to half-precision. - * - * This always succeeds. If the value cannot be converted without the - * loss of precision, it is not converted. - * - * This handles all subnormals and NaN payloads. - */ -IEEE754_union -IEEE754_SingleToHalf(float f); - - -#endif /* ieee754_h */ - -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ diff --git a/3rdparty/internal/QCBOR/src/qcbor_decode.c b/3rdparty/internal/QCBOR/src/qcbor_decode.c deleted file mode 100644 index 1eaba6bb247e..000000000000 --- a/3rdparty/internal/QCBOR/src/qcbor_decode.c +++ /dev/null @@ -1,7340 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2025, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ - - -#include "qcbor/qcbor_decode.h" -#include "qcbor/qcbor_spiffy_decode.h" -#include "ieee754.h" /* Does not use math.h */ - -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - -#include /* For isnan(), llround(), llroudf(), round(), roundf(), - * pow(), exp2() - */ -#include /* feclearexcept(), fetestexcept() */ - -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - - -#if (defined(__GNUC__) && !defined(__clang__)) -/* - * This is how the -Wmaybe-uninitialized compiler warning is - * handled. It can’t be ignored because some version of gcc enable it - * with -Wall which is a common and useful gcc warning option. It also - * can’t be ignored because it is the goal of QCBOR to compile clean - * out of the box in all environments. - * - * The big problem with -Wmaybe-uninitialized is that it generates - * false positives. It complains things are uninitialized when they - * are not. This is because it is not a thorough static analyzer. This - * is why “maybe” is in its name. The problem is it is just not - * thorough enough to understand all the code (and someone saw fit to - * put it in gcc and worse to enable it with -Wall). - * - * One solution would be to change the code so -Wmaybe-uninitialized - * doesn’t get confused, for example adding an unnecessary extra - * initialization to zero. (If variables were truly uninitialized, the - * correct path is to understand the code thoroughly and set them to - * the correct value at the correct time; in essence this is already - * done; -Wmaybe-uninitialized just can’t tell). This path is not - * taken because it makes the code bigger and is kind of the tail - * wagging the dog. - * - * The solution here is to just use a pragma to disable it for the - * whole file. Disabling it for each line makes the code fairly ugly - * requiring #pragma to push, pop and ignore. Another reason is the - * warnings issues vary by version of gcc and which optimization - * optimizations are selected. Another reason is that compilers other - * than gcc don’t have -Wmaybe-uninitialized. - * - * One may ask how to be sure these warnings are false positives and - * not real issues. 1) The code has been read carefully to check. 2) - * Testing is pretty thorough. 3) This code has been run through - * thorough high-quality static analyzers. - * - * In particularly, most of the warnings are about - * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext() - * *always* sets this value and test case confirm - * this. -Wmaybe-uninitialized just can't tell. - * - * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable - */ -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - - - - -#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type)) - - - - -static bool -QCBORItem_IsMapOrArray(const QCBORItem Item) -{ - const uint8_t uDataType = Item.uDataType; - return uDataType == QCBOR_TYPE_MAP || -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - uDataType == QCBOR_TYPE_MAP_AS_ARRAY || -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - uDataType == QCBOR_TYPE_ARRAY; -} - -static bool -QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item) -{ - if(!QCBORItem_IsMapOrArray(Item)){ - return false; - } - - if(Item.val.uCount != 0) { - return false; - } - return true; -} - -static bool -QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item) -{ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(!QCBORItem_IsMapOrArray(Item)){ - return false; - } - - if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { - return false; - } - return true; -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - (void)Item; - return false; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ -} - -/* Return true if the labels in Item1 and Item2 are the same. - Works only for integer and string labels. Returns false - for any other type. */ -static bool -QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2) -{ - if(Item1.uLabelType == QCBOR_TYPE_INT64) { - if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) { - return true; - } -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) { - if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) { - return true; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - } - - /* Other label types are never matched */ - return false; -} - - -/* - Returns true if Item1 and Item2 are the same type - or if either are of QCBOR_TYPE_ANY. - */ -static bool -QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2) -{ - if(Item1.uDataType == Item2.uDataType) { - return true; - } else if(Item1.uDataType == QCBOR_TYPE_ANY) { - return true; - } else if(Item2.uDataType == QCBOR_TYPE_ANY) { - return true; - } - return false; -} - - -/*=========================================================================== - DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting - ===========================================================================*/ - -/* - * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h, - * the data structure all these functions work on. - */ - - -static uint8_t -DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting) -{ - const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]); - /* Limit in DecodeNesting_Descend against more than - * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe - */ - return (uint8_t)nLevel; -} - - -static uint8_t -DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting) -{ - const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]); - /* Limit in DecodeNesting_Descend against more than - * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe - */ - return (uint8_t)nLevel; -} - - -static uint32_t -DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting) -{ - return pNesting->pCurrentBounded->u.ma.uStartOffset; -} - - -static bool -DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) { - return true; - } else { - return false; - } -} - - -static bool -DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent == &(pNesting->pLevels[0])) { - return true; - } else { - return false; - } -} - - -static bool -DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { - /* Not a map or array */ - return false; - } - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { - /* Is indefinite */ - return false; - } - -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - /* All checks passed; is a definte length map or array */ - return true; -} - -static bool -DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { - /* is a byte string */ - return true; - } - return false; -} - - -static bool -DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { - return true; - } - if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) { - return true; - } - return false; -} - - -static void -DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart) -{ - /* Should be only called on maps and arrays */ - /* - * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not - * larger than DecodeNesting_EnterBoundedMode which keeps it less than - * uin32_t so the cast is safe. - */ - pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart; - - if(bIsEmpty) { - pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH; - } -} - - -static void -DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET; -} - - -static bool -DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrentBounded == NULL) { - /* No bounded map or array set up */ - return false; - } - if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { - /* Not a map or array; end of those is by byte count */ - return false; - } - if(!DecodeNesting_IsCurrentBounded(pNesting)) { - /* In a traveral at a level deeper than the bounded level */ - return false; - } - /* Works for both definite- and indefinitelength maps/arrays */ - if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 && - pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) { - /* Count is not zero, still unconsumed item */ - return false; - } - /* All checks passed, got to the end of an array or map*/ - return true; -} - - -static bool -DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting) -{ - /* Must only be called on map / array */ - if(pNesting->pCurrent->u.ma.uCountCursor == 0) { - return true; - } else { - return false; - } -} - - -static bool -DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) { - return true; - } else { - return false; - } -} - - -static bool -DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) -{ - if(pNesting->pCurrentBounded == NULL) { - return false; - } - - uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType; -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { - uItemDataType = QCBOR_TYPE_ARRAY; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - if(uItemDataType != uType) { - return false; - } - - return true; -} - - -static void -DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting) -{ - /* Only call on a definite-length array / map */ - pNesting->pCurrent->u.ma.uCountCursor--; -} - - -static void -DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) -{ - /* Only call on a definite-length array / map */ - pNesting->pCurrent->u.ma.uCountCursor++; -} - - -static void -DecodeNesting_Ascend(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent--; -} - - -static QCBORError -DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType) -{ - /* Error out if nesting is too deep */ - if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) { - return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP; - } - - /* The actual descend */ - pNesting->pCurrent++; - - pNesting->pCurrent->uLevelType = uType; - - return QCBOR_SUCCESS; -} - - -static QCBORError -DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, - bool bIsEmpty, - size_t uOffset) -{ - /* - * Should only be called on map/array. - * - * Have descended into this before this is called. The job here is - * just to mark it in bounded mode. - * - * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that - * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET. - * - * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX. - */ - if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) { - return QCBOR_ERR_INPUT_TOO_LARGE; - } - - pNesting->pCurrentBounded = pNesting->pCurrent; - - DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset); - - return QCBOR_SUCCESS; -} - - -static QCBORError -DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, - const uint8_t uQCBORType, - const uint16_t uCount) -{ - QCBORError uError = QCBOR_SUCCESS; - - if(uCount == 0) { - /* Nothing to do for empty definite-length arrays. They are just are - * effectively the same as an item that is not a map or array. - */ - goto Done; - /* Empty indefinite-length maps and arrays are handled elsewhere */ - } - - /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length - * arrays and maps that are too long */ - - uError = DecodeNesting_Descend(pNesting, uQCBORType); - if(uError != QCBOR_SUCCESS) { - goto Done; - } - - pNesting->pCurrent->u.ma.uCountCursor = uCount; - pNesting->pCurrent->u.ma.uCountTotal = uCount; - - DecodeNesting_ClearBoundedMode(pNesting); - -Done: - return uError;; -} - - -static void -DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent = pNesting->pCurrentBounded - 1; -} - - -static void -DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting) -{ - while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) { - pNesting->pCurrentBounded--; - if(DecodeNesting_IsCurrentBounded(pNesting)) { - break; - } - } -} - - -static void -DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent = pNesting->pCurrentBounded; -} - - -static QCBORError -DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, - uint32_t uEndOffset, - uint32_t uStartOffset) -{ - QCBORError uError; - - uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING); - if(uError != QCBOR_SUCCESS) { - goto Done; - } - - /* Fill in the new byte string level */ - pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset; - pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset; - - /* Bstr wrapped levels are always bounded */ - pNesting->pCurrentBounded = pNesting->pCurrent; - -Done: - return uError;; -} - - -static void -DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent->u.ma.uCountCursor = 0; -} - - -static void -DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) { - pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal; - } -} - - -static void -DecodeNesting_Init(QCBORDecodeNesting *pNesting) -{ - /* Assumes that *pNesting has been zero'd before this call. */ - pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING; - pNesting->pCurrent = &(pNesting->pLevels[0]); -} - - -static void -DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, - QCBORDecodeNesting *pSave) -{ - *pSave = *pNesting; -} - - -static void -DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, - const QCBORDecodeNesting *pSave) -{ - *pNesting = *pSave; -} - - -static uint32_t -DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) -{ - return pMe->pCurrentBounded->u.bs.uSavedEndOffset; -} - - - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS -/*=========================================================================== - QCBORStringAllocate -- STRING ALLOCATOR INVOCATION - - The following four functions are pretty wrappers for invocation of - the string allocator supplied by the caller. - - ===========================================================================*/ - -static void -StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem) -{ - /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings. - * This is the one place where the const needs to be cast away so const can - * be use in the rest of the code. - */ - (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0); -} - -// StringAllocator_Reallocate called with pMem NULL is -// equal to StringAllocator_Allocate() -static UsefulBuf -StringAllocator_Reallocate(const QCBORInternalAllocator *pMe, - const void *pMem, - size_t uSize) -{ - /* See comment in StringAllocator_Free() */ - return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize); -} - -static UsefulBuf -StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize) -{ - return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize); -} - -static void -StringAllocator_Destruct(const QCBORInternalAllocator *pMe) -{ - /* See comment in StringAllocator_Free() */ - if(pMe->pfAllocator) { - (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0); - } -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - - -/*=========================================================================== - QCBORDecode -- The main implementation of CBOR decoding - - See qcbor/qcbor_decode.h for definition of the object - used here: QCBORDecodeContext - ===========================================================================*/ -/* - * Public function, see header file - */ -void -QCBORDecode_Init(QCBORDecodeContext *pMe, - UsefulBufC EncodedCBOR, - QCBORDecodeMode nDecodeMode) -{ - memset(pMe, 0, sizeof(QCBORDecodeContext)); - UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR); - /* Don't bother with error check on decode mode. If a bad value is - * passed it will just act as if the default normal mode of 0 was set. - */ - pMe->uDecodeMode = (uint8_t)nDecodeMode; - DecodeNesting_Init(&(pMe->nesting)); - - /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See - * GetNext_TaggedItem() and MapTagNumber(). */ - memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags)); -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - -/* - * Public function, see header file - */ -void -QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings) -{ - pMe->StringAllocator.pfAllocator = pfAllocateFunction; - pMe->StringAllocator.pAllocateCxt = pAllocateContext; - pMe->bStringAllocateAll = bAllStrings; -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - - -/* - * Deprecated public function, see header file - */ -void -QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, - const QCBORTagListIn *pTagList) -{ - /* This does nothing now. It is retained for backwards compatibility */ - (void)pMe; - (void)pTagList; -} - - - - -/* - * Decoding items is done in six layers, one calling the next one - * down. If a layer has no work to do for a particular item, it - * returns quickly. - * - * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes - * tagged data items, turning them into the local C representation. - * For the most simple it is just associating a QCBOR_TYPE with the - * data. For the complex ones that an aggregate of data items, there - * is some further decoding and some limited recursion. - * - * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the - * beginnings and ends of maps and arrays. It tracks descending into - * and ascending out of maps/arrays. It processes breaks that - * terminate indefinite-length maps and arrays. - * - * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining - * of two items, the label and the data, that make up a map entry. It - * only does work on maps. It combines the label and data items into - * one labeled item. - * - * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag - * numbers. It turns the tag numbers into bit flags associated with - * the data item. No actual decoding of the contents of the tag is - * performed here. - * - * 5. QCBORDecode_Private_GetNextFullString - This assembles the - * sub-items that make up an indefinite-length string into one string - * item. It uses the string allocator to create contiguous space for - * the item. It processes all breaks that are part of - * indefinite-length strings. - * - * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic - * data items in CBOR. Each atomic data item has a "major type", an - * integer "argument" and optionally some content. For text and byte - * strings, the content is the bytes that make up the string. These - * are the smallest data items that are considered to be well-formed. - * The content may also be other data items in the case of aggregate - * types. They are not handled in this layer. - * - * This uses about 350 bytes of stack. This number comes from - * instrumenting (printf address of stack variables) the code on x86 - * compiled for size optimization. - */ - - -/* - * Note about use of int and unsigned variables. - * - * See http://www.unix.org/whitepapers/64bit.html for reasons int is - * used carefully here, and in particular why it isn't used in the - * public interface. Also see - * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers - * - * Int is used for values that need less than 16-bits and would be - * subject to integer promotion and result in complaining from static - * analyzers. - */ - - -/** - * @brief Decode the CBOR head, the type and argument. - * - * @param[in] pUInBuf The input buffer to read from. - * @param[out] pnMajorType The decoded major type. - * @param[out] puArgument The decoded argument. - * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte. - * - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * - * This decodes the CBOR "head" that every CBOR data item has. See - * longer explaination of the head in documentation for - * QCBOREncode_EncodeHead(). - * - * This does the network->host byte order conversion. The conversion - * here also results in the conversion for floats in addition to that - * for lengths, tags and integer values. - * - * The int type is preferred to uint8_t for some variables as this - * avoids integer promotions, can reduce code size and makes static - * analyzers happier. - */ -static QCBORError -QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf, - int *pnMajorType, - uint64_t *puArgument, - int *pnAdditionalInfo) -{ - QCBORError uReturn; - - /* Get the initial byte that every CBOR data item has and break it - * down. */ - const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf); - const int nTmpMajorType = nInitialByte >> 5; - const int nAdditionalInfo = nInitialByte & 0x1f; - - /* Where the argument accumulates */ - uint64_t uArgument; - - if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) { - /* Need to get 1,2,4 or 8 additional argument bytes. Map - * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length. - */ - static const uint8_t aIterate[] = {1,2,4,8}; - - /* Loop getting all the bytes in the argument */ - uArgument = 0; - for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) { - /* This shift and add gives the endian conversion. */ - uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf); - } - } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) { - /* The reserved and thus-far unused additional info values */ - uReturn = QCBOR_ERR_UNSUPPORTED; - goto Done; - } else { - /* Less than 24, additional info is argument or 31, an - * indefinite-length. No more bytes to get. - */ - uArgument = (uint64_t)nAdditionalInfo; - } - - if(UsefulInputBuf_GetError(pUInBuf)) { - uReturn = QCBOR_ERR_HIT_END; - goto Done; - } - - /* All successful if arrived here. */ - uReturn = QCBOR_SUCCESS; - *pnMajorType = nTmpMajorType; - *puArgument = uArgument; - *pnAdditionalInfo = nAdditionalInfo; - -Done: - return uReturn; -} - - -/** - * @brief Decode integer types, major types 0 and 1. - * - * @param[in] nMajorType The CBOR major type (0 or 1). - * @param[in] uArgument The argument from the head. - * @param[in] nAdditionalInfo So it can be error-checked. - * @param[out] pDecodedItem The filled in decoded item. - * - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered. - * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. - * - * Must only be called when major type is 0 or 1. - * - * CBOR doesn't explicitly specify two's compliment for integers but - * all CPUs use it these days and the test vectors in the RFC are - * so. All integers in the CBOR structure are positive and the major - * type indicates positive or negative. CBOR can express positive - * integers up to 2^x - 1 where x is the number of bits and negative - * integers down to 2^x. Note that negative numbers can be one more - * away from zero than positive. Stdint, as far as I can tell, uses - * two's compliment to represent negative integers. - */ -static QCBORError -QCBOR_Private_DecodeInteger(const int nMajorType, - const uint64_t uArgument, - const int nAdditionalInfo, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - uReturn = QCBOR_ERR_BAD_INT; - goto Done; - } - - if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) { - if (uArgument <= INT64_MAX) { - pDecodedItem->val.int64 = (int64_t)uArgument; - pDecodedItem->uDataType = QCBOR_TYPE_INT64; - - } else { - pDecodedItem->val.uint64 = uArgument; - pDecodedItem->uDataType = QCBOR_TYPE_UINT64; - } - - } else { - if(uArgument <= INT64_MAX) { - /* CBOR's representation of negative numbers lines up with - * the two-compliment representation. A negative integer has - * one more in range than a positive integer. INT64_MIN is - * equal to (-INT64_MAX) - 1. - */ - pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1; - pDecodedItem->uDataType = QCBOR_TYPE_INT64; - - } else { - /* C can't represent a negative integer in this range so it - * is an error. - */ - uReturn = QCBOR_ERR_INT_OVERFLOW; - } - } - -Done: - return uReturn; -} - - -/** - * @brief Decode text and byte strings - * - * @param[in] pMe Decoder context. - * @param[in] bAllocate Whether to allocate and copy string. - * @param[in] nMajorType Whether it is a byte or text string. - * @param[in] uStrLen The length of the string. - * @param[in] nAdditionalInfo Whether it is an indefinite-length string. - * @param[out] pDecodedItem The filled-in decoded item. - * - * @retval QCBOR_ERR_HIT_END Unexpected end of input. - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator - * - * This reads @c uStrlen bytes from the input and fills in @c - * pDecodedItem. If @c bAllocate is true, then memory for the string - * is allocated. - */ -static QCBORError -QCBOR_Private_DecodeString(QCBORDecodeContext *pMe, - const bool bAllocate, - const int nMajorType, - const uint64_t uStrLen, - const int nAdditionalInfo, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - /* ---- Figure out the major type ---- */ - #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING - #error QCBOR_TYPE_BYTE_STRING not lined up with major type - #endif - - #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING - #error QCBOR_TYPE_TEXT_STRING not lined up with major type - #endif - pDecodedItem->uDataType = (uint8_t)(nMajorType + 4); - - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - /* --- Just the head of an indefinite-length string --- */ - pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE}; - - } else { - /* --- A definite-length string --- */ - /* --- (which might be a chunk of an indefinte-length string) --- */ - - /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all - * CPUs. This check makes the casts to size_t below safe. - * - * The max is 4 bytes less than the largest sizeof() so this can be - * tested by putting a SIZE_MAX length in the CBOR test input (no - * one will care the limit on strings is 4 bytes shorter). - */ - if(uStrLen > SIZE_MAX-4) { - uReturn = QCBOR_ERR_STRING_TOO_LONG; - goto Done; - } - - const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen); - if(UsefulBuf_IsNULLC(Bytes)) { - /* Failed to get the bytes for this string item */ - uReturn = QCBOR_ERR_HIT_END; - goto Done; - } - - if(bAllocate) { -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - /* --- Put string in allocated memory --- */ - - /* Note that this is not where allocation to coalesce - * indefinite-length strings is done. This is for when the - * caller has requested all strings be allocated. Disabling - * indefinite length strings also disables this allocate-all - * option. - */ - - if(pMe->StringAllocator.pfAllocator == NULL) { - uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; - goto Done; - } - UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen); - if(UsefulBuf_IsNULL(NewMem)) { - uReturn = QCBOR_ERR_STRING_ALLOCATE; - goto Done; - } - pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); - pDecodedItem->uDataAlloc = 1; -#else - uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; -#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - } else { - /* --- Normal case with no string allocator --- */ - pDecodedItem->val.string = Bytes; - } - } - -Done: - return uReturn; -} - - -/** - * @brief Decode array or map. - * - * @param[in] uMode Decoder mode. - * @param[in] nMajorType Whether it is a byte or text string. - * @param[in] uItemCount The length of the string. - * @param[in] nAdditionalInfo Whether it is an indefinite-length. - * @param[out] pDecodedItem The filled-in decoded item. - * - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled. - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. - * - * Not much to do for arrays and maps. Just the type item count (but a - * little messy because of ifdefs for indefinite-lengths and - * map-as-array decoding). - * - * This also does the bulk of the work for @ref - * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle - * arbitrarily complex map labels. This ifdefs out with - * QCBOR_DISABLE_NON_INTEGER_LABELS. - */ -static QCBORError -QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode, - const int nMajorType, - uint64_t uItemCount, - const int nAdditionalInfo, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn; - - /* ------ Sort out the data type ------ */ - #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY - #error QCBOR_TYPE_ARRAY value not lined up with major type - #endif - - #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP - #error QCBOR_TYPE_MAP value not lined up with major type - #endif - pDecodedItem->uDataType = (uint8_t)nMajorType; -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { - pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; - } -#else - (void)uMode; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - uReturn = QCBOR_SUCCESS; - - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - /* ------ Indefinite-length array/map ----- */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH; -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED; -#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - } else { - /* ----- Definite-length array/map ----- */ - if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) { - uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - - } else { -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { - /* ------ Map as array ------ */ - uItemCount *= 2; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - /* cast OK because of check above */ - pDecodedItem->val.uCount = (uint16_t)uItemCount; - } - } - - return uReturn; -} - - -/** - * @brief Decode a tag number. - * - * @param[in] uTagNumber The length of the string. - * @param[in] nAdditionalInfo So this can be error-checked. - * @param[out] pDecodedItem The filled-in decoded item. - * - * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE. - * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. - * - * Not much to do for tags, but fill in pDecodedItem and check for - * error in nAdditionalInfo. - */ -static QCBORError -QCBOR_Private_DecodeTag(const uint64_t uTagNumber, - const int nAdditionalInfo, - QCBORItem *pDecodedItem) -{ -#ifndef QCBOR_DISABLE_TAGS - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - return QCBOR_ERR_BAD_INT; - } else { - pDecodedItem->val.uTagV = uTagNumber; - pDecodedItem->uDataType = QCBOR_TYPE_TAG; - return QCBOR_SUCCESS; - } -#else /* QCBOR_DISABLE_TAGS */ - (void)nAdditionalInfo; - (void)uTagNumber; - (void)pDecodedItem; - return QCBOR_ERR_TAGS_DISABLED; -#endif /* QCBOR_DISABLE_TAGS */ -} - - -/* Make sure #define value line up as DecodeSimple counts on this. */ -#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE -#error QCBOR_TYPE_FALSE macro value wrong -#endif - -#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE -#error QCBOR_TYPE_TRUE macro value wrong -#endif - -#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL -#error QCBOR_TYPE_NULL macro value wrong -#endif - -#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF -#error QCBOR_TYPE_UNDEF macro value wrong -#endif - -#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK -#error QCBOR_TYPE_BREAK macro value wrong -#endif - -#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT -#error QCBOR_TYPE_DOUBLE macro value wrong -#endif - -#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT -#error QCBOR_TYPE_FLOAT macro value wrong -#endif - - -/** - * @brief Decode major type 7 -- true, false, floating-point, break... - * - * @param[in] nAdditionalInfo The lower five bits from the initial byte. - * @param[in] uArgument The argument from the head. - * @param[out] pDecodedItem The filled in decoded item. - * - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float - * decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple - * type in input. - */ -static QCBORError -QCBOR_Private_DecodeType7(const int nAdditionalInfo, - const uint64_t uArgument, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - /* uAdditionalInfo is 5 bits from the initial byte. Compile time - * checks above make sure uAdditionalInfo values line up with - * uDataType values. DecodeHead() never returns an AdditionalInfo - * > 0x1f so cast is safe. - */ - pDecodedItem->uDataType = (uint8_t)nAdditionalInfo; - - switch(nAdditionalInfo) { - /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they - * are caught before this is called. - */ - - case HALF_PREC_FLOAT: /* 25 */ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - /* Half-precision is returned as a double. The cast to - * uint16_t is safe because the encoded value was 16 bits. It - * was widened to 64 bits to be passed in here. - */ - pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument); - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ - uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS); - break; - case SINGLE_PREC_FLOAT: /* 26 */ -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - /* Single precision is normally returned as a double since - * double is widely supported, there is no loss of precision, - * it makes it easy for the caller in most cases and it can - * be converted back to single with no loss of precision - * - * The cast to uint32_t is safe because the encoded value was - * 32 bits. It was widened to 64 bits to be passed in here. - */ - { - const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument); -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - /* In the normal case, use HW to convert float to - * double. */ - pDecodedItem->val.dfnum = (double)f; - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; -#else /* QCBOR_DISABLE_FLOAT_HW_USE */ - /* Use of float HW is disabled, return as a float. */ - pDecodedItem->val.fnum = f; - pDecodedItem->uDataType = QCBOR_TYPE_FLOAT; - - /* IEEE754_FloatToDouble() could be used here to return as - * a double, but it adds object code and most likely - * anyone disabling FLOAT HW use doesn't care about floats - * and wants to save object code. - */ -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS); - break; - - case DOUBLE_PREC_FLOAT: /* 27 */ -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument); - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS); - break; - - case CBOR_SIMPLEV_FALSE: /* 20 */ - case CBOR_SIMPLEV_TRUE: /* 21 */ - case CBOR_SIMPLEV_NULL: /* 22 */ - case CBOR_SIMPLEV_UNDEF: /* 23 */ - case CBOR_SIMPLE_BREAK: /* 31 */ - break; /* nothing to do */ - - case CBOR_SIMPLEV_ONEBYTE: /* 24 */ - if(uArgument <= CBOR_SIMPLE_BREAK) { - /* This takes out f8 00 ... f8 1f which should be encoded - * as e0 … f7 - */ - uReturn = QCBOR_ERR_BAD_TYPE_7; - goto Done; - } - /* FALLTHROUGH */ - - default: /* 0-19 */ - pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE; - /* DecodeHead() will make uArgument equal to - * nAdditionalInfo when nAdditionalInfo is < 24. This cast is - * safe because the 2, 4 and 8 byte lengths of uNumber are in - * the double/float cases above - */ - pDecodedItem->val.uSimple = (uint8_t)uArgument; - break; - } - -Done: - return uReturn; -} - - -/** - * @brief Decode a single primitive data item (decode layer 6). - * - * @param[in] pMe Decoder context. - * @param[in] bAllocateStrings If true, use allocator for strings. - * @param[out] pDecodedItem The filled-in decoded item. - * - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved - * features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all - * float decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of - * simple type in input. - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array - * in input, but indefinite - * lengths disabled. - * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. - * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. - * - * This decodes the most primitive/atomic data item. It does no - * combining of data items. - */ -static QCBORError -QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe, - const bool bAllocateStrings, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn; - int nMajorType = 0; - uint64_t uArgument = 0; - int nAdditionalInfo = 0; - - memset(pDecodedItem, 0, sizeof(QCBORItem)); - - /* Decode the "head" that every CBOR item has into the major type, - * argument and the additional info. - */ - uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo); - if(uReturn != QCBOR_SUCCESS) { - return uReturn; - } - - /* All the functions below get inlined by the optimizer. This code - * is easier to read with them all being similar functions, even if - * some functions don't do much. - */ - switch (nMajorType) { - case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */ - case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */ - return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem); - break; - - case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */ - case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */ - return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); - break; - - case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */ - case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */ - return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); - break; - - case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */ - return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem); - break; - - case CBOR_MAJOR_TYPE_SIMPLE: - /* Major type 7: float, double, true, false, null... */ - return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem); - break; - - default: - /* Never happens because DecodeHead() should never return > 7 */ - return QCBOR_ERR_UNSUPPORTED; - break; - } -} - - -/** - * @brief Process indefinite-length strings (decode layer 5). - * - * @param[in] pMe Decoder context - * @param[out] pDecodedItem The decoded item that work is done on. - * - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved - * features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all - * float decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of - * simple type in input. - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array - * in input, but indefinite - * lengths disabled. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, - * but no string allocator. - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in - * input, but indefinite-length - * strings are disabled. - * - * If @c pDecodedItem is not an indefinite-length string, this does nothing. - * - * If it is, this loops getting the subsequent chunk data items that - * make up the string. The string allocator is used to make a - * contiguous buffer for the chunks. When this completes @c - * pDecodedItem contains the put-together string. - * - * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH - */ -static QCBORError -QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 32 16 - * 2 UsefulBufs 32 16 - * QCBORItem 56 52 - * TOTAL 120 74 - */ - QCBORError uReturn; - - /* A note about string allocation -- Memory for strings is - * allocated either because 1) indefinte-length string chunks are - * being coalecsed or 2) caller has requested all strings be - * allocated. The first case is handed below here. The second case - * is handled in DecodeString if the bAllocate is true. That - * boolean originates here with pMe->bStringAllocateAll immediately - * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called - * in two different contexts here 1) main-line processing which is - * where definite-length strings need to be allocated if - * bStringAllocateAll is true and 2) processing chunks of - * indefinite-lengths strings in in which case there must be no - * allocation. - */ - - - uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - - - /* This is where out-of-place break is detected for the whole - * decoding stack. Break is an error for everything that calls - * QCBORDecode_Private_GetNextFullString(), so the check is - * centralized here. - */ - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - uReturn = QCBOR_ERR_BAD_BREAK; - goto Done; - } - - - /* Skip out if not an indefinite-length string */ - const uint8_t uStringType = pDecodedItem->uDataType; - if(uStringType != QCBOR_TYPE_BYTE_STRING && - uStringType != QCBOR_TYPE_TEXT_STRING) { - goto Done; - } - if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) { - goto Done; - } - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - /* Can't decode indefinite-length strings without a string allocator */ - if(!pMe->StringAllocator.pfAllocator) { - uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; - goto Done; - } - - /* Loop getting chunks of the indefinite-length string */ - UsefulBufC FullString = NULLUsefulBufC; - - for(;;) { - /* Get QCBORItem for next chunk */ - QCBORItem StringChunkItem; - /* Pass false to DecodeAtomicDataItem() because the individual - * string chunks in an indefinite-length must not be - * allocated. They are always copied into the allocated - * contiguous buffer allocated here. - */ - uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem); - if(uReturn) { - break; - } - - /* Is item is the marker for end of the indefinite-length string? */ - if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) { - /* String is complete */ - pDecodedItem->val.string = FullString; - pDecodedItem->uDataAlloc = 1; - break; - } - - /* All chunks must be of the same type, the type of the item - * that introduces the indefinite-length string. This also - * catches errors where the chunk is not a string at all and an - * indefinite-length string inside an indefinite-length string. - */ - if(StringChunkItem.uDataType != uStringType || - StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) { - uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK; - break; - } - - if (StringChunkItem.val.string.len > 0) { - /* The first time throurgh FullString.ptr is NULL and this is - * equivalent to StringAllocator_Allocate(). Subsequently it is - * not NULL and a reallocation happens. - */ - UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator), - FullString.ptr, - FullString.len + StringChunkItem.val.string.len); - if(UsefulBuf_IsNULL(NewMem)) { - uReturn = QCBOR_ERR_STRING_ALLOCATE; - break; - } - - /* Copy new string chunk to the end of accumulated string */ - FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string); - } - } - - if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) { - /* Getting the item failed, clean up the allocated memory */ - StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr); - } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - -Done: - return uReturn; -} - - -#ifndef QCBOR_DISABLE_TAGS -/** - * @brief This converts a tag number to a shorter mapped value for storage. - * - * @param[in] pMe The decode context. - * @param[in] uUnMappedTag The tag number to map - * @param[out] puMappedTagNumer The stored tag number. - * - * @return error code. - * - * The main point of mapping tag numbers is make QCBORItem - * smaller. With this mapping storage of 4 tags takes up 8 - * bytes. Without, it would take up 32 bytes. - * - * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG. - * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16. - * - * See also UnMapTagNumber() and @ref QCBORItem. - */ -static QCBORError -QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe, - const uint64_t uUnMappedTag, - uint16_t *puMappedTagNumer) -{ - if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) { - unsigned uTagMapIndex; - /* Is there room in the tag map, or is it in it already? */ - for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) { - if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) { - break; - } - if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) { - break; - } - } - if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) { - return QCBOR_ERR_TOO_MANY_TAGS; - } - - /* Covers the cases where tag is new and were it is already in the map */ - pMe->auMappedTags[uTagMapIndex] = uUnMappedTag; - *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1); - - } else { - *puMappedTagNumer = (uint16_t)uUnMappedTag; - } - - return QCBOR_SUCCESS; -} - - -/** - * @brief This converts a mapped tag number to the actual tag number. - * - * @param[in] pMe The decode context. - * @param[in] uMappedTagNumber The stored tag number. - * - * @return The actual tag number is returned or - * @ref CBOR_TAG_INVALID64 on error. - * - * This is the reverse of MapTagNumber() - */ -static uint64_t -QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe, - const uint16_t uMappedTagNumber) -{ - if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) { - return uMappedTagNumber; - } else if(uMappedTagNumber == CBOR_TAG_INVALID16) { - return CBOR_TAG_INVALID64; - } else { - /* This won't be negative because of code below in - * MapTagNumber() - */ - const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1); - return pMe->auMappedTags[uIndex]; - } -} -#endif /* QCBOR_DISABLE_TAGS */ - - -/** - * @brief Aggregate all tags wrapping a data item (decode layer 4). - * - * @param[in] pMe Decoder context - * @param[out] pDecodedItem The decoded item that work is done on. - * - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved - * features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all - * float decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of - * simple type in input. - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array - * in input, but indefinite - * lengths disabled. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, - * but no string allocator. - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in - * input, but indefinite-length - * strings are disabled. - * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. - * - * This loops getting atomic data items until one is not a tag - * number. Usually this is largely pass-through because most - * item are not tag numbers. - */ -static QCBORError -QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem) -{ -#ifndef QCBOR_DISABLE_TAGS - /* Accummulate the tags from multiple items here and then copy them - * into the last item, the non-tag item. - */ - uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM]; - - /* Initialize to CBOR_TAG_INVALID16 */ - #if CBOR_TAG_INVALID16 != 0xffff - /* Be sure the memset does the right thing. */ - #err CBOR_TAG_INVALID16 tag not defined as expected - #endif - memset(auItemsTags, 0xff, sizeof(auItemsTags)); - - QCBORError uReturn = QCBOR_SUCCESS; - - /* Loop fetching data items until the item fetched is not a tag */ - for(;;) { - QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); - if(uErr != QCBOR_SUCCESS) { - uReturn = uErr; - goto Done; - } - - if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) { - /* Successful exit from loop; maybe got some tags, maybe not */ - memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags)); - break; - } - - if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) { - /* No room in the tag list */ - uReturn = QCBOR_ERR_TOO_MANY_TAGS; - /* Continue on to get all tags wrapping this item even though - * it is erroring out in the end. This allows decoding to - * continue. This is a resource limit error, not a problem - * with being well-formed CBOR. - */ - continue; - } - /* Slide tags over one in the array to make room at index 0. - * Must use memmove because the move source and destination - * overlap. - */ - memmove(&auItemsTags[1], - auItemsTags, - sizeof(auItemsTags) - sizeof(auItemsTags[0])); - - /* Map the tag */ - uint16_t uMappedTagNumber = 0; - uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber); - /* Continue even on error so as to consume all tags wrapping - * this data item so decoding can go on. If MapTagNumber() - * errors once it will continue to error. - */ - auItemsTags[0] = uMappedTagNumber; - } - -Done: - return uReturn; - -#else /* QCBOR_DISABLE_TAGS */ - - return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); - -#endif /* QCBOR_DISABLE_TAGS */ -} - - -/** - * @brief Combine a map entry label and value into one item (decode layer 3). - * - * @param[in] pMe Decoder context - * @param[out] pDecodedItem The decoded item that work is done on. - * - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved - * features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all - * float decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of - * simple type in input. - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array - * in input, but indefinite - * lengths disabled. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, - * but no string allocator. - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in - * input, but indefinite-length - * strings are disabled. - * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. - * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. - * - * If the current nesting level is a map, then this combines pairs of - * items into one data item with a label and value. - * - * This is passthrough if the current nesting level is not a map. - * - * This also implements maps-as-array mode where a map is treated like - * an array to allow caller to do their own label processing. - */ - -static QCBORError -QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem) -{ - QCBORItem LabelItem; - QCBORError uErr; - - uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); - if(QCBORDecode_IsUnrecoverableError(uErr)) { - goto Done; - } - - if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) { - /* Not decoding a map. Nothing to do. */ - /* When decoding maps-as-arrays, the type will be - * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit - * here. This is now map processing for maps-as-arrays is not - * done. */ - goto Done; - } - - /* Decoding a map entry, so the item decoded above was the label */ - LabelItem = *pDecodedItem; - - /* Get the value of the map item */ - uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); - if(QCBORDecode_IsUnrecoverableError(uErr)) { - goto Done; - } - - /* Combine the label item and value item into one */ - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; - pDecodedItem->uLabelType = LabelItem.uDataType; - -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe - * get rid of it in QCBOR 2.0 - */ - if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY && - LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) { - uErr = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - switch(LabelItem.uDataType) { - case QCBOR_TYPE_INT64: - pDecodedItem->label.int64 = LabelItem.val.int64; - break; - -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - case QCBOR_TYPE_UINT64: - pDecodedItem->label.uint64 = LabelItem.val.uint64; - break; - - case QCBOR_TYPE_TEXT_STRING: - case QCBOR_TYPE_BYTE_STRING: - pDecodedItem->label.string = LabelItem.val.string; - break; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - default: - uErr = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } - -Done: - return uErr; -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/** - * @brief Peek and see if next data item is a break; - * - * param[in] pUIB UsefulInputBuf to read from. - * @param[out] pbNextIsBreak Indicate if next was a break or not. - * - * @return Any decoding error. - * - * See if next item is a CBOR break. If it is, it is consumed, - * if not it is not consumed. -*/ -static QCBORError -QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak) -{ - *pbNextIsBreak = false; - if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) { - QCBORItem Peek; - size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf)); - QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek); - if(uReturn != QCBOR_SUCCESS) { - return uReturn; - } - if(Peek.uDataType != QCBOR_TYPE_BREAK) { - /* It is not a break, rewind so it can be processed normally. */ - UsefulInputBuf_Seek(&(pMe->InBuf), uPeek); - } else { - *pbNextIsBreak = true; - } - } - - return QCBOR_SUCCESS; -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - -/** - * @brief Ascend up nesting levels if all items in them have been consumed. - * - * @param[in] pMe The decode context. - * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero. - * @param[out] pbBreak Set to true if extra break was consumed. - * - * An item was just consumed, now figure out if it was the - * end of an array/map map that can be closed out. That - * may in turn close out the above array/map... - * - * When ascending indefinite-length arrays and maps, this will correctly - * consume the break for the level above. This is a problem for the - * implementation of QCBORDecode_GetArray() that must not return - * that break. @c pbBreak is set to true to indicate that one - * byte should be removed. - * - * Improvement: this could reduced further if indef is disabled - */ -static QCBORError -QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak) -{ - QCBORError uReturn; - - /* Loop ascending nesting levels as long as there is ascending to do */ - while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) { - if(pbBreak) { - *pbBreak = false; - } - - if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) { - /* Nesting level is bstr-wrapped CBOR */ - - /* Ascent for bstr-wrapped CBOR is always by explicit call - * so no further ascending can happen. - */ - break; - - } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) { - /* Level is a definite-length array/map */ - - /* Decrement the item count the definite-length array/map */ - DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting)); - if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) { - /* Didn't close out array/map, so all work here is done */ - break; - } - /* All items in a definite-length array were consumed so it - * is time to ascend one level. This happens below. - */ - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - } else { - /* Level is an indefinite-length array/map. */ - - /* Check for a break which is what ends indefinite-length arrays/maps */ - bool bIsBreak = false; - uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - - if(!bIsBreak) { - /* Not a break so array/map does not close out. All work is done */ - break; - } - - /* It was a break in an indefinitelength map / array so - * it is time to ascend one level. - */ - if(pbBreak) { - *pbBreak = true; - } - -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - } - - - /* All items in the array/map have been consumed. */ - - /* But ascent in bounded mode is only by explicit call to - * QCBORDecode_ExitBoundedMode(). - */ - if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) { - /* Set the count to zero for definite-length arrays to indicate - * cursor is at end of bounded array/map */ - if(bMarkEnd) { - /* Used for definite and indefinite to signal end */ - DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting)); - - } - break; - } - - /* Finally, actually ascend one level. */ - DecodeNesting_Ascend(&(pMe->nesting)); - } - - uReturn = QCBOR_SUCCESS; - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -Done: -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - return uReturn; -} - - -/** - * @brief Ascending & Descending out of nesting levels (decode layer 2). - * - * @param[in] pMe Decoder context - * @param[out] pbBreak Set to true if extra break was consumed. - * @param[out] pDecodedItem The decoded item that work is done on. - - * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved - * features - * @retval QCBOR_ERR_HIT_END Unexpected end of input - * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered - * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. - * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode - * of half-precision disabled - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all - * float decode is disabled. - * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of - * simple type in input. - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array - * in input, but indefinite - * lengths disabled. - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, - * but no string allocator. - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in - * input, but indefinite-length - * strings are disabled. - * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. - * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. - * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array. - * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong - * place. - * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR - * can handle. - * - * This handles the traversal descending into and asecnding out of - * maps, arrays and bstr-wrapped CBOR. It figures out the ends of - * definite- and indefinte-length maps and arrays by looking at the - * item count or finding CBOR breaks. It detects the ends of the - * top-level sequence and of bstr-wrapped CBOR by byte count. - */ -static QCBORError -QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe, - bool *pbBreak, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn; - /* ==== First: figure out if at the end of a traversal ==== */ - - /* If out of bytes to consume, it is either the end of the - * top-level sequence of some bstr-wrapped CBOR that was entered. - * - * In the case of bstr-wrapped CBOR, the length of the - * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When - * the bstr-wrapped CBOR is exited, the length is set back to the - * top-level's length or to the next highest bstr-wrapped CBOR. - */ - if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) { - uReturn = QCBOR_ERR_NO_MORE_ITEMS; - goto Done; - } - - /* Check to see if at the end of a bounded definite-length map or - * array. The check for a break ending indefinite-length array is - * later in QCBORDecode_NestLevelAscender(). - */ - if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) { - uReturn = QCBOR_ERR_NO_MORE_ITEMS; - goto Done; - } - - /* ==== Next: not at the end, so get another item ==== */ - uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem); - if(QCBORDecode_IsUnrecoverableError(uReturn)) { - /* Error is so bad that traversal is not possible. */ - goto Done; - } - - /* Record the nesting level for this data item before processing - * any of decrementing and descending. - */ - pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting)); - - - /* ==== Next: Process the item for descent, ascent, decrement... ==== */ - if(QCBORItem_IsMapOrArray(*pDecodedItem)) { - /* If the new item is a map or array, descend. - * - * Empty indefinite-length maps and arrays are descended into, - * but then ascended out of in the next chunk of code. - * - * Maps and arrays do count as items in the map/array that - * encloses them so a decrement needs to be done for them too, - * but that is done only when all the items in them have been - * processed, not when they are opened with the exception of an - * empty map or array. - */ - QCBORError uDescendErr; - uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting), - pDecodedItem->uDataType, - pDecodedItem->val.uCount); - if(uDescendErr != QCBOR_SUCCESS) { - /* This error is probably a traversal error and it overrides - * the non-traversal error. - */ - uReturn = uDescendErr; - goto Done; - } - } - - if(!QCBORItem_IsMapOrArray(*pDecodedItem) || - QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) || - QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) { - /* The following cases are handled here: - * - A non-aggregate item like an integer or string - * - An empty definite-length map or array - * - An indefinite-length map or array that might be empty or might not. - * - * QCBORDecode_NestLevelAscender() does the work of decrementing the count - * for an definite-length map/array and break detection for an - * indefinite-0length map/array. If the end of the map/array was - * reached, then it ascends nesting levels, possibly all the way - * to the top level. - */ - QCBORError uAscendErr; - uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak); - if(uAscendErr != QCBOR_SUCCESS) { - /* This error is probably a traversal error and it overrides - * the non-traversal error. - */ - uReturn = uAscendErr; - goto Done; - } - } - - /* ==== Last: tell the caller the nest level of the next item ==== */ - /* Tell the caller what level is next. This tells them what - * maps/arrays were closed out and makes it possible for them to - * reconstruct the tree with just the information returned in a - * QCBORItem. - */ - if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) { - /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */ - pDecodedItem->uNextNestLevel = 0; - } else { - pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting)); - } - -Done: - return uReturn; -} - - -#ifndef QCBOR_DISABLE_TAGS -/** - * @brief Shift 0th tag out of the tag list. - * - * pDecodedItem[in,out] The data item to convert. - * - * The 0th tag is discarded. @ref CBOR_TAG_INVALID16 is - * shifted into empty slot at the end of the tag list. - */ -static void -QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem) -{ - for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) { - pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1]; - } - pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16; -} -#endif /* QCBOR_DISABLE_TAGS */ - - -/** - * @brief Convert different epoch date formats in to the QCBOR epoch date format - * - * pDecodedItem[in,out] The data item to convert. - * - * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, - * floating-point date disabled. - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, - * all floating-point disabled. - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable - * error decoding date. - * - * The epoch date tag defined in QCBOR allows for floating-point - * dates. It even allows a protocol to flop between date formats when - * ever it wants. Floating-point dates aren't that useful as they are - * only needed for dates beyond the age of the earth. - * - * This converts all the date formats into one format of an unsigned - * integer plus a floating-point fraction. - */ -static QCBORError -QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - pDecodedItem->val.epochDate.fSecondsFraction = 0; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - switch (pDecodedItem->uDataType) { - - case QCBOR_TYPE_INT64: - pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64; - break; - - case QCBOR_TYPE_UINT64: - /* This only happens for CBOR type 0 > INT64_MAX so it is - * always an overflow. - */ - uReturn = QCBOR_ERR_DATE_OVERFLOW; - goto Done; - break; - - case QCBOR_TYPE_DOUBLE: - case QCBOR_TYPE_FLOAT: -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - { - /* Convert working value to double if input was a float */ - const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ? - pDecodedItem->val.dfnum : - (double)pDecodedItem->val.fnum; - - /* The conversion from float to integer requires overflow - * detection since floats can be much larger than integers. - * This implementation errors out on these large float values - * since they are beyond the age of the earth. - * - * These constants for the overflow check are computed by the - * compiler. They are not computed at run time. - * - * The factor of 0x7ff is added/subtracted to avoid a - * rounding error in the wrong direction when the compiler - * computes these constants. There is rounding because a - * 64-bit integer has 63 bits of precision where a double - * only has 53 bits. Without the 0x7ff factor, the compiler - * may round up and produce a double for the bounds check - * that is larger than can be stored in a 64-bit integer. The - * amount of 0x7ff is picked because it has 11 bits set. - * - * Without the 0x7ff there is a ~30 minute range of time - * values 10 billion years in the past and in the future - * where this code could go wrong. Some compilers - * generate a warning or error without the 0x7ff. - */ - const double dDateMax = (double)(INT64_MAX - 0x7ff); - const double dDateMin = (double)(INT64_MIN + 0x7ff); - - if(isnan(d) || d > dDateMax || d < dDateMin) { - uReturn = QCBOR_ERR_DATE_OVERFLOW; - goto Done; - } - - /* The actual conversion */ - pDecodedItem->val.epochDate.nSeconds = (int64_t)d; - pDecodedItem->val.epochDate.fSecondsFraction = - d - (double)pDecodedItem->val.epochDate.nSeconds; - } -#else /* QCBOR_DISABLE_FLOAT_HW_USE */ - - uReturn = QCBOR_ERR_HW_FLOAT_DISABLED; - goto Done; - -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - break; - - default: - /* It's the arrays and maps that are unrecoverable because - * they are not consumed here. Since this is just an error - * condition, no extra code is added here to make the error - * recoverable for non-arrays and maps like strings. */ - uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT; - goto Done; - } - - pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH; - -Done: - return uReturn; -} - - -/** - * @brief Convert the days epoch date. - * - * pDecodedItem[in,out] The data item to convert. - * - * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, - * floating-point date disabled. - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, - * all floating-point disabled. - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable - * error decoding date. - * - * This is much simpler than the other epoch date format because - * floating-porint is not allowed. This is mostly a simple type check. - */ -static QCBORError -QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - switch (pDecodedItem->uDataType) { - - case QCBOR_TYPE_INT64: - pDecodedItem->val.epochDays = pDecodedItem->val.int64; - break; - - case QCBOR_TYPE_UINT64: - /* This only happens for CBOR type 0 > INT64_MAX so it is - * always an overflow. - */ - uReturn = QCBOR_ERR_DATE_OVERFLOW; - goto Done; - break; - - default: - /* It's the arrays and maps that are unrecoverable because - * they are not consumed here. Since this is just an error - * condition, no extra code is added here to make the error - * recoverable for non-arrays and maps like strings. */ - uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT; - goto Done; - break; - } - - pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH; - -Done: - return uReturn; -} - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - -/* Forward declaration is necessary for - * QCBORDecode_MantissaAndExponent(). to be able to decode bignum - * tags in the mantissa. If the mantissa is a decimal fraction or big - * float in error, this will result in a recurive call to - * QCBORDecode_MantissaAndExponent(), but the recursion will unwined - * correctly and the correct error is returned. - */ -static QCBORError -QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem); - - -/** - * @brief Decode decimal fractions and big floats. - * - * @param[in] pMe The decode context. - * @param[in,out] pDecodedItem On input the array data item that - * holds the mantissa and exponent. On - * output the decoded mantissa and - * exponent. - * - * @returns Decoding errors from getting primitive data items or - * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA. - * - * When called pDecodedItem must be the array with two members, the - * exponent and mantissa. - * - * This will fetch and decode the exponent and mantissa and put the - * result back into pDecodedItem. - * - * This does no checking or processing of tag numbers. That is to be - * done by the code that calls this. - * - * This stuffs the type of the mantissa into pDecodedItem with the expectation - * the caller will process it. - */ -static QCBORError -QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn; - - /* --- Make sure it is an array; track nesting level of members --- */ - if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) { - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - - /* A check for pDecodedItem->val.uCount == 2 would work for - * definite-length arrays, but not for indefinite. Instead remember - * the nesting level the two integers must be at, which is one - * deeper than that of the array. - */ - const int nNestLevel = pDecodedItem->uNestingLevel + 1; - - /* --- Get the exponent --- */ - QCBORItem exponentItem; - uReturn = QCBORDecode_GetNext(pMe, &exponentItem); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - if(exponentItem.uNestingLevel != nNestLevel) { - /* Array is empty or a map/array encountered when expecting an int */ - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - if(exponentItem.uDataType == QCBOR_TYPE_INT64) { - /* Data arriving as an unsigned int < INT64_MAX has been - * converted to QCBOR_TYPE_INT64 and thus handled here. This is - * also means that the only data arriving here of type - * QCBOR_TYPE_UINT64 data will be too large for this to handle - * and thus an error that will get handled in the next else. - */ - pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64; - } else { - /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */ - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - - /* --- Get the mantissa --- */ - QCBORItem mantissaItem; - uReturn = QCBORDecode_GetNext(pMe, &mantissaItem); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - if(mantissaItem.uNestingLevel != nNestLevel) { - /* Mantissa missing or map/array encountered when expecting number */ - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - /* Stuff the mantissa data type into the item to send it up to the - * the next level. */ - pDecodedItem->uDataType = mantissaItem.uDataType; - if(mantissaItem.uDataType == QCBOR_TYPE_INT64) { - /* Data arriving as an unsigned int < INT64_MAX has been - * converted to QCBOR_TYPE_INT64 and thus handled here. This is - * also means that the only data arriving here of type - * QCBOR_TYPE_UINT64 data will be too large for this to handle - * and thus an error that will get handled in an else below. - */ - pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64; -#ifndef QCBOR_DISABLE_TAGS - /* With tags fully disabled a big number mantissa will error out - * in the call to QCBORDecode_GetNextWithTags() because it has - * a tag number. - */ - } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || - mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) { - /* Got a good big num mantissa */ - pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum; -#endif /* QCBOR_DISABLE_TAGS */ - } else { - /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */ - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - - /* --- Check that array only has the two numbers --- */ - if(mantissaItem.uNextNestLevel == nNestLevel) { - /* Extra items in the decimal fraction / big float */ - /* Improvement: this should probably be an unrecoverable error. */ - uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA; - goto Done; - } - pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel; - -Done: - return uReturn; -} -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - - -#ifndef QCBOR_DISABLE_TAGS - -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS -/** - * @brief Decode the MIME type tag - * - * @param[in,out] pDecodedItem The item to decode. - * - * Handle the text and binary MIME type tags. Slightly too complicated - * f or ProcessTaggedString() because the RFC 7049 MIME type was - * incorreclty text-only. - */ -static QCBORError -QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem) -{ - if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) { - pDecodedItem->uDataType = QCBOR_TYPE_MIME; - } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) { - pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME; - } else { - /* It's the arrays and maps that are unrecoverable because - * they are not consumed here. Since this is just an error - * condition, no extra code is added here to make the error - * recoverable for non-arrays and maps like strings. */ - return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT; - } - - return QCBOR_SUCCESS; -} -#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */ - -/** - * Table of CBOR tags whose content is either a text string or a byte - * string. The table maps the CBOR tag to the QCBOR type. The high-bit - * of uQCBORtype indicates the content should be a byte string rather - * than a text string - */ -struct StringTagMapEntry { - uint16_t uTagNumber; - uint8_t uQCBORtype; -}; - -#define IS_BYTE_STRING_BIT 0x80 -#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT - -static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = { - {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING}, - {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING}, - {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT}, - {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT}, - {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT}, - {CBOR_TAG_URI, QCBOR_TYPE_URI}, -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL}, - {CBOR_TAG_B64, QCBOR_TYPE_BASE64}, - {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX}, - {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT}, -#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */ - {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT}, - {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE} -}; - - -/** - * @brief Process standard CBOR tags whose content is a string - * - * @param[in] uTag The tag. - * @param[in,out] pDecodedItem The data item. - * - * @returns This returns QCBOR_SUCCESS if the tag was procssed, - * @ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and - * @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag. - * - * Process the CBOR tags that whose content is a byte string or a text - * string and for which the string is just passed on to the caller. - * - * This maps the CBOR tag to the QCBOR type and checks the content - * type. Nothing more. It may not be the most important - * functionality, but it part of implementing as much of RFC 8949 as - * possible. - */ -static QCBORError -QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) -{ - /* This only works on tags that were not mapped; no need for other yet */ - if(uTag > QCBOR_LAST_UNMAPPED_TAG) { - return QCBOR_ERR_UNSUPPORTED; - } - - unsigned uIndex; - for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) { - if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) { - break; - } - } - - const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype; - if(uQCBORType == QCBOR_TYPE_NONE) { - /* repurpose this error to mean not handled here */ - return QCBOR_ERR_UNSUPPORTED; - } - - uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING; - if(uQCBORType & IS_BYTE_STRING_BIT) { - uExpectedType = QCBOR_TYPE_BYTE_STRING; - } - - if(pDecodedItem->uDataType != uExpectedType) { - /* It's the arrays and maps that are unrecoverable because - * they are not consumed here. Since this is just an error - * condition, no extra code is added here to make the error - * recoverable for non-arrays and maps like strings. */ - return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT; - } - - pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK); - return QCBOR_SUCCESS; -} -#endif /* QCBOR_DISABLE_TAGS */ - - -#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -/** - * @brief Figures out data type for exponent mantissa tags. - * - * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or - * @ref CBOR_TAG_BIG_FLOAT. - * @param[in] pDecodedItem Item being decoded. - * - * @returns One of the 6 values between @ref QCBOR_TYPE_DECIMAL_FRACTION - * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM. - * - * Does mapping between a CBOR tag number and a QCBOR type. with a - * little bit of logic and arithmatic. - * - * Used in serveral contexts. Does the work where sometimes the data - * item is explicitly tagged and sometimes not. - */ -static uint8_t -QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess, - const QCBORItem *pDecodedItem) -{ - uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ? - QCBOR_TYPE_DECIMAL_FRACTION : - QCBOR_TYPE_BIGFLOAT; - if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) { - uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1); - } - return uBase; -} -#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */ - - -/** - * @brief Decode tag content for select tags (decoding layer 1). - * - * @param[in] pMe The decode context. - * @param[out] pDecodedItem The decoded item. - * - * @return Decoding error code. - * - * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(), - * but the whole tag was not decoded. Here, the whole tags (tag number - * and tag content) that are supported by QCBOR are decoded. This is a - * quick pass through for items that are not tags. - */ -static QCBORError -QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn; - - uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - -#ifndef QCBOR_DISABLE_TAGS - /* When there are no tag numbers for the item, this exits first - * thing and effectively does nothing. - * - * This loops over all the tag numbers accumulated for this item - * trying to decode and interpret them. This stops at the end of - * the list or at the first tag number that can't be interpreted by - * this code. This is effectively a recursive processing of the - * tags number list that handles nested tags. - */ - while(1) { - /* Don't bother to unmap tags via QCBORITem.uTags since this - * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG. - */ - const uint16_t uTagToProcess = pDecodedItem->uTags[0]; - - if(uTagToProcess == CBOR_TAG_INVALID16) { - /* Hit the end of the tag list. A successful exit. */ - break; - - } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) { - uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem); - - } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) { - uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem); - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION || - uTagToProcess == CBOR_TAG_BIGFLOAT) { - uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem); - /* --- Which is it, decimal fraction or a bigfloat? --- */ - pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem); - -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - } else if(uTagToProcess == CBOR_TAG_MIME || - uTagToProcess == CBOR_TAG_BINARY_MIME) { - uReturn = QCBOR_Private_DecodeMIME(pDecodedItem); -#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */ - - } else { - /* See if it is a passthrough byte/text string tag; process if so */ - uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem); - - if(uReturn == QCBOR_ERR_UNSUPPORTED) { - /* It wasn't a passthrough byte/text string tag so it is - * an unknown tag. This is the exit from the loop on the - * first unknown tag. It is a successful exit. - */ - uReturn = QCBOR_SUCCESS; - break; - } - } - - if(uReturn != QCBOR_SUCCESS) { - /* Error exit from the loop */ - break; - } - - /* A tag was successfully processed, shift it out of the list of - * tags returned. This is the loop increment. - */ - QCBOR_Private_ShiftTags(pDecodedItem); - } -#endif /* QCBOR_DISABLE_TAGS */ - -Done: - return uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - QCBORError uErr; - uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem); - if(uErr != QCBOR_SUCCESS) { - pDecodedItem->uDataType = QCBOR_TYPE_NONE; - pDecodedItem->uLabelType = QCBOR_TYPE_NONE; - } - return uErr; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - const QCBORDecodeNesting SaveNesting = pMe->nesting; - const UsefulInputBuf Save = pMe->InBuf; - - QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem); - - pMe->nesting = SaveNesting; - pMe->InBuf = Save; - - return uErr; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - pDecodedItem->uDataType = QCBOR_TYPE_NONE; - pDecodedItem->uLabelType = QCBOR_TYPE_NONE; - return; - } - - pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem); -} - - -static void -QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) -{ -#ifndef QCBOR_DISABLE_TAGS - memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags)); -#else - (void)pMe; - (void)pItem; -#endif -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - pDecodedItem->uDataType = QCBOR_TYPE_NONE; - pDecodedItem->uLabelType = QCBOR_TYPE_NONE; - return; - } - - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem); - QCBORDecode_Private_CopyTags(pMe, pDecodedItem); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe, - QCBORItem *pDecodedItem, - QCBORTagListOut *pTags) -{ -#ifndef QCBOR_DISABLE_TAGS - - QCBORError uReturn; - - uReturn = QCBORDecode_GetNext(pMe, pDecodedItem); - if(uReturn != QCBOR_SUCCESS) { - return uReturn; - } - - if(pTags != NULL) { - pTags->uNumUsed = 0; - /* Reverse the order because pTags is reverse of QCBORItem.uTags. */ - for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) { - if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) { - continue; - } - if(pTags->uNumUsed >= pTags->uNumAllocated) { - return QCBOR_ERR_TOO_MANY_TAGS; - } - pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]); - pTags->uNumUsed++; - } - } - - return QCBOR_SUCCESS; - -#else /* QCBOR_DISABLE_TAGS */ - (void)pMe; - (void)pDecodedItem; - (void)pTags; - return QCBOR_ERR_TAGS_DISABLED; -#endif /* QCBOR_DISABLE_TAGS */ -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -bool -QCBORDecode_IsTagged(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint64_t uTag) -{ -#ifndef QCBOR_DISABLE_TAGS - for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) { - if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) { - break; - } - if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) { - return true; - } - } -#else /* QCBOR_TAGS_DISABLED */ - (void)pMe; - (void)pItem; - (void)uTag; -#endif /* QCBOR_TAGS_DISABLED */ - - return false; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed) -{ - if(puConsumed != NULL) { - *puConsumed = pMe->InBuf.cursor; - } - - QCBORError uReturn = pMe->uLastError; - - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - - /* Error out if all the maps/arrays are not closed out */ - if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) { - uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED; - goto Done; - } - - /* Error out if not all the bytes are consumed */ - if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) { - uReturn = QCBOR_ERR_EXTRA_BYTES; - } - -Done: - return uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_Finish(QCBORDecodeContext *pMe) -{ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - /* Call the destructor for the string allocator if there is one. - * Always called, even if there are errors; always have to clean up. - */ - StringAllocator_Destruct(&(pMe->StringAllocator)); -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - return QCBORDecode_PartialFinish(pMe, NULL); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint32_t uIndex) -{ -#ifndef QCBOR_DISABLE_TAGS - if(pItem->uDataType == QCBOR_TYPE_NONE) { - return CBOR_TAG_INVALID64; - } - if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { - return CBOR_TAG_INVALID64; - } else { - return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]); - } -#else /* QCBOR_DISABLE_TAGS */ - (void)pMe; - (void)pItem; - (void)uIndex; - - return CBOR_TAG_INVALID64; -#endif /* QCBOR_DISABLE_TAGS */ -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, - uint32_t uIndex) -{ -#ifndef QCBOR_DISABLE_TAGS - - if(pMe->uLastError != QCBOR_SUCCESS) { - return CBOR_TAG_INVALID64; - } - if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { - return CBOR_TAG_INVALID64; - } else { - return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]); - } -#else /* QCBOR_DISABLE_TAGS */ - (void)pMe; - (void)uIndex; - - return CBOR_TAG_INVALID64; -#endif /* QCBOR_DISABLE_TAGS */ -} - - - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - -/* =========================================================================== - MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR - - This implements a simple sting allocator for indefinite-length - strings that can be enabled by calling QCBORDecode_SetMemPool(). It - implements the function type QCBORStringAllocate and allows easy - use of it. - - This particular allocator is built-in for convenience. The caller - can implement their own. All of this following code will get - dead-stripped if QCBORDecode_SetMemPool() is not called. - - This is a very primitive memory allocator. It does not track - individual allocations, only a high-water mark. A free or - reallocation must be of the last chunk allocated. - - The size of the pool and offset to free memory are packed into the - first 8 bytes of the memory pool so we don't have to keep them in - the decode context. Since the address of the pool may not be - aligned, they have to be packed and unpacked as if they were - serialized data of the wire or such. - - The sizes packed in are uint32_t to be the same on all CPU types - and simplify the code. - ========================================================================== */ - - -static int -MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset) -{ - // Use of UsefulInputBuf is overkill, but it is convenient. - UsefulInputBuf UIB; - - // Just assume the size here. It was checked during SetUp so - // the assumption is safe. - UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE}); - *puPoolSize = UsefulInputBuf_GetUint32(&UIB); - *puFreeOffset = UsefulInputBuf_GetUint32(&UIB); - return UsefulInputBuf_GetError(&UIB); -} - - -static int -MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset) -{ - // Use of UsefulOutBuf is overkill, but convenient. The - // length check performed here is useful. - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, Pool); - UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool - UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position - return UsefulOutBuf_GetError(&UOB); -} - - -/* - Internal function for an allocation, reallocation free and destuct. - - Having only one function rather than one each per mode saves space in - QCBORDecodeContext. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -static UsefulBuf -MemPool_Function(void *pPool, void *pMem, size_t uNewSize) -{ - UsefulBuf ReturnValue = NULLUsefulBuf; - - uint32_t uPoolSize; - uint32_t uFreeOffset; - - if(uNewSize > UINT32_MAX) { - // This allocator is only good up to 4GB. This check should - // optimize out if sizeof(size_t) == sizeof(uint32_t) - goto Done; - } - const uint32_t uNewSize32 = (uint32_t)uNewSize; - - if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) { - goto Done; - } - - if(uNewSize) { - if(pMem) { - // REALLOCATION MODE - // Calculate pointer to the end of the memory pool. It is - // assumed that pPool + uPoolSize won't wrap around by - // assuming the caller won't pass a pool buffer in that is - // not in legitimate memory space. - const void *pPoolEnd = (uint8_t *)pPool + uPoolSize; - - // Check that the pointer for reallocation is in the range of the - // pool. This also makes sure that pointer math further down - // doesn't wrap under or over. - if(pMem >= pPool && pMem < pPoolEnd) { - // Offset to start of chunk for reallocation. This won't - // wrap under because of check that pMem >= pPool. Cast - // is safe because the pool is always less than UINT32_MAX - // because of check in QCBORDecode_SetMemPool(). - const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool); - - // Check to see if the allocation will fit. uPoolSize - - // uMemOffset will not wrap under because of check that - // pMem is in the range of the uPoolSize by check above. - if(uNewSize <= uPoolSize - uMemOffset) { - ReturnValue.ptr = pMem; - ReturnValue.len = uNewSize; - - // Addition won't wrap around over because uNewSize was - // checked to be sure it is less than the pool size. - uFreeOffset = uMemOffset + uNewSize32; - } - } - } else { - // ALLOCATION MODE - // uPoolSize - uFreeOffset will not underflow because this - // pool implementation makes sure uFreeOffset is always - // smaller than uPoolSize through this check here and - // reallocation case. - if(uNewSize <= uPoolSize - uFreeOffset) { - ReturnValue.len = uNewSize; - ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset; - uFreeOffset += (uint32_t)uNewSize; - } - } - } else { - if(pMem) { - // FREE MODE - // Cast is safe because of limit on pool size in - // QCBORDecode_SetMemPool() - uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool); - } else { - // DESTRUCT MODE - // Nothing to do for this allocator - } - } - - UsefulBuf Pool = {pPool, uPoolSize}; - MemPool_Pack(Pool, uFreeOffset); - -Done: - return ReturnValue; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, - UsefulBuf Pool, - bool bAllStrings) -{ - // The pool size and free mem offset are packed into the beginning - // of the pool memory. This compile time check makes sure the - // constant in the header is correct. This check should optimize - // down to nothing. -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#endif - if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) { - return QCBOR_ERR_MEM_POOL_SIZE; - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - // The pool size and free offset packed in to the beginning of pool - // memory are only 32-bits. This check will optimize out on 32-bit - // machines. - if(Pool.len > UINT32_MAX) { - return QCBOR_ERR_MEM_POOL_SIZE; - } - - // This checks that the pool buffer given is big enough. - if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) { - return QCBOR_ERR_MEM_POOL_SIZE; - } - - QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings); - - return QCBOR_SUCCESS; -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - - -/** - * @brief Consume an entire map or array including its contents. - * - * @param[in] pMe The decoder context. - * @param[in] pItemToConsume The array/map whose contents are to be - * consumed. - * @param[out] pbBreak Set to true if extra break was consumed. - * Can be NULL. - * @param[out] puNextNestLevel The next nesting level after the item was - * fully consumed. - * - * This may be called when @c pItemToConsume is not an array or - * map. In that case, this is just a pass through for @c puNextNestLevel - * since there is nothing to do. - */ -static QCBORError -QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe, - const QCBORItem *pItemToConsume, - bool *pbBreak, - uint8_t *puNextNestLevel) -{ - QCBORError uReturn; - QCBORItem Item; - - /* If it is a map or array, this will tell if it is empty. */ - const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel); - - if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) { - /* There is only real work to do for non-empty maps and arrays */ - - /* This works for definite- and indefinite-length maps and - * arrays by using the nesting level - */ - do { - uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item); - if(QCBORDecode_IsUnrecoverableError(uReturn) || - uReturn == QCBOR_ERR_NO_MORE_ITEMS) { - goto Done; - } - } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel); - - *puNextNestLevel = Item.uNextNestLevel; - - uReturn = QCBOR_SUCCESS; - - } else { - /* pItemToConsume is not a map or array. Just pass the nesting - * level through. Ensure pbBreak is false. */ - *puNextNestLevel = pItemToConsume->uNextNestLevel; - if(pbBreak) { - *pbBreak = false; - } - - uReturn = QCBOR_SUCCESS; - } - -Done: - return uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - QCBORDecode_VGetNext(pMe, pDecodedItem); - - if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL, - &pDecodedItem->uNextNestLevel); - } -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_EndCheck(QCBORDecodeContext *pMe) -{ - size_t uCursorOffset; - QCBORError uErr; - - uErr = QCBORDecode_GetError(pMe); - if(uErr != QCBOR_SUCCESS) { - return uErr; - } - - uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); - - if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) { - return QCBOR_ERR_NO_MORE_ITEMS; - } - - return QCBOR_SUCCESS; -} - - -/** - * @brief Rewind cursor to start as if map or array were just entered. - * - * @param[in] pMe The decoding context - * - * This affects the nesting tracking and the UsefulInputBuf. - */ -static void -QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe) -{ - /* Reset nesting tracking to the deepest bounded level */ - DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); - - DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); - - /* Reposition traversal cursor to the start of the map/array */ - UsefulInputBuf_Seek(&(pMe->InBuf), - DecodeNesting_GetMapOrArrayStart(&(pMe->nesting))); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_Rewind(QCBORDecodeContext *pMe) -{ - if(pMe->nesting.pCurrentBounded != NULL) { - /* In a bounded map, array or bstr-wrapped CBOR */ - - if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) { - /* In bstr-wrapped CBOR. */ - - /* Reposition traversal cursor to start of wrapping byte string */ - UsefulInputBuf_Seek(&(pMe->InBuf), - pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset); - DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); - - } else { - /* In a map or array */ - QCBORDecode_Private_RewindMapOrArray(pMe); - } - - } else { - /* Not in anything bounded */ - - /* Reposition traversal cursor to the start of input CBOR */ - UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL); - - /* Reset nesting tracking to beginning of input. */ - DecodeNesting_Init(&(pMe->nesting)); - } - - pMe->uLastError = QCBOR_SUCCESS; -} - - - - - -typedef struct { - void *pCBContext; - QCBORItemCallback pfCallback; -} MapSearchCallBack; - -typedef struct { - size_t uStartOffset; - uint16_t uItemCount; -} MapSearchInfo; - - -/** - * @brief Search a map for a set of items. - * - * @param[in] pMe The decode context to search. - * @param[in,out] pItemArray The items to search for and the items found. - * @param[out] pInfo Several bits of meta-info returned by search. - * @param[in] pCallBack Callback object or @c NULL. - * - * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map. - * - * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) - * were found for one of the labels being - * search for. This duplicate detection is - * only performed for items in pItemArray, - * not every item in the map. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was - * wrong for the matchd label. - * - * @retval Also errors returned by QCBORDecode_GetNext(). - * - * On input, @c pItemArray contains a list of labels and data types of - * items to be found. - * - * On output, the fully retrieved items are filled in with values and - * such. The label was matched, so it never changes. - * - * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE. - * - * This also finds the ends of maps and arrays when they are exited. - */ -static QCBORError -QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe, - QCBORItem *pItemArray, - MapSearchInfo *pInfo, - MapSearchCallBack *pCallBack) -{ - QCBORError uReturn; - uint64_t uFoundItemBitMap = 0; - - if(pInfo != NULL) { - pInfo->uItemCount = 0; - pInfo->uStartOffset = UINT32_MAX; - } - - if(pMe->uLastError != QCBOR_SUCCESS) { - uReturn = pMe->uLastError; - goto Done2; - } - - if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) && - pItemArray->uLabelType != QCBOR_TYPE_NONE) { - /* QCBOR_TYPE_NONE as first item indicates just looking for the - * end of an array, so don't give error. */ - uReturn = QCBOR_ERR_MAP_NOT_ENTERED; - goto Done2; - } - - if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) { - /* It is an empty bounded array or map */ - if(pItemArray->uLabelType == QCBOR_TYPE_NONE) { - /* Just trying to find the end of the map or array */ - pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)); - uReturn = QCBOR_SUCCESS; - } else { - /* Nothing is ever found in an empty array or map. All items - * are marked as not found below. */ - uReturn = QCBOR_SUCCESS; - } - goto Done2; - } - - QCBORDecodeNesting SaveNesting; - size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf)); - DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); - - /* Reposition to search from the start of the map / array */ - QCBORDecode_Private_RewindMapOrArray(pMe); - - /* Loop over all the items in the map or array. Each item could be - * a map or array, but label matching is only at the main - * level. This handles definite- and indefinite- length maps and - * arrays. The only reason this is ever called on arrays is to find - * their end position. - * - * This will always run over all items in order to do duplicate - * detection. - * - * This will exit with failure if it encounters an unrecoverable - * error, but continue on for recoverable errors. - * - * If a recoverable error occurs on a matched item, then that error - * code is returned. - */ - const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting)); - uint8_t uNextNestLevel; - do { - QCBORItem Item; - bool bMatched; - QCBORError uResult; - /* Remember offset of the item because sometimes it has to be returned */ - const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); - - /* Get the item */ - /* QCBORDecode_Private_GetNextTagContent() rather than GetNext() - * because a label match is performed on recoverable errors to - * be able to return the the error code for the found item. */ - uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item); - if(QCBORDecode_IsUnrecoverableError(uResult)) { - /* The map/array can't be decoded when unrecoverable errors occur */ - uReturn = uResult; - goto Done; - } - if(uResult == QCBOR_ERR_NO_MORE_ITEMS) { - /* Unexpected end of map or array. */ - uReturn = uResult; - goto Done; - } - - /* See if item has one of the labels that are of interest */ - bMatched = false; - for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) { - if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) { - /* A label match has been found */ - if(uFoundItemBitMap & (0x01ULL << nIndex)) { - uReturn = QCBOR_ERR_DUPLICATE_LABEL; - goto Done; - } - if(uResult != QCBOR_SUCCESS) { - /* The label matches, but the data item is in error. - * It is OK to have recoverable errors on items that - * are not matched. */ - uReturn = uResult; - goto Done; - } - if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) { - /* The data item is not of the type(s) requested */ - uReturn = QCBOR_ERR_UNEXPECTED_TYPE; - goto Done; - } - - /* Successful match. Return the item. */ - pItemArray[nIndex] = Item; - uFoundItemBitMap |= 0x01ULL << nIndex; - if(pInfo != NULL) { - pInfo->uStartOffset = uOffset; - } - bMatched = true; - } - } - - - if(!bMatched && pCallBack != NULL) { - /* Call the callback on unmatched labels. - * (It is tempting to do duplicate detection here, but that - * would require dynamic memory allocation because the number - * of labels that might be encountered is unbounded.) */ - uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - } - - /* Consume the item whether matched or not. This does the work - * of traversing maps and array and everything in them. In this - * loop only the items at the current nesting level are examined - * to match the labels. */ - uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel); - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - - if(pInfo != NULL) { - pInfo->uItemCount++; - } - - } while (uNextNestLevel >= uMapNestLevel); - - uReturn = QCBOR_SUCCESS; - - const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); - - /* Check here makes sure that this won't accidentally be - * QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than - * QCBOR_MAX_DECODE_INPUT_SIZE. Cast to uint32_t to possibly - * address cases where SIZE_MAX < UINT32_MAX. It is near-impossible - * to test this, so test coverage of this function is not 100%, - * but it is 100% when this is commented out. */ - if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) { - uReturn = QCBOR_ERR_INPUT_TOO_LARGE; - goto Done; - } - /* Cast OK because encoded CBOR is limited to UINT32_MAX */ - pMe->uMapEndOffsetCache = (uint32_t)uEndOffset; - - Done: - DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); - UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos); - - Done2: - /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */ - for(int i = 0; pItemArray[i].uLabelType != 0; i++) { - if(!(uFoundItemBitMap & (0x01ULL << i))) { - pItemArray[i].uDataType = QCBOR_TYPE_NONE; - pItemArray[i].uLabelType = QCBOR_TYPE_NONE; - } - } - - return uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSearch[0].label.int64 = nLabel; - OneItemSearch[0].uDataType = uQcborType; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - - QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSearch, NULL, NULL); - - if(uReturn != QCBOR_SUCCESS) { - pItem->uDataType = QCBOR_TYPE_NONE; - pItem->uLabelType = QCBOR_TYPE_NONE; - goto Done; - } - - if(OneItemSearch[0].uDataType == QCBOR_TYPE_NONE) { - uReturn = QCBOR_ERR_LABEL_NOT_FOUND; - } - - *pItem = OneItemSearch[0]; - QCBORDecode_Private_CopyTags(pMe, pItem); - - Done: - pMe->uLastError = (uint8_t)uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSearch[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSearch[0].uDataType = uQcborType; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - - QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSearch, NULL, NULL); - - if(uReturn != QCBOR_SUCCESS) { - pItem->uDataType = QCBOR_TYPE_NONE; - pItem->uLabelType = QCBOR_TYPE_NONE; - goto Done; - } - if(OneItemSearch[0].uDataType == QCBOR_TYPE_NONE) { - uReturn = QCBOR_ERR_LABEL_NOT_FOUND; - goto Done; - } - - *pItem = OneItemSearch[0]; - QCBORDecode_Private_CopyTags(pMe, pItem); - -Done: -#else - (void)pMe; - (void)szLabel; - (void)uQcborType; - (void)pItem; - QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - pMe->uLastError = (uint8_t)uReturn; -} - - - -/** - * @brief Semi-private. Get pointer, length and item for an array or map. - * - * @param[in] pMe The decode context. - * @param[in] uType CBOR major type, either array/map. - * @param[out] pItem The item for the array/map. - * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. - * - * The next item to be decoded must be a map or array as specified by @c uType. - * - * @c pItem will be filled in with the label and tags of the array or map - * in addition to @c pEncodedCBOR giving the pointer and length of the - * encoded CBOR. - * - * When this is complete, the traversal cursor is at the end of the array or - * map that was retrieved. - */ -void -QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe, - const uint8_t uType, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - QCBORError uErr; - uint8_t uNestLevel; - size_t uStartingCursor; - size_t uStartOfReturned; - size_t uEndOfReturned; - size_t uTempSaveCursor; - bool bInMap; - QCBORItem LabelItem; - bool EndedByBreak; - - uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); - bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting)); - - /* Could call GetNext here, but don't need to because this - * is only interested in arrays and maps. */ - uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem); - if(uErr != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uErr; - return; - } - - uint8_t uItemDataType = pItem->uDataType; -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { - uItemDataType = QCBOR_TYPE_ARRAY; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - if(uItemDataType != uType) { - pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; - return; - } - - if(bInMap) { - /* If the item is in a map, the start of the array/map - * itself, not the label, must be found. Do this by - * rewinding to the starting position and fetching - * just the label data item. QCBORDecode_Private_GetNextTagNumber() - * doesn't do any of the array/map item counting or nesting - * level tracking. Used here it will just fetech the label - * data item. - * - * Have to save the cursor and put it back to the position - * after the full item once the label as been fetched by - * itself. - */ - uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); - UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor); - - /* Item has been fetched once so safe to ignore error */ - (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem); - - uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); - UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor); - } else { - uStartOfReturned = uStartingCursor; - } - - /* Consume the entire array/map to find the end */ - uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel); - if(uErr != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uErr; - goto Done; - } - - /* Fill in returned values */ - uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); - if(EndedByBreak) { - /* When ascending nesting levels, a break for the level above - * was consumed. That break is not a part of what is consumed here. */ - uEndOfReturned--; - } - pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned); - pEncodedCBOR->len = uEndOfReturned - uStartOfReturned; - -Done: - return; -} - - -/** - * @brief Semi-private. Get pointer, length and item count of an array or map. - * - * @param[in] pMe The decode context. - * @param[in] pTarget The label and type of the array or map to retrieve. - * @param[out] pItem The item for the array/map. - * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. - * - * When this is complete, the traversal cursor is unchanged. - */ -void -QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe, - QCBORItem *pTarget, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR) -{ - /* Heavy stack use, but it's only for a few QCBOR public methods */ - MapSearchInfo Info; - QCBORDecodeNesting SaveNesting; - size_t uSaveCursor; - - /* Find the array or map of interest */ - pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - if(pTarget->uDataType == QCBOR_TYPE_NONE) { - pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; - return; - } - - /* Save the traversal cursor and related */ - DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); - uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); - - /* Get the array or map of interest */ - DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); - UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); - QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR); - - /* Restore the traversal cursor */ - UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor); - DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); -} - - - - -/** - * @brief Is a QCBOR_TYPE in the type list? - * - * @param[in] uDataType Type to check for. - * @param[in] puTypeList List to check. - * - * @retval QCBOR_SUCCESS If in the list. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list. - */ -static QCBORError -QCBOR_Private_CheckTypeList(const int uDataType, - const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES]) -{ - for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) { - if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */ - return QCBOR_SUCCESS; - } - } - return QCBOR_ERR_UNEXPECTED_TYPE; -} - - -/** - * Match a tag/type specification against the type of the item. - * - * @param[in] TagSpec Specification for matching tags. - * @param[in] pItem The item to check. - * - * @retval QCBOR_SUCCESS @c uDataType is allowed by @c TagSpec - * @retval QCBOR_ERR_UNEXPECTED_TYPE @c uDataType is not allowed by @c TagSpec - * - * This checks the item data type of untagged items as well as of - * tagged items against a specification to see if decoding should - * proceed. - * - * This relies on the automatic tag decoding done by QCBOR that turns - * tag numbers into particular QCBOR_TYPEs so there is no actual - * comparsion of tag numbers, just of QCBOR_TYPEs. - * - * This checks the data item type as possibly representing the tag - * number or as the tag content type. - * - * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item - * data type against the allowed tag content types, but also checks - * against the tagged types. The QCBOR_TYPEs checked will never be - * associated with tag numbers, but this checking is needed for the - * text and byte string use cases . - */ -static QCBORError -QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec, - const QCBORItem *pItem) -{ - const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */ - const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS; - -#ifndef QCBOR_DISABLE_TAGS - /* -Wmaybe-uninitialized falsly warns here */ - if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) && - pItem->uTags[0] != CBOR_TAG_INVALID16) { - /* There are tags that QCBOR couldn't process on this item and - * the caller has told us there should not be. - */ - return QCBOR_ERR_UNEXPECTED_TYPE; - } - - if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { - /* Must match the tag number and only the tag */ - return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); - } - - QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); - if(uReturn == QCBOR_SUCCESS) { - return QCBOR_SUCCESS; - } - - if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) { - /* Must match the content type and only the content type. - * There was no match just above so it is a fail. */ - return QCBOR_ERR_UNEXPECTED_TYPE; - } - - /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either - * the tag or the content and it hasn't matched the content, so the - * end result is whether it matches the tag. This is the tag - * optional case that the CBOR standard discourages. - */ - - return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); - -#else /* QCBOR_DISABLE_TAGS */ - if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { - /* This is only checking base QCBOR types, not those associated - * with tag numbers since you can get here with tag numbers. - */ - return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); - } - - return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); - -#endif /* QCBOR_DISABLE_TAGS */ -} - - -/** - * @brief Get an item by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] nLabel The label to search map for. - * @param[in] TagSpec The tag number specification to match. - * @param[out] pItem The item found. - * - * This finds the item with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */ -static void -QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const QCBOR_Private_TagSpec TagSpec, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); -} - - -/** - * @brief Get an item by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] szLabel The label to search map for. - * @param[in] TagSpec The tag number specification to match. - * @param[out] pItem The item found. - * - * This finds the item with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */ -static void -QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const QCBOR_Private_TagSpec TagSpec, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); -} - - -/** - * @brief Semi-private to get an string by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] nLabel The label to search map for. - * @param[in] TagSpec The tag number specification to match. - * @param[out] pString The string found. - * - * This finds the string with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */ -void -QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pString) -{ - QCBORItem Item; - QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item); - if(pMe->uLastError == QCBOR_SUCCESS) { - *pString = Item.val.string; - } -} - - -/** - * @brief Semi-private to get an string by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] szLabel The label to search map for. - * @param[in] TagSpec The tag number specification to match. - * @param[out] pString The string found. - * - * This finds the string with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */void -QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - const QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pString) -{ - QCBORItem Item; - QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item); - if(pMe->uLastError == QCBOR_SUCCESS) { - *pString = Item.val.string; - } -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList) -{ - QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL); - pMe->uLastError = (uint8_t)uErr; -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB) -{ - MapSearchCallBack CallBack; - CallBack.pCBContext = pCallbackCtx; - CallBack.pfCallback = pfCB; - - QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack); - - pMe->uLastError = (uint8_t)uErr; -} - - -/** - * @brief Search for a map/array by label and enter it - * - * @param[in] pMe The decode context. - * @param[in] pSearch The map/array to search for. - * - * @c pSearch is expected to contain one item of type map or array - * with the label specified. The current bounded map will be searched for - * this and if found will be entered. - * - * If the label is not found, or the item found is not a map or array, - * the error state is set. - */ -static void -QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) -{ - // The first item in pSearch is the one that is to be - // entered. It should be the only one filled in. Any other - // will be ignored unless it causes an error. - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - MapSearchInfo Info; - pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - if(pSearch->uDataType == QCBOR_TYPE_NONE) { - pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; - return; - } - - - /* The map or array was found. Now enter it. - * - * QCBORDecode_EnterBoundedMapOrArray() used here, requires the - * next item for the pre-order traversal cursor to be the map/array - * found by MapSearch(). The next few lines of code force the - * cursor to that. - * - * There is no need to retain the old cursor because - * QCBORDecode_EnterBoundedMapOrArray() will set it to the - * beginning of the map/array being entered. - * - * The cursor is forced by: 1) setting the input buffer position to - * the item offset found by MapSearch(), 2) setting the map/array - * counter to the total in the map/array, 3) setting the nesting - * level. Setting the map/array counter to the total is not - * strictly correct, but this is OK because this cursor only needs - * to be used to get one item and MapSearch() has already found it - * confirming it exists. - */ - UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); - - DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); - - DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); - - QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) -{ - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSearch[0].label.int64 = nLabel; - OneItemSearch[0].uDataType = QCBOR_TYPE_MAP; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - /* The map to enter was found, now finish off entering it. */ - QCBORDecode_Private_SearchAndEnter(pMe, OneItemSearch); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) -{ -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSearch[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSearch[0].uDataType = QCBOR_TYPE_MAP; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndEnter(pMe, OneItemSearch); -#else - (void)szLabel; - pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) -{ - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSearch[0].label.int64 = nLabel; - OneItemSearch[0].uDataType = QCBOR_TYPE_ARRAY; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndEnter(pMe, OneItemSearch); -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) -{ -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - QCBORItem OneItemSearch[2]; - OneItemSearch[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSearch[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSearch[0].uDataType = QCBOR_TYPE_ARRAY; - OneItemSearch[1].uLabelType = QCBOR_TYPE_NONE; - - QCBORDecode_Private_SearchAndEnter(pMe, OneItemSearch); -#else - (void)szLabel; - pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -} - - -/** - * @brief Semi-private to do the the work for EnterMap() and EnterArray(). - * - * @param[in] pMe The decode context - * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY. - * @param[out] pItem The data item for the map or array entered. - * - * The next item in the traversal must be a map or array. This - * consumes that item and does the book keeping to enter the map or - * array. - */ -void -QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, - const uint8_t uType, - QCBORItem *pItem) -{ - QCBORError uErr; - - /* Must only be called on maps and arrays. */ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state; do nothing. - return; - } - - /* Get the data item that is the map or array being entered. */ - QCBORItem Item; - uErr = QCBORDecode_GetNext(pMe, &Item); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - uint8_t uItemDataType = Item.uDataType; - -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) { - uItemDataType = QCBOR_TYPE_ARRAY; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - if(uItemDataType != uType) { - uErr = QCBOR_ERR_UNEXPECTED_TYPE; - goto Done; - } - - QCBORDecode_Private_CopyTags(pMe, &Item); - - - const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel); - if(bIsEmpty) { - if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) { - // Undo decrement done by QCBORDecode_GetNext() so the the - // the decrement when exiting the map/array works correctly - pMe->nesting.pCurrent->u.ma.uCountCursor++; - } - // Special case to increment nesting level for zero-length maps - // and arrays entered in bounded mode. - DecodeNesting_Descend(&(pMe->nesting), uType); - } - - pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID; - - uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty, - UsefulInputBuf_Tell(&(pMe->InBuf))); - - if(pItem != NULL) { - *pItem = Item; - } - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/** - * @brief Exit a bounded map, array or bstr (semi-private). - * - * @param[in] pMe Decode context. - * @param[in] uEndOffset The input buffer offset of the end of item exited. - * - * @returns QCBOR_SUCCESS or an error code. - * - * This is the common work for exiting a level that is a bounded map, - * array or bstr wrapped CBOR. - * - * One chunk of work is to set up the pre-order traversal so it is at - * the item just after the bounded map, array or bstr that is being - * exited. This is somewhat complex. - * - * The other work is to level-up the bounded mode to next higest - * bounded mode or the top level if there isn't one. - */ -static QCBORError -QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe, - const uint32_t uEndOffset) -{ - QCBORError uErr; - - /* - * First the pre-order-traversal byte offset is positioned to the - * item just after the bounded mode item that was just consumed. - */ - UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset); - - /* - * Next, set the current nesting level to one above the bounded - * level that was just exited. - * - * DecodeNesting_CheckBoundedType() is always called before this - * and makes sure pCurrentBounded is valid. - */ - DecodeNesting_LevelUpCurrent(&(pMe->nesting)); - - /* - * This does the complex work of leveling up the pre-order - * traversal when the end of a map or array or another bounded - * level is reached. It may do nothing, or ascend all the way to - * the top level. - */ - uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, NULL); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - /* - * This makes the next highest bounded level the current bounded - * level. If there is no next highest level, then no bounded mode - * is in effect. - */ - DecodeNesting_LevelUpBounded(&(pMe->nesting)); - - pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID; - -Done: - return uErr; -} - - -/** - * @brief Get started exiting a map or array (semi-private) - * - * @param[in] pMe The decode context - * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP - * - * This does some work for map and array exiting (but not - * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel() - * is called to do the rest. - */ -void -QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, - const uint8_t uType) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state; do nothing. */ - return; - } - - QCBORError uErr; - - if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) { - uErr = QCBOR_ERR_EXIT_MISMATCH; - goto Done; - } - - /* - Have to set the offset to the end of the map/array - that is being exited. If there is no cached value, - from previous map search, then do a dummy search. - */ - if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) { - QCBORItem Dummy; - Dummy.uLabelType = QCBOR_TYPE_NONE; - uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - } - - uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache); - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/** - * @brief The main work of entering some byte-string wrapped CBOR. - * - * @param[in] pMe The decode context. - * @param[in] pItem The byte string item. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX - * @param[out] pBstr Pointer and length of byte string entered. - * - * This is called once the byte string item has been decoded to do all - * the book keeping work for descending a nesting level into the - * nested CBOR. - * - * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement. - */ -static QCBORError -QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - if(pBstr) { - *pBstr = NULLUsefulBufC; - } - - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state; do nothing. */ - return pMe->uLastError; - } - - QCBORError uError; - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); - if(uError != QCBOR_SUCCESS) { - goto Done; - } - - if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) { - /* Reverse the decrement done by GetNext() for the bstr so the - * increment in QCBORDecode_NestLevelAscender() called by - * ExitBoundedLevel() will work right. - */ - DecodeNesting_ReverseDecrement(&(pMe->nesting)); - } - - if(pBstr) { - *pBstr = pItem->val.string; - } - - /* This saves the current length of the UsefulInputBuf and then - * narrows the UsefulInputBuf to start and length of the wrapped - * CBOR that is being entered. - * - * Most of these calls are simple inline accessors so this doesn't - * amount to much code. - */ - - const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); - /* This check makes the cast of uPreviousLength to uint32_t below safe. */ - if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) { - uError = QCBOR_ERR_INPUT_TOO_LARGE; - goto Done; - } - - const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf), - pItem->val.string.ptr); - /* This check makes the cast of uStartOfBstr to uint32_t below safe. */ - if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) { - /* This should never happen because pItem->val.string.ptr should - * always be valid since it was just returned. - */ - uError = QCBOR_ERR_INPUT_TOO_LARGE; - goto Done; - } - - const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len; - - UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr); - UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr); - - uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting), - (uint32_t)uPreviousLength, - (uint32_t)uStartOfBstr); -Done: - return uError; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state; do nothing. - return; - } - - /* Get the data item that is the byte string being entered */ - QCBORItem Item; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - if(Item.uDataAlloc) { - pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING; - return; - } - - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state; do nothing. - return; - } - - if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) { - pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH; - return; - } - - const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); - - /* - Reset the length of the UsefulInputBuf to what it was before - the bstr wrapped CBOR was entered. - */ - UsefulInputBuf_SetBufferLength(&(pMe->InBuf), - DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting))); - - - QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr); - pMe->uLastError = (uint8_t)uErr; -} - - - -/** - * @brief Process simple type true and false, a boolean - * - * @param[in] pMe The decode context. - * @param[in] pItem The item with either true or false. - * @param[out] pBool The boolean value output. - * - * Sets the internal error if the item isn't a true or a false. Also - * records any tag numbers as the tag numbers of the last item. - */ -static void -QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - bool *pBool) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - - switch(pItem->uDataType) { - case QCBOR_TYPE_TRUE: - *pBool = true; - break; - - case QCBOR_TYPE_FALSE: - *pBool = false; - break; - - default: - pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; - break; - } -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - bool *pValue) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - bool *pValue) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); -} - - -/** - * @brief Process simple values. - * - * @param[in] pMe The decode context. - * @param[in] pItem The item with the simple value. - * @param[out] puSimple The simple value output. - * - * Sets the internal error if the item isn't a true or a false. Also - * records any tag numbers as the tag numbers of the last item. - */ -static void -QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint8_t *puSimple) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - /* It's kind of lame to remap true...undef back to simple values, but - * this function isn't used much and to not do it would require - * changing GetNext() behavior in an incompatible way. - */ - switch(pItem->uDataType) { - case QCBOR_TYPE_UKNOWN_SIMPLE: - *puSimple = pItem->val.uSimple; - break; - - case QCBOR_TYPE_TRUE: - *puSimple = CBOR_SIMPLEV_TRUE; - break; - - case QCBOR_TYPE_FALSE: - *puSimple = CBOR_SIMPLEV_FALSE; - break; - - case QCBOR_TYPE_NULL: - *puSimple = CBOR_SIMPLEV_NULL; - break; - - case QCBOR_TYPE_UNDEF: - *puSimple = CBOR_SIMPLEV_UNDEF; - break; - - default: - pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; - return; - } -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple); -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t *puSimpleValue) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); -} - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t *puSimpleValue) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); -} - - - -/** - * @brief Common processing for an epoch date. - * - * @param[in] pMe The decode context. - * @param[in] pItem The item with the date. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnTime The returned date. - * - * Common processing for the date tag. Mostly make sure the tag - * content is correct and copy forward any further other tag numbers. - */ -static void -QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - int64_t *pnTime) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing - return; - } - - QCBORError uErr; - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64} - }; - - uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) { - uErr = QCBOR_Private_DecodeDateEpoch(pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - } - - *pnTime = pItem->val.epochDate.nSeconds; - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); -} - - - -/** - * @brief Common processing for an epoch date. - * - * @param[in] pMe The decode context. - * @param[in] pItem The item with the date. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnDays The returned day count. - * - * Common processing for the RFC 8943 day-count tag. Mostly make sure - * the tag content is correct and copy forward any further other tag - * numbers. - */ -static void -QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe, - QCBORItem *pItem, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - - QCBORError uErr; - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) { - uErr = QCBOR_Private_DecodeDaysEpoch(pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - } - - *pnDays = pItem->val.epochDays; - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); -} - - - -/* - * @brief Get a string that matches the type/tag specification. - */ -void -QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, - const QCBOR_Private_TagSpec TagSpec, - UsefulBufC *pBstr) -{ - QCBORItem Item; - - QCBORDecode_VGetNext(pMe, &Item); - if(pMe->uLastError) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - *pBstr = Item.val.string; - } else { - *pBstr = NULLUsefulBufC; - } -} - - - - -/** - * @brief Common processing for a big number tag. - * - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[in] pItem The item with the date. - * @param[out] pValue The returned big number - * @param[out] pbIsNegative The returned sign of the big number. - * - * Common processing for the big number tag. Mostly make sure - * the tag content is correct and copy forward any further other tag - * numbers. - */ -static QCBORError -QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pValue, - bool *pbIsNegative) -{ - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - return uErr; - } - - *pValue = pItem->val.string; - - if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) { - *pbIsNegative = false; - } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) { - *pbIsNegative = true; - } - - return QCBOR_SUCCESS; -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h - */ -void -QCBORDecode_GetBignum(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - if(pMe->uLastError) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, - &Item, - pValue, - pbIsNegative); -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h - */ -void -QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, - &Item, - pValue, - pbIsNegative); -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h - */ -void -QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, - &Item, - pValue, - pbIsNegative); -} - - - -/** - * @brief Common processing for MIME tag (semi-private). - * - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[in] pItem The item with the date. - * @param[out] pMessage The returned MIME message. - * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME. - * - * Common processing for the MIME tag. Mostly make sure the tag - * content is correct and copy forward any further other tag - * numbers. See QCBORDecode_GetMIMEMessage(). - */ -QCBORError -QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - const QCBOR_Private_TagSpec TagSpecText = - { - uTagRequirement, - {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - const QCBOR_Private_TagSpec TagSpecBinary = - { - uTagRequirement, - {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORError uReturn; - - if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) { - *pMessage = pItem->val.string; - if(pbIsTag257 != NULL) { - *pbIsTag257 = false; - } - uReturn = QCBOR_SUCCESS; - } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) { - *pMessage = pItem->val.string; - if(pbIsTag257 != NULL) { - *pbIsTag257 = true; - } - uReturn = QCBOR_SUCCESS; - - } else { - uReturn = QCBOR_ERR_UNEXPECTED_TYPE; - } - - return uReturn; -} - -// Improvement: add methods for wrapped CBOR, a simple alternate -// to EnterBstrWrapped - - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - -/** - * @brief Prototype for conversion of exponent and mantissa to unsigned integer. - * - * @param[in] uMantissa The mantissa. - * @param[in] nExponent The exponent. - * @param[out] puResult The resulting integer. - * - * Concrete implementations of this are for exponent base 10 and 2 supporting - * decimal fractions and big floats. - */ -typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult); - - -/** - * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer. - * - * @param[in] uMantissa The unsigned integer mantissa. - * @param[in] nExponent The signed integer exponent. - * @param[out] puResult Place to return the unsigned integer result. - * - * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit - * unsigned integer. - * - * There are many inputs for which the result will not fit in the - * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will - * be returned. - */ -static QCBORError -QCBOR_Private_Exponentitate10(const uint64_t uMantissa, - int64_t nExponent, - uint64_t *puResult) -{ - uint64_t uResult = uMantissa; - - if(uResult != 0) { - /* This loop will run a maximum of 19 times because - * UINT64_MAX < 10 ^^ 19. More than that will cause - * exit with the overflow error - */ - for(; nExponent > 0; nExponent--) { - if(uResult > UINT64_MAX / 10) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - uResult = uResult * 10; - } - - for(; nExponent < 0; nExponent++) { - uResult = uResult / 10; - if(uResult == 0) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - } - } - /* else, mantissa is zero so this returns zero */ - - *puResult = uResult; - - return QCBOR_SUCCESS; -} - - -/** - * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer. - * - * @param[in] uMantissa The unsigned integer mantissa. - * @param[in] nExponent The signed integer exponent. - * @param[out] puResult Place to return the unsigned integer result. - * - * This computes: mantissa * 2 ^^ exponent as for a big float. The - * output is a 64-bit unsigned integer. - * - * There are many inputs for which the result will not fit in the - * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will - * be returned. - */ -static QCBORError -QCBOR_Private_Exponentitate2(const uint64_t uMantissa, - int64_t nExponent, - uint64_t *puResult) -{ - uint64_t uResult; - - uResult = uMantissa; - - /* This loop will run a maximum of 64 times because INT64_MAX < - * 2^31. More than that will cause exit with the overflow error - */ - while(nExponent > 0) { - if(uResult > UINT64_MAX >> 1) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - uResult = uResult << 1; - nExponent--; - } - - while(nExponent < 0 ) { - if(uResult == 0) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - uResult = uResult >> 1; - nExponent++; - } - - *puResult = uResult; - - return QCBOR_SUCCESS; -} - - -/** - * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result. - * - * @param[in] nMantissa Signed integer mantissa. - * @param[in] nExponent Signed integer exponent. - * @param[out] pnResult Place to put the signed integer result. - * @param[in] pfExp Exponentiation function. - * - * @returns Error code - * - * @c pfExp performs exponentiation on and unsigned mantissa and - * produces an unsigned result. This converts the mantissa from signed - * and converts the result to signed. The exponentiation function is - * either for base 2 or base 10 (and could be other if needed). - */ -static QCBORError -QCBOR_Private_ExponentiateNN(const int64_t nMantissa, - const int64_t nExponent, - int64_t *pnResult, - fExponentiator pfExp) -{ - uint64_t uResult; - uint64_t uMantissa; - - /* Take the absolute value and put it into an unsigned. */ - if(nMantissa >= 0) { - /* Positive case is straightforward */ - uMantissa = (uint64_t)nMantissa; - } else if(nMantissa != INT64_MIN) { - /* The common negative case. See next. */ - uMantissa = (uint64_t)-nMantissa; - } else { - /* int64_t and uint64_t are always two's complement per the - * C standard (and since QCBOR uses these it only works with - * two's complement, which is pretty much universal these - * days). The range of a negative two's complement integer is - * one more that than a positive, so the simple code above might - * not work all the time because you can't simply negate the - * value INT64_MIN because it can't be represented in an - * int64_t. -INT64_MIN can however be represented in a - * uint64_t. Some compilers seem to recognize this case for the - * above code and put the correct value in uMantissa, however - * they are not required to do this by the C standard. This next - * line does however work for all compilers. - * - * This does assume two's complement where -INT64_MIN == - * INT64_MAX + 1 (which wouldn't be true for one's complement or - * sign and magnitude (but we know we're using two's complement - * because int64_t requires it)). - * - * See these, particularly the detailed commentary: - * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always - * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour - */ - uMantissa = (uint64_t)INT64_MAX+1; - } - - /* Call the exponentiator passed for either base 2 or base 10. - * Here is where most of the overflow errors are caught. */ - QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult); - if(uReturn) { - return uReturn; - } - - /* Convert back to the sign of the original mantissa */ - if(nMantissa >= 0) { - if(uResult > INT64_MAX) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - *pnResult = (int64_t)uResult; - } else { - /* (uint64_t)INT64_MAX+1 is used to represent the absolute value - * of INT64_MIN. This assumes two's compliment representation - * where INT64_MIN is one increment farther from 0 than - * INT64_MAX. Trying to write -INT64_MIN doesn't work to get - * this because the compiler makes it an int64_t which can't - * represent -INT64_MIN. Also see above. - */ - if(uResult > (uint64_t)INT64_MAX+1) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - *pnResult = -(int64_t)uResult; - } - - return QCBOR_SUCCESS; -} - - -/** - * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result. - * - * @param[in] nMantissa Signed integer mantissa. - * @param[in] nExponent Signed integer exponent. - * @param[out] puResult Place to put the signed integer result. - * @param[in] pfExp Exponentiation function. - * - * @returns Error code - * - * @c pfExp performs exponentiation on and unsigned mantissa and - * produces an unsigned result. This errors out if the mantissa - * is negative because the output is unsigned. - */ -static QCBORError -QCBOR_Private_ExponentitateNU(const int64_t nMantissa, - const int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) -{ - if(nMantissa < 0) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } - - /* Cast to unsigned is OK because of check for negative. - * Cast to unsigned is OK because UINT64_MAX > INT64_MAX. - * Exponentiation is straight forward - */ - return (*pfExp)((uint64_t)nMantissa, nExponent, puResult); -} - - -/** - * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result. - * - * @param[in] uMantissa Unsigned integer mantissa. - * @param[in] nExponent Unsigned integer exponent. - * @param[out] puResult Place to put the unsigned integer result. - * @param[in] pfExp Exponentiation function. - * - * @returns Error code - * - * @c pfExp performs exponentiation on and unsigned mantissa and - * produces an unsigned result so this is just a wrapper that does - * nothing (and is likely inlined). - */ -static QCBORError -QCBOR_Private_ExponentitateUU(const uint64_t uMantissa, - const int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) -{ - return (*pfExp)(uMantissa, nExponent, puResult); -} - -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - - - - -/** - * @brief Convert a CBOR big number to a uint64_t. - * - * @param[in] BigNum Bytes of the big number to convert. - * @param[in] uMax Maximum value allowed for the result. - * @param[out] pResult Place to put the unsigned integer result. - * - * @returns Error code - * - * Many values will overflow because a big num can represent a much - * larger range than uint64_t. - */ -static QCBORError -QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum, - const uint64_t uMax, - uint64_t *pResult) -{ - uint64_t uResult; - - uResult = 0; - const uint8_t *pByte = BigNum.ptr; - size_t uLen = BigNum.len; - while(uLen--) { - if(uResult > (uMax >> 8)) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - uResult = (uResult << 8) + *pByte++; - } - - *pResult = uResult; - return QCBOR_SUCCESS; -} - - -/** - * @brief Convert a CBOR postive big number to a uint64_t. - * - * @param[in] BigNum Bytes of the big number to convert. - * @param[out] pResult Place to put the unsigned integer result. - * - * @returns Error code - * - * Many values will overflow because a big num can represent a much - * larger range than uint64_t. - */ -static QCBORError -QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, - uint64_t *pResult) -{ - return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult); -} - - -/** - * @brief Convert a CBOR positive big number to an int64_t. - * - * @param[in] BigNum Bytes of the big number to convert. - * @param[out] pResult Place to put the signed integer result. - * - * @returns Error code - * - * Many values will overflow because a big num can represent a much - * larger range than int64_t. - */ -static QCBORError -QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, - int64_t *pResult) -{ - uint64_t uResult; - QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, - INT64_MAX, - &uResult); - if(uError) { - return uError; - } - /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */ - *pResult = (int64_t)uResult; - return QCBOR_SUCCESS; -} - - -/** - * @brief Convert a CBOR negative big number to an int64_t. - * - * @param[in] BigNum Bytes of the big number to convert. - * @param[out] pnResult Place to put the signed integer result. - * - * @returns Error code - * - * Many values will overflow because a big num can represent a much - * larger range than int64_t. - */ -static QCBORError -QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, - int64_t *pnResult) -{ - uint64_t uResult; - /* The negative integer furthest from zero for a C int64_t is - * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a - * negative number in CBOR is computed as -n - 1 where n is the - * encoded integer, where n is what is in the variable BigNum. When - * converting BigNum to a uint64_t, the maximum value is thus - * INT64_MAX, so that when it -n - 1 is applied to it the result - * will never be further from 0 than INT64_MIN. - * - * -n - 1 <= INT64_MIN. - * -n - 1 <= -INT64_MAX - 1 - * n <= INT64_MAX. - */ - QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, - INT64_MAX, - &uResult); - if(uError != QCBOR_SUCCESS) { - return uError; - } - - /* Now apply -n - 1. The cast is safe because - * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit - * is the largest positive integer that an int64_t can - * represent. */ - *pnResult = -(int64_t)uResult - 1; - - return QCBOR_SUCCESS; -} - - - - -/** - * @brief Convert integers and floats to an int64_t. - * - * @param[in] pItem The item to convert. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pnValue The resulting converted value. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - * in uConvertTypes. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - * or too small. - * @retval QCBOR_ERR_FLOAT_EXCEPTION Encountered NaN or infinity or such. - */ -static QCBORError -QCBOR_Private_ConvertInt64(const QCBORItem *pItem, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - switch(pItem->uDataType) { -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - case QCBOR_TYPE_FLOAT: - if(!(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT)) { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - if(isnan(pItem->val.fnum)) { - /* In some environments, llround() will succeed on NaN - * when it really shouldn't, so catch the error here. */ - return QCBOR_ERR_FLOAT_EXCEPTION; - } - if(pItem->val.fnum == INFINITY || pItem->val.fnum == -INFINITY) { - return QCBOR_ERR_FLOAT_EXCEPTION; - } - /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html - * http://www.cplusplus.com/reference/cmath/llround/ - */ - /* Not interested in FE_INEXACT */ - feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO); - *pnValue = lroundf(pItem->val.fnum); - if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) { - /* llround() shouldn't result in divide by zero, but catch - * it here in case it unexpectedly does. Don't try to - * distinguish between the various exceptions because it seems - * they vary by CPU, compiler and OS. - */ - return QCBOR_ERR_FLOAT_EXCEPTION; - } - break; - - case QCBOR_TYPE_DOUBLE: - if(!(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT)) { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - if(isnan(pItem->val.dfnum)) { - /* In some environments, llround() will succeed on NaN - * when it really shouldn't, so catch the error here. */ - return QCBOR_ERR_FLOAT_EXCEPTION; - } - if(pItem->val.dfnum == INFINITY || pItem->val.dfnum == -INFINITY) { - return QCBOR_ERR_FLOAT_EXCEPTION; - } - /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html - * http://www.cplusplus.com/reference/cmath/llround/ - */ - /* Not interested in FE_INEXACT */ - feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO); - *pnValue = llround(pItem->val.dfnum); - if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) { - /* llround() shouldn't result in divide by zero, but catch - * it here in case it unexpectedly does. Don't try to - * distinguish between the various exceptions because it seems - * they vary by CPU, compiler and OS. - */ - return QCBOR_ERR_FLOAT_EXCEPTION; - } - break; - -#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */ - case QCBOR_TYPE_FLOAT: - case QCBOR_TYPE_DOUBLE: - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */ - break; - - case QCBOR_TYPE_INT64: - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - *pnValue = pItem->val.int64; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_UINT64: - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - if(pItem->val.uint64 < INT64_MAX) { - *pnValue = pItem->val.int64; - } else { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - default: - return QCBOR_ERR_UNEXPECTED_TYPE; - } - return QCBOR_SUCCESS; -} - - -/** - * @brief Almost-public method to decode a number and convert to int64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pnValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetInt64Convert(). - */ -void -QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) -{ - QCBORDecode_VGetNext(pMe, pItem); - if(pMe->uLastError) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, - uConvertTypes, - pnValue); -} - -/** - * @brief Almost-public method to decode a number and convert to int64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] nLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pnValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetInt64ConvertInMapN(). - */ -void -QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, - uConvertTypes, - pnValue); -} - -/** - * @brief Almost-public method to decode a number and convert to int64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] szLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pnValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetInt64ConvertInMapSZ(). - */ -void -QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, - uConvertTypes, - pnValue); -} - - -/** - * @brief Convert many number types to an int64_t. - * - * @param[in] pItem The item to convert. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pnValue The resulting converted value. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - * in uConvertTypes. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - * or too small. - */ -static QCBORError -QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - switch(pItem->uDataType) { - - case QCBOR_TYPE_POSBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_NEGBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - case QCBOR_TYPE_DECIMAL_FRACTION: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, - pItem->val.expAndMantissa.nExponent, - pnValue, - &QCBOR_Private_Exponentitate10); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, - pItem->val.expAndMantissa.nExponent, - pnValue, - QCBOR_Private_Exponentitate2); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - int64_t nMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); - if(uErr) { - return uErr; - } - return QCBOR_Private_ExponentiateNN(nMantissa, - pItem->val.expAndMantissa.nExponent, - pnValue, - QCBOR_Private_Exponentitate10); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - int64_t nMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); - if(uErr) { - return uErr; - } - return QCBOR_Private_ExponentiateNN(nMantissa, - pItem->val.expAndMantissa.nExponent, - pnValue, - QCBOR_Private_Exponentitate10); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - int64_t nMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); - if(uErr) { - return uErr; - } - return QCBOR_Private_ExponentiateNN(nMantissa, - pItem->val.expAndMantissa.nExponent, - pnValue, - QCBOR_Private_Exponentitate2); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - int64_t nMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); - if(uErr) { - return uErr; - } - return QCBOR_Private_ExponentiateNN(nMantissa, - pItem->val.expAndMantissa.nExponent, - pnValue, - QCBOR_Private_Exponentitate2); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - - - default: - return QCBOR_ERR_UNEXPECTED_TYPE; } -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - - QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, - uConvertTypes, - pnValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - - QCBORDecode_Private_GetInt64ConvertInMapN(pMe, - nLabel, - uConvertTypes, - pnValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, - uConvertTypes, - pnValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - int64_t *pnValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - pnValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, - uConvertTypes, - pnValue); -} - - -/** - * @brief Convert many number types to an uint64_t. - * - * @param[in] pItem The item to convert. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] puValue The resulting converted value. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - * in uConvertTypes. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - * or too small. - */ -static QCBORError -QCBOR_Private_ConvertUInt64(const QCBORItem *pItem, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - switch(pItem->uDataType) { - case QCBOR_TYPE_DOUBLE: - case QCBOR_TYPE_FLOAT: -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) { - // Can't use llround here because it will not convert values - // greater than INT64_MAX and less than UINT64_MAX that - // need to be converted so it is more complicated. - feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO); - if(pItem->uDataType == QCBOR_TYPE_DOUBLE) { - if(isnan(pItem->val.dfnum)) { - return QCBOR_ERR_FLOAT_EXCEPTION; - } else if(pItem->val.dfnum < 0) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } else { - double dRounded = round(pItem->val.dfnum); - // See discussion in DecodeDateEpoch() for - // explanation of - 0x7ff - if(dRounded > (double)(UINT64_MAX- 0x7ff)) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - *puValue = (uint64_t)dRounded; - } - } else { - if(isnan(pItem->val.fnum)) { - return QCBOR_ERR_FLOAT_EXCEPTION; - } else if(pItem->val.fnum < 0) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } else { - float fRounded = roundf(pItem->val.fnum); - // See discussion in DecodeDateEpoch() for - // explanation of - 0x7ff - if(fRounded > (float)(UINT64_MAX- 0x7ff)) { - return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; - } - *puValue = (uint64_t)fRounded; - } - } - if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) { - // round() and roundf() shouldn't result in exceptions here, but - // catch them to be robust and thorough. Don't try to - // distinguish between the various exceptions because it seems - // they vary by CPU, compiler and OS. - return QCBOR_ERR_FLOAT_EXCEPTION; - } - - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } -#else - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - break; - - case QCBOR_TYPE_INT64: - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - if(pItem->val.int64 >= 0) { - *puValue = (uint64_t)pItem->val.int64; - } else { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_UINT64: - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - *puValue = pItem->val.uint64; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - default: - return QCBOR_ERR_UNEXPECTED_TYPE; - } - - return QCBOR_SUCCESS; -} - - -/** - * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] puValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetUInt64Convert(). - */ -void -QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) -{ - QCBORDecode_VGetNext(pMe, pItem); - if(pMe->uLastError) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, - uConvertTypes, - puValue); -} - - -/** - * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] nLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] puValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetUInt64ConvertInMapN(). - */ -void -QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, - uConvertTypes, - puValue); -} - - -/** - * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] szLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] puValue Result of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetUInt64ConvertInMapSZ(). - */ -void -QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, - uConvertTypes, - puValue); -} - - -/** - * @brief Convert many number types to an unt64_t. - * - * @param[in] pItem The item to convert. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] puValue The resulting converted value. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - * in uConvertTypes. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - * or too small. - */ -static QCBORError -QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */ - - case QCBOR_TYPE_POSBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_NEGBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - - case QCBOR_TYPE_DECIMAL_FRACTION: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, - pItem->val.expAndMantissa.nExponent, - puValue, - QCBOR_Private_Exponentitate10); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, - pItem->val.expAndMantissa.nExponent, - puValue, - QCBOR_Private_Exponentitate2); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - uint64_t uMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); - if(uErr != QCBOR_SUCCESS) { - return uErr; - } - return QCBOR_Private_ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - QCBOR_Private_Exponentitate10); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - uint64_t uMantissa; - QCBORError uErr; - uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, - &uMantissa); - if(uErr != QCBOR_SUCCESS) { - return uErr; - } - return QCBOR_Private_ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - QCBOR_Private_Exponentitate2); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return QCBOR_ERR_NUMBER_SIGN_CONVERSION; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - default: - return QCBOR_ERR_UNEXPECTED_TYPE; - } -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - - QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, - uConvertTypes, - puValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - - QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, - nLabel, - uConvertTypes, - puValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, - uConvertTypes, - puValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - uint64_t *puValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - puValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, - uConvertTypes, - puValue); -} - - - - -#ifndef USEFULBUF_DISABLE_ALL_FLOAT -/** - * @brief Basic conversions to a double. - * - * @param[in] pItem The item to convert - * @param[in] uConvertTypes Bit flags indicating source types for conversion - * @param[out] pdValue The value converted to a double - * - * This does the conversions that don't need much object code, - * the conversions from int, uint and float to double. - * - * See QCBOR_Private_DoubleConvertAll() for the full set - * of conversions. - */ -static QCBORError -QCBOR_Private_ConvertDouble(const QCBORItem *pItem, - const uint32_t uConvertTypes, - double *pdValue) -{ - switch(pItem->uDataType) { - case QCBOR_TYPE_FLOAT: -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) { - if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) { - // Simple cast does the job. - *pdValue = (double)pItem->val.fnum; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - } -#else /* QCBOR_DISABLE_FLOAT_HW_USE */ - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - break; - - case QCBOR_TYPE_DOUBLE: - if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) { - if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) { - *pdValue = pItem->val.dfnum; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - } - break; - - case QCBOR_TYPE_INT64: -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - // A simple cast seems to do the job with no worry of exceptions. - // There will be precision loss for some values. - *pdValue = (double)pItem->val.int64; - - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } -#else - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - break; - - case QCBOR_TYPE_UINT64: -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) { - // A simple cast seems to do the job with no worry of exceptions. - // There will be precision loss for some values. - *pdValue = (double)pItem->val.uint64; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; -#else - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - - default: - return QCBOR_ERR_UNEXPECTED_TYPE; - } - - return QCBOR_SUCCESS; -} - - -/** - * @brief Almost-public method to decode a number and convert to double (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] uConvertTypes Bit mask list of conversion options - * @param[out] pdValue The output of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetDoubleConvert(). - */ -void -QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) -{ - QCBORDecode_VGetNext(pMe, pItem); - if(pMe->uLastError) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, - uConvertTypes, - pdValue); -} - - -/** - * @brief Almost-public method to decode a number and convert to double (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] nLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options - * @param[out] pdValue The output of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetDoubleConvertInMapN(). - */ -void -QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, - uConvertTypes, - pdValue); -} - - -/** - * @brief Almost-public method to decode a number and convert to double (semi-private). - * - * @param[in] pMe The decode context. - * @param[in] szLabel Label to find in map. - * @param[in] uConvertTypes Bit mask list of conversion options - * @param[out] pdValue The output of the conversion. - * @param[in,out] pItem Temporary space to store Item, returned item. - * - * See QCBORDecode_GetDoubleConvertInMapSZ(). - */ -void -QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) -{ - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, - uConvertTypes, - pdValue); -} - - -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -/** - * @brief Convert a big number to double-precision float. - * - * @param[in] BigNum The big number to convert - * - * @returns The double value. - * - * This will always succeed. It will lose precision for larger - * numbers. If the big number is too large to fit (more than - * 1.7976931348623157E+308) infinity will be returned. NaN is never - * returned. - */ -static double -QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum) -{ - double dResult; - - dResult = 0.0; - const uint8_t *pByte = BigNum.ptr; - size_t uLen = BigNum.len; - /* This will overflow and become the float value INFINITY if the number - * is too large to fit. */ - while(uLen--) { - dResult = (dResult * 256.0) + (double)*pByte++; - } - - return dResult; -} -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - - - - -/** - * @brief Convert many number types to a double. - * - * @param[in] pItem The item to convert. - * @param[in] uConvertTypes Bit mask list of conversion options. - * @param[out] pdValue The resulting converted value. - * - * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - * in uConvertTypes. - * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - * or too small. - */ -static QCBORError -QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem, - const uint32_t uConvertTypes, - double *pdValue) -{ -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - /* - * What Every Computer Scientist Should Know About Floating-Point Arithmetic - * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html - */ - switch(pItem->uDataType) { - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - case QCBOR_TYPE_DECIMAL_FRACTION: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - // Underflow gives 0, overflow gives infinity - *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt * - pow(10.0, (double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) { - // Underflow gives 0, overflow gives infinity - *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt * - exp2((double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - - case QCBOR_TYPE_POSBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_NEGBIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - /* Must subtract 1 for CBOR negative integer offset */ - double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; - - case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - break; -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - - default: - return QCBOR_ERR_UNEXPECTED_TYPE; - } - - return QCBOR_SUCCESS; - -#else - (void)pItem; - (void)uConvertTypes; - (void)pdValue; - return QCBOR_ERR_HW_FLOAT_DISABLED; -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, - const uint32_t uConvertTypes, - double *pdValue) -{ - - QCBORItem Item; - - QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, - uConvertTypes, - pdValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint32_t uConvertTypes, - double *pdValue) -{ - QCBORItem Item; - - QCBORDecode_Private_GetDoubleConvertInMapN(pMe, - nLabel, - uConvertTypes, - pdValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, - uConvertTypes, - pdValue); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint32_t uConvertTypes, - double *pdValue) -{ - QCBORItem Item; - QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, - szLabel, - uConvertTypes, - pdValue, - &Item); - - if(pMe->uLastError == QCBOR_SUCCESS) { - // The above conversion succeeded - return; - } - - if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) { - // The above conversion failed in a way that code below can't correct - return; - } - - pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, - uConvertTypes, - pdValue); -} -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - * @brief Convert an integer to a big number - * - * @param[in] uInt The integer to convert. - * @param[in] Buffer The buffer to output the big number to. - * - * @returns The big number or NULLUsefulBufC is the buffer is to small. - * - * This always succeeds unless the buffer is too small. - */ -static UsefulBufC -QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer) -{ - while((uInt & 0xff00000000000000UL) == 0) { - uInt = uInt << 8; - }; - - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, Buffer); - - while(uInt) { - UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56)); - uInt = uInt << 8; - } - - return UsefulOutBuf_OutUBuf(&UOB); -} - - -/** - * @brief Check and/or complete exponent and mantissa item. - * - * @param[in] pMe The decoder context. - * @param[in] TagSpec Expected type(s). - * @param[in,out] pItem See below. - * - * This is for decimal fractions and big floats, both of which are an - * exponent and mantissa. - * - * If the item item had a tag number indicating it was a - * decimal fraction or big float, then the input @c pItem will - * have been decoded as exponent and mantissa. If there was - * no tag number, the caller is asking this be decoded as a - * big float or decimal fraction and @c pItem just has the - * first item in an exponent and mantissa. - * - * On output, the item is always a fully decoded decimal fraction or - * big float. - * - * This errors out if the input type does not meet the TagSpec. - */ -static QCBORError -QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe, - const QCBOR_Private_TagSpec TagSpec, - QCBORItem *pItem) -{ - QCBORError uErr; - - /* pItem could either be a decoded exponent and mantissa or - * the opening array of an undecoded exponent and mantissa. This - * check will succeed on either, but doesn't say which it was. - */ - uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - if(pItem->uDataType == QCBOR_TYPE_ARRAY) { - /* The item is an array, which means is is an undecoded exponent - * and mantissa. This call consumes the items in the array and - * results in a decoded exponent and mantissa in pItem. This is - * the case where there was no tag. - */ - uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - /* The above decode didn't determine whether it is a decimal - * fraction or big num. Which of these two depends on what the - * caller wants it decoded as since there is no tag, so fish the - * type out of the TagSpec. */ - pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem); - - /* No need to check the type again. All that we need to know was - * that it decoded correctly as a exponent and mantissa. The - * QCBOR type is set out by what was requested. - */ - } - - /* If the item was not an array and the check passed, then - * it is a fully decoded big float or decimal fraction and - * matches what is requested. - */ - -Done: - return uErr; -} - - -/* Some notes from the work to disable tags. - * - * The API for big floats and decimal fractions seems good. - * If there's any issue with it it's that the code size to - * implement is a bit large because of the conversion - * to/from int and bignum that is required. There is no API - * that doesn't do the conversion so dead stripping will never - * leave that code out. - * - * The implementation itself seems correct, but not as clean - * and neat as it could be. It could probably be smaller too. - * - * The implementation has three main parts / functions - * - The decoding of the array of two - * - All the tag and type checking for the various API functions - * - Conversion to/from bignum and int - * - * The type checking seems like it wastes the most code for - * what it needs to do. - * - * The inlining for the conversion is probably making the - * overall code base larger. - * - * The tests cases could be organized a lot better and be - * more thorough. - * - * Seems also like there could be more common code in the - * first tier part of the public API. Some functions only - * vary by a TagSpec. - */ - -/** - * @brief Common processor for exponent and mantissa. - * - * @param[in] pMe The decode context. - * @param[in] TagSpec The expected/allowed tags. - * @param[in] pItem The data item to process. - * @param[out] pnMantissa The returned mantissa as an int64_t. - * @param[out] pnExponent The returned exponent as an int64_t. - * - * This handles exponent and mantissa for base 2 and 10. This - * is limited to a mantissa that is an int64_t. See also - * QCBORDecode_Private_ProcessExpMantissaBig(). - */ -static void -QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe, - const QCBOR_Private_TagSpec TagSpec, - QCBORItem *pItem, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORError uErr; - - if(pMe->uLastError) { - return; - } - - uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - switch (pItem->uDataType) { - - case QCBOR_TYPE_DECIMAL_FRACTION: - case QCBOR_TYPE_BIGFLOAT: - *pnExponent = pItem->val.expAndMantissa.nExponent; - *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt; - break; - -#ifndef QCBOR_DISABLE_TAGS - /* If tags are disabled, mantissas can never be big nums */ - case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: - case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); - break; -#endif /* QCBOR_DISABLE_TAGS */ - - default: - uErr = QCBOR_ERR_UNEXPECTED_TYPE; - } - - Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/** - * @brief Decode exponent and mantissa into a big number. - * - * @param[in] pMe The decode context. - * @param[in] TagSpec The expected/allowed tags. - * @param[in] pItem Item to decode and convert. - * @param[in] BufferForMantissa Buffer to output mantissa into. - * @param[out] pMantissa The output mantissa. - * @param[out] pbIsNegative The sign of the output. - * @param[out] pnExponent The mantissa of the output. - * - * This is the common processing of a decimal fraction or a big float - * into a big number. This will decode and consume all the CBOR items - * that make up the decimal fraction or big float. - */ -static void -QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe, - const QCBOR_Private_TagSpec TagSpec, - QCBORItem *pItem, - const UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) -{ - QCBORError uErr; - uint64_t uMantissa; - - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - switch (pItem->uDataType) { - - case QCBOR_TYPE_DECIMAL_FRACTION: - case QCBOR_TYPE_BIGFLOAT: - if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) { - uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt; - *pbIsNegative = false; - } else { - if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) { - uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt; - } else { - /* Can't negate like above when int64_t is INT64_MIN because it - * will overflow. See ExponentNN() */ - uMantissa = (uint64_t)INT64_MAX+1; - } - *pbIsNegative = true; - } - /* Reverse the offset by 1 for type 1 negative value to be consistent - * with big num case below which don't offset because it requires - * big number arithmetic. This is a bug fix for QCBOR v1.5. - */ - uMantissa--; - *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa, BufferForMantissa); - *pnExponent = pItem->val.expAndMantissa.nExponent; - break; - -#ifndef QCBOR_DISABLE_TAGS - /* If tags are disabled, mantissas can never be big nums */ - case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: - case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - *pnExponent = pItem->val.expAndMantissa.nExponent; - *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum; - *pbIsNegative = false; - break; - - case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - *pnExponent = pItem->val.expAndMantissa.nExponent; - *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum; - *pbIsNegative = true; - break; -#endif /* QCBOR_DISABLE_TAGS */ - - default: - uErr = QCBOR_ERR_UNEXPECTED_TYPE; - } - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - MantissaBuffer, - pMantissa, - pbMantissaIsNegative, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) -{ - - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBOR_Private_ProcessExpMantissa(pMe, - TagSpec, - &Item, - pnMantissa, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - const UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_VGetNext(pMe, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - MantissaBuffer, - pMantissa, - pbMantissaIsNegative, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - const UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) -{ - QCBORItem Item; - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - const QCBOR_Private_TagSpec TagSpec = - { - uTagRequirement, - {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE}, - {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} - }; - - QCBORDecode_Private_ProcessExpMantissaBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); -} - -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ diff --git a/3rdparty/internal/QCBOR/src/qcbor_encode.c b/3rdparty/internal/QCBOR/src/qcbor_encode.c deleted file mode 100644 index c30cbce11691..000000000000 --- a/3rdparty/internal/QCBOR/src/qcbor_encode.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* =========================================================================== - * Copyright (c) 2016-2018, The Linux Foundation. - * Copyright (c) 2018-2024, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors, nor the name "Laurence Lundblade" may be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ========================================================================= */ - - -#include "qcbor/qcbor_encode.h" -#include "ieee754.h" - - -/** - * @file qcbor_encode.c - * - * The entire implementation of the QCBOR encoder. - */ - - -/* - * == Nesting Tracking == - * - * The following functions and data type QCBORTrackNesting implement - * the nesting management for encoding. - * - * CBOR's two nesting types, arrays and maps, are tracked here. There - * is a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and - * maps that can be nested in one encoding so the encoding context - * stays small enough to fit on the stack. - * - * When an array/map is opened, pCurrentNesting points to the element - * in pArrays that records the type, start position and accumulates a - * count of the number of items added. When closed the start position - * is used to go back and fill in the type and number of items in the - * array/map. - * - * Encoded output can be a CBOR Sequence (RFC 8742) in which case - * there is no top-level array or map. It starts out with a string, - * integer or other non-aggregate type. It may have an array or map - * other than at the start, in which case that nesting is tracked - * here. - * - * QCBOR has a special feature to allow constructing byte string - * wrapped CBOR directly into the output buffer, so no extra buffer is - * needed for byte string wrapping. This is implemented as nesting - * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte - * string wrapped CBOR is used by COSE for data that is to be hashed. - */ -static void -Nesting_Init(QCBORTrackNesting *pNesting) -{ - /* Assumes pNesting has been zeroed. */ - pNesting->pCurrentNesting = &pNesting->pArrays[0]; - /* Implied CBOR array at the top nesting level. This is never - * returned, but makes the item count work correctly. - */ - pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY; -} - -static uint8_t -Nesting_Increase(QCBORTrackNesting *pNesting, - const uint8_t uMajorType, - const uint32_t uPos) -{ - if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) { - return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; - } else { - pNesting->pCurrentNesting++; - pNesting->pCurrentNesting->uCount = 0; - pNesting->pCurrentNesting->uStart = uPos; - pNesting->pCurrentNesting->uMajorType = uMajorType; - return QCBOR_SUCCESS; - } -} - -static void -Nesting_Decrease(QCBORTrackNesting *pNesting) -{ - if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) { - pNesting->pCurrentNesting--; - } -} - -static uint8_t -Nesting_Increment(QCBORTrackNesting *pNesting) -{ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pNesting->pCurrentNesting->uCount >= QCBOR_MAX_ITEMS_IN_ARRAY) { - return QCBOR_ERR_ARRAY_TOO_LONG; - } -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - pNesting->pCurrentNesting->uCount++; - - return QCBOR_SUCCESS; -} - -static void -Nesting_Decrement(QCBORTrackNesting *pNesting) -{ - /* No error check for going below 0 here needed because this - * is only used by QCBOREncode_CancelBstrWrap() and it checks - * the nesting level before calling this. */ - pNesting->pCurrentNesting->uCount--; -} - -static uint16_t -Nesting_GetCount(QCBORTrackNesting *pNesting) -{ - /* The nesting count recorded is always the actual number of - * individual data items in the array or map. For arrays CBOR uses - * the actual item count. For maps, CBOR uses the number of pairs. - * This function returns the number needed for the CBOR encoding, - * so it divides the number of items by two for maps to get the - * number of pairs. - */ - if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) { - /* Cast back to uint16_t after integer promotion from bit shift */ - return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1); - } else { - return pNesting->pCurrentNesting->uCount; - } -} - -static uint32_t -Nesting_GetStartPos(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting->uStart; -} - -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS -static uint8_t -Nesting_GetMajorType(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting->uMajorType; -} - -static bool -Nesting_IsInNest(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true; -} -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - - - -/* - * == Major CBOR Types == - * - * Encoding of the major CBOR types is by these functions: - * - * CBOR Major Type Public Function - * 0 QCBOREncode_AddUInt64() - * 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64() - * 2, 3 QCBOREncode_AddBuffer() - * 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(), - * QCBOREncode_OpenMapOrArrayIndefiniteLength(), - * QCBOREncode_CloseMapOrArrayIndefiniteLength() - * 6 QCBOREncode_AddTag() - * 7 QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), - * QCBOREncode_AddDoubleNoPreferred(), - * QCBOREncode_AddFloatNoPreferred(), QCBOREncode_AddType7() - * - * Additionally, encoding of decimal fractions and bigfloats is by - * QCBOREncode_AddExponentAndMantissa() and byte strings that wrap - * encoded CBOR are handled by QCBOREncode_OpenMapOrArray() and - * QCBOREncode_CloseBstrWrap2(). - * - * - * == Error Tracking Plan == - * - * Errors are tracked internally and not returned until - * QCBOREncode_Finish() or QCBOREncode_GetErrorState() is called. The - * CBOR errors are in me->uError. UsefulOutBuf also tracks whether - * the buffer is full or not in its context. Once either of these - * errors is set they are never cleared. Only QCBOREncode_Init() - * resets them. Or said another way, they must never be cleared or - * we'll tell the caller all is good when it is not. - * - * Only one error code is reported by QCBOREncode_Finish() even if - * there are multiple errors. The last one set wins. The caller might - * have to fix one error to reveal the next one they have to fix. - * This is OK. - * - * The buffer full error tracked by UsefulBuf is only pulled out of - * UsefulBuf in QCBOREncode_Finish() so it is the one that usually - * wins. UsefulBuf will never go off the end of the buffer even if it - * is called again and again when full. - * - * QCBOR_DISABLE_ENCODE_USAGE_GUARDS disables about half of the error - * checks here to reduce code size by about 150 bytes leaving only the - * checks for size to avoid buffer overflow. If the calling code is - * completely correct, checks are completely unnecessary. For - * example, there is no need to check that all the opens are matched - * by a close. - * - * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more - * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since - * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,534) it is very unlikely - * to be reached. If it is reached, the count will wrap around to zero - * and CBOR that is not well formed will be produced, but there will - * be no buffers overrun and new security issues in the code. - * - * The 8 errors returned here fall into three categories: - * - * Sizes - * QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX - * QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small - * QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1 - * QCBOR_ERR_ARRAY_TOO_LONG -- Too many items added to an array/map [1] - * - * Nesting constructed incorrectly - * QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens [1] - * QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open [1] - * QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes [1] - * - * Would generate not-well-formed CBOR - * QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31 [1] - * - * [1] indicated disabled by QCBOR_DISABLE_ENCODE_USAGE_GUARDS - */ - - -/* - * Public function for initialization. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage) -{ - memset(pMe, 0, sizeof(QCBOREncodeContext)); - UsefulOutBuf_Init(&(pMe->OutBuf), Storage); - Nesting_Init(&(pMe->nesting)); -} - - -/* - * Public function to encode a CBOR head. See qcbor/qcbor_encode.h - */ -UsefulBufC -QCBOREncode_EncodeHead(UsefulBuf Buffer, - uint8_t uMajorType, - uint8_t uMinLen, - uint64_t uArgument) -{ - /* - * == Description of the CBOR Head == - * - * The head of a CBOR data item - * +---+-----+ +--------+ +--------+ +--------+ +--------+ - * |M T| A R G U M E N T . . . | - * +---+-----+ +--------+ +--------+ +--------+ ... +--------+ - * - * Every CBOR data item has a "head". It is made up of the "major - * type" and the "argument". - * - * The major type indicates whether the data item is an integer, - * string, array or such. It is encoded in 3 bits giving it a range - * from 0 to 7. 0 indicates the major type is a positive integer, - * 1 a negative integer, 2 a byte string and so on. - * - * These 3 bits are the first part of the "initial byte" in a data - * item. Every data item has an initial byte, and some only have - * the initial byte. - * - * The argument is essentially a number between 0 and UINT64_MAX - * (18446744073709551615). This number is interpreted to mean - * different things for the different major types. For major type - * 0, a positive integer, it is value of the data item. For major - * type 2, a byte string, it is the length in bytes of the byte - * string. For major type 4, an array, it is the number of data - * items in the array. - * - * Special encoding is used so that the argument values less than - * 24 can be encoded very compactly in the same byte as the major - * type is encoded. When the lower 5 bits of the initial byte have - * a value less than 24, then that is the value of the argument. - * - * If the lower 5 bits of the initial byte are less than 24, then - * they are the value of the argument. This allows integer values 0 - * - 23 to be CBOR encoded in just one byte. - * - * When the value of lower 5 bits are 24, 25, 26, or 27 the - * argument is encoded in 1, 2, 4 or 8 bytes following the initial - * byte in network byte order (bit endian). The cases when it is - * 28, 29 and 30 are reserved for future use. The value 31 is a - * special indicator for indefinite length strings, arrays and - * maps. - * - * The lower 5 bits are called the "additional information." - * - * Thus the CBOR head may be 1, 2, 3, 5 or 9 bytes long. - * - * It is legal in CBOR to encode the argument using any of these - * lengths even if it could be encoded in a shorter length. For - * example it is legal to encode a data item representing the - * positive integer 0 in 9 bytes even though it could be encoded in - * only 0. This is legal to allow for for very simple code or even - * hardware-only implementations that just output a register - * directly. - * - * CBOR defines preferred encoding as the encoding of the argument - * in the smallest number of bytes needed to encode it. - * - * This function takes the major type and argument as inputs and - * outputs the encoded CBOR head for them. It does conversion to - * network byte order. It implements CBOR preferred encoding, - * outputting the shortest representation of the argument. - * - * == Endian Conversion == - * - * This code does endian conversion without hton() or knowing the - * endianness of the machine by using masks and shifts. This avoids - * the dependency on hton() and the mess of figuring out how to - * find the machine's endianness. - * - * This is a good efficient implementation on little-endian - * machines. A faster and smaller implementation is possible on - * big-endian machines because CBOR/network byte order is - * big-endian. However big-endian machines are uncommon. - * - * On x86, this is about 150 bytes instead of 500 bytes for the - * original, more formal unoptimized code. - * - * This also does the CBOR preferred shortest encoding for integers - * and is called to do endian conversion for floats. - * - * It works backwards from the least significant byte to the most - * significant byte. - * - * == Floating Point == - * - * When the major type is 7 and the 5 lower bits have the values - * 25, 26 or 27, the argument is a floating-point number that is - * half, single or double-precision. Note that it is not the - * conversion from a floating-point value to an integer value like - * converting 0x00 to 0.00, it is the interpretation of the bits in - * the argument as an IEEE 754 float-point number. - * - * Floating-point numbers must be converted to network byte - * order. That is accomplished here by exactly the same code that - * converts integer arguments to network byte order. - * - * There is preferred encoding for floating-point numbers in CBOR, - * but it is very different than for integers and it is not - * implemented here. Half-precision is preferred to - * single-precision which is preferred to double-precision only if - * the conversion can be performed without loss of precision. Zero - * and infinity can always be converted to half-precision, without - * loss but 3.141592653589 cannot. - * - * The way this function knows to not do preferred encoding on the - * argument passed here when it is a floating point number is the - * uMinLen parameter. It should be 2, 4 or 8 for half, single and - * double precision floating point values. This prevents and the - * incorrect removal of leading zeros when encoding arguments that - * are floating-point numbers. - * - * == Use of Type int and Static Analyzers == - * - * The type int is used here for several variables because of the - * way integer promotion works in C for variables that are uint8_t - * or uint16_t. The basic rule is that they will always be promoted - * to int if they will fit. These integer variables here need only - * hold values less than 255 so they will always fit into an int. - * - * Most of values stored are never negative, so one might think - * that unsigned int would be more correct than int. However the C - * integer promotion rules only promote to unsigned int if the - * result won't fit into an int even if the promotion is for an - * unsigned variable like uint8_t. - * - * By declaring these int, there are few implicit conversions and - * fewer casts needed. Code size is reduced a little. It makes - * static analyzers happier. - * - * Note also that declaring these uint8_t won't stop integer wrap - * around if the code is wrong. It won't make the code more - * correct. - * - * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules - * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be - * - * Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ - - /* The buffer must have room for the largest CBOR HEAD + one - * extra. The one extra is needed for this code to work as it does - * a pre-decrement. - */ - if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) { - return NULLUsefulBufC; - } - - /* Pointer to last valid byte in the buffer */ - uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1]; - - /* Point to the last byte and work backwards */ - uint8_t *pByte = pBufferEnd; - /* The 5 bits in the initial byte that are not the major type */ - int nAdditionalInfo; - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) { - /* Special case for start & end of indefinite length */ - uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER; - /* This takes advantage of design of CBOR where additional info - * is 31 for both opening and closing indefinite length - * maps and arrays. - */ - #if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE - #error additional info for opening array not the same as for closing - #endif - nAdditionalInfo = CBOR_SIMPLE_BREAK; - - } else -#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) { - /* Simple case where argument is < 24 */ - nAdditionalInfo = (int)uArgument; - - } else { - /* This encodes the argument in 1,2,4 or 8 bytes. The outer loop - * runs once for 1 byte and 4 times for 8 bytes. The inner loop - * runs 1, 2 or 4 times depending on outer loop counter. This - * works backwards shifting 8 bits off the argument being - * encoded at a time until all bits from uArgument have been - * encoded and the minimum encoding size is reached. Minimum - * encoding size is for floating-point numbers that have some - * zero-value bytes that must be output. - */ - static const uint8_t aIterate[] = {1,1,2,4}; - - /* uMinLen passed in is unsigned, but goes negative in the loop - * so it must be converted to a signed value. - */ - int nMinLen = (int)uMinLen; - int i; - for(i = 0; uArgument || nMinLen > 0; i++) { - const int nIterations = (int)aIterate[i]; - for(int j = 0; j < nIterations; j++) { - *--pByte = (uint8_t)(uArgument & 0xff); - uArgument = uArgument >> 8; - } - nMinLen -= nIterations; - } - - nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i; - } - - /* This expression integer-promotes to type int. The code above in - * function guarantees that nAdditionalInfo will never be larger - * than 0x1f. The caller may pass in a too-large uMajor type. The - * conversion to uint8_t will cause an integer wrap around and - * incorrect CBOR will be generated, but no security issue will - * occur. - */ - const int nInitialByte = (uMajorType << 5) + nAdditionalInfo; - *--pByte = (uint8_t)nInitialByte; - -#ifdef EXTRA_ENCODE_HEAD_CHECK - /* This is a sanity check that can be turned on to verify the - * pointer math in this function is not going wrong. Turn it on and - * run the whole test suite to perform the check. - */ - if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) { - return NULLUsefulBufC; - } -#endif /* EXTRA_ENCODE_HEAD_CHECK */ - - /* Length will not go negative because the loops run for at most 8 decrements - * of pByte, only one other decrement is made, and the array is sized - * for this. - */ - return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)}; -} - - -/** - * @brief Increment item counter for maps and arrays. - * - * @param pMe QCBOR encoding context. - * - * This is mostly a separate function to make code more readable and - * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - */ -static void -QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe) -{ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError == QCBOR_SUCCESS) { - pMe->uError = Nesting_Increment(&(pMe->nesting)); - } -#else - (void)Nesting_Increment(&(pMe->nesting)); -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ -} - - -/** - * @brief Append the CBOR head, the major type and argument - * - * @param pMe Encoder context. - * @param uMajorType Major type to insert. - * @param uArgument The argument (an integer value or a length). - * @param uMinLen The minimum number of bytes for encoding the CBOR argument. - * - * This formats the CBOR "head" and appends it to the output. - * - * This also increments the array/map item counter in most cases. - */ -void -QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, - const uint8_t uMajorType, - const uint64_t uArgument, - const uint8_t uMinLen) -{ - /* A stack buffer large enough for a CBOR head */ - UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); - - UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - uMinLen, - uArgument); - - /* No check for EncodedHead == NULLUsefulBufC is performed here to - * save object code. It is very clear that pBufferForEncodedHead is - * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no - * security hole introduced. - */ - - UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead); - - if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) { - /* Don't increment the map count for tag or break because that is - * not needed. Don't do it for indefinite-length arrays and maps - * because it is done elsewhere. This is never called for definite-length - * arrays and maps. - */ - QCBOREncode_Private_IncrementMapOrArrayCount(pMe); - } -} - - -/* - * Public function for adding signed integers. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum) -{ - uint8_t uMajorType; - uint64_t uValue; - - if(nNum < 0) { - /* In CBOR -1 encodes as 0x00 with major type negative int. - * First add one as a signed integer because that will not - * overflow. Then change the sign as needed for encoding. (The - * opposite order, changing the sign and subtracting, can cause - * an overflow when encoding INT64_MIN. */ - int64_t nTmp = nNum + 1; - uValue = (uint64_t)-nTmp; - uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT; - } else { - uValue = (uint64_t)nNum; - uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT; - } - QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0); -} - - -/** - * @brief Semi-private method to add a buffer full of bytes to encoded output. - * - * @param[in] pMe The encoding context to add the string to. - * @param[in] uMajorType The CBOR major type of the bytes. - * @param[in] Bytes The bytes to add. - * - * Called by inline functions to add text and byte strings. - * - * (This used to support QCBOREncode_AddEncoded() and - * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this - * smaller. This is one of the most used methods and they are some of - * the least used). - */ -void -QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe, - const uint8_t uMajorType, - const UsefulBufC Bytes) -{ - QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0); - UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes); -} - - -/* - * Public function for adding raw encoded CBOR. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded) -{ - UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded); - QCBOREncode_Private_IncrementMapOrArrayCount(pMe); -} - - -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT -/** - * @brief Semi-private method to add a double using preferred encoding. - * - * @param[in] pMe The encode context. - * @param[in] dNum The double to add. - * - * This converts the double to a float or half-precision if it can be done - * without a loss of precision. See QCBOREncode_AddDouble(). - */ -void -QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum) -{ - const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true); - QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); -} - - -/** - * @brief Semi-private method to add a float using preferred encoding. - * - * @param[in] pMe The encode context. - * @param[in] fNum The float to add. - * - * This converts the float to a half-precision if it can be done - * without a loss of precision. See QCBOREncode_AddFloat(). - */ -void -QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum) -{ - const IEEE754_union uNum = IEEE754_SingleToHalf(fNum); - QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); -} -#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - * @brief Semi-private method to add bigfloats and decimal fractions. - * - * @param[in] pMe The encoding context to add the value to. - * @param[in] uTag The type 6 tag indicating what this is to be. - * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an - * @c int64_t or the actual big number mantissa - * if not. - * @param[in] bBigNumIsNegative This is @c true if the big number is negative. - * @param[in] nMantissa The @c int64_t mantissa if it is not a big number. - * @param[in] nExponent The exponent. - * - * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or - * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64, - * then this outputs the "borrowed" content format. - * - * The tag content output by this is an array with two members, the - * exponent and then the mantissa. The mantissa can be either a big - * number or an @c int64_t. - * - * This implementation cannot output an exponent further from 0 than - * @c INT64_MAX. - * - * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0, - * it must be as a big number. - * - * Typically, QCBOREncode_AddTDecimalFraction(), QCBOREncode_AddTBigFloat(), - * QCBOREncode_AddTDecimalFractionBigNum() or QCBOREncode_AddTBigFloatBigNum() - * is called instead of this. - */ -void -QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe, - const uint64_t uTag, - const UsefulBufC BigNumMantissa, - const bool bBigNumIsNegative, - const int64_t nMantissa, - const int64_t nExponent) -{ - /* This is for encoding either a big float or a decimal fraction, - * both of which are an array of two items, an exponent and a - * mantissa. The difference between the two is that the exponent - * is base-2 for big floats and base-10 for decimal fractions, but - * that has no effect on the code here. - */ - if(uTag != CBOR_TAG_INVALID64) { - QCBOREncode_AddTag(pMe, uTag); - } - QCBOREncode_OpenArray(pMe); - QCBOREncode_AddInt64(pMe, nExponent); - if(!UsefulBuf_IsNULLC(BigNumMantissa)) { - if(bBigNumIsNegative) { - QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); - } else { - QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); - } - } else { - QCBOREncode_AddInt64(pMe, nMantissa); - } - QCBOREncode_CloseArray(pMe); -} -#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - - -/** - * @brief Semi-private method to open a map, array or bstr-wrapped CBOR - * - * @param[in] pMe The context to add to. - * @param[in] uMajorType The major CBOR type to close - * - * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or - * QCBOREncode_BstrWrap() instead of this. - */ -void -QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe, - const uint8_t uMajorType) -{ - /* Add one item to the nesting level we are in for the new map or array */ - QCBOREncode_Private_IncrementMapOrArrayCount(pMe); - - /* The offset where the length of an array or map will get written - * is stored in a uint32_t, not a size_t to keep stack usage - * smaller. This checks to be sure there is no wrap around when - * recording the offset. Note that on 64-bit machines CBOR larger - * than 4GB can be encoded as long as no array/map offsets occur - * past the 4GB mark, but the public interface says that the - * maximum is 4GB to keep the discussion simpler. - */ - size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); - - /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this - * code can run on a 32-bit machine and tests can pass on a 32-bit - * machine. If it was exactly UINT32_MAX, then this code would not - * compile or run on a 32-bit machine and an #ifdef or some machine - * size detection would be needed reducing portability. - */ - if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) { - pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE; - - } else { - /* Increase nesting level because this is a map or array. Cast - * from size_t to uin32_t is safe because of check above. - */ - pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition); - } -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/** - * @brief Semi-private method to open a map, array with indefinite length - * - * @param[in] pMe The context to add to. - * @param[in] uMajorType The major CBOR type to close - * - * Call QCBOREncode_OpenArrayIndefiniteLength() or - * QCBOREncode_OpenMapIndefiniteLength() instead of this. - */ -void -QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, - const uint8_t uMajorType) -{ - /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */ - QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0); - - /* Call the definite-length opener just to do the bookkeeping for - * nesting. It will record the position of the opening item in the - * encoded output but this is not used when closing this open. - */ - QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType); -} -#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - -/** - * @brief Check for errors when decreasing nesting. - * - * @param pMe QCBOR encoding context. - * @param uMajorType The major type of the nesting. - * - * Check that there is no previous error, that there is actually some - * nesting and that the major type of the opening of the nesting - * matches the major type of the nesting being closed. - * - * This is called when closing maps, arrays, byte string wrapping and - * open/close of byte strings. - */ -static bool -QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe, - const uint8_t uMajorType) -{ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError != QCBOR_SUCCESS) { - return true; - } - - if(!Nesting_IsInNest(&(pMe->nesting))) { - pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES; - return true; - } - - if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) { - pMe->uError = QCBOR_ERR_CLOSE_MISMATCH; - return true; - } - -#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - /* None of these checks are performed if the encode guards are - * turned off as they all relate to correct calling. - * - * Turning off all these checks does not turn off any checking for - * buffer overflows or pointer issues. - */ - - (void)uMajorType; - (void)pMe; -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - return false; -} - - -/** - * @brief Insert the CBOR head for a map, array or wrapped bstr. - * - * @param pMe QCBOR encoding context. - * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX. - * @param uLen The length of the data item. - * - * When an array, map or bstr was opened, nothing was done but note - * the position. This function goes back to that position and inserts - * the CBOR Head with the major type and length. - */ -static void -QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe, - uint8_t uMajorType, - size_t uLen) -{ - if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { - return; - } - - if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { - uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; - } - - /* A stack buffer large enough for a CBOR head (9 bytes) */ - UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); - - UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - 0, - uLen); - - /* No check for EncodedHead == NULLUsefulBufC is performed here to - * save object code. It is very clear that pBufferForEncodedHead is - * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no - * security hole introduced. - */ - UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf), - EncodedHead, - Nesting_GetStartPos(&(pMe->nesting))); - - Nesting_Decrease(&(pMe->nesting)); -} - - -/** - * @brief Semi-private method to close a map, array or bstr wrapped CBOR - * - * @param[in] pMe The context to add to. - * @param[in] uMajorType The major CBOR type to close. - * - * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this. - */ -void -QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe, - const uint8_t uMajorType) -{ - QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting))); -} - - -/* - * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe, - const bool bIncludeCBORHead, - UsefulBufC *pWrappedCBOR) -{ - const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting)); - const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); - - /* This subtraction can't go negative because the UsefulOutBuf - * always only grows and never shrinks. UsefulOutBut itself also - * has defenses such that it won't write where it should not even - * if given incorrect input lengths. - */ - const size_t uBstrLen = uEndPosition - uInsertPosition; - - /* Actually insert */ - QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen); - - if(pWrappedCBOR) { - /* Return pointer and length to the enclosed encoded CBOR. The - * intended use is for it to be hashed (e.g., SHA-256) in a COSE - * implementation. This must be used right away, as the pointer - * and length go invalid on any subsequent calls to this - * function because there might be calls to - * InsertEncodedTypeAndNumber() that slides data to the right. - */ - size_t uStartOfNew = uInsertPosition; - if(!bIncludeCBORHead) { - /* Skip over the CBOR head to just get the inserted bstr */ - const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); - uStartOfNew += uNewEndPosition - uEndPosition; - } - const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); - *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew); - } -} - - -/* - * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) -{ - if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) { - return; - } - -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); - if(pMe->nesting.pCurrentNesting->uStart != uCurrent) { - pMe->uError = QCBOR_ERR_CANNOT_CANCEL; - return; - } - /* QCBOREncode_CancelBstrWrap() can't correctly undo - * QCBOREncode_BstrWrapInMapSZ() or QCBOREncode_BstrWrapInMapN(). It - * can't undo the labels they add. It also doesn't catch the error - * of using it this way. QCBOREncode_CancelBstrWrap() is used - * infrequently and the the result is incorrect CBOR, not a - * security hole, so no extra code or state is added to handle this - * condition. - */ -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - Nesting_Decrease(&(pMe->nesting)); - Nesting_Decrement(&(pMe->nesting)); -} - - -/* - * Public function for opening a byte string. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace) -{ - *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf)); -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting)); - if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { - /* It's OK to nest a byte string in any type but - * another open byte string. */ - pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING; - return; - } -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR); -} - - -/* - * Public function for closing a byte string. See qcbor/qcbor_encode.h - */ -void -QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) -{ - UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount); - if(UsefulOutBuf_GetError(&(pMe->OutBuf))) { - /* Advance too far. Normal off-end error handling in effect here. */ - return; - } - - QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount); -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/** - * @brief Semi-private method to close a map, array with indefinite length - * - * @param[in] pMe The context to add to. - * @param[in] uMajorType The major CBOR type to close. - * - * Call QCBOREncode_CloseArrayIndefiniteLength() or - * QCBOREncode_CloseMapIndefiniteLength() instead of this. - */ -void -QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, - const uint8_t uMajorType) -{ - if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { - return; - } - - /* Append the break marker (0xff for both arrays and maps) */ - QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0); - Nesting_Decrease(&(pMe->nesting)); -} -#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - -/* - * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h - */ -QCBORError -QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR) -{ - if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) { - goto Done; - } - -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(Nesting_IsInNest(&(pMe->nesting))) { - pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; - goto Done; - } -#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); - -Done: - return pMe->uError; -} - - -/* - * Public function to get size of the encoded result. See qcbor/qcbor_encode.h - */ -QCBORError -QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen) -{ - UsefulBufC Enc; - - QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc); - - if(nReturn == QCBOR_SUCCESS) { - *puEncodedLen = Enc.len; - } - - return nReturn; -} - - -/* - * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h - */ -UsefulBufC -QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart) -{ - if(pMe->uError) { - return NULLUsefulBufC; - } - - /* An attempt was made to detect usage errors by comparing uStart - * to offsets of open arrays and maps in pMe->nesting, but it is - * not possible because there's not enough information in just - * the offset. It's not possible to known if Tell() was called before - * or after an Open(). To detect this error, the nesting level - * would also need to be known. This is not frequently used, so - * it is not worth adding this complexity. - */ - - const size_t uEnd = QCBOREncode_Tell(pMe); - - return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart); -} diff --git a/3rdparty/internal/QCBOR/src/qcbor_err_to_str.c b/3rdparty/internal/QCBOR/src/qcbor_err_to_str.c deleted file mode 100644 index f9588e5c01a3..000000000000 --- a/3rdparty/internal/QCBOR/src/qcbor_err_to_str.c +++ /dev/null @@ -1,92 +0,0 @@ -/* ========================================================================== - * err_to_str.c -- strings names for errors - * - * Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. - * Copyright (c) 2020,2024, Laurence Lundblade. - * Copyright (c) 2021, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in file named "LICENSE" - * - * Created on 3/21/20 - * ========================================================================== */ - -#include "qcbor/qcbor_common.h" -#include - -#define ERR_TO_STR_CASE(errpart) case errpart: return #errpart; - - -const char * -qcbor_err_to_str(const QCBORError uErr) { - switch (uErr) { - ERR_TO_STR_CASE(QCBOR_SUCCESS) - ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_SMALL) - ERR_TO_STR_CASE(QCBOR_ERR_ENCODE_UNSUPPORTED) - ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_LARGE) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) - ERR_TO_STR_CASE(QCBOR_ERR_CLOSE_MISMATCH) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_TOO_LONG) - ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_CLOSES) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) - ERR_TO_STR_CASE(QCBOR_ERR_OPEN_BYTE_STRING) - ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_CANCEL) - ERR_TO_STR_CASE(QCBOR_ERR_BAD_TYPE_7) - ERR_TO_STR_CASE(QCBOR_ERR_EXTRA_BYTES) - ERR_TO_STR_CASE(QCBOR_ERR_UNSUPPORTED) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) - ERR_TO_STR_CASE(QCBOR_ERR_BAD_INT) - ERR_TO_STR_CASE(QCBOR_ERR_INDEFINITE_STRING_CHUNK) - ERR_TO_STR_CASE(QCBOR_ERR_HIT_END) - ERR_TO_STR_CASE(QCBOR_ERR_BAD_BREAK) - ERR_TO_STR_CASE(QCBOR_ERR_INPUT_TOO_LARGE) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) - ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_TOO_LONG) - ERR_TO_STR_CASE(QCBOR_ERR_STRING_TOO_LONG) - ERR_TO_STR_CASE(QCBOR_ERR_BAD_EXP_AND_MANTISSA) - ERR_TO_STR_CASE(QCBOR_ERR_NO_STRING_ALLOCATOR) - ERR_TO_STR_CASE(QCBOR_ERR_STRING_ALLOCATE) - ERR_TO_STR_CASE(QCBOR_ERR_MAP_LABEL_TYPE) - ERR_TO_STR_CASE(QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) - ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_TAGS_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_TAGS) - ERR_TO_STR_CASE(QCBOR_ERR_UNEXPECTED_TYPE) - ERR_TO_STR_CASE(QCBOR_ERR_DUPLICATE_LABEL) - ERR_TO_STR_CASE(QCBOR_ERR_MEM_POOL_SIZE) - ERR_TO_STR_CASE(QCBOR_ERR_INT_OVERFLOW) - ERR_TO_STR_CASE(QCBOR_ERR_DATE_OVERFLOW) - ERR_TO_STR_CASE(QCBOR_ERR_EXIT_MISMATCH) - ERR_TO_STR_CASE(QCBOR_ERR_NO_MORE_ITEMS) - ERR_TO_STR_CASE(QCBOR_ERR_LABEL_NOT_FOUND) - ERR_TO_STR_CASE(QCBOR_ERR_NUMBER_SIGN_CONVERSION) - ERR_TO_STR_CASE(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) - ERR_TO_STR_CASE(QCBOR_ERR_MAP_NOT_ENTERED) - ERR_TO_STR_CASE(QCBOR_ERR_CALLBACK_FAIL) - ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_DATE_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_HALF_PRECISION_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_HW_FLOAT_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_EXCEPTION) - ERR_TO_STR_CASE(QCBOR_ERR_ALL_FLOAT_DISABLED) - ERR_TO_STR_CASE(QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT) - ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) - - default: - if(uErr >= QCBOR_ERR_FIRST_USER_DEFINED && uErr <= QCBOR_ERR_LAST_USER_DEFINED) { - /* Static buffer is not thread safe, but this is only a diagnostic */ - static char buf[20]; - strcpy(buf, "USER_DEFINED_"); - size_t uEndOffset = strlen(buf); - buf[uEndOffset] = (char)(uErr/100 + '0'); - buf[uEndOffset+1] = (char)(((uErr/10) % 10) + '0'); - buf[uEndOffset+2] = (char)((uErr % 10 )+ '0'); - buf[uEndOffset+3] = '\0'; - return buf; - - } else { - return "Unidentified QCBOR error"; - } - } -} diff --git a/3rdparty/internal/cose-openssl/.gitignore b/3rdparty/internal/cose-openssl/.gitignore new file mode 100644 index 000000000000..2c96eb1b6517 --- /dev/null +++ b/3rdparty/internal/cose-openssl/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/3rdparty/internal/cose-openssl/Cargo.toml b/3rdparty/internal/cose-openssl/Cargo.toml new file mode 100644 index 000000000000..6486a635134a --- /dev/null +++ b/3rdparty/internal/cose-openssl/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cose-openssl" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["lib"] + +[features] +pqc = [] + +[lints.rust] +warnings = "deny" + +[dependencies] +openssl-sys = "0.9" +cborrs = { git = "https://github.com/project-everest/everparse.git", tag = "v2026.02.25" } +cborrs-nondet = { git = "https://github.com/project-everest/everparse.git", tag = "v2026.02.25" } diff --git a/3rdparty/internal/cose-openssl/src/cbor.rs b/3rdparty/internal/cose-openssl/src/cbor.rs new file mode 100644 index 000000000000..9cc709226e43 --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/cbor.rs @@ -0,0 +1,616 @@ +use cborrs::cbordet::*; +use cborrs_nondet::cbornondet::*; + +struct SimpleArena(std::cell::RefCell>>); + +impl SimpleArena { + fn new() -> Self { + Self(std::cell::RefCell::new(Vec::new())) + } + + fn alloc(&self, val: T) -> &mut T { + self.alloc_extend(std::iter::once(val)).first_mut().unwrap() + } + + fn alloc_extend(&self, vals: impl IntoIterator) -> &mut [T] { + let boxed: Box<[T]> = vals.into_iter().collect(); + let mut store = self.0.borrow_mut(); + store.push(boxed); + let slot = store.last_mut().unwrap(); + // SAFETY: The returned reference borrows `self`, which owns the + // backing storage. Items are never moved or removed, so the + // reference remains valid for the lifetime of the arena. + unsafe { &mut *(slot.as_mut() as *mut [T]) } + } +} + +/// An owned CBOR value supporting arbitrary nesting. +/// +/// Covers the major CBOR types: integers, simple values, byte/text strings, +/// arrays, maps, and tagged values. Unlike [`CborNondet`], this type owns +/// all its data and can be freely stored, cloned, and nested. +#[derive(Clone, PartialEq)] +pub enum CborValue { + Int(i64), + Simple(u8), + ByteString(Vec), + TextString(String), + Array(Vec), + Map(Vec<(CborValue, CborValue)>), + Tagged { tag: u64, payload: Box }, +} + +impl CborValue { + /// Parse CBOR bytes into an owned `CborValue`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let (item, remainder) = cbor_nondet_parse(None, false, bytes) + .ok_or("Failed to parse CBOR bytes")?; + if !remainder.is_empty() { + return Err(format!( + "Trailing bytes: {} unconsumed byte(s)", + remainder.len() + )); + } + Self::from_raw(item) + } + + /// Serialize this value to deterministic CBOR bytes. + pub fn to_bytes(&self) -> Result, String> { + let item_arena: SimpleArena> = SimpleArena::new(); + let entry_arena: SimpleArena> = SimpleArena::new(); + let raw = self.to_raw(&item_arena, &entry_arena)?; + serialize_det(raw) + } + + /// Build a `CborDet` tree without serializing. + /// + /// Child nodes are allocated in the arenas so they stay alive long enough + /// for the parent to borrow them. The caller serializes the returned root + /// exactly once. + fn to_raw<'a>( + &'a self, + items: &'a SimpleArena>, + entries: &'a SimpleArena>, + ) -> Result, String> { + match self { + CborValue::Int(v) => { + let (kind, raw) = Self::i64_to_det_int(*v); + Ok(cbor_det_mk_int64(kind, raw)) + } + CborValue::Simple(v) => cbor_det_mk_simple_value(*v) + .ok_or("Failed to make CBOR simple value".to_string()), + CborValue::ByteString(b) => cbor_det_mk_byte_string(b) + .ok_or("Failed to make CBOR byte string".to_string()), + CborValue::TextString(s) => cbor_det_mk_text_string(s) + .ok_or("Failed to make CBOR text string".to_string()), + CborValue::Array(children) => { + let raw_children: Vec> = children + .iter() + .map(|c| c.to_raw(items, entries)) + .collect::>()?; + let slice = items.alloc_extend(raw_children); + cbor_det_mk_array(slice) + .ok_or("Failed to build CBOR array".to_string()) + } + CborValue::Map(map_entries) => { + let raw: Vec> = map_entries + .iter() + .map(|(k, v)| { + Ok(cbor_det_mk_map_entry( + k.to_raw(items, entries)?, + v.to_raw(items, entries)?, + )) + }) + .collect::>()?; + let slice = entries.alloc_extend(raw); + cbor_det_mk_map(slice) + .ok_or("Failed to build CBOR map".to_string()) + } + CborValue::Tagged { tag, payload } => { + let inner = payload.to_raw(items, entries)?; + let inner_ref = items.alloc(inner); + Ok(cbor_det_mk_tagged(*tag, inner_ref)) + } + } + } + + /// Get array element by index. Returns an error if not an array. + pub fn array_at(&self, index: usize) -> Result<&CborValue, String> { + match self { + CborValue::Array(items) => items + .get(index) + .ok_or_else(|| format!("Index {index} out of bounds")), + other => { + Err(format!("Expected Array, got {:?}", other.type_name())) + } + } + } + + /// Look up a map value by integer key. Returns an error if not a map. + pub fn map_at_int(&self, key: i64) -> Result<&CborValue, String> { + let target = CborValue::Int(key); + self.map_at(&target) + } + + /// Look up a map value by text string key. Returns an error if not a map. + pub fn map_at_str(&self, key: &str) -> Result<&CborValue, String> { + let target = CborValue::TextString(key.to_string()); + self.map_at(&target) + } + + /// Look up a map value by a CborValue key (must be Int or TextString). + /// Returns an error if not a map or if the key type is invalid. + pub fn map_at(&self, key: &CborValue) -> Result<&CborValue, String> { + match key { + CborValue::Int(_) | CborValue::TextString(_) => {} + _ => return Err("Map keys can only be Int or TextString".into()), + } + match self { + CborValue::Map(entries) => entries + .iter() + .find(|(k, _)| k == key) + .map(|(_, v)| v) + .ok_or_else(|| format!("Key {:?} not found in map", key)), + other => Err(format!("Expected Map, got {:?}", other.type_name())), + } + } + + /// Iterate over array elements. Returns an error if not an array. + pub fn iter_array( + &self, + ) -> Result, String> { + match self { + CborValue::Array(items) => Ok(items.iter()), + other => { + Err(format!("Expected Array, got {:?}", other.type_name())) + } + } + } + + /// Iterate over map entries as `(key, value)` pairs. + /// Returns an error if not a map. + pub fn iter_map( + &self, + ) -> Result, String> { + match self { + CborValue::Map(entries) => Ok(entries.iter().map(|(k, v)| (k, v))), + other => Err(format!("Expected Map, got {:?}", other.type_name())), + } + } + + /// Number of elements in an array or map. + /// Returns an error for other types. + pub fn len(&self) -> Result { + match self { + CborValue::Array(items) => Ok(items.len()), + CborValue::Map(entries) => Ok(entries.len()), + other => { + Err(format!("len() not applicable to {:?}", other.type_name())) + } + } + } + + fn type_name(&self) -> &'static str { + match self { + CborValue::Int(_) => "Int", + CborValue::Simple(_) => "Simple", + CborValue::ByteString(_) => "ByteString", + CborValue::TextString(_) => "TextString", + CborValue::Array(_) => "Array", + CborValue::Map(_) => "Map", + CborValue::Tagged { .. } => "Tagged", + } + } + + fn i64_to_det_int(v: i64) -> (CborDetIntKind, u64) { + if v >= 0 { + (CborDetIntKind::UInt64, v as u64) + } else { + (CborDetIntKind::NegInt64, (v as u64).wrapping_neg() - 1) + } + } + + fn nondet_int_to_i64( + kind: CborNondetIntKind, + value: u64, + ) -> Result { + match kind { + CborNondetIntKind::UInt64 => i64::try_from(value) + .map_err(|_| format!("CBOR uint {value} exceeds i64 range")), + CborNondetIntKind::NegInt64 => { + // CBOR negative: actual = -(value + 1) + // Compute as u64 first then reinterpret, to avoid overflow. + let neg_val = (!value) as i64; // bitwise NOT gives -(value+1) in two's complement + if value > (i64::MAX as u64) { + return Err(format!("CBOR nint exceeds i64 range")); + } + Ok(neg_val) + } + } + } + + fn from_raw(item: CborNondet) -> Result { + match cbor_nondet_destruct(item) { + CborNondetView::Int64 { kind, value } => { + Ok(CborValue::Int(Self::nondet_int_to_i64(kind, value)?)) + } + CborNondetView::SimpleValue { _0: v } => Ok(CborValue::Simple(v)), + CborNondetView::ByteString { payload } => { + Ok(CborValue::ByteString(payload.to_vec())) + } + CborNondetView::TextString { payload } => { + Ok(CborValue::TextString(payload.to_string())) + } + CborNondetView::Array { _0: arr } => { + let len = cbor_nondet_get_array_length(arr); + let mut items = Vec::with_capacity(len as usize); + for i in 0..len { + let child = cbor_nondet_get_array_item(arr, i) + .ok_or("Failed to get array item")?; + items.push(Self::from_raw(child)?); + } + Ok(CborValue::Array(items)) + } + CborNondetView::Map { _0: map } => { + let mut entries = Vec::with_capacity( + cbor_nondet_get_map_length(map) as usize, + ); + for entry in map { + let k = Self::from_raw(cbor_nondet_map_entry_key(entry))?; + let v = Self::from_raw(cbor_nondet_map_entry_value(entry))?; + entries.push((k, v)); + } + Ok(CborValue::Map(entries)) + } + CborNondetView::Tagged { tag, payload } => { + let inner = Self::from_raw(payload)?; + Ok(CborValue::Tagged { + tag, + payload: Box::new(inner), + }) + } + } + } +} + +fn serialize_det(item: CborDet) -> Result, String> { + let sz = cbor_det_size(item, usize::MAX) + .ok_or("Failed to estimate CBOR serialization size")?; + let mut buf = vec![0u8; sz]; + let written = + cbor_det_serialize(item, &mut buf).ok_or("Failed to serialize CBOR")?; + if sz != written { + return Err(format!( + "CBOR serialize mismatch: written {written} != expected {sz}" + )); + } + Ok(buf) +} + +impl std::fmt::Debug for CborValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CborValue::Int(v) => write!(f, "Int({})", v), + CborValue::Simple(v) => write!(f, "Simple({})", v), + CborValue::ByteString(b) => write!(f, "Bstr({} bytes)", b.len()), + CborValue::TextString(s) => write!(f, "Tstr({:?})", s), + CborValue::Array(items) => f.debug_list().entries(items).finish(), + CborValue::Map(entries) => f + .debug_map() + .entries(entries.iter().map(|(k, v)| (k, v))) + .finish(), + CborValue::Tagged { tag, payload } => { + write!(f, "Tag({}, {:?})", tag, payload) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn round_trip(val: &CborValue) { + let bytes = val.to_bytes().unwrap(); + let parsed = CborValue::from_bytes(&bytes).unwrap(); + // Det serialization may reorder map keys, so compare the + // re-serialized bytes rather than the structural values. + let bytes2 = parsed.to_bytes().unwrap(); + assert_eq!(bytes, bytes2); + } + + // --- Int --- + + #[test] + fn round_trip_uint() { + round_trip(&CborValue::Int(42)); + } + + #[test] + fn round_trip_nint() { + round_trip(&CborValue::Int(-7)); + } + + #[test] + fn round_trip_zero() { + round_trip(&CborValue::Int(0)); + } + + #[test] + fn round_trip_i64_min() { + round_trip(&CborValue::Int(i64::MIN)); + } + + // --- Simple --- + + #[test] + fn round_trip_simple_true() { + round_trip(&CborValue::Simple(21)); // CBOR true + } + + #[test] + fn round_trip_simple_null() { + round_trip(&CborValue::Simple(22)); // CBOR null + } + + // --- ByteString --- + + #[test] + fn round_trip_bstr() { + round_trip(&CborValue::ByteString(vec![0xDE, 0xAD, 0xBE, 0xEF])); + } + + #[test] + fn round_trip_bstr_empty() { + round_trip(&CborValue::ByteString(vec![])); + } + + // --- TextString --- + + #[test] + fn round_trip_tstr() { + round_trip(&CborValue::TextString("hello world".into())); + } + + #[test] + fn round_trip_tstr_empty() { + round_trip(&CborValue::TextString(String::new())); + } + + // --- Array --- + + #[test] + fn round_trip_flat_array() { + round_trip(&CborValue::Array(vec![ + CborValue::Int(1), + CborValue::Int(2), + CborValue::Int(3), + ])); + } + + #[test] + fn round_trip_nested_array() { + round_trip(&CborValue::Array(vec![ + CborValue::Int(1), + CborValue::Array(vec![ + CborValue::Int(-1), + CborValue::Array(vec![CborValue::Int(99)]), + ]), + CborValue::Int(3), + ])); + } + + #[test] + fn round_trip_empty_array() { + round_trip(&CborValue::Array(vec![])); + } + + // --- Map --- + + #[test] + fn round_trip_map_int_keys() { + round_trip(&CborValue::Map(vec![ + (CborValue::Int(1), CborValue::TextString("one".into())), + (CborValue::Int(2), CborValue::TextString("two".into())), + ])); + } + + #[test] + fn round_trip_map_str_keys() { + round_trip(&CborValue::Map(vec![ + ( + CborValue::TextString("name".into()), + CborValue::TextString("alice".into()), + ), + (CborValue::TextString("age".into()), CborValue::Int(30)), + ])); + } + + #[test] + fn round_trip_map_nested_value() { + round_trip(&CborValue::Map(vec![( + CborValue::Int(1), + CborValue::Array(vec![ + CborValue::ByteString(vec![1, 2]), + CborValue::Simple(22), + ]), + )])); + } + + #[test] + fn round_trip_empty_map() { + round_trip(&CborValue::Map(vec![])); + } + + // --- Tagged --- + + #[test] + fn round_trip_tagged() { + round_trip(&CborValue::Tagged { + tag: 18, + payload: Box::new(CborValue::ByteString(b"payload".to_vec())), + }); + } + + #[test] + fn round_trip_tagged_nested() { + round_trip(&CborValue::Tagged { + tag: 1, + payload: Box::new(CborValue::Array(vec![ + CborValue::Int(42), + CborValue::TextString("inside tag".into()), + ])), + }); + } + + // --- Mixed nesting --- + + #[test] + fn round_trip_complex() { + round_trip(&CborValue::Array(vec![ + CborValue::ByteString(vec![0xFF]), + CborValue::Map(vec![ + ( + CborValue::Int(1), + CborValue::Tagged { + tag: 99, + payload: Box::new(CborValue::TextString( + "nested".into(), + )), + }, + ), + ( + CborValue::Int(2), + CborValue::Array(vec![CborValue::Simple(22)]), + ), + ]), + CborValue::Int(-100), + ])); + } + + // --- Accessor: get (array index) --- + + #[test] + fn array_at_item() { + let arr = + CborValue::Array(vec![CborValue::Int(10), CborValue::Int(20)]); + assert_eq!(arr.array_at(0).unwrap(), &CborValue::Int(10)); + assert_eq!(arr.array_at(1).unwrap(), &CborValue::Int(20)); + assert!(arr.array_at(2).is_err()); + } + + #[test] + fn array_at_on_non_array_is_err() { + assert!(CborValue::Int(1).array_at(0).is_err()); + assert!(CborValue::TextString("hi".into()).array_at(0).is_err()); + assert!(CborValue::Map(vec![]).array_at(0).is_err()); + } + + // --- Accessor: map lookup --- + + #[test] + fn map_at_int_key() { + let map = CborValue::Map(vec![ + (CborValue::Int(1), CborValue::TextString("one".into())), + (CborValue::Int(2), CborValue::TextString("two".into())), + ]); + assert_eq!( + map.map_at_int(1).unwrap(), + &CborValue::TextString("one".into()) + ); + assert_eq!( + map.map_at_int(2).unwrap(), + &CborValue::TextString("two".into()) + ); + assert!(map.map_at_int(3).is_err()); + } + + #[test] + fn map_at_str_key() { + let map = CborValue::Map(vec![( + CborValue::TextString("key".into()), + CborValue::Int(42), + )]); + assert_eq!(map.map_at_str("key").unwrap(), &CborValue::Int(42)); + assert!(map.map_at_str("missing").is_err()); + } + + #[test] + fn map_at_invalid_key_type() { + let map = CborValue::Map(vec![]); + let bad_key = CborValue::ByteString(vec![]); + assert!(map.map_at(&bad_key).is_err()); + } + + #[test] + fn map_at_on_non_map_is_err() { + assert!(CborValue::Int(1).map_at_int(0).is_err()); + assert!(CborValue::Array(vec![]).map_at_str("x").is_err()); + } + + // --- Iterators --- + + #[test] + fn iter_array_elements() { + let arr = CborValue::Array(vec![ + CborValue::Int(1), + CborValue::Int(2), + CborValue::Int(3), + ]); + let collected: Vec<_> = arr.iter_array().unwrap().collect(); + assert_eq!(collected.len(), 3); + assert_eq!(collected[0], &CborValue::Int(1)); + } + + #[test] + fn iter_array_on_non_array_is_err() { + assert!(CborValue::Int(1).iter_array().is_err()); + } + + #[test] + fn iter_map_entries() { + let map = CborValue::Map(vec![ + (CborValue::Int(1), CborValue::TextString("a".into())), + (CborValue::Int(2), CborValue::TextString("b".into())), + ]); + let collected: Vec<_> = map.iter_map().unwrap().collect(); + assert_eq!(collected.len(), 2); + assert_eq!(collected[0].0, &CborValue::Int(1)); + } + + #[test] + fn iter_map_on_non_map_is_err() { + assert!(CborValue::Array(vec![]).iter_map().is_err()); + } + + // --- len --- + + #[test] + fn len_array() { + let arr = CborValue::Array(vec![CborValue::Int(1)]); + assert_eq!(arr.len().unwrap(), 1); + } + + #[test] + fn len_map() { + let map = CborValue::Map(vec![(CborValue::Int(1), CborValue::Int(2))]); + assert_eq!(map.len().unwrap(), 1); + } + + #[test] + fn len_on_other_types_is_err() { + assert!(CborValue::Int(0).len().is_err()); + assert!(CborValue::TextString("x".into()).len().is_err()); + } + + // --- Debug --- + + #[test] + fn debug_format() { + let val = + CborValue::Array(vec![CborValue::Int(42), CborValue::Int(-7)]); + let s = format!("{:?}", val); + assert!(s.contains("Int(42)")); + assert!(s.contains("Int(-7)")); + } +} diff --git a/3rdparty/internal/cose-openssl/src/cose.rs b/3rdparty/internal/cose-openssl/src/cose.rs new file mode 100644 index 000000000000..5741751127b7 --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/cose.rs @@ -0,0 +1,528 @@ +use crate::cbor::CborValue; +use crate::ossl_wrappers::{ + EvpKey, KeyType, WhichEC, WhichRSA, ecdsa_der_to_fixed, ecdsa_fixed_to_der, + rsa_pss_md_for_cose_alg, +}; + +#[cfg(feature = "pqc")] +use crate::ossl_wrappers::WhichMLDSA; + +const COSE_SIGN1_TAG: u64 = 18; +const COSE_HEADER_ALG: i64 = 1; +const SIG_STRUCTURE1_CONTEXT: &str = "Signature1"; +const CBOR_SIMPLE_VALUE_NULL: u8 = 22; + +/// Return the COSE algorithm identifier for a given key. +/// https://www.iana.org/assignments/cose/cose.xhtml +fn cose_alg(key: &EvpKey) -> Result { + match &key.typ { + KeyType::EC(WhichEC::P256) => Ok(-7), + KeyType::EC(WhichEC::P384) => Ok(-35), + KeyType::EC(WhichEC::P521) => Ok(-36), + KeyType::RSA(WhichRSA::PS256) => Ok(-37), + KeyType::RSA(WhichRSA::PS384) => Ok(-38), + KeyType::RSA(WhichRSA::PS512) => Ok(-39), + #[cfg(feature = "pqc")] + KeyType::MLDSA(which) => match which { + WhichMLDSA::P44 => Ok(-48), + WhichMLDSA::P65 => Ok(-49), + WhichMLDSA::P87 => Ok(-50), + }, + } +} + +/// Insert alg(1) into a CborValue map, return error if already exists. +fn insert_alg_value( + key: &EvpKey, + phdr: CborValue, +) -> Result { + let mut entries = match phdr { + CborValue::Map(entries) => entries, + _ => { + return Err("Protected header is not a CBOR map".to_string()); + } + }; + + let alg_key = CborValue::Int(COSE_HEADER_ALG); + if entries.iter().any(|(k, _)| k == &alg_key) { + return Err("Algorithm already set in protected header".to_string()); + } + + let alg_val = CborValue::Int(cose_alg(key)?); + entries.insert(0, (alg_key, alg_val)); + + Ok(CborValue::Map(entries)) +} + +/// To-be-signed (TBS). +/// https://www.rfc-editor.org/rfc/rfc9052.html#section-4.4. +fn sig_structure(phdr: &[u8], payload: &[u8]) -> Result, String> { + CborValue::Array(vec![ + CborValue::TextString(SIG_STRUCTURE1_CONTEXT.to_string()), + CborValue::ByteString(phdr.to_vec()), + CborValue::ByteString(vec![]), + CborValue::ByteString(payload.to_vec()), + ]) + .to_bytes() +} + +/// Produce a COSE_Sign1 envelope. +pub fn cose_sign1( + key: &EvpKey, + phdr: CborValue, + uhdr: CborValue, + payload: &[u8], + detached: bool, +) -> Result, String> { + let phdr_with_alg = insert_alg_value(key, phdr)?; + let phdr_bytes = phdr_with_alg.to_bytes()?; + let tbs = sig_structure(&phdr_bytes, payload)?; + let sig = crate::sign::sign(key, &tbs)?; + + let sig = match &key.typ { + KeyType::EC(_) => ecdsa_der_to_fixed(&sig, key.ec_field_size()?)?, + KeyType::RSA(_) => sig, + #[cfg(feature = "pqc")] + KeyType::MLDSA(_) => sig, + }; + + let payload_item = if detached { + CborValue::Simple(CBOR_SIMPLE_VALUE_NULL) + } else { + CborValue::ByteString(payload.to_vec()) + }; + + let envelope = CborValue::Tagged { + tag: COSE_SIGN1_TAG, + payload: Box::new(CborValue::Array(vec![ + CborValue::ByteString(phdr_bytes), + uhdr, + payload_item, + CborValue::ByteString(sig), + ])), + }; + + envelope.to_bytes() +} + +/// Verify a COSE_Sign1 from pre-parsed components. The caller supplies +/// the serialized protected header, payload, fixed-size signature (all +/// as byte slices), and the COSE algorithm integer (e.g. -7 for ES256). +pub fn cose_verify1( + key: &EvpKey, + alg: i64, + phdr: &[u8], + payload: &[u8], + sig: &[u8], +) -> Result { + match &key.typ { + KeyType::RSA(_) => { + // For RSA, accept any PS* algorithm regardless of key size. + rsa_pss_md_for_cose_alg(alg)?; + } + _ => { + let expected_alg = cose_alg(key)?; + if alg != expected_alg { + return Err( + "Algorithm mismatch between supplied alg and key".into() + ); + } + } + } + + let sig = match &key.typ { + KeyType::EC(_) => ecdsa_fixed_to_der(sig, key.ec_field_size()?)?, + KeyType::RSA(_) => sig.to_vec(), + #[cfg(feature = "pqc")] + KeyType::MLDSA(_) => sig.to_vec(), + }; + + let tbs = sig_structure(phdr, payload)?; + + match &key.typ { + KeyType::RSA(_) => { + let md = rsa_pss_md_for_cose_alg(alg)?; + crate::verify::verify_with_md(key, &sig, &tbs, md) + } + _ => crate::verify::verify(key, &sig, &tbs), + } +} + +#[cfg(test)] +mod tests { + use super::*; + fn hex_decode(s: &str) -> Vec { + assert!(s.len() % 2 == 0, "odd-length hex string"); + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) + .collect() + } + + const TEST_PHDR: &str = "A319018B020FA3061A698B72820173736572766963652E6578616D706C652E636F6D02706C65646765722E7369676E6174757265666363662E7631A1647478696465322E313334"; + + /// Helper: sign then verify via the new APIs. + fn sign_and_verify(key_type: KeyType) { + let key = EvpKey::new(key_type).unwrap(); + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"Good boy..."; + + let envelope = cose_sign1(&key, phdr, uhdr, payload, false).unwrap(); + + // Parse envelope to extract raw components for cose_verify1. + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + let alg = cose_alg(&key).unwrap(); + assert!(cose_verify1(&key, alg, &phdr_raw, payload, &sig_raw).unwrap()); + } + + #[test] + fn test_insert_alg() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let phdr_with_alg = insert_alg_value(&key, phdr).unwrap(); + + let alg = phdr_with_alg.map_at_int(COSE_HEADER_ALG).unwrap(); + assert_eq!(alg, &CborValue::Int(cose_alg(&key).unwrap())); + + assert!(insert_alg_value(&key, phdr_with_alg).is_err()); + } + + #[test] + fn cose_ec_p256() { + sign_and_verify(KeyType::EC(WhichEC::P256)); + } + + #[test] + fn cose_ec_p384() { + sign_and_verify(KeyType::EC(WhichEC::P384)); + } + + #[test] + fn cose_ec_p521() { + sign_and_verify(KeyType::EC(WhichEC::P521)); + } + + #[test] + fn cose_detached_payload() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"Good boy..."; + + let envelope = cose_sign1(&key, phdr, uhdr, payload, true).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + assert_eq!(items[2], CborValue::Simple(CBOR_SIMPLE_VALUE_NULL)); + + let alg = cose_alg(&key).unwrap(); + assert!(cose_verify1(&key, alg, &phdr_raw, payload, &sig_raw).unwrap()); + } + + #[test] + fn cose_verify1_wrong_alg() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + assert!(cose_verify1(&key, -35, b"", b"", b"").is_err()); + } + + #[test] + fn cose_with_der_imported_key() { + let original_key = EvpKey::new(KeyType::EC(WhichEC::P384)).unwrap(); + + let priv_der = original_key.to_der_private().unwrap(); + let signing_key = EvpKey::from_der_private(&priv_der).unwrap(); + + let pub_der = original_key.to_der_public().unwrap(); + let verification_key = EvpKey::from_der_public(&pub_der).unwrap(); + + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"test with DER-imported key"; + + let envelope = + cose_sign1(&signing_key, phdr, uhdr, payload, false).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + let alg = cose_alg(&verification_key).unwrap(); + assert!( + cose_verify1(&verification_key, alg, &phdr_raw, payload, &sig_raw) + .unwrap() + ); + } + + #[test] + fn cose_rsa_ps256() { + sign_and_verify(KeyType::RSA(WhichRSA::PS256)); + } + + #[test] + fn cose_rsa_ps384() { + sign_and_verify(KeyType::RSA(WhichRSA::PS384)); + } + + #[test] + fn cose_rsa_ps512() { + sign_and_verify(KeyType::RSA(WhichRSA::PS512)); + } + + #[test] + fn cose_rsa_with_der_imported_key() { + let original_key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + + let priv_der = original_key.to_der_private().unwrap(); + let signing_key = EvpKey::from_der_private(&priv_der).unwrap(); + + let pub_der = original_key.to_der_public().unwrap(); + let verification_key = EvpKey::from_der_public(&pub_der).unwrap(); + + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"RSA with DER-imported key"; + + let envelope = + cose_sign1(&signing_key, phdr, uhdr, payload, false).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + let alg = cose_alg(&verification_key).unwrap(); + assert!( + cose_verify1(&verification_key, alg, &phdr_raw, payload, &sig_raw) + .unwrap() + ); + } + + #[test] + fn cose_rsa_detached_payload() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS384)).unwrap(); + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"RSA detached"; + + let envelope = cose_sign1(&key, phdr, uhdr, payload, true).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + let alg = cose_alg(&key).unwrap(); + assert!(cose_verify1(&key, alg, &phdr_raw, payload, &sig_raw).unwrap()); + } + + /// Sign with a PS256 key (2048-bit RSA) but use SHA-384 (PS384 + /// algorithm). Verify must succeed because the header's algorithm + /// drives the digest, not the key's WhichRSA variant. + #[test] + fn cose_rsa_ps256_key_with_sha384() { + use crate::ossl_wrappers::rsa_pss_md_for_cose_alg; + + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let payload = b"PS256 key, SHA-384 digest"; + + // Build phdr with alg = -38 (PS384) already set. + let phdr_bytes = hex_decode(TEST_PHDR); + let mut phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + if let CborValue::Map(ref mut entries) = phdr { + entries.insert( + 0, + (CborValue::Int(COSE_HEADER_ALG), CborValue::Int(-38)), + ); + } + let phdr_ser = phdr.to_bytes().unwrap(); + + // Build TBS and sign with SHA-384. + let tbs = sig_structure(&phdr_ser, payload).unwrap(); + let md = rsa_pss_md_for_cose_alg(-38).unwrap(); + let sig = crate::sign::sign_with_md(&key, &tbs, md).unwrap(); + + // Verify with PS384 alg. + assert!(cose_verify1(&key, -38, &phdr_ser, payload, &sig).unwrap()); + } + + /// Verify that a &[u8] payload is stored directly in the envelope + /// bstr without double-encoding as bstr(bstr(...)). + #[test] + fn cose_sign1_no_double_encoding() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"test payload"; + + let envelope = cose_sign1(&key, phdr, uhdr, payload, false).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let payload_in_envelope = match &items[2] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("payload not bstr"), + }; + // The envelope payload must equal the raw data, not a + // CBOR-encoded bstr wrapping it. + assert_eq!( + payload_in_envelope, + payload.to_vec(), + "payload double-encoded as bstr(bstr(...))" + ); + } + + #[cfg(feature = "pqc")] + mod pqc_tests { + use super::*; + #[test] + fn cose_mldsa44() { + sign_and_verify(KeyType::MLDSA(WhichMLDSA::P44)); + } + #[test] + fn cose_mldsa65() { + sign_and_verify(KeyType::MLDSA(WhichMLDSA::P65)); + } + #[test] + fn cose_mldsa87() { + sign_and_verify(KeyType::MLDSA(WhichMLDSA::P87)); + } + + #[test] + fn cose_mldsa_with_der_imported_key() { + let original_key = + EvpKey::new(KeyType::MLDSA(WhichMLDSA::P65)).unwrap(); + + let priv_der = original_key.to_der_private().unwrap(); + let signing_key = EvpKey::from_der_private(&priv_der).unwrap(); + + let pub_der = original_key.to_der_public().unwrap(); + let verification_key = EvpKey::from_der_public(&pub_der).unwrap(); + + let phdr_bytes = hex_decode(TEST_PHDR); + let phdr = CborValue::from_bytes(&phdr_bytes).unwrap(); + let uhdr = CborValue::Map(vec![]); + let payload = b"ML-DSA with DER-imported key"; + + let envelope = + cose_sign1(&signing_key, phdr, uhdr, payload, false).unwrap(); + + let parsed = CborValue::from_bytes(&envelope).unwrap(); + let inner = match parsed { + CborValue::Tagged { payload, .. } => *payload, + _ => panic!("not tagged"), + }; + let items = match inner { + CborValue::Array(v) => v, + _ => panic!("not array"), + }; + let phdr_raw = match &items[0] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("phdr not bstr"), + }; + let sig_raw = match &items[3] { + CborValue::ByteString(b) => b.clone(), + _ => panic!("sig not bstr"), + }; + + let alg = cose_alg(&verification_key).unwrap(); + assert!( + cose_verify1( + &verification_key, + alg, + &phdr_raw, + payload, + &sig_raw + ) + .unwrap() + ); + } + } +} diff --git a/3rdparty/internal/cose-openssl/src/lib.rs b/3rdparty/internal/cose-openssl/src/lib.rs new file mode 100644 index 000000000000..ede1c5eb97a6 --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/lib.rs @@ -0,0 +1,12 @@ +mod cbor; +mod cose; +mod ossl_wrappers; +mod sign; +mod verify; + +pub use cbor::CborValue; +pub use cose::{cose_sign1, cose_verify1}; +pub use ossl_wrappers::{EvpKey, KeyType, WhichEC, WhichRSA}; + +#[cfg(feature = "pqc")] +pub use ossl_wrappers::WhichMLDSA; diff --git a/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs b/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs new file mode 100644 index 000000000000..846b51d0b840 --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs @@ -0,0 +1,778 @@ +use openssl_sys as ossl; +use std::ffi::CString; +use std::marker::PhantomData; +use std::ptr; + +// Not exposed by openssl-sys 0.9, but available at link time (OpenSSL 3.0+). +unsafe extern "C" { + fn EVP_PKEY_is_a( + pkey: *const ossl::EVP_PKEY, + name: *const std::ffi::c_char, + ) -> std::ffi::c_int; + + fn EVP_PKEY_get_group_name( + pkey: *const ossl::EVP_PKEY, + name: *mut std::ffi::c_char, + name_sz: usize, + gname_len: *mut usize, + ) -> std::ffi::c_int; +} + +#[cfg(feature = "pqc")] +#[derive(Debug)] +pub enum WhichMLDSA { + P44, + P65, + P87, +} + +#[cfg(feature = "pqc")] +impl WhichMLDSA { + fn openssl_str(&self) -> &'static str { + match self { + WhichMLDSA::P44 => "ML-DSA-44", + WhichMLDSA::P65 => "ML-DSA-65", + WhichMLDSA::P87 => "ML-DSA-87", + } + } +} + +#[derive(Debug)] +pub enum WhichRSA { + PS256, + PS384, + PS512, +} + +impl WhichRSA { + fn key_bits(&self) -> u32 { + match self { + WhichRSA::PS256 => 2048, + WhichRSA::PS384 => 3072, + WhichRSA::PS512 => 4096, + } + } +} + +#[derive(Debug)] +pub enum WhichEC { + P256, + P384, + P521, +} + +impl WhichEC { + fn openssl_str(&self) -> &'static str { + match self { + WhichEC::P256 => "P-256", + WhichEC::P384 => "P-384", + WhichEC::P521 => "P-521", + } + } + + fn openssl_group(&self) -> &'static str { + match self { + WhichEC::P256 => "prime256v1", + WhichEC::P384 => "secp384r1", + WhichEC::P521 => "secp521r1", + } + } +} + +#[derive(Debug)] +pub enum KeyType { + EC(WhichEC), + RSA(WhichRSA), + + #[cfg(feature = "pqc")] + MLDSA(WhichMLDSA), +} + +#[derive(Debug)] +pub struct EvpKey { + pub key: *mut ossl::EVP_PKEY, + pub typ: KeyType, +} + +impl EvpKey { + pub fn new(typ: KeyType) -> Result { + unsafe { + let key = match &typ { + KeyType::EC(which) => { + let crv = CString::new(which.openssl_str()).unwrap(); + let alg = CString::new("EC").unwrap(); + ossl::EVP_PKEY_Q_keygen( + ptr::null_mut(), + ptr::null_mut(), + alg.as_ptr(), + crv.as_ptr(), + ) + } + + KeyType::RSA(which) => { + let alg = CString::new("RSA").unwrap(); + ossl::EVP_PKEY_Q_keygen( + ptr::null_mut(), + ptr::null_mut(), + alg.as_ptr(), + which.key_bits() as std::ffi::c_uint, + ) + } + + #[cfg(feature = "pqc")] + KeyType::MLDSA(which) => { + let alg = CString::new(which.openssl_str()).unwrap(); + ossl::EVP_PKEY_Q_keygen( + ptr::null_mut(), + ptr::null_mut(), + alg.as_ptr(), + ) + } + }; + + if key.is_null() { + return Err("Failed to create signing key".to_string()); + } + + Ok(EvpKey { key, typ }) + } + } + + /// Create an `EvpKey` from a DER-encoded SubjectPublicKeyInfo. + /// Automatically detects key type (EC curve or ML-DSA variant). + pub fn from_der_public(der: &[u8]) -> Result { + let key = unsafe { + let mut ptr = der.as_ptr(); + let key = + ossl::d2i_PUBKEY(ptr::null_mut(), &mut ptr, der.len() as i64); + if key.is_null() { + return Err("Failed to parse DER public key".to_string()); + } + key + }; + + let typ = match Self::detect_key_type_raw(key) { + Ok(t) => t, + Err(e) => { + unsafe { + ossl::EVP_PKEY_free(key); + } + return Err(e); + } + }; + + Ok(EvpKey { key, typ }) + } + + /// Create an `EvpKey` from a DER-encoded private key + /// (PKCS#8 or traditional format). + /// Automatically detects key type (EC curve or ML-DSA variant). + pub fn from_der_private(der: &[u8]) -> Result { + let key = unsafe { + let mut ptr = der.as_ptr(); + let key = ossl::d2i_AutoPrivateKey( + ptr::null_mut(), + &mut ptr, + der.len() as i64, + ); + if key.is_null() { + return Err("Failed to parse DER private key".to_string()); + } + key + }; + + let typ = match Self::detect_key_type_raw(key) { + Ok(t) => t, + Err(e) => { + unsafe { + ossl::EVP_PKEY_free(key); + } + return Err(e); + } + }; + + Ok(EvpKey { key, typ }) + } + + fn detect_key_type_raw( + pkey: *mut ossl::EVP_PKEY, + ) -> Result { + unsafe { + let rsa = CString::new("RSA").unwrap(); + if EVP_PKEY_is_a(pkey as *const _, rsa.as_ptr()) == 1 { + let bits = ossl::EVP_PKEY_bits(pkey); + let which = match bits { + ..=2048 => WhichRSA::PS256, + 2049..=3072 => WhichRSA::PS384, + _ => WhichRSA::PS512, + }; + return Ok(KeyType::RSA(which)); + } + + let ec = CString::new("EC").unwrap(); + if EVP_PKEY_is_a(pkey as *const _, ec.as_ptr()) == 1 { + let mut buf = [0u8; 64]; + let mut len: usize = 0; + if EVP_PKEY_get_group_name( + pkey as *const _, + buf.as_mut_ptr() as *mut std::ffi::c_char, + buf.len(), + &mut len, + ) != 1 + { + return Err("Failed to get EC group name".to_string()); + } + let group = std::str::from_utf8(&buf[..len]) + .map_err(|_| "EC group name is not UTF-8".to_string())?; + + for variant in [WhichEC::P256, WhichEC::P384, WhichEC::P521] { + if group == variant.openssl_group() { + return Ok(KeyType::EC(variant)); + } + } + return Err(format!("Unsupported EC curve: {}", group)); + } + + #[cfg(feature = "pqc")] + for variant in [WhichMLDSA::P44, WhichMLDSA::P65, WhichMLDSA::P87] { + let cname = CString::new(variant.openssl_str()).unwrap(); + if EVP_PKEY_is_a(pkey as *const _, cname.as_ptr()) == 1 { + return Ok(KeyType::MLDSA(variant)); + } + } + + Err("Unsupported key type".to_string()) + } + } + + /// Export the public key as DER-encoded SubjectPublicKeyInfo. + pub fn to_der_public(&self) -> Result, String> { + unsafe { + let mut der_ptr: *mut u8 = ptr::null_mut(); + let len = ossl::i2d_PUBKEY(self.key, &mut der_ptr); + + if len <= 0 || der_ptr.is_null() { + return Err(format!( + "Failed to encode public key to DER (rc={})", + len + )); + } + + // Copy the DER data into a Vec and free the OpenSSL-allocated memory + let der_slice = std::slice::from_raw_parts(der_ptr, len as usize); + let der = der_slice.to_vec(); + ossl::CRYPTO_free( + der_ptr as *mut std::ffi::c_void, + concat!(file!(), "\0").as_ptr() as *const i8, + line!() as i32, + ); + + Ok(der) + } + } + + /// Export the private key as DER-encoded traditional format. + pub fn to_der_private(&self) -> Result, String> { + unsafe { + let mut der_ptr: *mut u8 = ptr::null_mut(); + let len = ossl::i2d_PrivateKey(self.key, &mut der_ptr); + + if len <= 0 || der_ptr.is_null() { + return Err(format!( + "Failed to encode private key to DER (rc={})", + len + )); + } + + let der_slice = std::slice::from_raw_parts(der_ptr, len as usize); + let der = der_slice.to_vec(); + ossl::CRYPTO_free( + der_ptr as *mut std::ffi::c_void, + concat!(file!(), "\0").as_ptr() as *const i8, + line!() as i32, + ); + + Ok(der) + } + } + + /// Compute the EC field-element byte size from the key's bit size. + /// Returns an error if the key is not an EC key. + pub fn ec_field_size(&self) -> Result { + if !matches!(self.typ, KeyType::EC(_)) { + return Err("ec_field_size called on a non-EC key".to_string()); + } + unsafe { + let bits = ossl::EVP_PKEY_bits(self.key); + if bits <= 0 { + return Err("EVP_PKEY_bits failed".to_string()); + } + Ok(((bits + 7) / 8) as usize) + } + } + + /// Return the OpenSSL digest matching the key's COSE algorithm. + /// Returns null for algorithms that do not use a separate digest + /// (e.g. ML-DSA). + pub fn digest(&self) -> *const ossl::EVP_MD { + unsafe { + match &self.typ { + KeyType::EC(WhichEC::P256) => ossl::EVP_sha256(), + KeyType::EC(WhichEC::P384) => ossl::EVP_sha384(), + KeyType::EC(WhichEC::P521) => ossl::EVP_sha512(), + KeyType::RSA(WhichRSA::PS256) => ossl::EVP_sha256(), + KeyType::RSA(WhichRSA::PS384) => ossl::EVP_sha384(), + KeyType::RSA(WhichRSA::PS512) => ossl::EVP_sha512(), + #[cfg(feature = "pqc")] + KeyType::MLDSA(_) => ptr::null(), + } + } + } +} + +impl Drop for EvpKey { + fn drop(&mut self) { + unsafe { + if !self.key.is_null() { + ossl::EVP_PKEY_free(self.key); + } + } + } +} + +// --------------------------------------------------------------------------- +// ECDSA signature format conversion (DER <-> IEEE P1363 fixed-size) +// using OpenSSL's ECDSA_SIG API. +// +// OpenSSL produces/consumes DER-encoded ECDSA signatures: +// SEQUENCE { INTEGER r, INTEGER s } +// +// COSE (RFC 9053) requires the fixed-size (r || s) representation. +// --------------------------------------------------------------------------- + +/// Convert a DER-encoded ECDSA signature to fixed-size (r || s). +pub fn ecdsa_der_to_fixed( + der: &[u8], + field_size: usize, +) -> Result, String> { + unsafe { + let mut p = der.as_ptr(); + let sig = ossl::d2i_ECDSA_SIG( + ptr::null_mut(), + &mut p, + der.len() as std::ffi::c_long, + ); + if sig.is_null() { + return Err("Failed to parse DER ECDSA signature".to_string()); + } + + let mut r: *const ossl::BIGNUM = ptr::null(); + let mut s: *const ossl::BIGNUM = ptr::null(); + ossl::ECDSA_SIG_get0(sig, &mut r, &mut s); + + let mut fixed = vec![0u8; field_size * 2]; + let rc_r = ossl::BN_bn2binpad( + r, + fixed.as_mut_ptr(), + field_size as std::ffi::c_int, + ); + let rc_s = ossl::BN_bn2binpad( + s, + fixed[field_size..].as_mut_ptr(), + field_size as std::ffi::c_int, + ); + ossl::ECDSA_SIG_free(sig); + + if rc_r != field_size as std::ffi::c_int + || rc_s != field_size as std::ffi::c_int + { + return Err("BN_bn2binpad failed for ECDSA r or s".to_string()); + } + + Ok(fixed) + } +} + +/// Convert a fixed-size (r || s) ECDSA signature to DER. +pub fn ecdsa_fixed_to_der( + fixed: &[u8], + field_size: usize, +) -> Result, String> { + if fixed.len() != field_size * 2 { + return Err(format!( + "Expected {} byte ECDSA signature, got {}", + field_size * 2, + fixed.len() + )); + } + + unsafe { + let r = ossl::BN_bin2bn( + fixed.as_ptr(), + field_size as std::ffi::c_int, + ptr::null_mut(), + ); + if r.is_null() { + return Err("BN_bin2bn failed for ECDSA r".to_string()); + } + + let s = ossl::BN_bin2bn( + fixed[field_size..].as_ptr(), + field_size as std::ffi::c_int, + ptr::null_mut(), + ); + if s.is_null() { + ossl::BN_free(r); + return Err("BN_bin2bn failed for ECDSA s".to_string()); + } + + let sig = ossl::ECDSA_SIG_new(); + if sig.is_null() { + ossl::BN_free(r); + ossl::BN_free(s); + return Err("ECDSA_SIG_new failed".to_string()); + } + + if ossl::ECDSA_SIG_set0(sig, r, s) != 1 { + ossl::ECDSA_SIG_free(sig); + ossl::BN_free(r); + ossl::BN_free(s); + return Err("ECDSA_SIG_set0 failed".to_string()); + } + // ECDSA_SIG_set0 takes ownership of r and s on success. + + let mut out_ptr: *mut u8 = ptr::null_mut(); + let len = ossl::i2d_ECDSA_SIG(sig, &mut out_ptr); + ossl::ECDSA_SIG_free(sig); + + if len <= 0 || out_ptr.is_null() { + return Err("i2d_ECDSA_SIG failed".to_string()); + } + + let der = std::slice::from_raw_parts(out_ptr, len as usize).to_vec(); + ossl::CRYPTO_free( + out_ptr as *mut std::ffi::c_void, + concat!(file!(), "\0").as_ptr() as *const i8, + line!() as i32, + ); + + Ok(der) + } +} + +#[derive(Debug)] +pub struct EvpMdContext { + op: PhantomData, + pub ctx: *mut ossl::EVP_MD_CTX, +} + +pub struct SignOp; +pub struct VerifyOp; + +pub trait ContextInit { + fn init( + ctx: *mut ossl::EVP_MD_CTX, + md: *const ossl::EVP_MD, + key: *mut ossl::EVP_PKEY, + pctx_out: *mut *mut ossl::EVP_PKEY_CTX, + ) -> Result<(), i32>; + fn purpose() -> &'static str; +} + +impl ContextInit for SignOp { + fn init( + ctx: *mut ossl::EVP_MD_CTX, + md: *const ossl::EVP_MD, + key: *mut ossl::EVP_PKEY, + pctx_out: *mut *mut ossl::EVP_PKEY_CTX, + ) -> Result<(), i32> { + unsafe { + let rc = ossl::EVP_DigestSignInit( + ctx, + pctx_out, + md, + ptr::null_mut(), + key, + ); + match rc { + 1 => Ok(()), + err => Err(err), + } + } + } + fn purpose() -> &'static str { + "Sign" + } +} + +impl ContextInit for VerifyOp { + fn init( + ctx: *mut ossl::EVP_MD_CTX, + md: *const ossl::EVP_MD, + key: *mut ossl::EVP_PKEY, + pctx_out: *mut *mut ossl::EVP_PKEY_CTX, + ) -> Result<(), i32> { + unsafe { + let rc = ossl::EVP_DigestVerifyInit( + ctx, + pctx_out, + md, + ptr::null_mut(), + key, + ); + match rc { + 1 => Ok(()), + err => Err(err), + } + } + } + fn purpose() -> &'static str { + "Verify" + } +} + +impl EvpMdContext { + pub fn new(key: &EvpKey) -> Result { + Self::new_with_md(key, key.digest()) + } + + /// Create a context with an explicit digest, allowing the caller + /// to override the digest that `key.digest()` would return. + pub fn new_with_md( + key: &EvpKey, + md: *const ossl::EVP_MD, + ) -> Result { + unsafe { + let ctx = ossl::EVP_MD_CTX_new(); + if ctx.is_null() { + return Err(format!( + "Failed to create ctx for: {}", + T::purpose() + )); + } + let mut pctx: *mut ossl::EVP_PKEY_CTX = ptr::null_mut(); + if let Err(err) = T::init(ctx, md, key.key, &mut pctx) { + ossl::EVP_MD_CTX_free(ctx); + return Err(format!( + "Failed to init context for {} with err {}", + T::purpose(), + err + )); + } + // For RSA keys, configure PSS padding. + if matches!(key.typ, KeyType::RSA(_)) && !pctx.is_null() { + const RSA_PSS_SALTLEN_DIGEST: std::ffi::c_int = -1; + if ossl::EVP_PKEY_CTX_set_rsa_padding( + pctx, + ossl::RSA_PKCS1_PSS_PADDING, + ) != 1 + { + ossl::EVP_MD_CTX_free(ctx); + return Err("Failed to set RSA PSS padding".into()); + } + if ossl::EVP_PKEY_CTX_set_rsa_pss_saltlen( + pctx, + RSA_PSS_SALTLEN_DIGEST, + ) != 1 + { + ossl::EVP_MD_CTX_free(ctx); + return Err("Failed to set RSA PSS salt length".into()); + } + } + Ok(EvpMdContext { + op: PhantomData, + ctx, + }) + } + } +} + +/// Return the OpenSSL digest for the given COSE RSA-PSS algorithm ID. +pub fn rsa_pss_md_for_cose_alg( + alg: i64, +) -> Result<*const ossl::EVP_MD, String> { + unsafe { + match alg { + -37 => Ok(ossl::EVP_sha256()), + -38 => Ok(ossl::EVP_sha384()), + -39 => Ok(ossl::EVP_sha512()), + _ => Err(format!("{alg} is not a COSE RSA-PSS algorithm")), + } + } +} + +impl Drop for EvpMdContext { + fn drop(&mut self) { + unsafe { + if !self.ctx.is_null() { + ossl::EVP_MD_CTX_free(self.ctx); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[cfg(feature = "pqc")] + fn create_ml_dsa_keys() { + assert!(EvpKey::new(KeyType::MLDSA(WhichMLDSA::P44)).is_ok()); + assert!(EvpKey::new(KeyType::MLDSA(WhichMLDSA::P65)).is_ok()); + assert!(EvpKey::new(KeyType::MLDSA(WhichMLDSA::P87)).is_ok()); + } + + #[test] + fn create_ec_keys() { + assert!(EvpKey::new(KeyType::EC(WhichEC::P256)).is_ok()); + assert!(EvpKey::new(KeyType::EC(WhichEC::P384)).is_ok()); + assert!(EvpKey::new(KeyType::EC(WhichEC::P521)).is_ok()); + } + + #[test] + fn create_rsa_keys() { + assert!(EvpKey::new(KeyType::RSA(WhichRSA::PS256)).is_ok()); + assert!(EvpKey::new(KeyType::RSA(WhichRSA::PS384)).is_ok()); + assert!(EvpKey::new(KeyType::RSA(WhichRSA::PS512)).is_ok()); + } + + #[test] + fn rsa_key_der_roundtrip() { + for which in [WhichRSA::PS256, WhichRSA::PS384, WhichRSA::PS512] { + let key = EvpKey::new(KeyType::RSA(which)).unwrap(); + let der = key.to_der_public().unwrap(); + let imported = EvpKey::from_der_public(&der).unwrap(); + assert!( + matches!(imported.typ, KeyType::RSA(_)), + "Expected RSA key type" + ); + let der2 = imported.to_der_public().unwrap(); + assert_eq!(der, der2); + } + } + + #[test] + fn rsa_key_private_der_roundtrip() { + for which in [WhichRSA::PS256, WhichRSA::PS384, WhichRSA::PS512] { + let key = EvpKey::new(KeyType::RSA(which)).unwrap(); + let priv_der = key.to_der_private().unwrap(); + let imported = EvpKey::from_der_private(&priv_der).unwrap(); + assert!( + matches!(imported.typ, KeyType::RSA(_)), + "Expected RSA key type" + ); + let priv_der2 = imported.to_der_private().unwrap(); + assert_eq!(priv_der, priv_der2); + + let pub1 = key.to_der_public().unwrap(); + let pub2 = imported.to_der_public().unwrap(); + assert_eq!(pub1, pub2); + } + } + + #[test] + fn ec_key_from_der_roundtrip() { + for which in [WhichEC::P256, WhichEC::P384, WhichEC::P521] { + let key = EvpKey::new(KeyType::EC(which)).unwrap(); + let der = key.to_der_public().unwrap(); + let imported = EvpKey::from_der_public(&der).unwrap(); + assert!( + matches!(imported.typ, KeyType::EC(_)), + "Expected EC key type" + ); + + // Verify the reimported key exports the same DER + let der2 = imported.to_der_public().unwrap(); + assert_eq!(der, der2); + } + } + + #[test] + fn ec_key_from_der_p256() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let der = key.to_der_public().unwrap(); + let imported = EvpKey::from_der_public(&der).unwrap(); + + assert!(matches!(imported.typ, KeyType::EC(WhichEC::P256))); + } + + #[test] + fn from_der_rejects_garbage() { + assert!(EvpKey::from_der_public(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + } + + #[test] + fn from_der_private_rejects_garbage() { + assert!(EvpKey::from_der_private(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + } + + #[test] + fn ec_key_private_der_roundtrip() { + for which in [WhichEC::P256, WhichEC::P384, WhichEC::P521] { + let key = EvpKey::new(KeyType::EC(which)).unwrap(); + let priv_der = key.to_der_private().unwrap(); + let imported = EvpKey::from_der_private(&priv_der).unwrap(); + assert!( + matches!(imported.typ, KeyType::EC(_)), + "Expected EC key type" + ); + + // Private key re-export must be identical. + let priv_der2 = imported.to_der_private().unwrap(); + assert_eq!(priv_der, priv_der2); + + // Public key extracted from the reimported private key must + // match the original. + let pub1 = key.to_der_public().unwrap(); + let pub2 = imported.to_der_public().unwrap(); + assert_eq!(pub1, pub2); + } + } + + #[test] + #[cfg(feature = "pqc")] + fn ml_dsa_key_from_der_roundtrip() { + for which in [WhichMLDSA::P44, WhichMLDSA::P65, WhichMLDSA::P87] { + let key = EvpKey::new(KeyType::MLDSA(which)).unwrap(); + let der = key.to_der_public().unwrap(); + let imported = EvpKey::from_der_public(&der).unwrap(); + assert!( + matches!(imported.typ, KeyType::MLDSA(_)), + "Expected ML-DSA key type" + ); + let der2 = imported.to_der_public().unwrap(); + assert_eq!(der, der2); + } + } + + #[test] + #[cfg(feature = "pqc")] + fn ml_dsa_key_private_der_roundtrip() { + for which in [WhichMLDSA::P44, WhichMLDSA::P65, WhichMLDSA::P87] { + let key = EvpKey::new(KeyType::MLDSA(which)).unwrap(); + let priv_der = key.to_der_private().unwrap(); + let imported = EvpKey::from_der_private(&priv_der).unwrap(); + assert!( + matches!(imported.typ, KeyType::MLDSA(_)), + "Expected ML-DSA key type" + ); + + // Private key re-export must be identical. + let priv_der2 = imported.to_der_private().unwrap(); + assert_eq!(priv_der, priv_der2); + + let pub1 = key.to_der_public().unwrap(); + let pub2 = imported.to_der_public().unwrap(); + assert_eq!(pub1, pub2); + } + } + + #[test] + #[ignore] + fn intentional_leak_for_sanitizer_validation() { + // This test intentionally leaks memory to verify sanitizers + // detect it if not ignored. + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + std::mem::forget(key); + } +} diff --git a/3rdparty/internal/cose-openssl/src/sign.rs b/3rdparty/internal/cose-openssl/src/sign.rs new file mode 100644 index 000000000000..69b7ce9fb45a --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/sign.rs @@ -0,0 +1,57 @@ +use crate::ossl_wrappers::{EvpKey, EvpMdContext, SignOp}; + +use openssl_sys as ossl; +use std::ptr; + +pub fn sign(key: &EvpKey, msg: &[u8]) -> Result, String> { + let ctx = EvpMdContext::::new(key)?; + sign_with_ctx(&ctx, msg) +} + +// Only used in tests to sign with an explicit digest that differs from the key's default. +#[cfg(test)] +pub fn sign_with_md( + key: &EvpKey, + msg: &[u8], + md: *const ossl::EVP_MD, +) -> Result, String> { + let ctx = EvpMdContext::::new_with_md(key, md)?; + sign_with_ctx(&ctx, msg) +} + +fn sign_with_ctx( + ctx: &EvpMdContext, + msg: &[u8], +) -> Result, String> { + unsafe { + let mut sig_size: usize = 0; + let res = ossl::EVP_DigestSign( + ctx.ctx, + ptr::null_mut(), + &mut sig_size, + msg.as_ptr(), + msg.len(), + ); + if res != 1 { + return Err(format!("Failed to signature size, err: {}", res)); + } + + let mut sig = vec![0u8; sig_size]; + let res = ossl::EVP_DigestSign( + ctx.ctx, + sig.as_mut_ptr(), + &mut sig_size, + msg.as_ptr(), + msg.len(), + ); + if res != 1 { + return Err(format!("Failed to sign, err: {}", res)); + } + + // Not always fixed size, e.g. for EC keys. More on this here: + // https://docs.openssl.org/3.0/man3/EVP_DigestSignInit/#description. + sig.truncate(sig_size); + + Ok(sig) + } +} diff --git a/3rdparty/internal/cose-openssl/src/verify.rs b/3rdparty/internal/cose-openssl/src/verify.rs new file mode 100644 index 000000000000..5cdafcdbb68a --- /dev/null +++ b/3rdparty/internal/cose-openssl/src/verify.rs @@ -0,0 +1,40 @@ +use crate::ossl_wrappers::{EvpKey, EvpMdContext, VerifyOp}; + +use openssl_sys as ossl; + +pub fn verify(key: &EvpKey, sig: &[u8], msg: &[u8]) -> Result { + let ctx = EvpMdContext::::new(key)?; + verify_with_ctx(&ctx, sig, msg) +} + +pub fn verify_with_md( + key: &EvpKey, + sig: &[u8], + msg: &[u8], + md: *const ossl::EVP_MD, +) -> Result { + let ctx = EvpMdContext::::new_with_md(key, md)?; + verify_with_ctx(&ctx, sig, msg) +} + +fn verify_with_ctx( + ctx: &EvpMdContext, + sig: &[u8], + msg: &[u8], +) -> Result { + unsafe { + let res = ossl::EVP_DigestVerify( + ctx.ctx, + sig.as_ptr(), + sig.len(), + msg.as_ptr(), + msg.len(), + ); + + match res { + 1 => Ok(true), + 0 => Ok(false), + err => Err(format!("Failed to verify signature, err: {}", err)), + } + } +} diff --git a/3rdparty/internal/t_cose/.github/workflows/ci.yml b/3rdparty/internal/t_cose/.github/workflows/ci.yml deleted file mode 100644 index 50f77ac0939f..000000000000 --- a/3rdparty/internal/t_cose/.github/workflows/ci.yml +++ /dev/null @@ -1,101 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - main: - strategy: - fail-fast: false - matrix: - c-compiler: [gcc, clang] - - config: - # OpenSSL 1.1.1 (Ubuntu 20.04) - - os-image: ubuntu-latest - container: ubuntu:20.04 - crypto-provider: OpenSSL - - # OpenSSL 3.0 (Ubuntu 22.04) - - os-image: ubuntu-latest - container: ubuntu:22.04 - crypto-provider: OpenSSL - - - os-image: ubuntu-latest - container: ubuntu:20.04 - crypto-provider: MbedTLS - crypto-provider-version: '2.28.0' - - - os-image: ubuntu-latest - container: ubuntu:20.04 - crypto-provider: MbedTLS - crypto-provider-version: '3.1.0' - - - os-image: ubuntu-latest - container: ubuntu:20.04 - crypto-provider: Test - - name: ${{ matrix.config.crypto-provider }} ${{ matrix.config.crypto-provider-version }} • ${{ matrix.c-compiler }} • ${{ matrix.config.container }} - - runs-on: ${{ matrix.config.os-image }} - container: ${{ matrix.config.container }} - - steps: - - uses: actions/checkout@v3 - - - name: Install build tools - run: | - set -ex - export DEBIAN_FRONTEND=noninteractive - apt-get update - apt-get install -y build-essential cmake python3 ${{ matrix.c-compiler }} - echo "CC=${{ matrix.c-compiler }}" >> $GITHUB_ENV - - - name: Install OpenSSL - if: matrix.config.crypto-provider == 'OpenSSL' - run: apt-get install -y libssl-dev - - - name: Fetch MbedTLS - if: matrix.config.crypto-provider == 'MbedTLS' - uses: actions/checkout@v3 - with: - repository: ARMmbed/mbedtls - ref: v${{ matrix.config.crypto-provider-version }} - path: mbedtls - - - name: Install MbedTLS - if: matrix.config.crypto-provider == 'MbedTLS' - run: | - cd mbedtls - make -j $(nproc) - make install - - - name: Fetch QCBOR - uses: actions/checkout@v3 - with: - repository: laurencelundblade/QCBOR - path: QCBOR - - - name: Install QCBOR - run: | - cd QCBOR - make -j$(nproc) - make install - - - name: Build t_cose - run: | - set -ex - mkdir build - cd build - cmake -DCRYPTO_PROVIDER=${{ matrix.config.crypto-provider }} .. - make -j $(nproc) - - - name: Run OpenSSL example - if: matrix.config.crypto-provider == 'OpenSSL' - run: build/t_cose_basic_example_ossl - - - name: Run MbedTLS example - if: matrix.config.crypto-provider == 'MbedTLS' - run: build/t_cose_basic_example_psa - - - name: Run tests - run: build/t_cose_test diff --git a/3rdparty/internal/t_cose/.github/workflows/pages.yml b/3rdparty/internal/t_cose/.github/workflows/pages.yml deleted file mode 100644 index bc2e45097109..000000000000 --- a/3rdparty/internal/t_cose/.github/workflows/pages.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: GitHub Pages - -on: - push: - branches: - - "master" - workflow_dispatch: - -permissions: read-all - -jobs: - main: - runs-on: ubuntu-latest - - permissions: - contents: write - - steps: - - uses: actions/checkout@v3 - - - name: Install Doxygen - run: sudo apt-get install doxygen - - - name: Run Doxygen - run: doxygen doxygen/t_cose_doxyfile - - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: doxygen/output/html - publish_branch: gh-pages - force_orphan: true diff --git a/3rdparty/internal/t_cose/.gitignore b/3rdparty/internal/t_cose/.gitignore deleted file mode 100644 index 6845d17bd558..000000000000 --- a/3rdparty/internal/t_cose/.gitignore +++ /dev/null @@ -1,62 +0,0 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -# Compiled binaries -t_cose_test -t_cose_basic_example_ossl - -# CMake build folder -build/ - -# Doxygen output folder -doxygen/output diff --git a/3rdparty/internal/t_cose/CMakeLists.txt b/3rdparty/internal/t_cose/CMakeLists.txt deleted file mode 100644 index aca76d525407..000000000000 --- a/3rdparty/internal/t_cose/CMakeLists.txt +++ /dev/null @@ -1,136 +0,0 @@ -cmake_minimum_required(VERSION 3.12) -project(t_cose - DESCRIPTION "t_cose" - LANGUAGES C - VERSION 1.1.3) - -# Constants -set(CRYPTO_PROVIDERS "OpenSSL" "MbedTLS" "Test") - -# Project options -set(CRYPTO_PROVIDER "OpenSSL" CACHE STRING "The crypto provider to use: ${CRYPTO_PROVIDERS}") -set(BUILD_TESTS ON CACHE BOOL "Build tests") -set(BUILD_EXAMPLES ON CACHE BOOL "Build examples") - -if (NOT CRYPTO_PROVIDER IN_LIST CRYPTO_PROVIDERS) - message(FATAL_ERROR "CRYPTO_PROVIDER must be one of ${CRYPTO_PROVIDERS}") -endif() - -# Built-in CMake options -set(BUILD_SHARED_LIBS OFF CACHE BOOL "Create shared instead of static libraries") - -# Used in find_package() calls as preferred search paths -set(QCBOR_ROOT "" CACHE PATH "Installation prefix of QCBOR") -set(MbedTLS_ROOT "" CACHE PATH "Installation prefix of MbedTLS") -set(OpenSSL_ROOT "" CACHE PATH "Installation prefix of OpenSSL") - -if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "No build type selected, defaulting to Release") - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) -endif() - -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) - -if(CRYPTO_PROVIDER STREQUAL "MbedTLS") - - find_package(MbedTLS REQUIRED) - set(CRYPTO_LIBRARY MbedTLS::MbedCrypto) - set(CRYPTO_COMPILE_DEFS -DT_COSE_USE_PSA_CRYPTO=1) - set(CRYPTO_ADAPTER_SRC crypto_adapters/t_cose_psa_crypto.c) - -elseif(CRYPTO_PROVIDER STREQUAL "OpenSSL") - - find_package(OpenSSL REQUIRED) - set(CRYPTO_LIBRARY OpenSSL::Crypto) - set(CRYPTO_COMPILE_DEFS -DT_COSE_USE_OPENSSL_CRYPTO=1) - set(CRYPTO_ADAPTER_SRC crypto_adapters/t_cose_openssl_crypto.c) - -elseif(CRYPTO_PROVIDER STREQUAL "Test") - - add_library(b_con_hash crypto_adapters/b_con_hash/sha256.c) - target_include_directories(b_con_hash PUBLIC crypto_adapters/b_con_hash) - - set(CRYPTO_LIBRARY b_con_hash) - set(CRYPTO_COMPILE_DEFS -DT_COSE_USE_B_CON_SHA256 -DT_COSE_ENABLE_HASH_FAIL_TEST) - set(CRYPTO_ADAPTER_SRC crypto_adapters/t_cose_test_crypto.c) - -else() - message(FATAL_ERROR "Bug!") -endif() - -# Global compile options applying to all targets -add_compile_options(-pedantic -Wall) - -set(T_COSE_SRC_COMMON - src/t_cose_sign1_sign.c - src/t_cose_parameters.c - src/t_cose_sign1_verify.c - src/t_cose_util.c - src/t_cose_short_circuit.c -) - -find_package(QCBOR REQUIRED) - -add_library(t_cose ${T_COSE_SRC_COMMON} ${CRYPTO_ADAPTER_SRC}) -target_compile_options(t_cose PRIVATE -ffunction-sections) -target_compile_definitions(t_cose PRIVATE ${CRYPTO_COMPILE_DEFS}) -target_include_directories(t_cose PUBLIC inc PRIVATE src) -target_link_libraries(t_cose PUBLIC QCBOR::QCBOR PRIVATE ${CRYPTO_LIBRARY}) - -include(GNUInstallDirs) - -install(TARGETS t_cose - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -) -install(DIRECTORY inc/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -if (BUILD_EXAMPLES) - - if (CRYPTO_PROVIDER STREQUAL "MbedTLS") - add_executable(t_cose_basic_example_psa examples/t_cose_basic_example_psa.c) - target_link_libraries(t_cose_basic_example_psa PRIVATE t_cose ${CRYPTO_LIBRARY}) - elseif (CRYPTO_PROVIDER STREQUAL "OpenSSL") - add_executable(t_cose_basic_example_ossl examples/t_cose_basic_example_ossl.c) - target_link_libraries(t_cose_basic_example_ossl PRIVATE t_cose ${CRYPTO_LIBRARY}) - endif() - -endif() - -if (BUILD_TESTS) - - enable_testing() - - set(TEST_SRC_COMMON - main.c - test/run_tests.c - test/t_cose_make_test_messages.c - test/t_cose_test.c - ) - - if (NOT CRYPTO_PROVIDER STREQUAL "Test") - list(APPEND TEST_SRC_COMMON test/t_cose_sign_verify_test.c) - endif() - - if (CRYPTO_PROVIDER STREQUAL "MbedTLS") - set(TEST_SRC_EXTRA test/t_cose_make_psa_test_key.c) - set(TEST_EXTRA_DEFS) - elseif(CRYPTO_PROVIDER STREQUAL "OpenSSL") - set(TEST_SRC_EXTRA test/t_cose_make_openssl_test_key.c) - set(TEST_EXTRA_DEFS) - elseif(CRYPTO_PROVIDER STREQUAL "Test") - set(TEST_SRC_EXTRA) - set(TEST_EXTRA_DEFS -DT_COSE_ENABLE_HASH_FAIL_TEST -DT_COSE_DISABLE_SIGN_VERIFY_TESTS) - else() - message(FATAL_ERROR "Bug!") - endif() - - add_executable(t_cose_test ${TEST_SRC_COMMON} ${TEST_SRC_EXTRA}) - target_include_directories(t_cose_test PRIVATE src test) - target_link_libraries(t_cose_test PRIVATE t_cose ${CRYPTO_LIBRARY}) - # Crypto defs are needed because the tests include headers from src/ - target_compile_definitions(t_cose_test PRIVATE ${CRYPTO_COMPILE_DEFS} ${TEST_EXTRA_DEFS}) - - add_test(NAME t_cose_test COMMAND t_cose_test) - -endif() diff --git a/3rdparty/internal/t_cose/CONTRIBUTING.md b/3rdparty/internal/t_cose/CONTRIBUTING.md deleted file mode 100644 index 4aa1ffc3c747..000000000000 --- a/3rdparty/internal/t_cose/CONTRIBUTING.md +++ /dev/null @@ -1,180 +0,0 @@ -## Branch strategy - -The master branch is maintained at commercial quality. It only supports -COSE_Sign1. Changes against it must be very complete. Periodically a -new 1.x release is made from the master branch. - -The "dev" branch is to become t_cose 2.0 when it gets to commercial -quality. It is to support COSE_Mac, COSE_Encrypt, multiple signers and -such. PRs to it mainly need to not break the build and the CI. - - -## Tests and CI - -Generally any PR should still have all these tests passing before it -will be merged. - -### Basic tests - -Make will produce the executable t_cose_test. Running it will perform -all the regression tests. When new features are added regression tests -for them must be added here. - -However, it only runs with one crypto library, one compiler and one -set of #defines at a time. See tdv/b.sh for that. - -### CI tests - -GitHub CI is used to provide the general benefit of CI. It gives test -fanout for the standard major crypto libraries and versions, plus -build environments. It does NOT give full fanout for #define -configurations or for other special configurations. See tdv/b.sh for -that. - -The time GitHub CI takes to run must be kept to a few minutes so as to -not cause excess delay in the commit/merge cycle and disrupt the -human workflow. This is the main reason testing done by it is -limited. The full fanout from tdv/b.sh takes tens of minutes so -it can't be run during CI. - -### tdv/b.sh tests - -In the "tdv" repository there are some makes files and build scripts -run the full configuration fan out testing. They are too large and -take too long to run to make them part of normal CI. Here's a few -things they do: - -* Build with a fairly maximal set of compiler warning flags set (e.g., - -Wall) - -* Build and test every combination of `#define` for configuration (this - is what takes a long time) - -* Build for use in a C++ program - -* Measure and output code size - - -## PR Characteristics - -I review PRs pretty thoroughly largely because I assume I am going to -have to provide support for them long term as I aim to make sure this -is high-quality, tested commercial code. No one pays me for this and -there is no team or company behind this. - -Here's a few notes on getting PRs merged: - -* Only change what you need to. Don't beautify code that is not - related to your change. Don't adjust tabs and spaces. Don't fix - spelling mistakes or comment formatting that is not related to the - change. This helps reduce merge conflicts and makes review - easier. If you want to beautify and such, please do, but in - separate PRs so intent is clear. - -* Make sure all the tests mentioned above in Tests and CI are passing - -* Target the right branch. It is fairly easy to change the target - branch of a PR in GitHub. - - - -## Makefile and project files - -There are makefiles for both cmake and regular make. Both sets need to -be kept up to date and functioning. - -The GitHub CI uses cmake. - -There are several "Makefile"s for different crypto -libraries. Generally, a change to one means a change to the others -(though we can probably make that better with a little more work). - - -## Coding Style - -QCBOR uses camelCase and t_cose follows [Arm's coding -guidelines](https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/docs/contributing/coding_guide.rst) -resulting in code with mixed styles. For better or worse, an Arm-style -version of UsefulBuf is created and used and so there is a duplicate -of UsefulBuf. The two are identical. They just have different names. - - -## Features and conditionality - -The goal is for t_cose's use of #defines to be much simpler than most other libraries. - -A couple of principles govern feature variation and conditional compiliation: - -* A #define is NOT required to enable features. All features are "on" by - default. - -* The internal function link dependency of t_cose is designed to work - well with the compiler -dead_strip option so linked object code is - minimized. - -* Attempts to call t_cose APIs or use t_cose features which are not - supported by the crypto library often result in an error code being - returned and sometimes in a link error. - -* The primary use of #defines is to disable features to reduce object - code size for use cases that need small code size. - -### Users of t_cose - -Most users of t_cose do not need to be concerned with #defines as they -are not needed to enable features in the library. All the features are -already enabled. - -Users may find that sometimes they get error codes indicating a -feature isn't supported. This will usually be because the underlying -crypto library they are linking against doesn't support the feature, -not because the feature needs to be enabled in t_cose. - -Users may also find that sometimes they get a link error reporting an -undefined symbol. This will again usually be because the underlying -crypto library being linked against doesn't support the feature. - -For example, t_cose works with several versions of MbedTLS older -versions of which don't support AES key wrap. You can use t_cose with -these older versions just fine as long as you don't call any t_cose -APIs or use any t_cose features that need key wrap. If you do, you'll -probably get a T_COSE_ERR_UNSUPPORTED_XX error. - -If your use case needs small object code, then it may be time to make -use of T_COSE_DISABLE_XXXX #defines and recompile the t_cose library. -But it also might be that the minimized link dependency and --dead_strip does everything you need too. - - -### Contributing to t_cose - -If you are adding a feature to t_cose don't assume that a #define will -be needed and try hard to avoid one. - -Try to implement with minimal symbol/link dependency. One way to do -this is to create a new signer or recipient object just for the -feature. This might involve a new function in the crypto adaptor layer -for a new feature from the crypto library put to use. The new function -is only linked when the new feature is used. - -The crypto layer has a facility for listing and discovering crypto -algorithms that are supported by a particular crypto library. This -facility is mostly used to know what to test, but not exclusively. - -If a feature can work in multiple modes or have multiple behaviors, -don't control that with a #define. Instead control that with an option -flag or with some API methods. That makes install and configuration of -the library simpler. It also works much better for a shared library -because different users of it can use different modes. - -Then, in the end, the only reason to use a #ifdef should be to reduce -object code if there's no other way. - -When an #fdef has to be used, it should be in the least intrusive way -and it shouldn't make the code hard to read. Maybe even restructure -the code a little so the #ifdef is cleaner. - - - - - diff --git a/3rdparty/internal/t_cose/LICENSE b/3rdparty/internal/t_cose/LICENSE deleted file mode 100644 index 8b7974121fdc..000000000000 --- a/3rdparty/internal/t_cose/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2019, Laurence Lundblade -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3rdparty/internal/t_cose/Makefile.ossl b/3rdparty/internal/t_cose/Makefile.ossl deleted file mode 100644 index da00b226e034..000000000000 --- a/3rdparty/internal/t_cose/Makefile.ossl +++ /dev/null @@ -1,142 +0,0 @@ -# Makefile -- UNIX-style make for t_cose using OpenSSL crypto -# -# Copyright (c) 2019-2021, Laurence Lundblade. All rights reserved. -# Copyright (c) 2020, Michael Eckel, Fraunhofer SIT. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# See BSD-3-Clause license in README.md -# - -# ---- comment ---- -# This is for OpenSSL Crypto. Adjust CRYPTO_INC and CRYPTO_LIB for the -# location of the openssl libraries on your build machine. - - -# ---- QCBOR location ---- - -# This is for direct reference to QCBOR that is not installed in -# /usr/local or some system location. The path may need to be -# adjusted for your location of QCBOR. -#QCBOR_DIR=../../QCBOR/master -#QCBOR_INC=-I $(QCBOR_DIR)/inc -#QCBOR_LIB=$(QCBOR_DIR)/libqcbor.a - -# This is for reference to QCBOR that has been installed in -# /usr/local/ or in some system location. This will typically -# use dynamic linking if there is a libqcbor.so -QCBOR_INC=-I /usr/local/include -QCBOR_LIB=-lqcbor - - -# ---- crypto configuration ----- - -# These two are for direct reference to OpenSSL that is not installed -# in /usr/local/ /usr/local or some system location. The path names -# may need to be adjusted for your location of OpenSSL -#CRYPTO_INC=-I ../../openssl/openssl-1.1.1b/include/openssl -I ../../openssl/openssl-1.1.1b/include -#CRYPTO_LIB=../../openssl/openssl-1.1.1b/libcrypto.a - -# These two are for reference to OpenSSL that has been installed in -# /usr/local/ or in some system location. -CRYPTO_LIB=-l crypto -CRYPTO_INC=-I /usr/local/include - -CRYPTO_CONFIG_OPTS=-DT_COSE_USE_OPENSSL_CRYPTO -CRYPTO_OBJ=crypto_adapters/t_cose_openssl_crypto.o -CRYPTO_TEST_OBJ=test/t_cose_make_openssl_test_key.o - - -# ---- compiler configuration ----- -# Optimize for size -C_OPTS=-Os -fPIC - - -# ---- T_COSE Config and test options ---- -TEST_CONFIG_OPTS= -TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test/t_cose_make_test_messages.o $(CRYPTO_TEST_OBJ) - - -# ---- the main body that is invariant ---- -T_COSE_INC=-I inc -I test -I src -ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) -CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) - -SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o - -.PHONY: all install install_headers install_so uninstall clean - -all: libt_cose.a t_cose_test t_cose_basic_example_ossl - -libt_cose.a: $(SRC_OBJ) $(CRYPTO_OBJ) - ar -r $@ $^ - -# The shared library is not made by default because of platform -# variability For example MacOS and Linux behave differently and some -# IoT OS's don't support them at all. -libt_cose.so: $(SRC_OBJ) $(CRYPTO_OBJ) - cc -shared $^ -o $@ $(CRYPTO_LIB) $(QCBOR_LIB) - -t_cose_test: main.o $(TEST_OBJ) libt_cose.a - cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB) - - -t_cose_basic_example_ossl: examples/t_cose_basic_example_ossl.o libt_cose.a - cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB) - - -# ---- Installation ---- -ifeq ($(PREFIX),) - PREFIX := /usr/local -endif - -install: libt_cose.a install_headers - install -d $(DESTDIR)$(PREFIX)/lib/ - install -m 644 libt_cose.a $(DESTDIR)$(PREFIX)/lib/ - -install_headers: $(PUBLIC_INTERFACE) - install -d $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_common.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/q_useful_buf.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_sign1_sign.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_sign1_verify.h $(DESTDIR)$(PREFIX)/include/t_cose - -# The shared library is not installed by default because of platform variability. -install_so: libt_cose.so install_headers - install -m 755 libt_cose.so $(DESTDIR)$(PREFIX)/lib/libt_cose.so.1.0.0 - ln -sf libt_cose.so.1 $(DESTDIR)$(PREFIX)/lib/libt_cose.so - ln -sf libt_cose.so.1.0.0 $(DESTDIR)$(PREFIX)/lib/libt_cose.so.1 - -uninstall: libt_cose.a $(PUBLIC_INTERFACE) - $(RM) -d $(DESTDIR)$(PREFIX)/include/t_cose/* - $(RM) -d $(DESTDIR)$(PREFIX)/include/t_cose/ - $(RM) $(addprefix $(DESTDIR)$(PREFIX)/lib/, \ - libt_cose.a libt_cose.so libt_cose.so.1 libt_cose.so.1.0.0) - -clean: - rm -f $(SRC_OBJ) $(TEST_OBJ) $(CRYPTO_OBJ) t_cose_basic_example_ossl examples/*.o t_cose_test libt_cose.a libt_cose.so main.o - - -# ---- public headers ----- -PUBLIC_INTERFACE=inc/t_cose/t_cose_common.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_sign1_verify.h - -# ---- source dependecies ----- -src/t_cose_util.o: src/t_cose_util.h src/t_cose_standard_constants.h inc/t_cose/t_cose_common.h src/t_cose_crypto.h -src/t_cose_sign1_verify.o: inc/t_cose/t_cose_sign1_verify.h src/t_cose_crypto.h src/t_cose_util.h src/t_cose_parameters.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_short_circuit.h -src/t_cose_parameters.o: src/t_cose_parameters.h src/t_cose_standard_constants.h inc/t_cose/t_cose_sign1_verify.h inc/t_cose/t_cose_common.h -src/t_cose_sign1_sign.o: inc/t_cose/t_cose_sign1_sign.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h inc/t_cose/t_cose_common.h src/t_cose_short_circuit.h -src/t_cose_short_circuit.o: src/t_cose_short_circuit.h src/t_cose_standard_constants.h src/t_cose_crypto.h - - -# ---- test dependencies ----- -test/t_cose_test.o: test/t_cose_test.h test/t_cose_make_test_messages.h src/t_cose_crypto.h $(PUBLIC_INTERFACE) -test/t_cose_sign_verify_test.o: test/t_cose_sign_verify_test.h test/t_cose_make_test_messages.h src/t_cose_crypto.h test/t_cose_make_test_pub_key.h $(PUBLIC_INTERFACE) -test/t_cose_make_test_messages.o: test/t_cose_make_test_messages.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h -test/run_test.o: test/run_test.h test/t_cose_test.h test/t_cose_hash_fail_test.h -test/t_cose_make_openssl_test_key.o: test/t_cose_make_test_pub_key.h test/t_cose_rsa_test_key.h src/t_cose_standard_constants.h inc/t_cose/t_cose_common.h - -# ---- crypto dependencies ---- -crypto_adapters/t_cose_openssl_crypto.o: src/t_cose_crypto.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h inc/t_cose/q_useful_buf.h - -# ---- example dependencies ---- -examples/t_cose_basic_example_ossl.o: $(PUBLIC_INTERFACE) diff --git a/3rdparty/internal/t_cose/Makefile.psa b/3rdparty/internal/t_cose/Makefile.psa deleted file mode 100644 index 3604beb0eefb..000000000000 --- a/3rdparty/internal/t_cose/Makefile.psa +++ /dev/null @@ -1,144 +0,0 @@ -# Makefile -- UNIX-style make for t_cose using crypto with Mbed Crypto -# Mbed Crypto uses the PSA Crypto interface -# -# Copyright (c) 2019-2021, Laurence Lundblade. All rights reserved. -# Copyright (c) 2020, Michael Eckel, Fraunhofer SIT. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# See BSD-3-Clause license in README.md -# - -# ---- comment ---- -# This is for PSA Crypto / Mbed Crypto. See longer explanation in README.md -# Adjust CRYPTO_INC and CRYPTO_LIB for the -# location of the openssl libraries on your build machine. - - -# ---- QCBOR location ---- - -# This is for direct reference to QCBOR that is not installed in -# /usr/local or some system location. The path may need to be -# adjusted for your location of QCBOR. -#QCBOR_DIR=../../QCBOR/master -#QCBOR_INC=-I $(QCBOR_DIR)/inc -#QCBOR_LIB=$(QCBOR_DIR)/libqcbor.a - -# This is for reference to QCBOR that has been installed in -# /usr/local/ or in some system location. This will typically -# use dynamic linking if there is a libqcbor.so -QCBOR_INC=-I /usr/local/include -QCBOR_LIB=-lqcbor - - -# ---- crypto configuration ----- - -# These two are for direct reference to Mbed Crypto that is not installed -# in /usr/local/ /usr/local or some system location. The path names -# may need to be adjusted for your location of Mbed Crypto -#CRYPTO_INC=-I ../../mbedtls/include/ -#CRYPTO_LIB=../../mbedtls/library/libmbedcrypto.a - -# These two are for reference to Mbed Crypto that has been installed in -# /usr/local/ or in some system location. -CRYPTO_LIB=-l mbedcrypto -CRYPTO_INC=-I /usr/local/include - -CRYPTO_CONFIG_OPTS=-DT_COSE_USE_PSA_CRYPTO -CRYPTO_OBJ=crypto_adapters/t_cose_psa_crypto.o -CRYPTO_TEST_OBJ=test/t_cose_make_psa_test_key.o - - -# ---- compiler configuration ----- -# Optimize for size -C_OPTS=-Os -fPIC - - -# ---- T_COSE Config and test options ---- -TEST_CONFIG_OPTS= -TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test/t_cose_make_test_messages.o $(CRYPTO_TEST_OBJ) - - -# ---- the main body that is invariant ---- -T_COSE_INC=-I inc -I test -I src -ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) -CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) - -SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o - -.PHONY: all install install_headers install_so uninstall clean - -all: libt_cose.a t_cose_test t_cose_basic_example_psa - -libt_cose.a: $(SRC_OBJ) $(CRYPTO_OBJ) - ar -r $@ $^ - -# The shared library is not made by default because of platform -# variability For example MacOS and Linux behave differently and some -# IoT OS's don't support them at all. -libt_cose.so: $(SRC_OBJ) $(CRYPTO_OBJ) - cc -shared $^ -o $@ $(CRYPTO_LIB) $(QCBOR_LIB) - -t_cose_test: main.o $(TEST_OBJ) libt_cose.a - cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB) - - -t_cose_basic_example_psa: examples/t_cose_basic_example_psa.o libt_cose.a - cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB) - - -# ---- Installation ---- -ifeq ($(PREFIX),) - PREFIX := /usr/local -endif - -install: libt_cose.a install_headers - install -d $(DESTDIR)$(PREFIX)/lib/ - install -m 644 libt_cose.a $(DESTDIR)$(PREFIX)/lib/ - -install_headers: $(PUBLIC_INTERFACE) - install -d $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_common.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/q_useful_buf.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_sign1_sign.h $(DESTDIR)$(PREFIX)/include/t_cose - install -m 644 inc/t_cose/t_cose_sign1_verify.h $(DESTDIR)$(PREFIX)/include/t_cose - -# The shared library is not installed by default because of platform variability. -install_so: libt_cose.so install_headers - install -m 755 libt_cose.so $(DESTDIR)$(PREFIX)/lib/libt_cose.so.1.0.0 - ln -sf libt_cose.so.1 $(DESTDIR)$(PREFIX)/lib/libt_cose.so - ln -sf libt_cose.so.1.0.0 $(DESTDIR)$(PREFIX)/lib/libt_cose.so.1 - -uninstall: libt_cose.a $(PUBLIC_INTERFACE) - $(RM) -d $(DESTDIR)$(PREFIX)/include/t_cose/* - $(RM) -d $(DESTDIR)$(PREFIX)/include/t_cose/ - $(RM) $(addprefix $(DESTDIR)$(PREFIX)/lib/, \ - libt_cose.a libt_cose.so libt_cose.so.1 libt_cose.so.1.0.0) - -clean: - rm -f $(SRC_OBJ) $(TEST_OBJ) $(CRYPTO_OBJ) t_cose_basic_example_psa t_cose_test libt_cose.a libt_cose.so examples/*.o main.o - - -# ---- public headers ----- -PUBLIC_INTERFACE=inc/t_cose/t_cose_common.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_sign1_verify.h - -# ---- source dependecies ----- -src/t_cose_util.o: src/t_cose_util.h src/t_cose_standard_constants.h inc/t_cose/t_cose_common.h src/t_cose_crypto.h -src/t_cose_sign1_verify.o: inc/t_cose/t_cose_sign1_verify.h src/t_cose_crypto.h src/t_cose_util.h src/t_cose_parameters.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_short_circuit.h -src/t_cose_parameters.o: src/t_cose_parameters.h src/t_cose_standard_constants.h inc/t_cose/t_cose_sign1_verify.h inc/t_cose/t_cose_common.h -src/t_cose_sign1_sign.o: inc/t_cose/t_cose_sign1_sign.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h inc/t_cose/t_cose_common.h src/t_cose_short_circuit.h -src/t_cose_short_circuit.o: src/t_cose_short_circuit.h src/t_cose_standard_constants.h src/t_cose_crypto.h - - -# ---- test dependencies ----- -test/t_cose_test.o: test/t_cose_test.h test/t_cose_make_test_messages.h src/t_cose_crypto.h $(PUBLIC_INTERFACE) -test/t_cose_sign_verify_test.o: test/t_cose_sign_verify_test.h test/t_cose_make_test_messages.h src/t_cose_crypto.h test/t_cose_make_test_pub_key.h $(PUBLIC_INTERFACE) -test/t_cose_make_test_messages.o: test/t_cose_make_test_messages.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h -test/run_test.o: test/run_test.h test/t_cose_test.h test/t_cose_hash_fail_test.h -test/t_cose_make_psa_test_key.o: test/t_cose_make_test_pub_key.h test/t_cose_rsa_test_key.h src/t_cose_standard_constants.h inc/t_cose/t_cose_common.h - -# ---- crypto dependencies ---- -crypto_adapters/t_cose_psa_crypto.o: src/t_cose_crypto.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h inc/t_cose/q_useful_buf.h - -# ---- example dependencies ---- -examples/t_cose_basic_example_psa.o: $(PUBLIC_INTERFACE) diff --git a/3rdparty/internal/t_cose/Makefile.test b/3rdparty/internal/t_cose/Makefile.test deleted file mode 100644 index c5d40049bfcb..000000000000 --- a/3rdparty/internal/t_cose/Makefile.test +++ /dev/null @@ -1,91 +0,0 @@ -# Makefile -- UNIX-style make for no-crypto test config for t_cose -# -# Copyright (c) 2019-2022, Laurence Lundblade. All rights reserved. -# Copyright (c) 2020, Michael Eckel, Fraunhofer SIT. -# -# SPDX-License-Identifier: BSD-3-Clause -# -# See BSD-3-Clause license in README.md -# - -# ---- comment ---- -# This t_cose makefile is for test crypto -# It has no dependency on any external crypto library, but doesn't -# support real ECDSA signing. The only external code needed is QCBOR. - - -# ---- QCBOR location ---- -# Adjust this to the location of QCBOR in your build environment -#QCBOR_DIR=../../QCBOR/master -#QCBOR_INC=-I $(QCBOR_DIR)/inc -#QCBOR_LIB=$(QCBOR_DIR)/libqcbor.a - -QCBOR_INC= -I/usr/include -I/usr/local/include -QCBOR_LIB= -l qcbor - - -# ---- crypto configuration ----- -# Uses only the internal Brad Conte hash implementation that is bundled with t_cose -CRYPTO_INC=-I crypto_adapters/b_con_hash -CRYPTO_LIB= -CRYPTO_CONFIG_OPTS=-DT_COSE_USE_B_CON_SHA256 -CRYPTO_OBJ=crypto_adapters/t_cose_test_crypto.o crypto_adapters/b_con_hash/sha256.o -CRYPTO_TEST_OBJ= - - -# ---- compiler configuration ----- -# Optimize for size -C_OPTS=-Os -fPIC - - -# ---- T_COSE Config and test options ---- -TEST_CONFIG_OPTS=-DT_COSE_ENABLE_HASH_FAIL_TEST -DT_COSE_DISABLE_SIGN_VERIFY_TESTS -TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_make_test_messages.o $(CRYPTO_TEST_OBJ) - - -# ---- the main body that is invariant ---- -T_COSE_INC=-I inc -I test -I src -ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) -CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) - -SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o - -.PHONY: all clean - -all: libt_cose.a t_cose_test - - -libt_cose.a: $(SRC_OBJ) $(CRYPTO_OBJ) - ar -r $@ $^ - -libt_cose.so: $(SRC_OBJ) $(CRYPTO_OBJ) - cc $^ $(CFLAGS) -dead_strip -o $@ -shared $(QCBOR_LIB) $(CRYPTO_LIB) - -t_cose_test: main.o $(TEST_OBJ) libt_cose.a - cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB) - - -clean: - rm -f $(SRC_OBJ) $(TEST_OBJ) $(CRYPTO_OBJ) libt_cose.a libt_cose.so t_cose_test main.o - - -# ---- public headers ----- -PUBLIC_INTERFACE=inc/t_cose/t_cose_common.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_sign1_verify.h - -# ---- source dependecies ----- -src/t_cose_util.o: src/t_cose_util.h src/t_cose_standard_constants.h inc/t_cose/t_cose_common.h src/t_cose_crypto.h -src/t_cose_sign1_verify.o: inc/t_cose/t_cose_sign1_verify.h src/t_cose_crypto.h src/t_cose_util.h src/t_cose_parameters.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_short_circuit.h -src/t_cose_parameters.o: src/t_cose_parameters.h src/t_cose_standard_constants.h inc/t_cose/t_cose_sign1_verify.h inc/t_cose/t_cose_common.h -src/t_cose_sign1_sign.o: inc/t_cose/t_cose_sign1_sign.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h inc/t_cose/t_cose_common.h src/t_cose_short_circuit.h -src/t_cose_short_circuit.o: src/t_cose_short_circuit.h src/t_cose_standard_constants.h src/t_cose_crypto.h - - -# ---- test dependencies ----- -test/t_cose_test.o: test/t_cose_test.h test/t_cose_make_test_messages.h src/t_cose_crypto.h $(PUBLIC_INTERFACE) -test/t_cose_make_test_messages.o: test/t_cose_make_test_messages.h inc/t_cose/t_cose_sign1_sign.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h -test/run_test.o: test/run_test.h test/t_cose_test.h test/t_cose_hash_fail_test.h - - -# ---- crypto dependencies ---- -crypto_adapters/t_cose_test_crypto.o: src/t_cose_crypto.h inc/t_cose/t_cose_common.h src/t_cose_standard_constants.h inc/t_cose/q_useful_buf.h crypto_adapters/b_con_hash/sha256.h -crypto_adapters/b_con_hash/sha256.o: crypto_adapters/b_con_hash/sha256.h diff --git a/3rdparty/internal/t_cose/README.md b/3rdparty/internal/t_cose/README.md deleted file mode 100644 index 56452d4c2e2f..000000000000 --- a/3rdparty/internal/t_cose/README.md +++ /dev/null @@ -1,317 +0,0 @@ -![t_cose](https://github.com/laurencelundblade/t_cose/blob/master/t-cose-logo.png?raw=true) - - -*t_cose* implements enough of COSE to support [CBOR Web Token, RFC 8392](https://tools.ietf.org/html/rfc8392) -and [Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-01). -This is the COSE_Sign1 part of [COSE, RFC 9052](https://tools.ietf.org/html/rfc9052). - -**Implemented in C with minimal dependency** – There are three main -dependencies: 1) [QCBOR](https://github.com/laurencelundblade/QCBOR), -2) A cryptographic library for ECDSA and SHA-2, 3) C99, , -, and . It is highly -portable to different HW, OS's and cryptographic libraries. Except for -some minor configuration for the cryptographic library, no #ifdefs or -compiler options need to be set for it to run correctly. - -**Crypto Library Integration Layer** – Works with different cryptographic -libraries via a simple integration layer. The integration layer is kept small and simple, -just enough for the use cases, so that integration is simpler. Integration layers for -the OpenSSL and ARM Mbed TLS (PSA Cryptography API) cryptographic libraries -are included. - -**Secure coding style** – Uses a construct called UsefulBuf / q_useful_buf as a -discipline for safe coding and handling of binary data. - -**Small simple memory model** – Malloc is not needed. Besides the -cryptographic library and payload buffer, about 600 bytes of heap/stack is needed -for signing and 1500 bytes for verifying. The caller supplies the output buffer -and context structures so the caller has control over memory usage making it -useful for embedded implementations that have to run in small fixed memory. - -## Documentation - -[API documentation is here](https://www.securitytheory.com/t_cose-docs) - - -## Code Status - -As of March 2022, the code is in good working order and the public interface has been -stable for over a year. - -Integration with the [OpenSSL](https://www.openssl.org) and [Arm Mbed -TLS](https://github.com/ARMmbed/mbedtls) cryptographic libraries is -fully supported. - -t_cose 1.0 only supports COSE Sign1, signing with one recipeint. - - -## t_cose 2.0 - -As of August 2022, there are alpha releases of t_cose 2.0. It supports: -* COSE_Sign -* Multiple signatures -* COSE_MAC0 -* COSE_Encrypt and COSE_Encrypt0 -* Encryption with ECDH per RFC 9053 - -See the dev branch and the releases. - -## Building and Dependencies - -Except for the crypto library set up, t_cose is very portable and -should largely just work in any environment. It needs a few standard -libraries and [QCBOR](https://github.com/laurencelundblade/QCBOR) -(which is also very portable). Hence most of this section is about -crypto library set up. - -### QCBOR - -If QCBOR is installed in /usr/local, then the makefiles should find -it. If not then QCBOR may need to be downloaded. The makefiles can be -modified to reference it other than in /usr/local. - -This works with both QCBOR v1 and v2. When running with v2 it -uses the QCBOR v1 compatibility mode for tag decoding. - -### Supported Cryptographic Libraries - -Here's three crypto library configurations that are supported. Others -can be added with relative ease. - -#### Test Crypto -- Makefile.test - -This configuration should work instantly on any device and is useful -to do a large amount of testing with, but can't be put to full -commercial use. What it lacks is integration with an ECDSA -implementation so it can't produce real ECDSA signatures. It does -however produce fake signatures called "short-circuit -signatures" that are very useful for testing. See header -documentation for details on short-circuit sigs. - -This configuration (and only this configuration) uses a bundled -SHA-256 implementation (SHA-256 is simple and easy to bundle, ECDSA is -not). - -To build run: - - make -f Makefile.test - -#### OpenSSL Crypto -- Makefile.ossl - -This OpenSSL integration supports SHA-256, SHA-384 and SHA-512 with -ECDSA, EdDSA, or RSAPSS to support the COSE algorithms ES256, ES384 and -ES512, PS256, PS384 and PS512. It is a full and tested integration -with OpenSSL crypto. - -If OpenSSL is installed in /usr/local or as a standar library, you can -probably just run make: - - make -f Makefile.ossl - -The specific things that Makefile.ossl does is: - * Links the crypto_adapters/t_cose_openssl_crypto.o into libt_cose.a - * Links test/test/t_cose_make_openssl_test_key.o into the test binary - * `#define T_COSE_USE_OPENSSL_CRYPTO` - -t_cose is regularly tested against OpenSSL 1.1.1 and 3.0. - -The crypto adaptor for OpenSSL is about twice the size of that for -Mbed TLS because the API doesn't line up well with the needs for COSE -(OpenSSL is ASN.1/DER oriented). Memory allocation is performed inside -OpenSSL and in the crypto adaptation layer. This makes the OpenSSL -crypto library less suitable for embedded use. - -No deprecated or to-be-deprecated APIs are used. - -There are several different sets of APIs in OpenSSL that can be used -to implement ECDSA and hashing. The ones chosen are the most official -and well-supported, however others might suit particular uses cases -better. An older t_cose used some to-be-deprecated APIs and is a more -efficient than this one. It is unfortunate that these APIs -(ECDSA_do_sign and ECDSA_do_verify) are slated for deprecation and -there is no supported alternative to those that work only with DER-encoded -signatures. - -There are no known problems with the code and test coverage for the -adaptor is good. Not every single memory allocation failure has -test coverage, but the code should handle them all correctly. - - -#### PSA Crypto -- Makefile.psa - -As of March 2022, t_cose works with the PSA 1.0 Crypto API as -implemented by Mbed TLS 2.x and 3.x. - -This integration supports SHA-256, SHA-384 and SHA-512 with -ECDSA, EdDSA or RSAPSS to support the COSE algorithms ES256, ES384 and -ES512, PS256, PS384 and PS512. - -If Mbed TLS is installed in /usr/local, you can probably just run -make: - - make -f Makefile.psa - -If this doesn't work or you have Mbed TLS elsewhere edit the makefile. - -The specific things that Makefile.psa does is: - * Links the crypto_adapters/t_cose_psa_crypto.o into libt_cose.a - * Links test/test/t_cose_make_psa_test_key.o into the test binary - * `#define T_COSE_USE_PSA_CRYPTO` - -This crypto adapter is small and simple. The adapter allocates no -memory and as far as I know it internally allocates no memory. It is a -good choice for embedded use. - -It makes use of the 1.0 version of the PSA cryptographic API. No -deprecated or to-be-deprecated functions are called (an older t_cose -used some to be deprecated APIs). - -It is regularly tested against the latest version 2 and version 3 of -Mbed TLS, an implementation of the PSA crypto API. - -Confidence in the adaptor code is high and reasonably well tested -because it is simple. - - -### General Crypto Library Strategy - -The functions that t_cose needs from the crypto library are all -defined in src/t_cose_crypto.h. This is a porting or adaption -layer. There are no #ifdefs in the main t_cose code for different -crypto libraries. When it needs a crypto function it just calls the -interface defined in t_cose_crypto.h. - -When integrating t_cose with a new cryptographic library, what is -necessary is to write some code, an "adaptor", that implements -t_cose_crypto.h using the new target cryptographic library. This can -be done without changes to any t_cose code for many cryptographic -libraries. See the interface documentation in t_cose_crypto.h for what -needs to be implemented. - -That said, there is one case where t_cose source code needs to be -modified. This is for hash algorithm implementations that are linked -into and run inline with t_cose and that have a context structure. In -this case t_cose_crypto.h should be modified to use that context -structure. Use the OpenSSL configuration as an example. - -To complete the set up for a new cryptographic library and test it, a -new test adaptation file is also needed. This file makes public key -pairs of the correct type for use with testing. This file is usually -named test/t_cose_make_xxxx_test_key.c and is linked in with the test -app. The keys it makes are passed through t_cose untouched, through -the t_cose_crypto.h interface into the underlying crypto. - - -## Memory Usage - -### Code - -Here are code sizes on 64-bit x86 optimized for size - - | | smallest | largest | - |---------------------------|----------|---------| - | signing only | 1500 | 2300 | - | verification only | 2500 | 3300 | - | common to sign and verify | (500)| (800)| - | combined | 3500 | 4800 | - -Things that make the code smaller: -* PSA / Mbed crypto takes less code to interface with than OpenSSL -* gcc is usually smaller than llvm because stack guards are off by default -* Use only 256-bit crypto with the T_COSE_DISABLE_ESXXX options -* Disable short-circut sig debug faclity T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -* Disable the content type header T_COSE_DISABLE_CONTENT_TYPE - -#### Change in code size with spiffy decode - -The encode size is as before. - -Compared to the previous t_cose, the code size for decoding/verifying -is reduced by about 600 bytes. However, spiffy decode functions in -QCBOR are now required and they are about 2KB, so there is a net size -increase of 1.4KB. But use of spiffy decode will also make other parts -of the overall SW stack smaller, perhaps by a lot, so this will likely -break even. For example, EAT or CWT decoding will be reduced a lot -through use of spiffy decode. Basically, the more CBOR maps a SW -stack has to handle, the more saving there will be from spiffy decode. - - -### Heap and stack - -Malloc is not used. - -Stack usage is variable depending on the key and hash size and the -stack usage by the cryptographic library that performs the hash and -public key crypto functions. The maximum requirement is roughly -2KB. This is an estimate from examining the code, not an actual -measurement. - -Since the keys, hash outputs and signatures are stored on the stack, -the stronger the security, the more stack is used. By default up to -512 bit EC is enabled. Disable 512 and 384 bit EC to reduce stack -usage by about 100 bytes. - -Different cryptographic libraries may have very different stack usage -characteristics. For example if one use malloc rather than the stack, -it will (hopefully) use less stack. The guess estimate range of usage -by the cryptographic library is between 64 and 1024 bytes of stack. - -Aside from the cryptographic library, the base stack use by t_cose is -500 bytes for signing and 1500 bytes for verification. With a large -cryptographic library, the total is about 1500 bytes for signing and -2000 bytes for verification (for verification, the crypto library -stack re uses stack used to decode header parameters so the increment -isn't so large). - -The design is such that only one copy of the output, the COSE_Sign1, -need be in memory. It makes use of special features in QCBOR that -allows contstuction of the output including the payload, using just -the single output buffer to accomplish this. - -A buffer to hold the signed COSE result must be passed in. It must be -about 100 bytes larger than the combined size of the payload and key -id for ECDSA 256. It can be allocated as the caller wishes. - -### Crypto library memory usage -In addition to the above memory usage, the crypto library will use -some stack and/or heap memory. This will vary quite a bit by crypto -library. Some may use malloc. Some may not. - -The OpenSSL library does use malloc, even with ECDSA. Another -implementation of ECDSA might not use malloc, as the keys are small -enough. - -### Mixed code style -QCBOR uses camelCase and t_cose follows -[Arm's coding guidelines](https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/docs/contributing/coding_guide.rst) -resulting in code with mixed styles. For better or worse, an Arm-style version of UsefulBuf -is created and used and so there is a duplicate of UsefulBuf. The two are identical. They -just have different names. - -## Limitations - -* Most inputs and outputs must be in a continguous buffer. One - exception to this is that CBOR payloads being signed can be - constructed piecemeal into the output buffer and signed without - using a separate buffer. -* Doesn't handle COSE string algorithm IDs. Only COSE integer - algorithm IDs are handled. Thus far no string algorithm IDs have - been assigned by IANA. -* No way to add custom headers when creating signed messages or - process them during verification. -* Does not handle CBOR indefinite length strings (indefinite length - maps and arrays are handled). -* Counter signatures are not supported. - -## Credit - -* Paul Liétar for RSA PSS (PS256..PS512) and EdDSA -* Maik Riechert for cmake, CI and other. -* Ken Takayama for the bulk of the detached content implementation. -* Tamas Ban for lots code review comments, design ideas and porting to ARM PSA. -* Rob Coombs, Shebu Varghese Kuriakose and other ARM folks for sponsorship. -* Michael Eckel for makefile fixes. - -## Copyright and License - -t_cose is available under the 3-Clause BSD License. diff --git a/3rdparty/internal/t_cose/SECURITY.md b/3rdparty/internal/t_cose/SECURITY.md deleted file mode 100644 index b96d08c28a2d..000000000000 --- a/3rdparty/internal/t_cose/SECURITY.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -Please report security vulnerabilities by sending email to lgl@island-resort.com. -Please include "t_cose SECURITY" in the subject line. - -In most cases the vulnerability should not be reported by filing an issue in GitHub as this -will publically disclose the issue before a fix is available. - -Laurence Lundblade maintains this code and will respond in a day or two with an initial -evaluation. - -Security fixes will be prioritized over other work. - -Vulnerabilities will be fixed promptly, but some may be more complex than others -and take longer. If the fix is quick, it will usually be turned around in a -few days. - -## Availability of Fixes - -When the fix has been created, it will be privately verified with the party that reported it. -Only after the fix has been verified and the reporter has had a chance to integrate the fix, -will it be made available as a public commit in GitHub. - -If the reporter doesn't respond or can't integrate the fix, it will be made public after 30 days. - diff --git a/3rdparty/internal/t_cose/cmake/FindMbedTLS.cmake b/3rdparty/internal/t_cose/cmake/FindMbedTLS.cmake deleted file mode 100644 index feb651f927f3..000000000000 --- a/3rdparty/internal/t_cose/cmake/FindMbedTLS.cmake +++ /dev/null @@ -1,108 +0,0 @@ -#[=======================================================================[.rst: -FindMbedTLS -------- - -Finds the mbedTLS library. - -Imported Targets -^^^^^^^^^^^^^^^^ - -This module provides the following imported targets, if found: - -``MbedTLS::MbedTLS`` - The mbedTLS library - -``MbedTLS::MbedCrypto`` - The mbedTLS crypto library - -``MbedTLS::MbedX509`` - The mbedTLS X509 library - -Result Variables -^^^^^^^^^^^^^^^^ - -This will define the following variables: - -``MbedTLS_FOUND`` - True if the system has the MbedTLS library. -``MbedTLS_INCLUDE_DIRS`` - Include directories needed to use MbedTLS. -``MbedTLS_LIBRARIES`` - Libraries needed to link to MbedTLS. - -Cache Variables -^^^^^^^^^^^^^^^ - -The following cache variables may also be set: - -``MbedTLS_INCLUDE_DIR`` - The directory containing ``mbedtls/``. -``MbedTLS_LIBRARY`` - The path to the mbedtls library. -``MbedTLS_CRYPTO_LIBRARY`` - The path to the mbedcrypto library. -``MbedTLS_X509_LIBRARY`` - The path to the mbedx509 library. - -#]=======================================================================] - -find_path(MbedTLS_INCLUDE_DIR - NAMES mbedtls/version.h -) -find_library(MbedTLS_LIBRARY - NAMES mbedtls -) -find_library(MbedTLS_CRYPTO_LIBRARY - NAMES mbedcrypto -) -find_library(MbedTLS_X509_LIBRARY - NAMES mbedx509 -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MbedTLS - FOUND_VAR MbedTLS_FOUND - REQUIRED_VARS - MbedTLS_LIBRARY - MbedTLS_CRYPTO_LIBRARY - MbedTLS_X509_LIBRARY - MbedTLS_INCLUDE_DIR -) - -if(MbedTLS_FOUND) - set(MbedTLS_LIBRARIES "${MbedTLS_LIBRARY}" "${MbedTLS_X509_LIBRARY}" "${MbedTLS_CRYPTO_LIBRARY}") - set(MbedTLS_INCLUDE_DIRS "${MbedTLS_INCLUDE_DIR}") -endif() - -if(MbedTLS_FOUND AND NOT TARGET MbedTLS::MbedCrypto) - add_library(MbedTLS::MbedCrypto UNKNOWN IMPORTED) - set_target_properties(MbedTLS::MbedCrypto PROPERTIES - IMPORTED_LOCATION "${MbedTLS_CRYPTO_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${MbedTLS_INCLUDE_DIR}" - ) -endif() - -if(MbedTLS_FOUND AND NOT TARGET MbedTLS::MbedX509) - add_library(MbedTLS::MbedX509 UNKNOWN IMPORTED) - set_target_properties(MbedTLS::MbedX509 PROPERTIES - IMPORTED_LOCATION "${MbedTLS_X509_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${MbedTLS_INCLUDE_DIR}" - ) - target_link_libraries(MbedTLS::MbedX509 INTERFACE MbedTLS::MbedCrypto) -endif() - -if(MbedTLS_FOUND AND NOT TARGET MbedTLS::MbedTLS) - add_library(MbedTLS::MbedTLS UNKNOWN IMPORTED) - set_target_properties(MbedTLS::MbedTLS PROPERTIES - IMPORTED_LOCATION "${MbedTLS_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${MbedTLS_INCLUDE_DIR}" - ) - target_link_libraries(MbedTLS::MbedX509 INTERFACE MbedTLS::MbedCrypto MbedTLS::MbedX509) -endif() - -mark_as_advanced( - MbedTLS_INCLUDE_DIR - MbedTLS_LIBRARY - MbedTLS_CRYPTO_LIBRARY - MbedTLS_X509_LIBRARY -) diff --git a/3rdparty/internal/t_cose/cmake/FindQCBOR.cmake b/3rdparty/internal/t_cose/cmake/FindQCBOR.cmake deleted file mode 100644 index 1bbd3dc7aea0..000000000000 --- a/3rdparty/internal/t_cose/cmake/FindQCBOR.cmake +++ /dev/null @@ -1,81 +0,0 @@ -#[=======================================================================[.rst: -FindQCBOR -------- - -Finds the QCBOR library. - -Imported Targets -^^^^^^^^^^^^^^^^ - -This module provides the following imported targets, if found: - -``QCBOR::QCBOR`` - The QCBOR library - -Result Variables -^^^^^^^^^^^^^^^^ - -This will define the following variables: - -``QCBOR_FOUND`` - True if the system has the QCBOR library. -``QCBOR_INCLUDE_DIRS`` - Include directories needed to use QCBOR. -``QCBOR_LIBRARIES`` - Libraries needed to link to QCBOR. - -Cache Variables -^^^^^^^^^^^^^^^ - -The following cache variables may also be set: - -``QCBOR_INCLUDE_DIR`` - The directory containing ``t_cose/``. -``QCBOR_LIBRARY`` - The path to the QCBOR library. - -#]=======================================================================] - -include(CheckLibraryExists) - -find_path(QCBOR_INCLUDE_DIR - NAMES qcbor/qcbor.h -) -find_library(QCBOR_LIBRARY - NAMES qcbor -) - -CHECK_LIBRARY_EXISTS(m sin "" HAVE_LIB_M) -set(EXTRA_LIBS) -if(HAVE_LIB_M) - set(EXTRA_LIBS m) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(QCBOR - FOUND_VAR QCBOR_FOUND - REQUIRED_VARS - QCBOR_LIBRARY - QCBOR_INCLUDE_DIR -) - -if(QCBOR_FOUND) - set(QCBOR_LIBRARIES "${QCBOR_LIBRARY} ${EXTRA_LIBS}") - set(QCBOR_INCLUDE_DIRS "${QCBOR_INCLUDE_DIR}") -endif() - -if(QCBOR_FOUND AND NOT TARGET QCBOR::QCBOR) - add_library(QCBOR::QCBOR UNKNOWN IMPORTED) - set_target_properties(QCBOR::QCBOR PROPERTIES - IMPORTED_LOCATION "${QCBOR_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${QCBOR_INCLUDE_DIR}" - ) - if (EXTRA_LIBS) - target_link_libraries(QCBOR::QCBOR INTERFACE ${EXTRA_LIBS}) - endif() -endif() - -mark_as_advanced( - QCBOR_INCLUDE_DIR - QCBOR_LIBRARY -) diff --git a/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.c b/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.c deleted file mode 100644 index 5a5335a0bcae..000000000000 --- a/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.c +++ /dev/null @@ -1,161 +0,0 @@ -/********************************************************************* -* Filename: sha256.c -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Implementation of the SHA-256 hashing algorithm. - SHA-256 is one of the three algorithms in the SHA2 - specification. The others, SHA-384 and SHA-512, are not - offered in this implementation. - Algorithm specification can be found here: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf - This implementation uses little endian byte order. - - * Copyright Laurence Lundblade 2020 for addition of casts so it - compiles without warnings with pendantic compilers settings. -*********************************************************************/ - -/*************************** HEADER FILES ***************************/ -#include -#include -#include "sha256.h" - -/****************************** MACROS ******************************/ -#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) -#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) - -#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) -#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) -#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) - -/**************************** VARIABLES *****************************/ -static const WORD k[64] = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 -}; - -/*********************** FUNCTION DEFINITIONS ***********************/ -void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) -{ - WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; - - for (i = 0, j = 0; i < 16; ++i, j += 4) - m[i] = (WORD)((data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3])); - for ( ; i < 64; ++i) - m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; - - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->state[0] += a; - ctx->state[1] += b; - ctx->state[2] += c; - ctx->state[3] += d; - ctx->state[4] += e; - ctx->state[5] += f; - ctx->state[6] += g; - ctx->state[7] += h; -} - -void sha256_init(SHA256_CTX *ctx) -{ - ctx->datalen = 0; - ctx->bitlen = 0; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; -} - -void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) -{ - WORD i; - - for (i = 0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx, ctx->data); - ctx->bitlen += 512; - ctx->datalen = 0; - } - } -} - -void sha256_final(SHA256_CTX *ctx, BYTE hash[]) -{ - WORD i; - - i = ctx->datalen; - - // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { - ctx->data[i++] = 0x80; - while (i < 56) - ctx->data[i++] = 0x00; - } - else { - ctx->data[i++] = 0x80; - while (i < 64) - ctx->data[i++] = 0x00; - sha256_transform(ctx, ctx->data); - memset(ctx->data, 0, 56); - } - - // Append to the padding the total message's length in bits and transform. - ctx->bitlen += ctx->datalen * 8; - ctx->data[63] = (BYTE)(ctx->bitlen); - ctx->data[62] = (BYTE)(ctx->bitlen >> 8); - ctx->data[61] = (BYTE)(ctx->bitlen >> 16); - ctx->data[60] = (BYTE)(ctx->bitlen >> 24); - ctx->data[59] = (BYTE)(ctx->bitlen >> 32); - ctx->data[58] = (BYTE)(ctx->bitlen >> 40); - ctx->data[57] = (BYTE)(ctx->bitlen >> 48); - ctx->data[56] = (BYTE)(ctx->bitlen >> 56); - sha256_transform(ctx, ctx->data); - - // Since this implementation uses little endian byte ordering and SHA uses big endian, - // reverse all the bytes when copying the final state to the output hash. - for (i = 0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; - hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; - hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; - hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; - hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; - hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; - hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; - hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; - } -} diff --git a/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.h b/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.h deleted file mode 100644 index 7123a30dd496..000000000000 --- a/3rdparty/internal/t_cose/crypto_adapters/b_con_hash/sha256.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************************************************************* -* Filename: sha256.h -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Defines the API for the corresponding SHA1 implementation. -*********************************************************************/ - -#ifndef SHA256_H -#define SHA256_H - -/*************************** HEADER FILES ***************************/ -#include - -/****************************** MACROS ******************************/ -#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest - -/**************************** DATA TYPES ****************************/ -typedef unsigned char BYTE; // 8-bit byte -typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines - -typedef struct { - BYTE data[64]; - WORD datalen; - unsigned long long bitlen; - WORD state[8]; -} SHA256_CTX; - -/*********************** FUNCTION DECLARATIONS **********************/ -void sha256_init(SHA256_CTX *ctx); -void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); -void sha256_final(SHA256_CTX *ctx, BYTE hash[]); - -#endif // SHA256_H diff --git a/3rdparty/internal/t_cose/crypto_adapters/t_cose_openssl_crypto.c b/3rdparty/internal/t_cose/crypto_adapters/t_cose_openssl_crypto.c deleted file mode 100644 index de46507a9267..000000000000 --- a/3rdparty/internal/t_cose/crypto_adapters/t_cose_openssl_crypto.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * t_cose_openssl_crypto.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - * - * Created 3/31/2019. - */ - - -#include "t_cose_crypto.h" /* The interface this code implements */ - -#include /* Needed for signature format conversion */ -#include -#include -#include - -/** - * \file t_cose_openssl_crypto.c - * - * \brief Crypto Adaptation for t_cose to use OpenSSL ECDSA and hashes. - * - * This connects up the abstracted crypto services defined in - * t_cose_crypto.h to the OpenSSL implementation of them. - * - * Having this adapter layer doesn't bloat the implementation as everything here - * had to be done anyway -- the mapping of algorithm IDs, the data format - * rearranging, the error code translation. - * - * This code should just work out of the box if compiled and linked - * against OpenSSL and with the T_COSE_USE_OPENSSL_CRYPTO preprocessor - * define set for the build. - * - * This works with OpenSSL 1.1.1 and 3.0. It uses the APIs common - * to these two and that are not marked for future deprecation. - * - * A few complaints about OpenSSL in comparison to Mbed TLS: - * - * OpenSSL mallocs for various things where MBed TLS does not. - * This makes the OpenSSL code more complex because checks for malloc - * failures are necessary. - * - * There's a lot of APIs in OpenSSL, but there's a needle to thread to - * get the APIS that are in 1.1.1, 3.0 and not slated for future - * deprecation. - * - * The APIs that fit the above only work for DER-encoded signatures. - * t_cose encodes signatures in a more simple way. This difference - * requires the code here to do conversion which increases its size - * and complexity and requires intermediate buffers and requires more - * use of malloc. - * - * An older version of t_cose (anything from 2021) uses simpler - * OpenSSL APIs. They still work but may be deprecated in the - * future. They could be used in use cases where a particular version - * of the OpenSSL library is selected and reduce code size - * a llittle. - */ - -/* - * See documentation in t_cose_crypto.h - * - * This will typically not be referenced and thus not linked, - * for deployed code. This is mainly used for test. - */ -bool t_cose_crypto_is_algorithm_supported(int32_t cose_algorithm_id) -{ - static const int32_t supported_algs[] = { - COSE_ALGORITHM_SHA_256, - COSE_ALGORITHM_SHA_384, - COSE_ALGORITHM_SHA_512, - COSE_ALGORITHM_ES256, -#ifndef T_COSE_DISABLE_ES384 - COSE_ALGORITHM_ES384, -#endif -#ifndef T_COSE_DISABLE_ES512 - COSE_ALGORITHM_ES512, -#endif -#ifndef T_COSE_DISABLE_PS256 - COSE_ALGORITHM_PS256, -#endif -#ifndef T_COSE_DISABLE_PS384 - COSE_ALGORITHM_PS384, -#endif -#ifndef T_COSE_DISABLE_PS512 - COSE_ALGORITHM_PS512, -#endif -#ifndef T_COSE_DISABLE_EDDSA - COSE_ALGORITHM_EDDSA, -#endif - 0 /* List terminator */ - }; - - return t_cose_check_list(cose_algorithm_id, supported_algs); -} - -/** - * \brief Get the rounded up size of an ECDSA key in bytes. - */ -static unsigned ecdsa_key_size(EVP_PKEY *key_evp) -{ - int key_len_bits; - unsigned key_len_bytes; - - key_len_bits = EVP_PKEY_bits(key_evp); - - /* Calculation of size per RFC 8152 section 8.1 -- round up to - * number of bytes. */ - key_len_bytes = (unsigned)key_len_bits / 8; - if(key_len_bits % 8) { - key_len_bytes++; - } - - return key_len_bytes; -} - - -/** - * \brief Convert DER-encoded ECDSA signature to COSE-serialized signature - * - * \param[in] key_len Size of the key in bytes -- governs sig size. - * \param[in] der_signature DER-encoded signature. - * \param[in] signature_buffer The buffer for output. - * - * \return The pointer and length of serialized signature in \c signature_buffer - or NULL_Q_USEFUL_BUF_C on error. - * - * The serialized format is defined by COSE in RFC 8152 section - * 8.1. The signature which consist of two integers, r and s, - * are simply zero padded to the nearest byte length and - * concatenated. - */ -static inline struct q_useful_buf_c -ecdsa_signature_der_to_cose(EVP_PKEY *key_evp, - struct q_useful_buf_c der_signature, - struct q_useful_buf signature_buffer) -{ - unsigned key_len; - size_t r_len; - size_t s_len; - const BIGNUM *r_bn; - const BIGNUM *s_bn; - struct q_useful_buf_c cose_signature; - void *r_start_ptr; - void *s_start_ptr; - const unsigned char *temp_der_sig_pointer; - ECDSA_SIG *es; - - key_len = ecdsa_key_size(key_evp); - - /* Put DER-encode sig into an ECDSA_SIG so we can get the r and s out. */ - temp_der_sig_pointer = der_signature.ptr; - es = d2i_ECDSA_SIG(NULL, &temp_der_sig_pointer, (long)der_signature.len); - if(es == NULL) { - cose_signature = NULL_Q_USEFUL_BUF_C; - goto Done; - } - - /* Zero the buffer so that bytes r and s are padded with zeros */ - q_useful_buf_set(signature_buffer, 0); - - /* Get the signature r and s as BIGNUMs */ - r_bn = NULL; - s_bn = NULL; - ECDSA_SIG_get0(es, &r_bn, &s_bn); - /* ECDSA_SIG_get0 returns void */ - - - /* Internal consistency check that the r and s values will fit - * into the expected size. Be sure the output buffer is not - * overrun. - */ - /* Cast is safe because BN_num_bytes() is documented to not return - * negative numbers. - */ - r_len = (size_t)BN_num_bytes(r_bn); - s_len = (size_t)BN_num_bytes(s_bn); - if(r_len + s_len > signature_buffer.len) { - cose_signature = NULL_Q_USEFUL_BUF_C; - goto Done2; - } - - /* Copy r and s of signature to output buffer and set length */ - r_start_ptr = (uint8_t *)(signature_buffer.ptr) + key_len - r_len; - BN_bn2bin(r_bn, r_start_ptr); - - s_start_ptr = (uint8_t *)signature_buffer.ptr + 2 * key_len - s_len; - BN_bn2bin(s_bn, s_start_ptr); - - cose_signature = (UsefulBufC){signature_buffer.ptr, 2 * key_len}; - -Done2: - ECDSA_SIG_free(es); - -Done: - return cose_signature; -} - - -/** - * \brief Convert COSE-serialized ECDSA signature to DER-encoded signature. - * - * \param[in] key_len Size of the key in bytes -- governs sig size. - * \param[in] cose_signature The COSE-serialized signature. - * \param[in] buffer Place to write DER-format signature. - * \param[out] der_signature The returned DER-encoded signature - * - * \return one of the \ref t_cose_err_t error codes. - * - * The serialized format is defined by COSE in RFC 8152 section - * 8.1. The signature which consist of two integers, r and s, - * are simply zero padded to the nearest byte length and - * concatenated. - * - * OpenSSL has a preference for DER-encoded signatures. - * - * This uses an ECDSA_SIG as an intermediary to convert - * between the two. - */ -static enum t_cose_err_t -ecdsa_signature_cose_to_der(EVP_PKEY *key_evp, - struct q_useful_buf_c cose_signature, - struct q_useful_buf buffer, - struct q_useful_buf_c *der_signature) -{ - unsigned key_len; - enum t_cose_err_t return_value; - BIGNUM *signature_r_bn = NULL; - BIGNUM *signature_s_bn = NULL; - int ossl_result; - ECDSA_SIG *signature; - unsigned char *der_signature_ptr; - int der_signature_len; - - key_len = ecdsa_key_size(key_evp); - - /* Check the signature length against expected */ - if(cose_signature.len != key_len * 2) { - return_value = T_COSE_ERR_SIG_VERIFY; - goto Done; - } - - /* Put the r and the s from the signature into big numbers */ - signature_r_bn = BN_bin2bn(cose_signature.ptr, (int)key_len, NULL); - if(signature_r_bn == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - signature_s_bn = BN_bin2bn(((const uint8_t *)cose_signature.ptr)+key_len, - (int)key_len, - NULL); - if(signature_s_bn == NULL) { - BN_free(signature_r_bn); - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - /* Put the signature bytes into an ECDSA_SIG */ - signature = ECDSA_SIG_new(); - if(signature == NULL) { - /* Don't leak memory in error condition */ - BN_free(signature_r_bn); - BN_free(signature_s_bn); - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - /* Put the r and s bignums into an ECDSA_SIG. Freeing - * ossl_sig_to_verify will now free r and s. - */ - ossl_result = ECDSA_SIG_set0(signature, - signature_r_bn, - signature_s_bn); - if(ossl_result != 1) { - BN_free(signature_r_bn); - BN_free(signature_s_bn); - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* Now output the ECDSA_SIG structure in DER format. - * - * Code safety is the priority here. i2d_ECDSA_SIG() has two - * output buffer modes, one where it just writes to the buffer - * given and the other were it allocates memory. It would be - * better to avoid the allocation, but the copy mode is not safe - * because you can't give it a buffer length. This is bad stuff - * from last century. - * - * So the allocation mode is used on the presumption that it is - * safe and correct even though there is more copying and memory - * use. - */ - der_signature_ptr = NULL; - der_signature_len = i2d_ECDSA_SIG(signature, &der_signature_ptr); - ECDSA_SIG_free(signature); - if(der_signature_len < 0) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - *der_signature = q_useful_buf_copy_ptr(buffer, - der_signature_ptr, - (size_t)der_signature_len); - if(q_useful_buf_c_is_null_or_empty(*der_signature)) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - OPENSSL_free(der_signature_ptr); - - return_value = T_COSE_SUCCESS; - -Done: - /* All the memory frees happen along the way in the code above. */ - return return_value; -} - -/** - * \brief Common checks and conversions for signing and verification key. - * - * \param[in] t_cose_key The key to check and convert. - * \param[out] return_ossl_ec_key The OpenSSL key in memory. - * - * \return Error or \ref T_COSE_SUCCESS. - * - * It pulls the OpenSSL key out of \c t_cose_key and checks it. - */ -static enum t_cose_err_t -key_convert(struct t_cose_key t_cose_key, EVP_PKEY **return_ossl_ec_key) -{ - enum t_cose_err_t return_value; - - /* Check the signing key and get it out of the union */ - if(t_cose_key.crypto_lib != T_COSE_CRYPTO_LIB_OPENSSL) { - return_value = T_COSE_ERR_INCORRECT_KEY_FOR_LIB; - goto Done; - } - if(t_cose_key.k.key_ptr == NULL) { - return_value = T_COSE_ERR_EMPTY_KEY; - goto Done; - } - *return_ossl_ec_key = (EVP_PKEY *)t_cose_key.k.key_ptr; - - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - -/* - * Public Interface. See documentation in t_cose_crypto.h - */ -enum t_cose_err_t t_cose_crypto_sig_size(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - size_t *sig_size) -{ - enum t_cose_err_t return_value; - EVP_PKEY *signing_key_evp; - - return_value = key_convert(signing_key, &signing_key_evp); - if(return_value != T_COSE_SUCCESS) { - return return_value; - } - - if(t_cose_algorithm_is_ecdsa(cose_algorithm_id)) { - /* EVP_PKEY_size is not suitable because it returns the size - * of the DER-encoded signature, which is larger than the COSE - * signatures. - * - * We instead compute the size ourselves based on the COSE - * encoding of two r and s values, each the same size as the key. - */ - *sig_size = ecdsa_key_size(signing_key_evp) * 2; - return_value = T_COSE_SUCCESS; - goto Done; - } else if (t_cose_algorithm_is_rsassa_pss(cose_algorithm_id) - || cose_algorithm_id == T_COSE_ALGORITHM_EDDSA) { - *sig_size = (size_t)EVP_PKEY_size(signing_key_evp); - return_value = T_COSE_SUCCESS; - goto Done; - } else { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - -Done: - return return_value; -} - - -/** - * \brief Configure an EVP_PKEY_CTX for a given algorithm. - * - * \param[in] context The OpenSSL context to configure. - * \param[in] cose_algorithm_id The algorithm ID. - * - * \return Error or \ref T_COSE_SUCCESS. - */ -static enum t_cose_err_t -configure_pkey_context(EVP_PKEY_CTX* context, int32_t cose_algorithm_id) -{ - enum t_cose_err_t return_value; - const EVP_MD *md; - int ossl_result; - - if (t_cose_algorithm_is_ecdsa(cose_algorithm_id)) { - /* ECDSA doesn't need any further configuration of its context. - * The parameters are inferred from the key. - */ - return_value = T_COSE_SUCCESS; - } else if (t_cose_algorithm_is_rsassa_pss(cose_algorithm_id)) { - /** - * These parameters are specified in Section 2 of RFC8230. - * In a nutshell: - * - PSS padding - * - MGF1 mask generation, using the same hash function used to digest - * the message. - * - Salt length should match the size of the output of the hash - * function. - */ - switch (cose_algorithm_id) { - case T_COSE_ALGORITHM_PS256: - md = EVP_sha256(); - break; - - case T_COSE_ALGORITHM_PS384: - md = EVP_sha384(); - break; - - case T_COSE_ALGORITHM_PS512: - md = EVP_sha512(); - break; - - default: - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - ossl_result = EVP_PKEY_CTX_set_rsa_padding(context, RSA_PKCS1_PSS_PADDING); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* EVP_PKEY_CTX_set_signature_md and EVP_PKEY_CTX_set_rsa_mgf1_md are - * macro wrappers around the EVP_PKEY_CTX_ctrl function, and cast - * the `const EVP_MD*` argument into a void*. This would cause a - * cast-qual warning, if not for the pragmas. Clang supports GCC - * pragmas, so it works on clang too. - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - ossl_result = EVP_PKEY_CTX_set_signature_md(context, md); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - ossl_result = EVP_PKEY_CTX_set_rsa_mgf1_md(context, md); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } -#pragma GCC diagnostic pop - - ossl_result = EVP_PKEY_CTX_set_rsa_pss_saltlen(context, RSA_PSS_SALTLEN_DIGEST); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - return_value = T_COSE_SUCCESS; - } else { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - -Done: - return return_value; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign(const int32_t cose_algorithm_id, - const struct t_cose_key signing_key, - const struct q_useful_buf_c hash_to_sign, - const struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - /* This is the overhead for the DER encoding of an EC signature as - * described by ECDSA-Sig-Value in RFC 3279. It is at max 3 * (1 - * type byte and 2 length bytes) + 2 zero pad bytes = 11 - * bytes. We make it 16 to have a little extra. It is expected that - * EVP_PKEY_sign() will not over write the buffer so there will - * be no security problem if this is too short. */ - #define DER_SIG_ENCODE_OVER_HEAD 16 - - enum t_cose_err_t return_value; - EVP_PKEY_CTX *sign_context; - EVP_PKEY *signing_key_evp; - int ossl_result; - - /* This buffer is passed to OpenSSL to write the ECDSA signature into, in - * DER format, before it can be converted to the expected COSE format. When - * RSA signing is selected, this buffer is unused since OpenSSL's output is - * suitable for use in COSE directly. - */ - MakeUsefulBufOnStack( der_format_signature, T_COSE_MAX_ECDSA_SIG_SIZE + DER_SIG_ENCODE_OVER_HEAD); - - /* This implementation supports only ECDSA so far. The - * interface allows it to support other, but none are implemented. - * - * This implementation works for different key lengths and - * curves. That is, the curve and key length is associated with - * the signing_key passed in, not the cose_algorithm_id This - * check looks for ECDSA signing as indicated by COSE and rejects - * what is not since it only supports ECDSA. - */ - if(!t_cose_algorithm_is_ecdsa(cose_algorithm_id) && - !t_cose_algorithm_is_rsassa_pss(cose_algorithm_id)) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done2; - } - - /* Pull the pointer to the OpenSSL-format EVP_PKEY out of the - * t_cose key structure. */ - return_value = key_convert(signing_key, &signing_key_evp); - if(return_value != T_COSE_SUCCESS) { - goto Done2; - } - - /* Create and initialize the OpenSSL EVP_PKEY_CTX that is the - * signing context. */ - sign_context = EVP_PKEY_CTX_new(signing_key_evp, NULL); - if(sign_context == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - ossl_result = EVP_PKEY_sign_init(sign_context); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - return_value = configure_pkey_context(sign_context, cose_algorithm_id); - if (return_value) { - goto Done; - } - - /* Actually do the signature operation. */ - if (t_cose_algorithm_is_ecdsa(cose_algorithm_id)) { - ossl_result = EVP_PKEY_sign(sign_context, - der_format_signature.ptr, - &der_format_signature.len, - hash_to_sign.ptr, - hash_to_sign.len); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* The signature produced by OpenSSL is DER-encoded. That encoding - * has to be removed and turned into the serialization format used - * by COSE. It is unfortunate that the OpenSSL APIs that create - * signatures that are not in DER-format are slated for - * deprecation. - */ - *signature = ecdsa_signature_der_to_cose( - signing_key_evp, - q_usefulbuf_const(der_format_signature), - signature_buffer); - - if(q_useful_buf_c_is_null(*signature)) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - return_value = T_COSE_SUCCESS; - } else if (t_cose_algorithm_is_rsassa_pss(cose_algorithm_id)) { - /* signature->len gets adjusted to match just the signature size. - */ - *signature = q_usefulbuf_const(signature_buffer); - ossl_result = EVP_PKEY_sign(sign_context, - signature_buffer.ptr, - &signature->len, - hash_to_sign.ptr, - hash_to_sign.len); - - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - return_value = T_COSE_SUCCESS; - } else { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - -Done: - /* This checks for NULL before free, so it is not - * necessary to check for NULL here. - */ - EVP_PKEY_CTX_free(sign_context); - -Done2: - return return_value; -} - - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify(const int32_t cose_algorithm_id, - const struct t_cose_key verification_key, - const struct q_useful_buf_c kid, - const struct q_useful_buf_c hash_to_verify, - const struct q_useful_buf_c cose_signature) -{ - int ossl_result; - enum t_cose_err_t return_value; - EVP_PKEY_CTX *verify_context = NULL; - EVP_PKEY *verification_key_evp; - - /* This buffer is used to convert COSE ECDSA signature to DER format, - * before it can be consumed by OpenSSL. When RSA signatures are - * selected the buffer is unused. - */ - MakeUsefulBufOnStack( der_format_buffer, T_COSE_MAX_ECDSA_SIG_SIZE + DER_SIG_ENCODE_OVER_HEAD); - - /* This is the signature that will be passed to OpenSSL. It will either - * point to `cose_signature`, or into `der_format_buffer`, depending on - * whether an RSA or ECDSA signature is used - */ - struct q_useful_buf_c openssl_signature; - - /* This implementation doesn't use any key store with the ability - * to look up a key based on kid. */ - (void)kid; - - if(!t_cose_algorithm_is_ecdsa(cose_algorithm_id) && - !t_cose_algorithm_is_rsassa_pss(cose_algorithm_id)) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - /* Get the verification key in an EVP_PKEY structure which is what - * is needed for sig verification. */ - return_value = key_convert(verification_key, &verification_key_evp); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - if (t_cose_algorithm_is_ecdsa(cose_algorithm_id)) { - /* Unfortunately the officially supported OpenSSL API supports - * only DER-encoded signatures so the COSE format ECDSA signatures must - * be converted to DER for verification. This requires a temporary - * buffer and a fair bit of work inside ecdsa_signature_cose_to_der(). - */ - return_value = ecdsa_signature_cose_to_der(verification_key_evp, - cose_signature, - der_format_buffer, - &openssl_signature); - if(return_value) { - goto Done; - } - } else if (t_cose_algorithm_is_rsassa_pss(cose_algorithm_id)) { - /* COSE RSA signatures are already in the format OpenSSL - * expects, they can be used without any re-encoding. - */ - openssl_signature = cose_signature; - } else { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - /* Create the verification context and set it up with the - * necessary verification key. - */ - verify_context = EVP_PKEY_CTX_new(verification_key_evp, NULL); - if(verify_context == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - ossl_result = EVP_PKEY_verify_init(verify_context); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - return_value = configure_pkey_context(verify_context, cose_algorithm_id); - if (return_value) { - goto Done; - } - - /* Actually do the signature verification */ - ossl_result = EVP_PKEY_verify(verify_context, - openssl_signature.ptr, - openssl_signature.len, - hash_to_verify.ptr, - hash_to_verify.len); - - - if(ossl_result == 0) { - /* The operation succeeded, but the signature doesn't match */ - return_value = T_COSE_ERR_SIG_VERIFY; - goto Done; - } else if (ossl_result != 1) { - /* Failed before even trying to verify the signature */ - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* Everything succeeded */ - return_value = T_COSE_SUCCESS; - -Done: - EVP_PKEY_CTX_free(verify_context); - - return return_value; -} - - - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id) -{ - int ossl_result; - int nid; - const EVP_MD *message_digest; - - switch(cose_hash_alg_id) { - - case COSE_ALGORITHM_SHA_256: - nid = NID_sha256; - break; - -#if !defined(T_COSE_DISABLE_ES384) || !defined(T_COSE_DISABLE_PS384) - case COSE_ALGORITHM_SHA_384: - nid = NID_sha384; - break; -#endif - -#if !defined(T_COSE_DISABLE_ES512) || !defined(T_COSE_DISABLE_PS512) - case COSE_ALGORITHM_SHA_512: - nid = NID_sha512; - break; -#endif - - default: - return T_COSE_ERR_UNSUPPORTED_HASH; - } - - message_digest = EVP_get_digestbynid(nid); - if(message_digest == NULL){ - return T_COSE_ERR_UNSUPPORTED_HASH; - } - - hash_ctx->evp_ctx = EVP_MD_CTX_new(); - if(hash_ctx->evp_ctx == NULL) { - return T_COSE_ERR_INSUFFICIENT_MEMORY; - } - - ossl_result = EVP_DigestInit_ex(hash_ctx->evp_ctx, message_digest, NULL); - if(ossl_result == 0) { - EVP_MD_CTX_free(hash_ctx->evp_ctx); - return T_COSE_ERR_HASH_GENERAL_FAIL; - } - - hash_ctx->cose_hash_alg_id = cose_hash_alg_id; - hash_ctx->update_error = 1; /* 1 is success in OpenSSL */ - - return T_COSE_SUCCESS; -} - - -/* - * See documentation in t_cose_crypto.h - */ -void -t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf_c data_to_hash) -{ - if(hash_ctx->update_error) { /* 1 is no error, 0 means error for OpenSSL */ - if(data_to_hash.ptr) { - hash_ctx->update_error = EVP_DigestUpdate(hash_ctx->evp_ctx, - data_to_hash.ptr, - data_to_hash.len); - } - } -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf buffer_to_hold_result, - struct q_useful_buf_c *hash_result) -{ - int ossl_result; - unsigned int hash_result_len; - - if(!hash_ctx->update_error) { - EVP_MD_CTX_free(hash_ctx->evp_ctx); - return T_COSE_ERR_HASH_GENERAL_FAIL; - } - - hash_result_len = (unsigned int)buffer_to_hold_result.len; - ossl_result = EVP_DigestFinal_ex(hash_ctx->evp_ctx, - buffer_to_hold_result.ptr, - &hash_result_len); - - *hash_result = (UsefulBufC){buffer_to_hold_result.ptr, hash_result_len}; - - EVP_MD_CTX_free(hash_ctx->evp_ctx); - - /* OpenSSL returns 1 for success, not 0 */ - return ossl_result ? T_COSE_SUCCESS : T_COSE_ERR_HASH_GENERAL_FAIL; -} - -#ifndef T_COSE_DISABLE_EDDSA - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign_eddsa(struct t_cose_key signing_key, - struct q_useful_buf_c tbs, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - enum t_cose_err_t return_value; - int ossl_result; - EVP_MD_CTX *sign_context = NULL; - EVP_PKEY *signing_key_evp; - - return_value = key_convert(signing_key, &signing_key_evp); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - sign_context = EVP_MD_CTX_new(); - if(sign_context == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - ossl_result = EVP_DigestSignInit(sign_context, - NULL, - NULL, - NULL, - signing_key_evp); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - *signature = q_usefulbuf_const(signature_buffer); - /** Must use EVP_DigestSign rather than EVP_PKEY_verify, since - * the tbs data is not hashed yet. Because of how EdDSA works, we - * cannot hash the data ourselves separately. - */ - ossl_result = EVP_DigestSign(sign_context, - signature_buffer.ptr, - &signature->len, - tbs.ptr, - tbs.len); - if (ossl_result != 1) { - /* Failed before even trying to verify the signature */ - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* Everything succeeded */ - return_value = T_COSE_SUCCESS; - -Done: - EVP_MD_CTX_free(sign_context); - - return return_value; -} - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify_eddsa(struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c tbs, - struct q_useful_buf_c signature) -{ - enum t_cose_err_t return_value; - int ossl_result; - EVP_MD_CTX *verify_context = NULL; - EVP_PKEY *verification_key_evp; - - /* This implementation doesn't use any key store with the ability - * to look up a key based on kid. */ - (void)kid; - - return_value = key_convert(verification_key, &verification_key_evp); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - verify_context = EVP_MD_CTX_new(); - if(verify_context == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - ossl_result = EVP_DigestVerifyInit(verify_context, - NULL, - NULL, - NULL, - verification_key_evp); - if(ossl_result != 1) { - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /** Must use EVP_DigestVerify rather than EVP_PKEY_verify, since - * the tbs data is not hashed yet. Because of how EdDSA works, we - * cannot hash the data ourselves separately. - */ - ossl_result = EVP_DigestVerify(verify_context, - signature.ptr, - signature.len, - tbs.ptr, - tbs.len); - if(ossl_result == 0) { - /* The operation succeeded, but the signature doesn't match */ - return_value = T_COSE_ERR_SIG_VERIFY; - goto Done; - } else if (ossl_result != 1) { - /* Failed before even trying to verify the signature */ - return_value = T_COSE_ERR_SIG_FAIL; - goto Done; - } - - /* Everything succeeded */ - return_value = T_COSE_SUCCESS; - -Done: - EVP_MD_CTX_free(verify_context); - - return return_value; -} - -#endif /* T_COSE_DISABLE_EDDSA */ diff --git a/3rdparty/internal/t_cose/crypto_adapters/t_cose_psa_crypto.c b/3rdparty/internal/t_cose/crypto_adapters/t_cose_psa_crypto.c deleted file mode 100644 index 1b5c274cd946..000000000000 --- a/3rdparty/internal/t_cose/crypto_adapters/t_cose_psa_crypto.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * t_cose_psa_crypto.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -/** - * \file t_cose_psa_crypto.c - * - * \brief Crypto Adaptation for t_cose to use ARM's PSA. - * - * This connects up the abstract interface in t_cose_crypto.h to the - * implementations of signing and hashing in ARM's Mbed TLS crypto - * library that implements the Arm PSA 1.0 crypto API. - * - * This adapter layer doesn't bloat the implementation as everything - * here had to be done anyway -- the mapping of algorithm IDs, the - * data format rearranging, the error code translation. - * - * This code should just work out of the box if compiled and linked - * against ARM's PSA crypto. No preprocessor #defines are needed. - * - * You can disable SHA-384 and SHA-512 to save code and space by - * defining T_COSE_DISABLE_ES384 or T_COSE_DISABLE_ES512. This saving - * is most in stack space in the main t_cose implementation. (It seems - * likely that changes to PSA itself would be needed to remove the - * SHA-384 and SHA-512 implementations to save that code. Lack of - * reference and dead stripping the executable won't do it). - */ - - -#include "t_cose_crypto.h" /* The interface this implements */ -#include /* PSA Crypto Interface to mbed crypto or such */ - - - -/* Avoid compiler warning due to unused argument */ -#define ARG_UNUSED(arg) (void)(arg) - -/* - * See documentation in t_cose_crypto.h - * - * This will typically not be referenced and thus not linked, - * for deployed code. This is mainly used for test. - */ -bool t_cose_crypto_is_algorithm_supported(int32_t cose_algorithm_id) -{ - /* Notably, this list does not include EDDSA, regardless of how - * t_cose is configured, since PSA doesn't support it. - */ - static const int32_t supported_algs[] = { - COSE_ALGORITHM_SHA_256, - COSE_ALGORITHM_SHA_384, - COSE_ALGORITHM_SHA_512, - COSE_ALGORITHM_ES256, -#ifndef T_COSE_DISABLE_ES384 - COSE_ALGORITHM_ES384, -#endif -#ifndef T_COSE_DISABLE_ES512 - COSE_ALGORITHM_ES512, -#endif -#ifndef T_COSE_DISABLE_PS256 - COSE_ALGORITHM_PS256, -#endif -#ifndef T_COSE_DISABLE_PS384 - COSE_ALGORITHM_PS384, -#endif -#ifndef T_COSE_DISABLE_PS512 - COSE_ALGORITHM_PS512, -#endif - 0 /* List terminator */ - }; - - return t_cose_check_list(cose_algorithm_id, supported_algs); -} - - -/** - * \brief Map a COSE signing algorithm ID to a PSA signing algorithm ID - * - * \param[in] cose_alg_id The COSE algorithm ID. - * - * \return The PSA algorithm ID or 0 if this doesn't map the COSE ID. - */ -static psa_algorithm_t cose_alg_id_to_psa_alg_id(int32_t cose_alg_id) -{ - /* The #ifdefs save a little code when algorithms are disabled */ - - return cose_alg_id == COSE_ALGORITHM_ES256 ? PSA_ALG_ECDSA(PSA_ALG_SHA_256) : -#ifndef T_COSE_DISABLE_ES384 - cose_alg_id == COSE_ALGORITHM_ES384 ? PSA_ALG_ECDSA(PSA_ALG_SHA_384) : -#endif -#ifndef T_COSE_DISABLE_ES512 - cose_alg_id == COSE_ALGORITHM_ES512 ? PSA_ALG_ECDSA(PSA_ALG_SHA_512) : -#endif -#ifndef T_COSE_DISABLE_PS256 - cose_alg_id == COSE_ALGORITHM_PS256 ? PSA_ALG_RSA_PSS(PSA_ALG_SHA_256) : -#endif -#ifndef T_COSE_DISABLE_PS384 - cose_alg_id == COSE_ALGORITHM_PS384 ? PSA_ALG_RSA_PSS(PSA_ALG_SHA_384) : -#endif -#ifndef T_COSE_DISABLE_PS512 - cose_alg_id == COSE_ALGORITHM_PS512 ? PSA_ALG_RSA_PSS(PSA_ALG_SHA_512) : -#endif - 0; - /* psa/crypto_values.h doesn't seem to define a "no alg" value, - * but zero seems OK for that use in the signing context. */ -} - - -/** - * \brief Map a PSA error into a t_cose error for signing. - * - * \param[in] err The PSA status. - * - * \return The \ref t_cose_err_t. - */ -static enum t_cose_err_t psa_status_to_t_cose_error_signing(psa_status_t err) -{ - /* Intentionally keeping to fewer mapped errors to save object code */ - return err == PSA_SUCCESS ? T_COSE_SUCCESS : - err == PSA_ERROR_INVALID_SIGNATURE ? T_COSE_ERR_SIG_VERIFY : - err == PSA_ERROR_NOT_SUPPORTED ? T_COSE_ERR_UNSUPPORTED_SIGNING_ALG: - err == PSA_ERROR_INSUFFICIENT_MEMORY ? T_COSE_ERR_INSUFFICIENT_MEMORY : - err == PSA_ERROR_CORRUPTION_DETECTED ? T_COSE_ERR_TAMPERING_DETECTED : - T_COSE_ERR_SIG_FAIL; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify(int32_t cose_algorithm_id, - struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c hash_to_verify, - struct q_useful_buf_c signature) -{ - psa_algorithm_t psa_alg_id; - psa_status_t psa_result; - enum t_cose_err_t return_value; - mbedtls_svc_key_id_t verification_key_psa; - - /* This implementation does no look up keys by kid in the key - * store */ - ARG_UNUSED(kid); - - /* Convert to PSA algorithm ID scheme */ - psa_alg_id = cose_alg_id_to_psa_alg_id(cose_algorithm_id); - if(!PSA_ALG_IS_ECDSA(psa_alg_id) && !PSA_ALG_IS_RSA_PSS(psa_alg_id)) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - verification_key_psa = (mbedtls_svc_key_id_t)verification_key.k.key_handle; - - psa_result = psa_verify_hash(verification_key_psa, - psa_alg_id, - hash_to_verify.ptr, - hash_to_verify.len, - signature.ptr, - signature.len); - - return_value = psa_status_to_t_cose_error_signing(psa_result); - - Done: - return return_value; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - enum t_cose_err_t return_value; - psa_status_t psa_result; - psa_algorithm_t psa_alg_id; - mbedtls_svc_key_id_t signing_key_psa; - size_t signature_len; - - psa_alg_id = cose_alg_id_to_psa_alg_id(cose_algorithm_id); - if(!PSA_ALG_IS_ECDSA(psa_alg_id) && !PSA_ALG_IS_RSA_PSS(psa_alg_id)) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - signing_key_psa = (mbedtls_svc_key_id_t)signing_key.k.key_handle; - - /* It is assumed that this call is checking the signature_buffer - * length and won't write off the end of it. - */ - - psa_result = psa_sign_hash(signing_key_psa, - psa_alg_id, - hash_to_sign.ptr, - hash_to_sign.len, - signature_buffer.ptr, /* Sig buf */ - signature_buffer.len, /* Sig buf size */ - &signature_len); /* Sig length */ - - return_value = psa_status_to_t_cose_error_signing(psa_result); - - if(return_value == T_COSE_SUCCESS) { - /* Success, fill in the return useful_buf */ - signature->ptr = signature_buffer.ptr; - signature->len = signature_len; - } - - Done: - return return_value; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t t_cose_crypto_sig_size(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - size_t *sig_size) -{ - enum t_cose_err_t return_value; - psa_algorithm_t psa_alg_id; - mbedtls_svc_key_id_t signing_key_psa; - psa_key_attributes_t key_attributes; - psa_key_type_t key_type; - size_t key_len_bits; - psa_status_t status; - - psa_alg_id = cose_alg_id_to_psa_alg_id(cose_algorithm_id); - if(!PSA_ALG_IS_ECDSA(psa_alg_id) && !PSA_ALG_IS_RSA_PSS(psa_alg_id)) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - signing_key_psa = (mbedtls_svc_key_id_t)signing_key.k.key_handle; - key_attributes = psa_key_attributes_init(); - status = psa_get_key_attributes(signing_key_psa, &key_attributes); - return_value = psa_status_to_t_cose_error_signing(status); - if(return_value) { - goto Done; - } - - key_type = psa_get_key_type(&key_attributes); - key_len_bits = psa_get_key_bits(&key_attributes); - *sig_size = (size_t)PSA_SIGN_OUTPUT_SIZE(key_type, (int)key_len_bits, psa_alg_id); - - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - - - -/** - * \brief Convert COSE hash algorithm ID to a PSA hash algorithm ID - * - * \param[in] cose_hash_alg_id The COSE-based ID for the - * - * \return PSA-based hash algorithm ID, or USHRT_MAX on error. - * - */ -static inline psa_algorithm_t -cose_hash_alg_id_to_psa(int32_t cose_hash_alg_id) -{ - return cose_hash_alg_id == COSE_ALGORITHM_SHA_256 ? PSA_ALG_SHA_256 : -#if !defined(T_COSE_DISABLE_ES384) || !defined(T_COSE_DISABLE_PS384) - cose_hash_alg_id == COSE_ALGORITHM_SHA_384 ? PSA_ALG_SHA_384 : -#endif -#if !defined(T_COSE_DISABLE_ES512) || !defined(T_COSE_DISABLE_PS512) - cose_hash_alg_id == COSE_ALGORITHM_SHA_512 ? PSA_ALG_SHA_512 : -#endif - UINT16_MAX; -} - - -/** - * \brief Map a PSA error into a t_cose error for hashes. - * - * \param[in] status The PSA status. - * - * \return The \ref t_cose_err_t. - */ -static enum t_cose_err_t -psa_status_to_t_cose_error_hash(psa_status_t status) -{ - /* Intentionally limited to just this minimum set of errors to - * save object code as hashes don't really fail much - */ - return status == PSA_SUCCESS ? T_COSE_SUCCESS : - status == PSA_ERROR_NOT_SUPPORTED ? T_COSE_ERR_UNSUPPORTED_HASH : - status == PSA_ERROR_INVALID_ARGUMENT ? T_COSE_ERR_UNSUPPORTED_HASH : - status == PSA_ERROR_BUFFER_TOO_SMALL ? T_COSE_ERR_HASH_BUFFER_SIZE : - T_COSE_ERR_HASH_GENERAL_FAIL; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id) -{ - psa_algorithm_t psa_alg; - - /* Map the algorithm ID */ - psa_alg = cose_hash_alg_id_to_psa(cose_hash_alg_id); - - /* initialize PSA hash context */ - hash_ctx->ctx = psa_hash_operation_init(); - - /* Actually do the hash set up */ - hash_ctx->status = psa_hash_setup(&(hash_ctx->ctx), psa_alg); - - /* Map errors and return */ - return psa_status_to_t_cose_error_hash((psa_status_t)hash_ctx->status); -} - - -/* - * See documentation in t_cose_crypto.h - */ -void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf_c data_to_hash) -{ - if(hash_ctx->status != PSA_SUCCESS) { - /* In error state. Nothing to do. */ - return; - } - - if(data_to_hash.ptr == NULL) { - /* This allows for NULL buffers to be passed in all the way at - * the top of signer or message creator when all that is - * happening is the size of the result is being computed. - */ - return; - } - - /* Actually hash the data */ - hash_ctx->status = psa_hash_update(&(hash_ctx->ctx), - data_to_hash.ptr, - data_to_hash.len); -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf buffer_to_hold_result, - struct q_useful_buf_c *hash_result) -{ - if(hash_ctx->status != PSA_SUCCESS) { - /* Error state. Nothing to do */ - goto Done; - } - - /* Actually finish up the hash */ - hash_ctx->status = psa_hash_finish(&(hash_ctx->ctx), - buffer_to_hold_result.ptr, - buffer_to_hold_result.len, - &(hash_result->len)); - - hash_result->ptr = buffer_to_hold_result.ptr; - -Done: - return psa_status_to_t_cose_error_hash(hash_ctx->status); -} - -#ifndef T_COSE_DISABLE_EDDSA - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign_eddsa(struct t_cose_key signing_key, - struct q_useful_buf_c tbs, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - (void)signing_key; - (void)tbs; - (void)signature_buffer; - (void)signature; - - /* MbedTLS does not support EdDSA */ - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify_eddsa(struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c tbs, - struct q_useful_buf_c signature) -{ - (void)verification_key; - (void)kid; - (void)tbs; - (void)signature; - - /* MbedTLS does not support EdDSA */ - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - -#endif /* T_COSE_DISABLE_EDDSA */ diff --git a/3rdparty/internal/t_cose/crypto_adapters/t_cose_test_crypto.c b/3rdparty/internal/t_cose/crypto_adapters/t_cose_test_crypto.c deleted file mode 100644 index 0ffb493e51a3..000000000000 --- a/3rdparty/internal/t_cose/crypto_adapters/t_cose_test_crypto.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * t_cose_test_crypto.c - * - * Copyright 2019-2020, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - * - * Created 3/31/2019. - */ - - -#include "t_cose_crypto.h" - - -/* - * This file is stub crypto for initial bring up and test of t_cose. - * It is NOT intended for commercial use. When this file is used as - * the crypto adapter, no external crypto library is necessary. This is - * convenient because sometime it takes a while to sort out the crypto - * porting layer for a new platform. With this most of t_cose can be tested - * and demo signatures (short-circuit signatures) can be generated to - * simulate out this would work. - * - * This file uses no signature algorithm. It uses the Brad Conte hash - * implementation that is bundled with t_cose for the purpose of this - * testing, not for commercial use. - */ - - -/* The Brad Conte hash implementaiton bundled with t_cose */ -#include "sha256.h" - -/* Use of this file requires definition of T_COSE_USE_B_CON_SHA256 when - * making t_cose_crypto.h. - * - * This only implements SHA-256 as that is all that is needed for the - * non signing and verification tests using short-circuit signatures. - */ - -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST -/* Global variable just for this particular test. Not thread - * safe or good for commercial use. - */ -int hash_test_mode = 0; -#endif - -/* - * See documentation in t_cose_crypto.h - * - * This will typically not be referenced and thus not linked, - * for deployed code. This is mainly used for test. - */ -bool -t_cose_crypto_is_algorithm_supported(int32_t cose_algorithm_id) -{ - static const int32_t supported_algs[] = { - COSE_ALGORITHM_SHA_256, - 0 /* List terminator */ - }; - - return t_cose_check_list(cose_algorithm_id, supported_algs); -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t t_cose_crypto_sig_size(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - size_t *sig_size) -{ - (void)cose_algorithm_id; - (void)signing_key; - - *sig_size = T_COSE_MAX_ECDSA_SIG_SIZE; - - return T_COSE_SUCCESS; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - (void)cose_algorithm_id; - (void)signing_key; - (void)hash_to_sign; - (void)signature_buffer; - (void)signature; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify(int32_t cose_algorithm_id, - struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c hash_to_verify, - struct q_useful_buf_c signature) -{ - (void)cose_algorithm_id; - (void)verification_key; - (void)kid; - (void)hash_to_verify; - (void)signature; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -int check_for_key_pair_leaks(void) -{ - /* No check for leaks with this stubbed out crypto. With this test - crypto there is no file with code to make keys so there is no place - but here for this function to live. - */ - return 0; -} - - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id) -{ -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST - if(hash_test_mode == 1) { - return T_COSE_ERR_HASH_GENERAL_FAIL; - } -#endif - - if(cose_hash_alg_id != COSE_ALGORITHM_SHA_256) { - return T_COSE_ERR_UNSUPPORTED_HASH; - } - - sha256_init(&(hash_ctx->b_con_hash_context)); - return 0; -} - -/* - * See documentation in t_cose_crypto.h - */ -void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf_c data_to_hash) -{ - if(data_to_hash.ptr) { - sha256_update(&(hash_ctx->b_con_hash_context), - data_to_hash.ptr, - data_to_hash.len); - } -} - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf buffer_to_hold_result, - struct q_useful_buf_c *hash_result) -{ -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST - if(hash_test_mode == 2) { - return T_COSE_ERR_HASH_GENERAL_FAIL; - } -#endif - - sha256_final(&(hash_ctx->b_con_hash_context), buffer_to_hold_result.ptr); - *hash_result = (UsefulBufC){buffer_to_hold_result.ptr, 32}; - - return 0; -} - - -#ifndef T_COSE_DISABLE_EDDSA - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_sign_eddsa(struct t_cose_key signing_key, - struct q_useful_buf_c tbs, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - (void)signing_key; - (void)tbs; - (void)signature_buffer; - (void)signature; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_verify_eddsa(struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c tbs, - struct q_useful_buf_c signature) -{ - (void)verification_key; - (void)kid; - (void)tbs; - (void)signature; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - -#endif /* T_COSE_DISABLE_EDDSA */ diff --git a/3rdparty/internal/t_cose/examples/t_cose_basic_example_ossl.c b/3rdparty/internal/t_cose/examples/t_cose_basic_example_ossl.c deleted file mode 100644 index 73239078eba7..000000000000 --- a/3rdparty/internal/t_cose/examples/t_cose_basic_example_ossl.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * t_cose_basic_example_ossl.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -/** - * \file t_cose_basic_example_ossl.c - * - * \brief Example code for signing and verifying a COSE_Sign1 message - * using OpenSSL - * - * This file has simple code to sign a payload and verify it. - * - * This works with OpenSSL. It assumes t_cose has been wired up to the - * OpenSSL crypto library and hase code specific to OpenSSL to make an - * EC key pair. See t_cose README for more details on how integration - * with crypto libraries works. - */ - -#include "t_cose/t_cose_common.h" -#include "t_cose/t_cose_sign1_sign.h" -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose/q_useful_buf.h" - -#include - -#include "openssl/ecdsa.h" -#include "openssl/err.h" -#include "openssl/evp.h" - - - -/** - * \brief Make a key pair in OpenSSL library form. - * - * \param[in] cose_algorithm_id The algorithm to sign with, for example - * \ref T_COSE_ALGORITHM_ES256. - * \param[out] key_pair The key pair. This must be freed. - * - * The key made here is fixed and just useful for testing. - */ -enum t_cose_err_t make_ossl_key_pair(int32_t cose_algorithm_id, - struct t_cose_key *key_pair) -{ - enum t_cose_err_t return_value; - int ossl_result; - int ossl_key_type; - int ossl_curve_nid; - EVP_PKEY *pkey = NULL; - EVP_PKEY_CTX *ctx; - - switch (cose_algorithm_id) { - case T_COSE_ALGORITHM_ES256: - ossl_key_type = EVP_PKEY_EC; - ossl_curve_nid = NID_X9_62_prime256v1; - break; - - case T_COSE_ALGORITHM_ES384: - ossl_key_type = EVP_PKEY_EC; - ossl_curve_nid = NID_secp384r1; - break; - - case T_COSE_ALGORITHM_ES512: - ossl_key_type = EVP_PKEY_EC; - ossl_curve_nid = NID_secp521r1; - break; - - case T_COSE_ALGORITHM_EDDSA: - ossl_key_type = EVP_PKEY_ED25519; - break; - - default: - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - ctx = EVP_PKEY_CTX_new_id(ossl_key_type, NULL); - if(ctx == NULL) { - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - if (EVP_PKEY_keygen_init(ctx) <= 0) { - return_value = T_COSE_ERR_FAIL; - goto Done; - } - - if (ossl_key_type == EVP_PKEY_EC) { - ossl_result = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, ossl_curve_nid); - if(ossl_result != 1) { - return_value = T_COSE_ERR_FAIL; - goto Done; - } - } - - pkey = EVP_PKEY_new(); - - ossl_result = EVP_PKEY_keygen(ctx, &pkey); - - if(ossl_result != 1) { - return_value = T_COSE_ERR_FAIL; - goto Done; - } - - key_pair->k.key_ptr = pkey; - key_pair->crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - -/** - * \brief Free an OpenSSL key. - * - * \param[in] key_pair The key pair to close / deallocate / free. - */ -void free_ossl_key_pair(struct t_cose_key key_pair) -{ - EVP_PKEY_free(key_pair.k.key_ptr); -} - - -/** - * \brief Print a q_useful_buf_c on stdout in hex ASCII text. - * - * \param[in] string_label A string label to output first - * \param[in] buf The q_useful_buf_c to output. - * - * This is just for pretty printing. - */ -static void print_useful_buf(const char *string_label, struct q_useful_buf_c buf) -{ - if(string_label) { - printf("%s", string_label); - } - - printf(" %ld bytes\n", buf.len); - - printf(" "); - - size_t i; - for(i = 0; i < buf.len; i++) { - const uint8_t Z = ((const uint8_t *)buf.ptr)[i]; - printf("%02x ", Z); - if((i % 8) == 7) { - printf("\n "); - } - } - printf("\n"); - - fflush(stdout); -} - - -/** - * \brief Sign and verify example with one-step signing - * - * The one-step (plus init and key set up) signing uses more memory, but - * is simpler to use. In the code below constructed_payload_buffer is - * the extra buffer that two-step signing avoids. - */ -int32_t one_step_sign_example(void) -{ - - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - Q_USEFUL_BUF_MAKE_STACK_UB( constructed_payload_buffer, 300); - struct q_useful_buf_c constructed_payload; - struct q_useful_buf_c returned_payload; - struct t_cose_key key_pair; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - QCBORError qcbor_result; - - - /* ------ Construct the payload ------ - * - * The payload is constructed into its own continguous buffer. - * In this case the payload is CBOR format so it uses QCBOR to - * encode it, but CBOR is not required for COSE payloads so it could - * be anything at all. - * - * The payload constructed here is a map of some label-value - * pairs similar to a CWT or EAT, but using string labels - * rather than integers. It is just a little example. - */ - QCBOREncode_Init(&cbor_encode, constructed_payload_buffer); - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BeingType", "Humanoid"); - QCBOREncode_AddSZStringToMap(&cbor_encode, "Greeting", "We come in peace"); - QCBOREncode_AddInt64ToMap(&cbor_encode, "ArmCount", 2); - QCBOREncode_AddInt64ToMap(&cbor_encode, "HeadCount", 1); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BrainSize", "medium"); - QCBOREncode_AddBoolToMap(&cbor_encode, "DrinksWater", true); - QCBOREncode_CloseMap(&cbor_encode); - qcbor_result = QCBOREncode_Finish(&cbor_encode, &constructed_payload); - - printf("Encoded payload (size = %ld): %d (%s)\n", - constructed_payload.len, - qcbor_result, - qcbor_result ? "fail" : "success"); - if(qcbor_result) { - return_value = (enum t_cose_err_t)qcbor_result; - goto Done; - } - - - /* ------ Make an ECDSA key pair ------ - * - * The key pair will be used for both signing and encryption. The - * data type is struct t_cose_key on the outside, but internally - * the format is that of the crypto library used, PSA in this - * case. They key is just passed through t_cose to the underlying - * crypto library. - * - * The making and destroying of the key pair is the only code - * dependent on the crypto library in this file. - */ - return_value = make_ossl_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - - printf("Made EC key with curve prime256v1: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Initialize for signing ------ - * - * Initialize the signing context by telling it the signing - * algorithm and signing options. No options are set here hence - * the 0 value. - * - * Set up the signing key and kid (key ID). No kid is passed here - * hence the NULL_Q_USEFUL_BUF_C. - */ - - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - - printf("Initialized t_cose and configured signing key\n"); - - - /* ------ Sign ------ - * - * This performs encoding of the headers, the signing and formatting - * in one shot. - * - * With this API the payload ends up in memory twice, once as the - * input and once in the output. If the payload is large, this - * needs about double the size of the payload to work. - */ - return_value = t_cose_sign1_sign(/* The context set up with signing key */ - &sign_ctx, - /* Pointer and length of payload to be - * signed. - */ - constructed_payload, - /* Non-const pointer and length of the - * buffer where the completed output is - * written to. The length here is that - * of the whole buffer. - */ - signed_cose_buffer, - /* Const pointer and actual length of - * the completed, signed and encoded - * COSE_Sign1 message. This points - * into the output buffer and has the - * lifetime of the output buffer. - */ - &signed_cose); - - printf("Finished signing: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Completed COSE_Sign1 message:\n", signed_cose); - - - printf("\n"); - - - /* ------ Set up for verification ------ - * - * Initialize the verification context. - * - * The verification key works the same way as the signing - * key. Internally it must be in the format for the crypto library - * used. It is passed straight through t_cose. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - - printf("Initialized t_cose for verification and set verification key\n"); - - - /* ------ Perform the verification ------ - * - * Verification is relatively simple. The COSE_Sign1 message to - * verify is passed in and the payload is returned if verification - * is successful. The key must be of the correct type for the - * algorithm used to sign the COSE_Sign1. - * - * The COSE header parameters will be returned if requested, but - * in this example they are not as NULL is passed for the location - * to put them. - */ - return_value = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &returned_payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - printf("Verification complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Signed payload:\n", returned_payload); - - - /* ------ Free key pair ------ - * - * Some implementations of PSA allocate slots for the keys in - * use. This call indicates that the key slot can be de allocated. - */ - printf("Freeing key pair\n\n\n"); - free_ossl_key_pair(key_pair); - -Done: - return (int32_t)return_value; -} - - - - -/** - * \brief Sign and verify example with two-step signing - * - * The two-step (plus init and key set up) signing has the payload - * constructed directly into the output buffer, uses less memory, - * but is more complicated to use. - */ -int two_step_sign_example(void) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - struct t_cose_key key_pair; - QCBOREncodeContext cbor_encode; - QCBORError cbor_error; - struct t_cose_sign1_verify_ctx verify_ctx; - - - - /* ------ Make an ECDSA key pair ------ - * - * The key pair will be used for both signing and encryption. The - * data type is struct t_cose_key on the outside, but internally - * the format is that of the crypto library used, PSA in this - * case. They key is just passed through t_cose to the underlying - * crypto library. - * - * The making and destroying of the key pair is the only code - * dependent on the crypto library in this file. - */ - return_value = make_ossl_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - - printf("Made EC key with curve prime256v1: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Initialize for signing ------ - * - * Set up the QCBOR encoding context with the output buffer. This - * is where all the outputs including the payload goes. In this - * case the maximum size is small and known so a fixed length - * buffer is given. If it is not known then QCBOR and t_cose can - * run without a buffer to calculate the needed size. In all - * cases, if the buffer is too small QCBOR and t_cose will error - * out gracefully and not overrun any buffers. - * - * Initialize the signing context by telling it the signing - * algorithm and signing options. No options are set here hence - * the 0 value. - * - * Set up the signing key and kid (key ID). No kid is passed here - * hence the NULL_Q_USEFUL_BUF_C. - */ - - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - - printf("Initialized QCBOR, t_cose and configured signing key\n"); - - - /* ------ Encode the headers ------ - * - * This just outputs the COSE_Sign1 header parameters and gets set - * up for the payload to be output. - */ - return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - - printf("Encoded COSE headers: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Output the payload ------ - * - * QCBOREncode functions are used to add the payload. It all goes - * directly into the output buffer without any temporary copies. - * QCBOR keeps track of the what is the payload so t_cose knows - * what to hash and sign. - * - * The encoded CBOR here can be very large and complex. The only - * limit is that the output buffer is large enough. If it is too - * small, one of the following two calls will report the error as - * QCBOR tracks encoding errors internally so the code calling it - * doesn't have to. - * - * The payload constructed here is a map of some label-value - * pairs similar to a CWT or EAT, but using string labels - * rather than integers. It is just a little example. - * - * A simpler alternative is to call t_cose_sign1_sign() instead of - * t_cose_sign1_encode_parameters() and - * t_cose_sign1_encode_signature(), however this requires memory - * to hold a copy of the payload and the output COSE_Sign1 - * message. For that call the payload is just passed in as a - * buffer. - */ - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BeingType", "Humanoid"); - QCBOREncode_AddSZStringToMap(&cbor_encode, "Greeting", "We come in peace"); - QCBOREncode_AddInt64ToMap(&cbor_encode, "ArmCount", 2); - QCBOREncode_AddInt64ToMap(&cbor_encode, "HeadCount", 1); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BrainSize", "medium"); - QCBOREncode_AddBoolToMap(&cbor_encode, "DrinksWater", true); - QCBOREncode_CloseMap(&cbor_encode); - - printf("Payload added\n"); - - - /* ------ Sign ------ - * - * This call signals the end payload construction, causes the actual - * signing to run. - */ - return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - - printf("Fnished signing: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Complete CBOR Encoding ------ - * - * This closes out the CBOR encoding returning any errors that - * might have been recorded. - * - * The resulting signed message is returned in signed_cose. It is - * a pointer and length into the buffer give to - * QCBOREncode_Init(). - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - printf("Finished CBOR encoding: %d (%s)\n", cbor_error, return_value ? "fail" : "success"); - if(cbor_error) { - goto Done; - } - - print_useful_buf("Completed COSE_Sign1 message:\n", signed_cose); - - - printf("\n"); - - - /* ------ Set up for verification ------ - * - * Initialize the verification context. - * - * The verification key works the same way as the signing - * key. Internally it must be in the format for the crypto library - * used. It is passed straight through t_cose. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - - printf("Initialized t_cose for verification and set verification key\n"); - - - /* ------ Perform the verification ------ - * - * Verification is relatively simple. The COSE_Sign1 message to - * verify is passed in and the payload is returned if verification - * is successful. The key must be of the correct type for the - * algorithm used to sign the COSE_Sign1. - * - * The COSE header parameters will be returned if requested, but - * in this example they are not as NULL is passed for the location - * to put them. - */ - return_value = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - printf("Verification complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Signed payload:\n", payload); - - - /* ------ Free key pair ------ - * - * OpenSSL uses memory allocation for keys, so they must be freed. - */ - printf("Freeing key pair\n\n\n"); - free_ossl_key_pair(key_pair); - -Done: - return (int)return_value; -} - -/** - * \brief Sign and verify example with dynamically allocated buffers - * - * The signing operation of t_cose requires the caller to provide a - * buffer large enough to hold the result. If the provided buffer is - * too small, the operation will fail. - * - * When EDDSA is used, an additional auxiliary buffer is needed for - * both signing and verification. - * - * While memory-constrained applications may want to use stack or - * statically allocated buffers of a fixed size, others prefer the - * flexibility of dynamically allocating buffers of the right size on - * demand. - * - * This example shows how to call t_cose to determine the size of the - * output and auxiliary buffers, before dynamically allocating them - * using malloc and free. Any alternative allocator could also have - * been used. - * - */ -int32_t dynamic_buffer_example(void) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t return_value; - struct q_useful_buf signed_cose_buffer; - struct q_useful_buf_c signed_cose; - struct q_useful_buf auxiliary_buffer; - struct q_useful_buf_c constructed_payload; - struct q_useful_buf_c returned_payload; - struct t_cose_key key_pair; - struct t_cose_sign1_verify_ctx verify_ctx; - - /* ------ Prepare the payload ------ */ - constructed_payload = Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"); - printf("Encoded payload size = %ld\n", constructed_payload.len); - - - /* ------ Make an EDDSA key pair ------ */ - return_value = make_ossl_key_pair(T_COSE_ALGORITHM_EDDSA, &key_pair); - printf("Made EC key with curve ed25519: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - /* ------ Initialize for signing ------ */ - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_EDDSA); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - - /* ------ Compute the size of the output and auxiliary buffers ------ - * - * A large but NULL output buffer is given to the signing operation. - * The size of result, signed_cose, will reflect how big of a buffer - * needs to be provided for the real operation. - * - * Similarly, the necessary auxiliary buffer size is saved in the - * signing context and available by calling t_cose_sign1_sign_auxiliary_buffer_size. - * - * Both sizes are used later on to allocate the proper buffers. - */ - return_value = t_cose_sign1_sign(&sign_ctx, - constructed_payload, - (struct q_useful_buf){ NULL, SIZE_MAX }, - &signed_cose); - printf("Computed signing size %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - printf("Output buffer size = %zu bytes\n", signed_cose.len); - printf("Auxiliary buffer size = %zu bytes\n", t_cose_sign1_sign_auxiliary_buffer_size(&sign_ctx)); - - /* ------ Allocate buffers of the right size ------ */ - signed_cose_buffer.ptr = malloc(signed_cose.len); - signed_cose_buffer.len = signed_cose.len; - - auxiliary_buffer.len = t_cose_sign1_sign_auxiliary_buffer_size(&sign_ctx); - auxiliary_buffer.ptr = malloc(auxiliary_buffer.len); - - if (signed_cose_buffer.ptr == NULL || auxiliary_buffer.ptr == NULL) { - printf("Buffer allocation failed\n"); - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - /* ------ Sign ------ - * - * Call the sign function again, this time providing it with the - * real buffers. - */ - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - return_value = t_cose_sign1_sign(&sign_ctx, - constructed_payload, - signed_cose_buffer, - &signed_cose); - - printf("Finished signing: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Completed COSE_Sign1 message:\n", signed_cose); - - - printf("\n"); - - /* ------ Free the auxiliary buffer ------ - * - * We could have re-used the allocation for the verification step - * (since it would be the same size), but for demonstration purpose - * we deallocate it here and re-compute its size from the signed - * message. - */ - free(auxiliary_buffer.ptr); - - /* ------ Compute the size of the auxiliary buffer ------ - * - * We call the verify procedure with the DECODE_ONLY flag. - * - * This is only necessary because EDDSA is used as a signing - * algorithm. Other algorithms have no need for an auxiliary - * buffer. - */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); - printf("Initialized t_cose for decoding\n"); - - return_value = t_cose_sign1_verify(&verify_ctx, signed_cose, NULL, NULL); - printf("Decode-only complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - printf("Auxiliary buffer size = %zu bytes\n", t_cose_sign1_verify_auxiliary_buffer_size(&verify_ctx)); - - /* ------ Allocate an auxiliary buffer of the right size ------ */ - auxiliary_buffer.len = t_cose_sign1_verify_auxiliary_buffer_size(&verify_ctx); - auxiliary_buffer.ptr = malloc(auxiliary_buffer.len); - if (auxiliary_buffer.ptr == NULL) { - printf("Auxiliary buffer allocation failed\n"); - return_value = T_COSE_ERR_INSUFFICIENT_MEMORY; - goto Done; - } - - /* ------ Set up for verification ------ - * - * We re-initialize the context, without any flags this time so it - * performs the actual verification. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, auxiliary_buffer); - - printf("Initialized t_cose for verification and set verification key\n"); - - /* ------ Perform the verification ------ */ - return_value = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &returned_payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - printf("Verification complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Signed payload:\n", returned_payload); - - /* ------ Free the output and auxiliary buffers ------ */ - free(signed_cose_buffer.ptr); - free(auxiliary_buffer.ptr); - - /* ------ Free key pair ------ */ - printf("Freeing key pair\n\n\n"); - free_ossl_key_pair(key_pair); - -Done: - return (int32_t)return_value; - -} - -int main(int argc, const char * argv[]) -{ - (void)argc; /* Avoid unused parameter error */ - (void)argv; - - one_step_sign_example(); - two_step_sign_example(); - dynamic_buffer_example(); -} diff --git a/3rdparty/internal/t_cose/examples/t_cose_basic_example_psa.c b/3rdparty/internal/t_cose/examples/t_cose_basic_example_psa.c deleted file mode 100644 index 58afb0fc1474..000000000000 --- a/3rdparty/internal/t_cose/examples/t_cose_basic_example_psa.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * t_cose_basic_example_psa.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#include "t_cose/t_cose_common.h" -#include "t_cose/t_cose_sign1_sign.h" -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose/q_useful_buf.h" - -#include "psa/crypto.h" - -#include - - -/** - * \file t_cose_basic_example_psa.c - * - * \brief Example code for signing and verifying a COSE_Sign1 message using PSA - * - * This file has simple code to sign a payload and verify it. - * - * This works with PSA / MBed Crypto. It assumes t_cose has been wired - * up to PSA / MBed Crypto and has code specific to this library to - * make a key pair that will be passed through t_cose. See t_cose - * README for more details on how integration with crypto libraries - * works. - */ - - -/* - * Some hard coded keys for the test cases here. - */ -#define PRIVATE_KEY_prime256v1 \ -0xf1, 0xb7, 0x14, 0x23, 0x43, 0x40, 0x2f, 0x3b, 0x5d, 0xe7, 0x31, 0x5e, 0xa8, \ -0x94, 0xf9, 0xda, 0x5c, 0xf5, 0x03, 0xff, 0x79, 0x38, 0xa3, 0x7c, 0xa1, 0x4e, \ -0xb0, 0x32, 0x86, 0x98, 0x84, 0x50 - -#define PRIVATE_KEY_secp384r1 \ -0x03, 0xdf, 0x14, 0xf4, 0xb8, 0xa4, 0x3f, 0xd8, 0xab, 0x75, 0xa6, 0x04, 0x6b, \ -0xd2, 0xb5, 0xea, 0xa6, 0xfd, 0x10, 0xb2, 0xb2, 0x03, 0xfd, 0x8a, 0x78, 0xd7, \ -0x91, 0x6d, 0xe2, 0x0a, 0xa2, 0x41, 0xeb, 0x37, 0xec, 0x3d, 0x4c, 0x69, 0x3d, \ -0x23, 0xba, 0x2b, 0x4f, 0x6e, 0x5b, 0x66, 0xf5, 0x7f - -#define PRIVATE_KEY_secp521r1 \ -0x00, 0x45, 0xd2, 0xd1, 0x43, 0x94, 0x35, 0xfa, 0xb3, 0x33, 0xb1, 0xc6, 0xc8, \ -0xb5, 0x34, 0xf0, 0x96, 0x93, 0x96, 0xad, 0x64, 0xd5, 0xf5, 0x35, 0xd6, 0x5f, \ -0x68, 0xf2, 0xa1, 0x60, 0x65, 0x90, 0xbb, 0x15, 0xfd, 0x53, 0x22, 0xfc, 0x97, \ -0xa4, 0x16, 0xc3, 0x95, 0x74, 0x5e, 0x72, 0xc7, 0xc8, 0x51, 0x98, 0xc0, 0x92, \ -0x1a, 0xb3, 0xb8, 0xe9, 0x2d, 0xd9, 0x01, 0xb5, 0xa4, 0x21, 0x59, 0xad, 0xac, \ -0x6d - - -/** - * \brief Make an EC key pair in PSA / Mbed library form. - * - * \param[in] cose_algorithm_id The algorithm to sign with, for example - * \ref T_COSE_ALGORITHM_ES256. - * \param[out] key_pair The key pair. This must be freed. - * - * The key made here is fixed and just useful for testing. - */ -enum t_cose_err_t make_psa_ecdsa_key_pair(int32_t cose_algorithm_id, - struct t_cose_key *key_pair) -{ - psa_key_type_t key_type; - psa_status_t crypto_result; - mbedtls_svc_key_id_t key_handle; - psa_algorithm_t key_alg; - const uint8_t *private_key; - size_t private_key_len; - psa_key_attributes_t key_attributes; - - - static const uint8_t private_key_256[] = {PRIVATE_KEY_prime256v1}; - static const uint8_t private_key_384[] = {PRIVATE_KEY_secp384r1}; - static const uint8_t private_key_521[] = {PRIVATE_KEY_secp521r1}; - - /* There is not a 1:1 mapping from alg to key type, but - * there is usually an obvious curve for an algorithm. That - * is what this does. - */ - - switch(cose_algorithm_id) { - case T_COSE_ALGORITHM_ES256: - private_key = private_key_256; - private_key_len = sizeof(private_key_256); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); - break; - - case T_COSE_ALGORITHM_ES384: - private_key = private_key_384; - private_key_len = sizeof(private_key_384); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384); - break; - - case T_COSE_ALGORITHM_ES512: - private_key = private_key_521; - private_key_len = sizeof(private_key_521); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_512); - break; - - default: - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - - /* OK to call this multiple times */ - crypto_result = psa_crypto_init(); - if(crypto_result != PSA_SUCCESS) { - return T_COSE_ERR_FAIL; - } - - - /* When importing a key with the PSA API there are two main things - * to do. - * - * First you must tell it what type of key it is as this cannot be - * discovered from the raw data. The variable key_type contains - * that information including the EC curve. This is sufficient for - * psa_import_key() to succeed, but you probably want actually use - * the key. - * - * Second, you must say what algorithm(s) and operations the key - * can be used as the PSA Crypto Library has policy enforcement. - * - * How this is done varies quite a lot in the newer - * PSA Crypto API compared to the older. - */ - - key_attributes = psa_key_attributes_init(); - - /* Say what algorithm and operations the key can be used with / for */ - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_algorithm(&key_attributes, key_alg); - - /* The type of key including the EC curve */ - psa_set_key_type(&key_attributes, key_type); - - /* Import the private key. psa_import_key() automatically - * generates the public key from the private so no need to import - * more than the private key. (With ECDSA the public key is always - * deterministically derivable from the private key). - */ - crypto_result = psa_import_key(&key_attributes, - private_key, - private_key_len, - &key_handle); - - if (crypto_result != PSA_SUCCESS) { - return T_COSE_ERR_FAIL; - } - - key_pair->k.key_handle = key_handle; - key_pair->crypto_lib = T_COSE_CRYPTO_LIB_PSA; - - return T_COSE_SUCCESS; -} - - -/** - * \brief Free a PSA / MBed key. - * - * \param[in] key_pair The key pair to close / deallocate / free. - */ -void free_psa_ecdsa_key_pair(struct t_cose_key key_pair) -{ - psa_close_key((mbedtls_svc_key_id_t)key_pair.k.key_handle); -} - - -/** - * \brief Print a q_useful_buf_c on stdout in hex ASCII text. - * - * \param[in] string_label A string label to output first - * \param[in] buf The q_useful_buf_c to output. - * - * This is just for pretty printing. - */ -static void print_useful_buf(const char *string_label, struct q_useful_buf_c buf) -{ - if(string_label) { - printf("%s", string_label); - } - - printf(" %ld bytes\n", buf.len); - - printf(" "); - - size_t i; - for(i = 0; i < buf.len; i++) { - const uint8_t Z = ((const uint8_t *)buf.ptr)[i]; - printf("%02x ", Z); - if((i % 8) == 7) { - printf("\n "); - } - } - printf("\n"); - - fflush(stdout); -} - -/** - * \brief Sign and verify example with one-step signing - * - * The one-step (plus init and key set up) signing uses more memory, but - * is simpler to use. In the code below constructed_payload_buffer is - * the extra buffer that two-step signing avoids. - */ -int32_t one_step_sign_example(void) -{ - - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - Q_USEFUL_BUF_MAKE_STACK_UB( constructed_payload_buffer, 300); - struct q_useful_buf_c constructed_payload; - struct q_useful_buf_c returned_payload; - struct t_cose_key key_pair; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - QCBORError qcbor_result; - - - /* ------ Construct the payload ------ - * - * The payload is constructed into its own continguous buffer. - * In this case the payload is CBOR formatm so it uses QCBOR to - * encode it, but CBOR is not - * required by COSE so it could be anything at all. - * - * The payload constructed here is a map of some label-value - * pairs similar to a CWT or EAT, but using string labels - * rather than integers. It is just a little example. - */ - QCBOREncode_Init(&cbor_encode, constructed_payload_buffer); - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BeingType", "Humanoid"); - QCBOREncode_AddSZStringToMap(&cbor_encode, "Greeting", "We come in peace"); - QCBOREncode_AddInt64ToMap(&cbor_encode, "ArmCount", 2); - QCBOREncode_AddInt64ToMap(&cbor_encode, "HeadCount", 1); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BrainSize", "medium"); - QCBOREncode_AddBoolToMap(&cbor_encode, "DrinksWater", true); - QCBOREncode_CloseMap(&cbor_encode); - qcbor_result = QCBOREncode_Finish(&cbor_encode, &constructed_payload); - - printf("Encoded payload (size = %ld): %d (%s)\n", - constructed_payload.len, - qcbor_result, - qcbor_result ? "fail" : "success"); - if(qcbor_result) { - return_value = (enum t_cose_err_t)qcbor_result; - goto Done; - } - - - /* ------ Make an ECDSA key pair ------ - * - * The key pair will be used for both signing and encryption. The - * data type is struct t_cose_key on the outside, but internally - * the format is that of the crypto library used, PSA in this - * case. They key is just passed through t_cose to the underlying - * crypto library. - * - * The making and destroying of the key pair is the only code - * dependent on the crypto library in this file. - */ - return_value = make_psa_ecdsa_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - - printf("Made EC key with curve prime256v1: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Initialize for signing ------ - * - * Initialize the signing context by telling it the signing - * algorithm and signing options. No options are set here hence - * the 0 value. - * - * Set up the signing key and kid (key ID). No kid is passed here - * hence the NULL_Q_USEFUL_BUF_C. - */ - - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - - printf("Initialized t_cose and configured signing key\n"); - - - /* ------ Sign ------ - * - * This performs encoding of the headers, the signing and formatting - * in one shot. - * - * With this API the payload ends up in memory twice, once as the - * input and once in the output. If the payload is large, this - * needs about double the size of the payload to work. - */ - return_value = t_cose_sign1_sign(/* The context set up with signing key */ - &sign_ctx, - /* Pointer and length of payload to be - * signed. - */ - constructed_payload, - /* Non-const pointer and length of the - * buffer where the completed output is - * written to. The length here is that - * of the whole buffer. - */ - signed_cose_buffer, - /* Const pointer and actual length of - * the completed, signed and encoded - * COSE_Sign1 message. This points - * into the output buffer and has the - * lifetime of the output buffer. - */ - &signed_cose); - - printf("Finished signing: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Completed COSE_Sign1 message:\n", signed_cose); - - - printf("\n"); - - - /* ------ Set up for verification ------ - * - * Initialize the verification context. - * - * The verification key works the same way as the signing - * key. Internally it must be in the format for the crypto library - * used. It is passed straight through t_cose. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - - printf("Initialized t_cose for verification and set verification key\n"); - - - /* ------ Perform the verification ------ - * - * Verification is relatively simple. The COSE_Sign1 message to - * verify is passed in and the payload is returned if verification - * is successful. The key must be of the correct type for the - * algorithm used to sign the COSE_Sign1. - * - * The COSE header parameters will be returned if requested, but - * in this example they are not as NULL is passed for the location - * to put them. - */ - return_value = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &returned_payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - printf("Verification complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Signed payload:\n", returned_payload); - - - /* ------ Free key pair ------ - * - * Some implementations of PSA allocate slots for the keys in - * use. This call indicates that the key slot can be de allocated. - */ - printf("Freeing key pair\n\n\n"); - free_psa_ecdsa_key_pair(key_pair); - -Done: - return (int32_t)return_value; -} - - - - -/** - * \brief Sign and verify example with two-step signing - * - * The two-step (plus init and key set up) signing has the payload - * constructed directly into the output buffer, uses less memory, - * but is more complicated to use. - */ -int two_step_sign_example(void) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - struct t_cose_key key_pair; - QCBOREncodeContext cbor_encode; - QCBORError cbor_error; - struct t_cose_sign1_verify_ctx verify_ctx; - - - - /* ------ Make an ECDSA key pair ------ - * - * The key pair will be used for both signing and encryption. The - * data type is struct t_cose_key on the outside, but internally - * the format is that of the crypto library used, PSA in this - * case. They key is just passed through t_cose to the underlying - * crypto library. - * - * The making and destroying of the key pair is the only code - * dependent on the crypto library in this file. - */ - return_value = make_psa_ecdsa_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - - printf("Made EC key with curve prime256v1: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Initialize for signing ------ - * - * Set up the QCBOR encoding context with the output buffer. This - * is where all the outputs including the payload goes. In this - * case the maximum size is small and known so a fixed length - * buffer is given. If it is not known then QCBOR and t_cose can - * run without a buffer to calculate the needed size. In all - * cases, if the buffer is too small QCBOR and t_cose will error - * out gracefully and not overrun any buffers. - * - * Initialize the signing context by telling it the signing - * algorithm and signing options. No options are set here hence - * the 0 value. - * - * Set up the signing key and kid (key ID). No kid is passed here - * hence the NULL_Q_USEFUL_BUF_C. - */ - - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - - printf("Initialized QCBOR, t_cose and configured signing key\n"); - - - /* ------ Encode the headers ------ - * - * This just outputs the COSE_Sign1 header parameters and gets set - * up for the payload to be output. - */ - return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - - printf("Encoded COSE headers: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Output the payload ------ - * - * QCBOREncode functions are used to add the payload. It all goes - * directly into the output buffer without any temporary copies. - * QCBOR keeps track of the what is the payload so t_cose knows - * what to hash and sign. - * - * The encoded CBOR here can be very large and complex. The only - * limit is that the output buffer is large enough. If it is too - * small, one of the following two calls will report the error as - * QCBOR tracks encoding errors internally so the code calling it - * doesn't have to. - * - * The payload constructed here is a map of some label-value - * pairs similar to a CWT or EAT, but using string labels - * rather than integers. It is just a little example. - * - * A simpler alternative is to call t_cose_sign1_sign() instead of - * t_cose_sign1_encode_parameters() and - * t_cose_sign1_encode_signature(), however this requires memory - * to hold a copy of the payload and the output COSE_Sign1 - * message. For that call the payload is just passed in as a - * buffer. - */ - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BeingType", "Humanoid"); - QCBOREncode_AddSZStringToMap(&cbor_encode, "Greeting", "We come in peace"); - QCBOREncode_AddInt64ToMap(&cbor_encode, "ArmCount", 2); - QCBOREncode_AddInt64ToMap(&cbor_encode, "HeadCount", 1); - QCBOREncode_AddSZStringToMap(&cbor_encode, "BrainSize", "medium"); - QCBOREncode_AddBoolToMap(&cbor_encode, "DrinksWater", true); - QCBOREncode_CloseMap(&cbor_encode); - - printf("Payload added\n"); - - - /* ------ Sign ------ - * - * This call signals the end payload construction, causes the actual - * signing to run. - */ - return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - - printf("Fnished signing: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - - /* ------ Complete CBOR Encoding ------ - * - * This closes out the CBOR encoding returning any errors that - * might have been recorded. - * - * The resulting signed message is returned in signed_cose. It is - * a pointer and length into the buffer give to - * QCBOREncode_Init(). - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - printf("Finished CBOR encoding: %d (%s)\n", cbor_error, return_value ? "fail" : "success"); - if(cbor_error) { - goto Done; - } - - print_useful_buf("Completed COSE_Sign1 message:\n", signed_cose); - - - printf("\n"); - - - /* ------ Set up for verification ------ - * - * Initialize the verification context. - * - * The verification key works the same way as the signing - * key. Internally it must be in the format for the crypto library - * used. It is passed straight through t_cose. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - - printf("Initialized t_cose for verification and set verification key\n"); - - - /* ------ Perform the verification ------ - * - * Verification is relatively simple. The COSE_Sign1 message to - * verify is passed in and the payload is returned if verification - * is successful. The key must be of the correct type for the - * algorithm used to sign the COSE_Sign1. - * - * The COSE header parameters will be returned if requested, but - * in this example they are not as NULL is passed for the location - * to put them. - */ - return_value = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - printf("Verification complete: %d (%s)\n", return_value, return_value ? "fail" : "success"); - if(return_value) { - goto Done; - } - - print_useful_buf("Signed payload:\n", payload); - - - /* ------ Free key pair ------ - * - * Some implementations of PSA allocate slots for the keys in - * use. This call indicates that the key slot can be de allocated. - */ - printf("Freeing key pair\n\n\n"); - free_psa_ecdsa_key_pair(key_pair); - -Done: - return (int)return_value; -} - -int main(int argc, const char * argv[]) -{ - (void)argc; /* Avoid unused parameter error */ - (void)argv; - - one_step_sign_example(); - two_step_sign_example(); -} diff --git a/3rdparty/internal/t_cose/inc/t_cose/q_useful_buf.h b/3rdparty/internal/t_cose/inc/t_cose/q_useful_buf.h deleted file mode 100644 index 548d29fa904e..000000000000 --- a/3rdparty/internal/t_cose/inc/t_cose/q_useful_buf.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * q_useful_buf.h - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef __Q_USEFUL_BUF_H__ -#define __Q_USEFUL_BUF_H__ - -#include "qcbor/UsefulBuf.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * \file q_useful_buf.h - * - * \brief This is a TF-M coding style version of UsefulBuf. - * See UsefulBuf for documentation of these functions. - */ - - -#define NULL_Q_USEFUL_BUF_C NULLUsefulBufC - -#define NULL_Q_USEFUL_BUF NULLUsefulBuf - - -static inline int q_useful_buf_c_is_null(struct q_useful_buf_c in) -{ - return UsefulBuf_IsNULLC(in); -} - - -static inline int q_useful_buf_is_null(struct q_useful_buf in) -{ - return UsefulBuf_IsNULL(in); -} - - -static inline int q_useful_buf_c_is_empty(struct q_useful_buf_c in) -{ - return UsefulBuf_IsEmptyC(in); -} - -static inline int q_useful_buf_is_empty(struct q_useful_buf in) -{ - return UsefulBuf_IsEmpty(in); -} - - -static inline int q_useful_buf_is_null_or_empty(struct q_useful_buf in) -{ - return UsefulBuf_IsNULLOrEmpty(in); -} - - -static inline int q_useful_buf_c_is_null_or_empty(struct q_useful_buf_c in) -{ - return UsefulBuf_IsNULLOrEmptyC(in); -} - -static inline struct q_useful_buf_c q_usefulbuf_const(struct q_useful_buf ub) -{ - return UsefulBuf_Const(ub); -} - - -static inline struct q_useful_buf q_useful_buf_unconst(struct q_useful_buf_c in) -{ - return UsefulBuf_Unconst(in); -} - -#define Q_USEFUL_BUF_FROM_SZ_LITERAL UsefulBuf_FROM_SZ_LITERAL - -#define Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL UsefulBuf_FROM_BYTE_ARRAY_LITERAL - -#define Q_USEFUL_BUF_MAKE_STACK_UB UsefulBuf_MAKE_STACK_UB - -#define Q_USEFUL_BUF_FROM_BYTE_ARRAY UsefulBuf_FROM_BYTE_ARRAY - - -static inline struct q_useful_buf_c q_useful_buf_from_sz(const char *string) -{ - return UsefulBuf_FromSZ(string); -} - -static inline struct q_useful_buf_c -useful_buf_copy_offset(struct q_useful_buf dest, - size_t offset, - struct q_useful_buf_c src) -{ - return UsefulBuf_CopyOffset(dest, offset, src); -} - - - -static inline struct q_useful_buf_c q_useful_buf_copy(struct q_useful_buf dest, - struct q_useful_buf_c src) -{ - return UsefulBuf_Copy(dest, src); -} - - -static inline struct q_useful_buf_c q_useful_buf_set(struct q_useful_buf dest, - uint8_t value) -{ - return UsefulBuf_Set(dest, value); -} - - -static inline struct q_useful_buf_c q_useful_buf_copy_ptr(struct q_useful_buf d, - const void *ptr, - size_t len) -{ - return UsefulBuf_CopyPtr(d, ptr, len); -} - - -static inline struct q_useful_buf_c q_useful_buf_head(struct q_useful_buf_c buf, - size_t amount) -{ - return UsefulBuf_Head(buf, amount); -} - -static inline struct q_useful_buf_c q_useful_buf_tail(struct q_useful_buf_c buf, - size_t amount) -{ - return UsefulBuf_Tail(buf, amount); -} - -static inline int q_useful_buf_compare(const struct q_useful_buf_c buf1, - const struct q_useful_buf_c buf2) -{ - return UsefulBuf_Compare(buf1, buf2); -} - -static inline size_t q_useful_buf_is_value(const struct q_useful_buf_c buf, - uint8_t uValue) -{ - return UsefulBuf_IsValue(buf, uValue); -} - -static inline size_t -q_useful_buf_find_bytes(const struct q_useful_buf_c bytes_to_search, - const struct q_useful_buf_c bytes_to_find) -{ - return UsefulBuf_FindBytes(bytes_to_search, bytes_to_find); -} - - -#ifdef __cplusplus -} -#endif - -#endif /* __Q_USEFUL_BUF_H__ */ diff --git a/3rdparty/internal/t_cose/inc/t_cose/t_cose_common.h b/3rdparty/internal/t_cose/inc/t_cose/t_cose_common.h deleted file mode 100644 index 93a975ef2d12..000000000000 --- a/3rdparty/internal/t_cose/inc/t_cose/t_cose_common.h +++ /dev/null @@ -1,466 +0,0 @@ -/* - * t_cose_common.h - * - * Copyright 2019-2024, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef __T_COSE_COMMON_H__ -#define __T_COSE_COMMON_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - - -/** - * \file t_cose_common.h - * - * \brief This file contains definitions common to all public t_cose - * interfaces. - * - * t_cose_common.h contains the definitions common to all public - * t_cose interfaces, particularly the error codes, algorithm - * identification constants and the structure containing a key. - * - * **Compile Time Configuration Options** - * - * \c T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -- This disables short-circuit - * signing test mode. This saves a small amount of object code - * - * \c T_COSE_DISABLE_ES512 -- Disables the COSE algorithm ES512 - * algorithm. This saves a tiny amount of code and a few hundred bytes - * of stack. It saves more than \c T_COSE_DISABLE_ES384. - * - * \c T_COSE_DISABLE_ES384 -- Disables the COSE algorithm ES384 - * algorithm. This saves a tiny amount of code and a few hundred bytes - * of stack. No stack will be saved if \c T_COSE_DISABLE_ES512 is not - * also defined. - * - * \c T_COSE_DISABLE_PS256 -- Disables the COSE algorithm PS256 - * algorithm. - * - * \c T_COSE_DISABLE_PS384 -- Disables the COSE algorithm PS384 - * algorithm. - * - * \c T_COSE_DISABLE_PS512 -- Disables the COSE algorithm PS512 - * algorithm. - * - * \c T_COSE_DISABLE_CONTENT_TYPE -- Disables the content type - * parameters for both signing and verifying. - */ - - -/** - * Semantic versioning for t_cose x.y.z. Note that these were not defined - * for some releases of t_cose 1.x so !defined(T_COSE_VERSION_MAJOR) - * indicates t_cose 1.x. - */ -#define T_COSE_VERSION_MAJOR 1 -#define T_COSE_VERSION_MINOR 1 -#define T_COSE_VERSION_PATCH 3 - - -/** - * \def T_COSE_ALGORITHM_ES256 - * - * \brief Indicates ECDSA with SHA-256. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * - * The COSE standard recommends a key using the secp256r1 curve with - * this algorithm. This curve is also known as prime256v1 and P-256. - */ -#define T_COSE_ALGORITHM_ES256 -7 - -/** - * \def T_COSE_ALGORITHM_EDDSA - * - * \brief Indicates EDDSA, as described by RFC8032. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * - * Keys using either the edwards25519 or edwards448 curves can be used - * with this algorithm. - */ -#define T_COSE_ALGORITHM_EDDSA -8 - -/** - * \def T_COSE_ALGORITHM_ES384 - * - * \brief Indicates ECDSA with SHA-384. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * - * The COSE standard recommends a key using the secp384r1 curve with - * this algorithm. This curve is also known as P-384. - */ -#define T_COSE_ALGORITHM_ES384 -35 - -/** - * \def T_COSE_ALGORITHM_ES512 - * - * \brief Indicates ECDSA with SHA-512. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * - * The COSE standard recommends a key using the secp521r1 curve with - * this algorithm. This curve is also known as P-521. - */ -#define T_COSE_ALGORITHM_ES512 -36 - -/** - * \def T_COSE_ALGORITHM_PS256 - * - * \brief Indicates RSASSA-PSS with SHA-256. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - */ -#define T_COSE_ALGORITHM_PS256 -37 - -/** - * \def T_COSE_ALGORITHM_PS384 - * - * \brief Indicates RSASSA-PSS with SHA-384. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - */ -#define T_COSE_ALGORITHM_PS384 -38 - -/** - * \def T_COSE_ALGORITHM_PS512 - * - * \brief Indicates RSASSA-PSS with SHA-512. - * - * This value comes from the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - */ -#define T_COSE_ALGORITHM_PS512 -39 - - - - -/** - * Indicates the cryptographic library the \ref t_cose_key is intended - * for. Usually only one cryptographic library is integrated so this - * serves as a cross-check. - */ -enum t_cose_crypto_lib_t { - /** can be used for integrations - * that don't have or don't want to have any cross-check. - */ - T_COSE_CRYPTO_LIB_UNIDENTIFIED = 0, - /** \c key_ptr points to a malloced OpenSSL EC_KEY. The caller - * needs to free it after the operation is done. */ - T_COSE_CRYPTO_LIB_OPENSSL = 1, - /** \c key_handle is a \c psa_key_handle_t in Arm's Platform Security - * Architecture */ - T_COSE_CRYPTO_LIB_PSA = 2 -}; - - -/** - * This structure is used to indicate or pass a key through the t_cose - * implementation to the underlying, platform-specific cryptography - * libraries for signing and verifying signature. You must know the - * cryptographic library that is integrated with t_cose to know how to - * fill in this data structure. - * - * For example, in the OpenSSL integration, \ref key_ptr should point - * to an OpenSSL \c EVP_KEY type. - */ -struct t_cose_key { - /** Identifies the crypto library this key was created for. The - * crypto library knows if it uses the handle or the pointer so - * this indirectly selects the union member. */ - enum t_cose_crypto_lib_t crypto_lib; - union { - /** For libraries that use a pointer to the key or key - * handle. \c NULL indicates empty. */ - void *key_ptr; - /** For libraries that use an integer handle to the key */ - uint64_t key_handle; - } k; -}; - - -/** An empty or \c NULL \c t_cose_key */ -/* - * This has to be definied differently in C than C++ because there is - * no common construct for a literal structure. - * - * In C compound literals are used. - * - * In C++ list initalization is used. This only works - * in C++11 and later. - * - * Note that some popular C++ compilers can handle compound - * literals with on-by-default extensions, however - * this code aims for full correctness with strict - * compilers so they are not used. - */ -#ifdef __cplusplus -#define T_COSE_NULL_KEY {T_COSE_CRYPTO_LIB_UNIDENTIFIED, {0}} -#else -#define T_COSE_NULL_KEY \ - ((struct t_cose_key){T_COSE_CRYPTO_LIB_UNIDENTIFIED, {0}}) -#endif - - -/* Private value. Intentionally not documented for Doxygen. This is - * the size allocated for the encoded protected header parameters. It - * needs to be big enough for encode_protected_parameters() to - * succeed. It currently sized for one parameter with an algorithm ID - * up to 32 bits long -- one byte for the wrapping map, one byte for - * the label, 5 bytes for the ID. If this is made accidentally too - * small, QCBOR will only return an error, and not overrun any - * buffers. - * - * 17 extra bytes are added, rounding it up to 24 total, in case some - * other protected header parameter is to be added and so the test - * using T_COSE_TEST_CRIT_PARAMETER_EXIST can work. - */ -#define T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS (1+1+5+17) - - -/** - * Error codes return by t_cose. - */ -/* - * Do not reorder these. It is OK to add new ones at the end. - * - * Explicit values are included because some tools like debuggers show - * only the value, not the symbol, and it is hard to count up through - * 35 lines to figure out the actual value. - */ -enum t_cose_err_t { - /** Operation completed successfully. */ - T_COSE_SUCCESS = 0, - - /** The requested signing algorithm is not supported. */ - T_COSE_ERR_UNSUPPORTED_SIGNING_ALG = 1, - - /** Internal error when encoding protected parameters, usually - * because they are too big. It is internal because the caller - * can't really affect the size of the protected parameters. */ - T_COSE_ERR_MAKING_PROTECTED = 2, - - /** The hash algorithm needed is not supported. Note that the - * signing algorithm identifier identifies the hash algorithm. */ - T_COSE_ERR_UNSUPPORTED_HASH = 3, - - /** Some system failure when running the hash algorithm. */ - T_COSE_ERR_HASH_GENERAL_FAIL = 4, - - /** The buffer to receive a hash result is too small. */ - T_COSE_ERR_HASH_BUFFER_SIZE = 5, - - /** The buffer to receive result of a signing operation is too - * small. */ - T_COSE_ERR_SIG_BUFFER_SIZE = 6, - - /** When verifying a \c COSE_Sign1, the CBOR is "well-formed", but - * something is wrong with the format of the CBOR outside of the - * header parameters. For example, it is missing something like - * the payload or something is of an unexpected type. */ - T_COSE_ERR_SIGN1_FORMAT = 8, - - /** When decoding some CBOR like a \c COSE_Sign1, the CBOR was not - * "well-formed". Most likely what was supposed to be CBOR is - * either not or is corrupted. The CBOR is can't be decoded. */ - T_COSE_ERR_CBOR_NOT_WELL_FORMED = 9, - - /** The CBOR is "well-formed", but something is wrong with format - * in the header parameters. For example, a parameter is labeled - * with other than an integer or string or the value is an integer - * when a byte string is expected. */ - T_COSE_ERR_PARAMETER_CBOR = 10, - - /** No algorithm ID was found when one is needed. For example, - * when verifying a \c COSE_Sign1. */ - T_COSE_ERR_NO_ALG_ID = 11, - - /** No kid (key ID) was found when one is needed. For example, - * when verifying a \c COSE_Sign1. */ - T_COSE_ERR_NO_KID = 12, - - /** Signature verification failed. For example, the cryptographic - * operations completed successfully but hash wasn't as - * expected. */ - T_COSE_ERR_SIG_VERIFY = 13, - - /** Verification of a short-circuit signature failed. */ - T_COSE_ERR_BAD_SHORT_CIRCUIT_KID = 14, - - /** Some (unspecified) argument was not valid. */ - T_COSE_ERR_INVALID_ARGUMENT = 15, - - /** Out of heap memory. This originates in crypto library as - * t_cose does not use malloc. */ - T_COSE_ERR_INSUFFICIENT_MEMORY = 16, - - /** General unspecific failure. */ - T_COSE_ERR_FAIL = 17, - - /** Equivalent to \c PSA_ERROR_CORRUPTION_DETECTED. */ - T_COSE_ERR_TAMPERING_DETECTED = 18, - - /** The key identified by a \ref t_cose_key or a key ID was not - * found. */ - T_COSE_ERR_UNKNOWN_KEY = 19, - - /** The key was found, but it was the wrong type for the - * operation. */ - T_COSE_ERR_WRONG_TYPE_OF_KEY = 20, - - /** Error constructing the COSE \c Sig_structure when signing or - * verify. */ - T_COSE_ERR_SIG_STRUCT = 21, - - /** Signature was short-circuit. The option \ref - * T_COSE_OPT_ALLOW_SHORT_CIRCUIT to allow verification of - * short-circuit signatures was not set. */ - T_COSE_ERR_SHORT_CIRCUIT_SIG = 22, - - /** Something generally went wrong in the crypto adaptor when - * signing or verifying. */ - T_COSE_ERR_SIG_FAIL = 23, - - /** Something went wrong formatting the CBOR. Possibly the - * payload has maps or arrays that are not closed when using - * t_cose_sign1_encode_parameters() and - * t_cose_sign1_encode_signature() to sign a \c COSE_Sign1. */ - T_COSE_ERR_CBOR_FORMATTING = 24, - - /** The buffer passed in to receive the output is too small. */ - T_COSE_ERR_TOO_SMALL = 25, - - /** More parameters (more than \ref T_COSE_PARAMETER_LIST_MAX) - * than this implementation can handle. Note that all parameters - * need to be checked for criticality so all parameters need to be - * examined. */ - T_COSE_ERR_TOO_MANY_PARAMETERS = 26, - - /** A parameter was encountered that was unknown and also listed in - * the crit labels parameter. */ - T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER = 27, - - /** A request was made to signed with a short-circuit sig, \ref - * T_COSE_OPT_SHORT_CIRCUIT_SIG, but short circuit signature are - * disabled (compiled out) for this implementation. */ - T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED = 28, - - /** The key type in a \ref t_cose_key is wrong for the - * cryptographic library used by this integration of t_cose. - */ - T_COSE_ERR_INCORRECT_KEY_FOR_LIB = 29, - - /** This implementation only handles integer COSE algorithm IDs with - * values less than \c INT32_MAX. */ - T_COSE_ERR_NON_INTEGER_ALG_ID = 30, - - /** The content type parameter contains a content type that is - * neither integer or text string or it is an integer not in the - * range of 0 to \c UINT16_MAX. */ - T_COSE_ERR_BAD_CONTENT_TYPE = 31, - - /** If the option \ref T_COSE_OPT_TAG_REQUIRED is set for - * t_cose_sign1_verify() and the tag is absent, this error is - * returned. */ - T_COSE_ERR_INCORRECTLY_TAGGED = 32, - - /** The signing or verification key given is empty. */ - T_COSE_ERR_EMPTY_KEY = 33, - - /** A header parameter occurs twice, perhaps once in protected and - * once in unprotected. Duplicate header parameters are not - * allowed in COSE. - */ - T_COSE_ERR_DUPLICATE_PARAMETER = 34, - - /** A header parameter that should be protected (alg id or crit) - * is not. This occurs when verifying a \c COSE_Sign1 that is - * improperly constructed. */ - T_COSE_ERR_PARAMETER_NOT_PROTECTED = 35, - - /** Something is wrong with the crit parameter. */ - T_COSE_ERR_CRIT_PARAMETER = 36, - - /** More than \ref T_COSE_MAX_TAGS_TO_RETURN unprocessed tags when - * verifying a signature. */ - T_COSE_ERR_TOO_MANY_TAGS = 37, - - /** The signature algorithm needs an extra buffer, but none was provided. - * See \ref t_cose_sign1_verify_set_auxiliary_buffer for more details. - */ - T_COSE_ERR_NEED_AUXILIARY_BUFFER = 38, - - /** The auxiliary buffer is too small */ - T_COSE_ERR_AUXILIARY_BUFFER_SIZE = 39, -}; - - - - -/** - * The maximum number of header parameters that can be handled during - * verification of a \c COSE_Sign1 message. \ref - * T_COSE_ERR_TOO_MANY_PARAMETERS will be returned by - * t_cose_sign1_verify() if the input message has more. - * - * There can be both \ref T_COSE_PARAMETER_LIST_MAX integer-labeled - * parameters and \ref T_COSE_PARAMETER_LIST_MAX string-labeled - * parameters. - * - * This is a hard maximum so the implementation doesn't need - * malloc. This constant can be increased if needed. Doing so will - * increase stack usage. - */ -#define T_COSE_PARAMETER_LIST_MAX 10 - - - -/** - * The value of an unsigned integer content type indicating no content - * type. See \ref t_cose_parameters. - */ -#define T_COSE_EMPTY_UINT_CONTENT_TYPE UINT16_MAX+1 - -/** - * \brief Check whether an algorithm is supported. - * - * \param[in] cose_algorithm_id COSE Integer algorithm ID. - * - * \returns \c true if algorithm is supported, \c false if not. - * - * Algorithms identifiers are from COSE algorithm registry: - * https://www.iana.org/assignments/cose/cose.xhtml#algorithms - * - * A primary use for this is to determine whether or not to run a test case. - * It is often unneccessary for regular use, because all the APIs will return - * T_COSE_ERR_UNSUPPORTED_XXXX if the algorithm is not supported. - */ -bool -t_cose_is_algorithm_supported(int32_t cose_algorithm_id); - - -#ifdef __cplusplus -} -#endif - - -#endif /* __T_COSE_COMMON_H__ */ diff --git a/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_sign.h b/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_sign.h deleted file mode 100644 index 3df77f1f0d8d..000000000000 --- a/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_sign.h +++ /dev/null @@ -1,718 +0,0 @@ -/* - * t_cose_sign1_sign.h - * - * Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. - * Copyright (c) 2020, Michael Eckel - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_SIGN1_H__ -#define __T_COSE_SIGN1_H__ - -#include -#include -#include "qcbor/qcbor.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose/t_cose_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * \file t_cose_sign1_sign.h - * - * \brief Create a \c COSE_Sign1 message, such as for EAT or CWT Token. - * - * This creates a \c COSE_Sign1 message in compliance with - * [COSE (RFC 8152)](https://tools.ietf.org/html/rfc8152). - * A \c COSE_Sign1 message is a CBOR encoded binary blob that contains - * header parameters, a payload and a signature. Usually the signature is made - * with an EC signing algorithm like ECDSA. - * - * This implementation is intended to be small and portable to - * different OS's and platforms. Its dependencies are: - * - [QCBOR](https://github.com/laurencelundblade/QCBOR) - * - , , - * - Hash functions like SHA-256 - * - Signing functions like ECDSA - * - * There is a cryptographic adaptation layer defined in - * t_cose_crypto.h. An implementation can be made of the functions in - * it for different cryptographic libraries. This means that different - * integrations with different cryptographic libraries may support - * only signing with a particular set of algorithms. Integration with - * [OpenSSL](https://www.openssl.org) is supported. Key ID look up - * also varies by different cryptographic library integrations. - * - * This implementation has a mode where a CBOR-format payload can be - * output directly into the output buffer. This saves having two - * copies of the payload in memory. For this mode use - * t_cose_sign1_encode_parameters() and - * t_cose_sign1_encode_signature(). For a simpler API that just takes - * the payload as an input buffer use t_cose_sign1_sign(). - * - * See t_cose_common.h for preprocessor defines to reduce object code - * and stack use by disabling features. - */ - - -/** - * This is the context for creating a \c COSE_Sign1 structure. The - * caller should allocate it and pass it to the functions here. This - * is about 100 bytes so it fits easily on the stack. - */ -struct t_cose_sign1_sign_ctx { - /* Private data structure */ - struct q_useful_buf_c protected_parameters; /* Encoded protected paramssy */ - int32_t cose_algorithm_id; - struct t_cose_key signing_key; - uint32_t option_flags; - struct q_useful_buf_c kid; -#ifndef T_COSE_DISABLE_CONTENT_TYPE - uint32_t content_type_uint; - const char * content_type_tstr; -#endif - -#ifndef T_COSE_DISABLE_EDDSA - /** - * A auxiliary buffer provided by the caller, used to serialize - * the Sig_Structure. This is only needed when using EdDSA, as - * otherwise the Sig_Structure is hashed incrementally. - */ - struct q_useful_buf auxiliary_buffer; - - /* The size of the serialized Sig_Structure used in the last - * signing operation. This can be used by the user to determine - * a suitable auxiliary buffer size. - */ - size_t auxiliary_buffer_size; -#endif -}; - - -/** - * This selects a signing test mode called _short_ _circuit_ - * _signing_. This mode is useful when there is no signing key - * available, perhaps because it has not been provisioned or - * configured for the particular device. It may also be because the - * public key cryptographic functions have not been connected up in - * the cryptographic adaptation layer. - * - * It has no value for security at all. Data signed this way MUST NOT - * be trusted as anyone can sign like this. - * - * In this mode, the signature is the hash of that which would - * normally be signed by the public key algorithm. To make the - * signature the correct size for the particular algorithm, instances - * of the hash are concatenated to pad it out. - * - * This mode is very useful for testing because all the code except - * the actual signing algorithm is run exactly as it would if a proper - * signing algorithm was run. This can be used for end-end system - * testing all the way to a server or relying party, not just for - * testing device code as t_cose_sign1_verify() supports it too. - */ -#define T_COSE_OPT_SHORT_CIRCUIT_SIG 0x00000001 - - -/** - * An \c option_flag for t_cose_sign1_sign_init() to not add the CBOR - * type 6 tag for \c COSE_Sign1 whose value is 18. Some uses of COSE - * may require this tag be absent because it is known that it is a \c - * COSE_Sign1 from surrounding context. - * - * Or said another way, per the COSE RFC, this code produces a \c - * COSE_Sign1_Tagged by default and a \c COSE_Sign1 when this flag is - * set. The only difference between these two is the CBOR tag. - */ -#define T_COSE_OPT_OMIT_CBOR_TAG 0x00000002 - - -/** - * \brief Initialize to start creating a \c COSE_Sign1. - * - * \param[in] context The t_cose signing context. - * \param[in] option_flags One of \c T_COSE_OPT_XXXX. - * \param[in] cose_algorithm_id The algorithm to sign with, for example - * \ref T_COSE_ALGORITHM_ES256. - * - * Initialize the \ref t_cose_sign1_sign_ctx context. Typically, no - * \c option_flags are needed and 0 can be passed. A \c cose_algorithm_id - * must always be given. See \ref T_COSE_OPT_SHORT_CIRCUIT_SIG and - * related for possible option flags. - * - * The algorithm ID space is from - * [COSE (RFC8152)](https://tools.ietf.org/html/rfc8152) and the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * \ref T_COSE_ALGORITHM_ES256 and a few others are defined here for - * convenience. The signing algorithms supported depends on the - * cryptographic library that t_cose is integrated with. - * - * Errors such as the passing of an unsupported \c cose_algorithm_id - * are reported when t_cose_sign1_sign() or - * t_cose_sign1_encode_parameters() is called. - */ -static void -t_cose_sign1_sign_init(struct t_cose_sign1_sign_ctx *context, - uint32_t option_flags, - int32_t cose_algorithm_id); - - -/** - * \brief Set the key and kid (key ID) for signing. - * - * \param[in] context The t_cose signing context. - * \param[in] signing_key The signing key to use or \ref T_COSE_NULL_KEY. - * \param[in] kid COSE kid (key ID) parameter or \c NULL_Q_USEFUL_BUF_C. - * - * This needs to be called to set the signing key to use. The \c kid - * may be omitted by giving \c NULL_Q_USEFUL_BUF_C. - * - * If short-circuit signing is used, - * \ref T_COSE_OPT_SHORT_CIRCUIT_SIG, then this does not need to be - * called. If it is called the \c kid given will be used, but the \c - * signing_key is never used. When the \c kid is given with a - * short-circuit signature, the internally fixed kid for short circuit - * will not be used and this \c COSE_Sign1 message can not be verified - * by t_cose_sign1_verify(). - */ -static void -t_cose_sign1_set_signing_key(struct t_cose_sign1_sign_ctx *context, - struct t_cose_key signing_key, - struct q_useful_buf_c kid); - -/** - * \brief Configure an auxiliary buffer used to serialize the Sig_Structure. - * - * \param[in] context The t_cose signing context. - * \param[in] auxiliary_buffer The buffer used to serialize the Sig_Structure. - * - * Some signature algorithms (namely EdDSA), require two passes over - * their input. In order to achieve this, the library needs to serialize - * a temporary to-be-signed structure into an auxiliary buffer. This function - * allows the user to configure such a buffer. - * - * The buffer must be big enough to accomodate the Sig_Structure type, - * which is roughly the sum of sizes of the encoded protected parameters, aad - * and payload, along with a few dozen bytes of overhead. - * - * To compute the exact size needed, an auxiliary buffer with a NULL - * pointer and a large size, such as \c UINT32_MAX, can be used. No - * actual signing will take place, but the auxiliary buffer will be shrunk - * to the to expected size. - * - */ -static void -t_cose_sign1_sign_set_auxiliary_buffer(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf auxiliary_buffer); - -/** - * \brief Get the required auxiliary buffer size for the most recent - * signing operation. - * - * \param[in] context The t_cose signing context. - * - * \return The number of bytes of auxiliary buffer used by the most - * recent signing operation. - * - * This function can be called after \ref t_cose_sign1_sign (or - * equivalent) was called. If a NULL output buffer was passed to the - * signing function (to operate in size calculation mode), this returns - * the number of bytes that would have been used by the signing - * operation. This allows the caller to allocate an appropriately sized - * buffer before performing the actual verification. - * - * This function returns if the signature algorithm used does not need - * an auxiliary buffer. - */ -static size_t -t_cose_sign1_sign_auxiliary_buffer_size(struct t_cose_sign1_sign_ctx *context); - - - -#ifndef T_COSE_DISABLE_CONTENT_TYPE -/** - * \brief Set the payload content type using CoAP content types. - * - * \param[in] context The t_cose signing context. - * \param[in] content_type The content type of the payload as defined - * in the IANA CoAP Content-Formats registry. - * - * It is not allowed to have both a CoAP and MIME content type. This - * error will show up when t_cose_sign1_sign() or - * t_cose_sign1_encode_parameters() is called as no error is returned by - * this function. - * - * The IANA CoAP Content-Formats registry is found - * [here](https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#content-formats). - */ -static inline void -t_cose_sign1_set_content_type_uint(struct t_cose_sign1_sign_ctx *context, - uint16_t content_type); - -/** - * \brief Set the payload content type using MIME content types. - * - * \param[in] context The t_cose signing context. - * \param[in] content_type The content type of the payload as defined - * in the IANA Media Types registry. - - * - * It is not allowed to have both a CoAP and MIME content type. This - * error will show up when t_cose_sign1_sign() or - * t_cose_sign1_encode_parameters() is called. - * - * The IANA Media Types registry can be found - * [here](https://www.iana.org/assignments/media-types/media-types.xhtml). - * These have been known as MIME types in the past. - */ -static inline void -t_cose_sign1_set_content_type_tstr(struct t_cose_sign1_sign_ctx *context, - const char *content_type); -#endif /* T_COSE_DISABLE_CONTENT_TYPE */ - - - -/** - * \brief Create and sign a \c COSE_Sign1 message with a payload in one call. - * - * \param[in] context The t_cose signing context. - * \param[in] payload Pointer and length of payload to sign. - * \param[in] out_buf Pointer and length of buffer to output to. - * \param[out] result Pointer and length of the resulting \c COSE_Sign1. - * - * The \c context must have been initialized with - * t_cose_sign1_sign_init() and the key set with - * t_cose_sign1_set_signing_key() before this is called. - * - * This creates the COSE header parameter, hashes and signs the - * payload and creates the signature all in one go. \c out_buf gives - * the pointer and length of the memory into which the output is - * written. The pointer and length of the completed \c COSE_Sign1 is - * returned in \c result. (\c out_buf and \c result are used instead - * of the usual in/out parameter for length because it is the - * convention for q_useful_buf and is more const correct.) - * - * The size of \c out_buf must be the size of the payload plus - * overhead for formating, the signature and the key id (if used). The - * formatting overhead is minimal at about 30 bytes.The total overhead - * is about 150 bytes for ECDSA 256 with a 32-byte key ID. - * - * To compute the size of the buffer needed before it is allocated - * call this with \c out_buf containing a \c NULL pointer and large - * length like \c UINT32_MAX. The algorithm and key, kid and such - * must be set up just as if the real \c COSE_Sign1 were to be created - * as these values are needed to compute the size correctly. The - * contents of \c result will be a \c NULL pointer and the length of - * the \c COSE_Sign1. When this is run like this, the cryptographic - * functions will not actually run, but the size of their output will - * be taken into account to give an exact size. - * - * This function requires the payload be complete and formatted in a - * contiguous buffer. The resulting \c COSE_Sign1 message also - * contains the payload preceded by the header parameters and followed - * by the signature, all CBOR formatted. This function thus requires - * two copies of the payload to be in memory. Alternatively - * t_cose_sign1_encode_parameters() and - * t_cose_sign1_encode_signature() can be used. They are more complex - * to use, but avoid the two copies of the payload and can reduce - * memory requirements by close to half. - * - * See also t_cose_sign1_sign_aad() and t_cose_sign1_sign_detached(). - */ -static enum t_cose_err_t -t_cose_sign1_sign(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result); - - -/** - * \brief Create and sign a \c COSE_Sign1 message with a payload in one call. - * - * \param[in] context The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of payload to sign. - * \param[in] out_buf Pointer and length of buffer to output to. - * \param[out] result Pointer and length of the resulting \c COSE_Sign1. - * - * This is the same as t_cose_sign1_sign() additionally allowing AAD. - * AAD (Additional Authenticated Data) is extra bytes to be covered by the - * signature. See t_cose_sign1_encode_signature_aad() for more details - * about AAD. - * - * Calling this with \c aad as \c NULL_Q_USEFUL_BUF_C is equivalent to - * t_cose_sign1_sign(). - * - * See also t_cose_sign1_sign_detached(). - */ -static enum t_cose_err_t -t_cose_sign1_sign_aad(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result); - - -/** - * \brief Create and sign a \c COSE_Sign1 message with detached payload in one call. - * - * \param[in] context The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] detached_payload Pointer and length of the detached payload to sign. - * \param[in] out_buf Pointer and length of buffer to output to. - * \param[out] result Pointer and length of the resulting \c COSE_Sign1. - * - * This is similar to, but not the same as - * t_cose_sign1_sign_aad(). Here the payload is detached, not inside - * the \c COSE_Sign1 and conveyed separately. The signature is still - * over the payload as with t_cose_sign1_sign_aad(). They payload must - * conveyed to recipient by some other means than by being inside the - * \c COSE_Sign1. The recipient will be unable to verify the \c - * COSE_Sign1 without it. - * - * This may be called with \c aad as \c NULL_Q_USEFUL_BUF_C if there is - * no AAD. - */ -static enum t_cose_err_t -t_cose_sign1_sign_detached(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result); - - - -/** - * \brief Output first part and parameters for a \c COSE_Sign1 message. - * - * \param[in] context The t_cose signing context. - * \param[in] cbor_encode_ctx Encoding context to output to. - * - * This is the more complex and more memory efficient alternative to - * t_cose_sign1_sign(). Like t_cose_sign1_sign(), - * t_cose_sign1_sign_init() and t_cose_sign1_set_signing_key() must be - * called before calling this. - * - * When this is called, the opening parts of the \c COSE_Sign1 message - * are output to the \c cbor_encode_ctx. - * - * After this is called, the CBOR-formatted payload must be written to - * the \c cbor_encode_ctx by calling all the various - * \c QCBOREncode_AddXxx calls. It can be as simple or complex as needed. - * - * To complete the \c COSE_Sign1 call t_cose_sign1_encode_signature(). - * - * The \c cbor_encode_ctx must have been initialized with an output - * buffer to hold the \c COSE_Sign1 header parameters, the payload and the - * signature. - * - * This and t_cose_sign1_encode_signature() can be used to calculate - * the size of the \c COSE_Sign1 in the way \c QCBOREncode is usually - * used to calculate sizes. In this case the \c t_cose_sign1_ctx must - * be initialized with the options, algorithm, key and kid just as - * normal as these are needed to calculate the size. Then set up the - * output buffer for \c cbor_encode_ctx with a \c NULL pointer and - * large length like \c UINT32_MAX. Call - * t_cose_sign1_encode_parameters(), then format the payload into the - * encoder context, then call t_cose_sign1_encode_signature(). - * Finally call \c QCBOREncode_FinishGetSize() to get the length. - */ -static enum t_cose_err_t -t_cose_sign1_encode_parameters(struct t_cose_sign1_sign_ctx *context, - QCBOREncodeContext *cbor_encode_ctx); - - -/** - * \brief Finish a \c COSE_Sign1 message by outputting the signature. - * - * \param[in] context The t_cose signing context. - * \param[in] cbor_encode_ctx Encoding context to output to. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * Call this to complete creation of a signed \c COSE_Sign1 started - * with t_cose_sign1_encode_parameters(). - * - * This is when the cryptographic signature algorithm is run. - * - * The completed \c COSE_Sign1 message is retrieved from the - * \c cbor_encode_ctx by calling \c QCBOREncode_Finish(). - */ -static enum t_cose_err_t -t_cose_sign1_encode_signature(struct t_cose_sign1_sign_ctx *context, - QCBOREncodeContext *cbor_encode_ctx); - - -/** - * \brief Finish a \c COSE_Sign1 message with AAD by outputting the signature. - * - * \param[in] context The t_cose signing context. - * \param[in] aad The Additional Authenticated Data. - * \param[in] cbor_encode_ctx Encoding context to output to. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This is the same as t_cose_sign1_encode_signature() and it allows - * passing in AAD (Additional Authenticated Data) to be covered by the - * signature. - * - * AAD is simply any data that should also be covered by the - * signature. The verifier of the \c COSE_Sign1 must also have exactly - * this data to be able to successfully verify the signature. Often - * this data is some parameters or fields in the protocol carrying the - * COSE message. - */ -static inline enum t_cose_err_t -t_cose_sign1_encode_signature_aad(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf_c aad, - QCBOREncodeContext *cbor_encode_ctx); - - - - - - -/* ------------------------------------------------------------------------ - * Inline implementations of public functions defined above. - */ -static inline void -t_cose_sign1_sign_init(struct t_cose_sign1_sign_ctx *me, - uint32_t option_flags, - int32_t cose_algorithm_id) -{ - memset(me, 0, sizeof(*me)); -#ifndef T_COSE_DISABLE_CONTENT_TYPE - me->content_type_uint = T_COSE_EMPTY_UINT_CONTENT_TYPE; -#endif - - me->cose_algorithm_id = cose_algorithm_id; - me->option_flags = option_flags; - -#ifndef T_COSE_DISABLE_EDDSA - /* Start with large (but NULL) auxiliary buffer. If EdDSA is used, - * the Sig_Structure data will be serialized here. - */ - me->auxiliary_buffer.len = SIZE_MAX; -#endif -} - - -static inline void -t_cose_sign1_set_signing_key(struct t_cose_sign1_sign_ctx *me, - struct t_cose_key signing_key, - struct q_useful_buf_c kid) -{ - me->kid = kid; - me->signing_key = signing_key; -} - -static inline void -t_cose_sign1_sign_set_auxiliary_buffer(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf auxiliary_buffer) -{ -#ifndef T_COSE_DISABLE_EDDSA - me->auxiliary_buffer = auxiliary_buffer; -#else - (void)me; - (void)auxiliary_buffer; -#endif -} - -static inline size_t -t_cose_sign1_sign_auxiliary_buffer_size(struct t_cose_sign1_sign_ctx *me) -{ -#ifndef T_COSE_DISABLE_EDDSA - return me->auxiliary_buffer_size; -#else - /* If EdDSA is disabled we don't ever need an auxiliary buffer. */ - (void)me; - return 0; -#endif -} - - -/** - * \brief Semi-private function that ouputs the COSE parameters, startng a - * \c COSE_Sign1 message. - * - * \param[in] context The t_cose signing context. - * \param[in] payload_is_detached If the payload is to be detached, this - * is \c true. - * \param[in] cbor_encode_ctx Encoding context to output to. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This does the actual work for encoding the COSE parameters, but is - * a private function inside the implementation. Call - * t_cose_sign1_encode_parameters() instead of this. - */ -enum t_cose_err_t -t_cose_sign1_encode_parameters_internal(struct t_cose_sign1_sign_ctx *context, - bool payload_is_detached, - QCBOREncodeContext *cbor_encode_ctx); - - -static inline enum t_cose_err_t -t_cose_sign1_encode_parameters(struct t_cose_sign1_sign_ctx *context, - QCBOREncodeContext *cbor_encode_ctx) -{ - return t_cose_sign1_encode_parameters_internal(context, - false, - cbor_encode_ctx); -} - - -/** - * \brief Semi-private function that ouputs the signature, finishing a - * \c COSE_Sign1 message. - * - * \param[in] context The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or - * \c NULL_Q_USEFUL_BUF_C. - * \param[in] detached_payload The detached payload or \c NULL_Q_USEFUL_BUF_C. - * \param[in] cbor_encode_ctx Encoding context to output to. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This does the actual work for several public methods that output a - * signature. It is internal to the implmentation and - * t_cose_sign1_encode_signature_aad() should be called instead. - * - * If \c detached_payload is \c NULL_Q_USEFUL_BUF_C then the payload - * is to be inline and must have been added by calls to QCBOREncode - * after the call to t_cose_sign1_encode_parameters(). - */ -enum t_cose_err_t -t_cose_sign1_encode_signature_aad_internal(struct t_cose_sign1_sign_ctx *context, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - QCBOREncodeContext *cbor_encode_ctx); - -/** - * \brief Semi-private function that does a complete signing in one call. - * - * \param[in] context The t_cose signing context. - * \param[in] payload_is_detached If \c true, then \c payload is detached. - * \param[in] payload The payload, inline or detached. - * \param[in] aad The Additional Authenticated Data or - * \c NULL_Q_USEFUL_BUF_C. - * \param[in] out_buf Pointer and length of buffer to output to. - * \param[out] result Pointer and length of the resulting - * \c COSE_Sign1. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This is where the work actually gets done for signing that is done - * all in one call with or without AAD and for included or detached - * payloads. - * - * This is a private function internal to the implementation. Call - * t_cose_sign1_sign_aad() instead of this. - */ -enum t_cose_err_t -t_cose_sign1_sign_aad_internal(struct t_cose_sign1_sign_ctx *context, - bool payload_is_detached, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result); - - -static inline enum t_cose_err_t -t_cose_sign1_sign_aad(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result) -{ - return t_cose_sign1_sign_aad_internal(me, - false, - aad, - payload, - out_buf, - result); -} - - -static inline enum t_cose_err_t -t_cose_sign1_sign(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result) -{ - return t_cose_sign1_sign_aad_internal(me, - false, - payload, - NULL_Q_USEFUL_BUF_C, - out_buf, - result); -} - - -static inline enum t_cose_err_t -t_cose_sign1_sign_detached(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result) -{ - return t_cose_sign1_sign_aad_internal(me, - true, - detached_payload, - aad, - out_buf, - result); -} - - -static inline enum t_cose_err_t -t_cose_sign1_encode_signature_aad(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - QCBOREncodeContext *cbor_encode_ctx) -{ - return t_cose_sign1_encode_signature_aad_internal(me, - aad, - NULL_Q_USEFUL_BUF_C, - cbor_encode_ctx); -} - - -static inline enum t_cose_err_t -t_cose_sign1_encode_signature(struct t_cose_sign1_sign_ctx *me, - QCBOREncodeContext *cbor_encode_ctx) -{ - return t_cose_sign1_encode_signature_aad_internal(me, - NULL_Q_USEFUL_BUF_C, - NULL_Q_USEFUL_BUF_C, - cbor_encode_ctx); -} - - -#ifndef T_COSE_DISABLE_CONTENT_TYPE -static inline void -t_cose_sign1_set_content_type_uint(struct t_cose_sign1_sign_ctx *me, - uint16_t content_type) -{ - me->content_type_uint = content_type; -} - - -static inline void -t_cose_sign1_set_content_type_tstr(struct t_cose_sign1_sign_ctx *me, - const char *content_type) -{ - me->content_type_tstr = content_type; -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __T_COSE_SIGN1_H__ */ diff --git a/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_verify.h b/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_verify.h deleted file mode 100644 index 87a20d5e3b75..000000000000 --- a/3rdparty/internal/t_cose/inc/t_cose/t_cose_sign1_verify.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - * t_cose_sign1_verify.h - * - * Copyright 2019-2021, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef __T_COSE_SIGN1_VERIFY_H__ -#define __T_COSE_SIGN1_VERIFY_H__ - -#include -#include -#include "t_cose/q_useful_buf.h" -#include "t_cose/t_cose_common.h" -#include "qcbor/qcbor_common.h" - -#ifdef __cplusplus -extern "C" { -#if 0 -} /* Keep editor indention formatting happy */ -#endif -#endif - -#ifndef QCBOR_SPIFFY_DECODE -#error This version of t_cose requires a version of QCBOR that supports spiffy decode -#endif - -/** - * \file t_cose_sign1_verify.h - * - * \brief Verify a COSE_Sign1 Message - * - * This verifies a \c COSE_Sign1 message in compliance with [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152). A \c COSE_Sign1 message is a CBOR - * encoded binary blob that contains header parameters, a payload and a - * signature. Usually the signature is made with an EC signing - * algorithm like ECDSA. - * - * This implementation is intended to be small and portable to - * different OS's and platforms. Its dependencies are: - * - [QCBOR](https://github.com/laurencelundblade/QCBOR) - * - , , - * - Hash functions like SHA-256 - * - Signing functions like ECDSA - * - * There is a cryptographic adaptation layer defined in - * t_cose_crypto.h. An implementation can be made of the functions in - * it for different cryptographic libraries. This means that different - * integrations with different cryptographic libraries may support - * only signing with a particular set of algorithms. Integration with - * [OpenSSL](https://www.openssl.org) is supported. Key ID look up - * also varies by different cryptographic library integrations. - * - * See t_cose_common.h for preprocessor defines to reduce object code - * and stack use by disabling features. - */ - - -/** - * The result of parsing a set of COSE header parameters. The pointers - * in this are all back into the \c COSE_Sign1 blob passed in to - * t_cose_sign1_verify() as the \c sign1 parameter. - * - * Approximate size on a 64-bit machine is 80 bytes and on a 32-bit - * machine is 40. - */ -struct t_cose_parameters { - /** The algorithm ID. \ref T_COSE_UNSET_ALGORITHM_ID if the algorithm ID - * parameter is not present. String type algorithm IDs are not - * supported. See the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml) - * for the algorithms corresponding to the integer values. - */ - int32_t cose_algorithm_id; - - /** The COSE key ID. \c NULL_Q_USEFUL_BUF_C if parameter is not - * present */ - struct q_useful_buf_c kid; - - /** The initialization vector. \c NULL_Q_USEFUL_BUF_C if parameter - * is not present */ - struct q_useful_buf_c iv; - - /** The partial initialization vector. \c NULL_Q_USEFUL_BUF_C if - * parameter is not present */ - struct q_useful_buf_c partial_iv; - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - /** The content type as a MIME type like - * "text/plain". \c NULL_Q_USEFUL_BUF_C if parameter is not present */ - struct q_useful_buf_c content_type_tstr; - - /** The content type as a CoAP Content-Format - * integer. \ref T_COSE_EMPTY_UINT_CONTENT_TYPE if parameter is not - * present. Allowed range is 0 to UINT16_MAX per RFC 7252. */ - uint32_t content_type_uint; -#endif /* T_COSE_DISABLE_CONTENT_TYPE */ -}; - - -/** - * A special COSE algorithm ID that indicates no COSE algorithm ID or an unset - * COSE algorithm ID. - */ -#define T_COSE_UNSET_ALGORITHM_ID 0 - - - - -/** - * Pass this as \c option_flags to allow verification of short-circuit - * signatures. This should only be used as a test mode as - * short-circuit signatures are not secure. - * - * See also \ref T_COSE_OPT_SHORT_CIRCUIT_SIG. - */ -#define T_COSE_OPT_ALLOW_SHORT_CIRCUIT 0x00000001 - - -/** - * The error \ref T_COSE_ERR_NO_KID is returned if the kid parameter - * is missing. Note that the kid parameter is primarily passed on to - * the crypto layer so the crypto layer can look up the key. If the - * verification key is determined by other than the kid, then it is - * fine if there is no kid. - */ -#define T_COSE_OPT_REQUIRE_KID 0x00000002 - - -/** - * Normally this will decode the CBOR presented as a \c COSE_Sign1 - * message whether it is tagged using QCBOR tagging as such or not. - * If this option is set, then \ref T_COSE_ERR_INCORRECTLY_TAGGED is - * returned if it is not a \ref CBOR_TAG_COSE_SIGN1 tag. - * - * See also \ref T_COSE_OPT_TAG_PROHIBITED. If neither this or - * \ref T_COSE_OPT_TAG_PROHIBITED is set then the content can - * either be COSE message (COSE_Sign1 CDDL from RFC 8152) or - * a COSESign1 tagg (COSE_Sign1_Tagged from RFC 8152). - * - * See t_cose_sign1_get_nth_tag() to get further tags that enclose - * the COSE message. - */ -#define T_COSE_OPT_TAG_REQUIRED 0x00000004 - - -/** - * Normally this will decode the CBOR presented as a \c COSE_Sign1 - * message whether it is tagged using QCBOR tagging as such or not. - * If this option is set, then \ref T_COSE_ERR_INCORRECTLY_TAGGED is - * returned if a \ref CBOR_TAG_COSE_SIGN1 tag. When this option is set the caller - * knows for certain that a COSE signed message is expected. - * - * See discussion on @ref T_COSE_OPT_TAG_REQUIRED. - */ -#define T_COSE_OPT_TAG_PROHIBITED 0x00000010 - - -/** - * See t_cose_sign1_set_verification_key(). - * - * This option disables cryptographic signature verification. With - * this option the \c verification_key is not needed. This is useful - * to decode the \c COSE_Sign1 message to get the kid (key ID). The - * verification key can be looked up or otherwise obtained by the - * caller. Once the key in in hand, t_cose_sign1_verify() can be - * called again to perform the full verification. - * - * The payload will always be returned whether this is option is given - * or not, but it should not be considered secure when this option is - * given. - */ -#define T_COSE_OPT_DECODE_ONLY 0x00000008 - - -/** - * This option disables verification that critical header parameters are - * known. - * - * Without this flag set, an error is raised during verification if there - * is an unknown header parameter in the critical header parameters list. - * However, if this flag is set then that part of verification is skipped. - */ -#define T_COSE_OPT_UNKNOWN_CRIT_ALLOWED 0x00000020 - - -/** - * The maximum number of unprocessed tags that can be returned by - * t_cose_sign1_get_nth_tag(). The CWT - * tag is an example of the tags that might returned. The COSE tags - * that are processed, don't count here. - */ -#define T_COSE_MAX_TAGS_TO_RETURN 4 - - -/** - * Context for signature verification. It is about 80 bytes on a - * 64-bit machine and 54 bytes on a 32-bit machine, or less if - * certain features are disabled. - */ -struct t_cose_sign1_verify_ctx { - /* Private data structure */ - struct t_cose_key verification_key; - uint32_t option_flags; - uint64_t auTags[T_COSE_MAX_TAGS_TO_RETURN]; - -#ifndef T_COSE_DISABLE_EDDSA - /** - * A auxiliary buffer provided by the caller, used to serialize - * the Sig_Structure. This is only needed when using EdDSA, as - * otherwise the Sig_Structure is hashed incrementally. - */ - struct q_useful_buf auxiliary_buffer; - - /* The size of the serialized Sig_Structure used in the last - * verification. This can be used by the user to determine a - * suitable auxiliary buffer size. - */ - size_t auxiliary_buffer_size; -#endif -}; - - -/** - * \brief Initialize for \c COSE_Sign1 message verification. - * - * \param[in,out] context The context to initialize. - * \param[in] option_flags Options controlling the verification. - * - * This must be called before using the verification context. - */ -static void -t_cose_sign1_verify_init(struct t_cose_sign1_verify_ctx *context, - uint32_t option_flags); - - -/** - * \brief Set key for \c COSE_Sign1 message verification. - * - * \param[in,out] context The t_cose signature verification context. - * \param[in] verification_key The verification key to use. - * - * There are four ways that the verification key is found and - * supplied to t_cose so that t_cose_sign1_verify() succeeds. - * - * -# Look up by kid parameter and set by t_cose_sign1_set_verification_key() - * -# Look up by other and set by t_cose_sign1_set_verification_key() - * -# Determination by kid that short circuit signing is used (test only) - * -# Look up by kid parameter in cryptographic adaptation layer - * - * Note that there is no means where certificates, like X.509 - * certificates, are provided in the COSE parameters. Perhaps there - * will be in the future but that is not in common use or supported by - * this implementation. - * - * To use 1, it is necessary to call t_cose_sign1_verify_init() and - * t_cose_sign1_verify() twice. The first time - * t_cose_sign1_verify_init() is called, give the \ref - * T_COSE_OPT_DECODE_ONLY option. Then call t_cose_sign1_verify() and - * the kid will be returned in \c parameters. The caller finds the kid on - * their own. Then call this to set the key. Last call - * t_cose_sign1_verify(), again without the \ref T_COSE_OPT_DECODE_ONLY - * option. - * - * To use 2, the key is somehow determined without the kid and - * t_cose_sign1_set_verification_key() is called with it. Then - * t_cose_sign1_verify() is called. Note that this implementation - * cannot return non-standard header parameters, at least not yet. - * - * To use 3, initialize with \ref T_COSE_OPT_ALLOW_SHORT_CIRCUIT. No - * call to t_cose_sign1_set_verification_key() is necessary. If you do - * call t_cose_sign1_set_verification_key(), the kid for short circuit - * signing will be recognized and the set key will be ignored. - * - * To use 4, first be sure that the cryptographic adapter supports - * look up by kid. There's no API to determine this, so it is - * probably determined by other system documentation (aka source - * code). In this mode, all that is necessary is to call - * t_cose_sign1_verify(). - * - * 3 always works no matter what is done in the cryptographic - * adaptation layer because it never calls out to it. The OpenSSL - * adaptor supports 1 and 2. - */ -static void -t_cose_sign1_set_verification_key(struct t_cose_sign1_verify_ctx *context, - struct t_cose_key verification_key); - - -/** - * \brief Configure a buffer used to serialize the Sig_Structure. - * - * \param[in,out] context The t_cose signature verification context. - * \param[in] auxiliary_buffer The auxiliary buffer to be used. - * - * Some signature algorithms (namely EdDSA), require two passes over - * their input. In order to achieve this, the library needs to serialize - * a temporary to-be-signed structure into an auxiliary buffer. This function - * allows the user to configure such a buffer. - * - * The buffer must be big enough to accomodate the Sig_Structure type, - * which is roughly the sum of sizes of the encoded protected parameters, - * aad and payload, along with a few dozen bytes of overhead. - * - * To compute the exact size needed, initialize the context with - * the \ref T_COSE_OPT_DECODE_ONLY option, and call the - * \ref t_cose_sign1_verify (or similar). After the message decoding, - * the necessary auxiliary buffer size is available by calling - * \ref t_cose_sign1_verify_auxiliary_buffer_size. - * - */ -static void -t_cose_sign1_verify_set_auxiliary_buffer(struct t_cose_sign1_verify_ctx *context, - struct q_useful_buf auxiliary_buffer); - -/** - * \brief Get the required auxiliary buffer size for the most recent - * verification operation. - * - * \param[in,out] context The t_cose signature verification context. - * - * \return The number of bytes of auxiliary buffer used by the most - * recent verification operation. - * - * This function can be called after \ref t_cose_sign1_verify (or - * equivalent) was called. If the context was initialized with the - * DECODE_ONLY flag, it returns the number of bytes that would have - * been used by the signing operation. This allows the caller to - * allocate an appropriately sized buffer before performing the - * actual verification. - * - * This function returns zero if the signature algorithm used does not - * need an auxiliary buffer. - */ -static size_t -t_cose_sign1_verify_auxiliary_buffer_size(struct t_cose_sign1_verify_ctx *context); - -/** - * \brief Verify a \c COSE_Sign1. - * - * \param[in,out] context The t_cose signature verification context. - * \param[in] sign1 Pointer and length of CBOR encoded \c COSE_Sign1 - * message that is to be verified. - * \param[out] payload Pointer and length of the payload. - * \param[out] parameters Place to return parsed parameters. May be \c NULL. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * See t_cose_sign1_set_verification_key() for discussion on where - * the verification key comes from. - * - * Verification involves the following steps. - * - * - The CBOR-format \c COSE_Sign1 structure is parsed. This makes - * sure \c COSE_Sign1 is valid CBOR and follows the required structure - * for \c COSE_Sign1. - * - * - The protected header parameters are decoded, particular the algorithm id. - * - * - The unprotected headers parameters are decoded, particularly the kid. - * - * - The payload is identified. The internals of the payload are not decoded. - * - * - The expected hash, the "to-be-signed" bytes are computed. The hash - * algorithm used comes from the signing algorithm. If the algorithm is - * unknown or not supported this will error out. - * - * - Finally, the signature verification is performed. - * - * If verification is successful, the pointer to the CBOR-encoded payload is - * returned. The parameters are returned if requested. All pointers - * returned are to memory in the \c sign1 passed in. - * - * Note that this only handles standard COSE header parameters. There - * are no facilities for custom header parameters, even though they - * are allowed by the COSE standard. - * - * This will recognize the special key ID for short-circuit signing - * and verify it if the \ref T_COSE_OPT_ALLOW_SHORT_CIRCUIT is set. - * - * Indefinite length CBOR strings are not supported by this - * implementation. \ref T_COSE_ERR_SIGN1_FORMAT will be returned if - * they are in the input \c COSE_Sign1 messages. For example, if the - * payload is an indefinite-length byte string, this error will be - * returned. - */ -static enum t_cose_err_t -t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *context, - struct q_useful_buf_c sign1, - struct q_useful_buf_c *payload, - struct t_cose_parameters *parameters); - - -/** - * \brief Verify a COSE_Sign1 with Additional Authenticated Data. - * - * \param[in,out] context The t_cose signature verification context. - * \param[in] sign1 Pointer and length of CBOR encoded \c COSE_Sign1 - * message that is to be verified. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[out] payload Pointer and length of the payload. - * \param[out] parameters Place to return parsed parameters. May be \c NULL. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This is just like t_cose_sign1_verify(), but allows passing AAD - * (Additional Authenticated Data) for verification. - * - * AAD is some additional bytes that are covered by the signature in - * addition to the payload. They may be any bytes, but are often some - * options or commands that are sent along with the \c COSE_Sign1. If - * a \c COSE_Sign1 was created with AAD, that AAD must be passed in - * here to successfully verify the signature. If it is not, a \ref - * T_COSE_ERR_SIG_VERIFY will occur. There is no indication in the \c - * COSE_Sign1 to know whether there was AAD input when it was - * created. It has to be known by context. - * - * Calling this with \c aad as \c NULL_Q_USEFUL_BUF_C is the same as - * calling t_cose_sign1_verify(). - */ -static enum t_cose_err_t -t_cose_sign1_verify_aad(struct t_cose_sign1_verify_ctx *context, - struct q_useful_buf_c sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c *payload, - struct t_cose_parameters *parameters); - - -/** - * \brief Verify a COSE_Sign1 with detached payload. - * - * \param[in,out] context The t_cose signature verification context. - * \param[in] cose_sign1 Pointer and length of CBOR encoded \c COSE_Sign1 - * message that is to be verified. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] detached_payload Pointer and length of the payload. - * \param[out] parameters Place to return parsed parameters. May be \c NULL. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * A detached payload is one that is not inside the \c COSE_Sign1, but - * is conveyed separately. It is still covered by the signature - * exactly as if it was the payload inside the \c COSE_Sign1. - * - * This function is the same as t_cose_sign1_verify_aad(), but for use - * with a detached payload. Instead of the payload being returned, it - * must be passed in as it must have arrived separately from the - * \c COSE_Sign1. The signature covers it so it must be passed in to - * complete the verification. - * - * \c aad may be \c NULL_Q_USEFUL_BUF_C if there is no AAD. - */ -static inline enum t_cose_err_t -t_cose_sign1_verify_detached(struct t_cose_sign1_verify_ctx *context, - struct q_useful_buf_c cose_sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - struct t_cose_parameters *parameters); - - -/** - * \brief Return unprocessed tags from most recent signature verify. - * - * \param[in] context The t_cose signature verification context. - * \param[in] n Index of the tag to return. - * - * \return The tag value or \ref CBOR_TAG_INVALID64 if there is no tag - * at the index or the index is too large. - * - * The 0th tag is the one for which the COSE message is the content. Loop - * from 0 up until \ref CBOR_TAG_INVALID64 is returned. The maximum - * is \ref T_COSE_MAX_TAGS_TO_RETURN. - * - * It will be necessary to call this for a general implementation - * of a CWT since sometimes the CWT tag is required. This is also - * needed for recursive processing of nested COSE signing and/or - * encryption. - */ -static uint64_t -t_cose_sign1_get_nth_tag(const struct t_cose_sign1_verify_ctx *context, - size_t n); - - - - -/* ------------------------------------------------------------------------ - * Inline implementations of public functions defined above. - */ -static inline void -t_cose_sign1_verify_init(struct t_cose_sign1_verify_ctx *me, - uint32_t option_flags) -{ - memset(me, 0, sizeof(*me)); - me->option_flags = option_flags; - -#ifndef T_COSE_DISABLE_EDDSA - /* Start with large (but NULL) auxiliary buffer. If EdDSA is used, - * the Sig_Structure data will be serialized here. - */ - me->auxiliary_buffer.len = SIZE_MAX; -#endif -} - - -static inline void -t_cose_sign1_set_verification_key(struct t_cose_sign1_verify_ctx *me, - struct t_cose_key verification_key) -{ - me->verification_key = verification_key; -} - -static inline void -t_cose_sign1_verify_set_auxiliary_buffer(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf auxiliary_buffer) -{ -#ifndef T_COSE_DISABLE_EDDSA - me->auxiliary_buffer = auxiliary_buffer; -#else - (void)me; - (void)auxiliary_buffer; -#endif -} - -static inline size_t -t_cose_sign1_verify_auxiliary_buffer_size(struct t_cose_sign1_verify_ctx *me) -{ -#ifndef T_COSE_DISABLE_EDDSA - return me->auxiliary_buffer_size; -#else - /* If EdDSA is disabled we don't ever need an auxiliary buffer. */ - (void)me; - return 0; -#endif -} - - -static inline uint64_t -t_cose_sign1_get_nth_tag(const struct t_cose_sign1_verify_ctx *context, - size_t n) -{ - if(n > T_COSE_MAX_TAGS_TO_RETURN) { - return CBOR_TAG_INVALID64; - } - return context->auTags[n]; -} - - -/** - * \brief Semi-private function to verify a COSE_Sign1. - * - * \param[in,out] me The t_cose signature verification context. - * \param[in] sign1 Pointer and length of CBOR encoded \c COSE_Sign1 - * message that is to be verified. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in,out] payload Pointer and length of the payload. - * \param[out] parameters Place to return parsed parameters. May be \c NULL. - * \param[in] is_detached Indicates the payload is detached. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This does the work for t_cose_sign1_verify(), - * t_cose_sign1_verify_aad() and t_cose_sign1_verify_detached(). It is - * a semi-private function which means its interface isn't guaranteed - * so it should not to call it directly. - */ -enum t_cose_err_t -t_cose_sign1_verify_internal(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf_c sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c *payload, - struct t_cose_parameters *parameters, - bool is_detached); - - -static inline enum t_cose_err_t -t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf_c sign1, - struct q_useful_buf_c *payload, - struct t_cose_parameters *parameters) -{ - return t_cose_sign1_verify_internal(me, - sign1, - NULL_Q_USEFUL_BUF_C, - payload, - parameters, - false); -} - - -static inline enum t_cose_err_t -t_cose_sign1_verify_aad(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf_c cose_sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c *payload, - struct t_cose_parameters *parameters) -{ - return t_cose_sign1_verify_internal(me, - cose_sign1, - aad, - payload, - parameters, - false); -} - - -static inline enum t_cose_err_t -t_cose_sign1_verify_detached(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf_c cose_sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - struct t_cose_parameters *parameters) -{ - return t_cose_sign1_verify_internal(me, - cose_sign1, - aad, - &detached_payload, - parameters, - true); -} - -#ifdef __cplusplus -} -#endif - -#endif /* __T_COSE_SIGN1_VERIFY_H__ */ diff --git a/3rdparty/internal/t_cose/main.c b/3rdparty/internal/t_cose/main.c deleted file mode 100644 index bb256e3ac98e..000000000000 --- a/3rdparty/internal/t_cose/main.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * main.c - * - * Copyright 2019-2020, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md. - * - * Created 4/21/2019. - */ - -#include -#include "run_tests.h" -#include "t_cose_make_test_pub_key.h" - - -/* - This is an implementation of OutputStringCB built using stdio. If - you don't have stdio, replaces this. - */ -static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) -{ - fputs(szString, (FILE *)pOutCtx); - if(bNewLine) { - fputs("\n", pOutCtx); - } -} - - -int main(int argc, const char * argv[]) -{ - int return_value; - - (void)argc; // Avoid unused parameter error - - // This call prints out sizes of data structures to remind us - // to keep them small. - PrintSizesTCose(&fputs_wrapper, stdout); - - // This runs all the tests - return_value = RunTestsTCose(argv+1, &fputs_wrapper, stdout, NULL); - - if(return_value) { - return return_value; - } - - return_value = check_for_key_pair_leaks(); - if(return_value) { - printf("Detected key pair leaks: %d FAIL\n", return_value); - } - - return return_value; -} diff --git a/3rdparty/internal/t_cose/mainpage.dox b/3rdparty/internal/t_cose/mainpage.dox deleted file mode 100644 index 0fb69c71f88c..000000000000 --- a/3rdparty/internal/t_cose/mainpage.dox +++ /dev/null @@ -1,18 +0,0 @@ -/*! @mainpage t_cose Documentation - -t_cose 1.x is available for download [here on github](http://github.com/laurencelundblade/t_cose) -(alpha release of t_cose 2.x which supports encryption, multiple signature and mac is also available). - -This documentation is for t_cose 1.x. - -@par Table of Contents - -API Reference: -- Common - - Error codes and common constants: @ref inc/t_cose/t_cose_common.h "t_cose_common.h" -- Signing - - Main/Basic signing functions: @ref inc/t_cose/t_cose_sign1_sign.h "t_cose_sign1_sign.h" -- Verification - - Main/Basic verification functions: @ref inc/t_cose/t_cose_sign1_verify.h "t_cose_sign1_verify.h" - -*/ diff --git a/3rdparty/internal/t_cose/src/t_cose_crypto.h b/3rdparty/internal/t_cose/src/t_cose_crypto.h deleted file mode 100644 index 9eba64f8eb30..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_crypto.h +++ /dev/null @@ -1,710 +0,0 @@ -/* - * t_cose_crypto.h - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef __T_COSE_CRYPTO_H__ -#define __T_COSE_CRYPTO_H__ - -#include -#include -#include "t_cose/t_cose_common.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose_standard_constants.h" - -#ifdef __cplusplus -extern "C" { -#endif - - - - -/** - * \file t_cose_crypto.h - * - * \brief This defines the adaptation layer for cryptographic - * functions needed by t_cose. - * - * This is small wrapper around the cryptographic functions to: - * - Map COSE algorithm IDs to cryptographic library IDs - * - Map cryptographic library errors to \ref t_cose_err_t errors - * - Have inputs and outputs be \c struct \c q_useful_buf_c and - * \c struct \c q_useful_buf - * - Handle key selection - * - * An implementation must be made of these functions - * for the various cryptographic libraries that are used on - * various platforms and OSs. The functions are: - * - t_cose_t_crypto_sig_size() - * - t_cose_crypto_pub_key_sign() - * - t_cose_crypto_pub_key_verify() - * - t_cose_crypto_hash_start() - * - t_cose_crypto_hash_update() - * - t_cose_crypto_hash_finish() - * - * This runs entirely off of COSE-style algorithm identifiers. They - * are simple integers and thus work nice as function parameters. An - * initial set is defined by [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152). New ones can be registered - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). Local use new - * ones can also be defined (\c \#define) if what is needed is not in - * the IANA registry. - * - * \anchor useful_buf_use - * Binary data is returned to the caller using a \c struct \c - * q_useful_buf to pass the buffer to receive the data and its length in - * and a \c q_useful_buf_c to return the pointer and length of the - * returned data. The point of this is coding hygiene. The buffer - * passed in is not const as it is to be modified. The \c - * q_useful_buf_c returned is const. The lengths of buffers are - * handled in a clear, consistent and enforced manner. - * - * The pointer in the \c q_useful_buf_c will always point to the - * buffer passed in via the \c q_useful_buf so the lifetime of the - * data is under control of the caller. - * - * This is not intended as any sort of general cryptographic API. It - * is just the functions needed by t_cose in the form that is most - * useful for t_cose. - * - * No other file in t_cose should need modification for new algorithms, - * new key types and sizes or the integration of cryptographic libraries - * except on some occasions, this file as follows: - * - * - Support for a new COSE_ALGORITHM_XXX signature algorithm - * - See t_cose_algorithm_is_ecdsa() - * - If not ECDSA add another function like t_cose_algorithm_is_ecdsa() - * - Support for a new COSE_ALGORITHM_XXX signature algorithm is added - * - See \ref T_COSE_CRYPTO_MAX_HASH_SIZE for additional hashes - * - Support another hash implementation that is not a service - * - See struct \ref t_cose_crypto_hash - * - * To reduce stack usage and save a little code these can be defined. - * - T_COSE_DISABLE_ES384 - * - T_COSE_DISABLE_ES512 - * - * The actual code that implements these hashes in the crypto library may - * or may not be saved with these defines depending on how the library - * works, whether dead stripping of object code is on and such. - */ - - - - -#define T_COSE_EC_P256_SIG_SIZE 64 /* size for secp256r1 */ -#define T_COSE_EC_P384_SIG_SIZE 96 /* size for secp384r1 */ -#define T_COSE_EC_P512_SIG_SIZE 132 /* size for secp521r1 */ - - -/** - * There is a stack variable to hold the output of the signing - * operation. This sets the maximum signature size this code can - * handle based on the COSE algorithms configured. The size of the - * signature goes with the size of the key, not the algorithm, so a - * key could be given for signing or verification that is larger than - * this. However, it is not typical to do so. If the key or signature - * is too large the failure will be graceful with an error. - * - * For ECDSA the signature format used is defined in RFC 8152 section - * 8.1. It is the concatenation of r and s, each of which is the key - * size in bits rounded up to the nearest byte. That is twice the key - * size in bytes. - * - * RSA signatures are typically much larger than this, but do not need - * to be stored on the stack, since the COSE format is the same as the - * one OpenSSL understands natively. The stack variable therefore does - * not need to be made large enough to fit these signatures. - */ -#ifndef T_COSE_DISABLE_ES512 - #define T_COSE_MAX_ECDSA_SIG_SIZE T_COSE_EC_P512_SIG_SIZE -#else - #ifndef T_COSE_DISABLE_ES384 - #define T_COSE_MAX_ECDSA_SIG_SIZE T_COSE_EC_P384_SIG_SIZE - #else - #define T_COSE_MAX_ECDSA_SIG_SIZE T_COSE_EC_P256_SIG_SIZE - #endif -#endif - - - -/* - * Says where a particular algorithm is supported or not. - * Most useful for test code that wants to know if a - * test should be attempted or not. - * - * See t_cose_is_algorithm_supported() - */ -bool t_cose_crypto_is_algorithm_supported(int32_t cose_algorithm_id); - -/** - * \brief Returns the size of a signature given the key and algorithm. - * - * \param[in] cose_algorithm_id The algorithm ID - * \param[in] signing_key Key to compute size of - * \param[out] sig_size The returned size in bytes. - * - * \return An error code or \ref T_COSE_SUCCESS. - * - * This is used the caller wishes to compute the size of a token in - * order to allocate memory for it. - * - * The size of a signature depends primarily on the key size but it is - * usually necessary to know the algorithm too. - * - * This always returns the exact size of the signature. - */ -enum t_cose_err_t -t_cose_crypto_sig_size(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - size_t *sig_size); - - -/** - * \brief Perform public key signing. Part of the t_cose crypto - * adaptation layer. - * - * \param[in] cose_algorithm_id The algorithm to sign with. The IDs are - * defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) or - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * A proprietary ID can also be defined - * locally (\c \#define) if the needed - * one hasn't been registered. - * \param[in] signing_key Indicates or contains key to sign with. - * \param[in] hash_to_sign The bytes to sign. Typically, a hash of - * a payload. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \retval T_COSE_SUCCESS - * Successfully created the signature. - * \retval T_COSE_ERR_SIG_BUFFER_SIZE - * The \c signature_buffer too small. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * The requested signing algorithm, \c cose_algorithm_id, is not - * supported. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select was not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Insufficient heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_CORRUPTION_DETECTED. - * - * This is called to do public key signing. The implementation will - * vary from one platform / OS to another but should conform to the - * description here. - * - * The contents of signing_key is usually the type that holds - * a key for the cryptographic library. - * - * See the note in the Detailed Description (the \\file comment block) - * for details on how \c q_useful_buf and \c q_useful_buf_c are used - * to return the signature. - * - */ -enum t_cose_err_t -t_cose_crypto_sign(int32_t cose_algorithm_id, - struct t_cose_key signing_key, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature); - - -/** - * \brief Perform public key signature verification. Part of the - * t_cose crypto adaptation layer. - * - * \param[in] cose_algorithm_id The algorithm to use for verification. - * The IDs are defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) - * or in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * A proprietary ID can also be defined - * locally (\c \#define) if the needed one - * hasn't been registered. - * \param[in] verification_key The verification key to use. - * \param[in] kid The COSE kid (key ID) or \c NULL_Q_USEFUL_BUF_C. - * \param[in] hash_to_verify The hash of the data that is to be verified. - * \param[in] signature The COSE-format signature. - * - * This verifies that the \c signature passed in was over the \c - * hash_to_verify passed in. - * - * The public key used to verify the signature is selected by the \c - * kid if it is not \c NULL_Q_USEFUL_BUF_C or the \c key_select if it - * is. - * - * The key selected must be, or include, a public key of the correct - * type for \c cose_algorithm_id. - * - * \retval T_COSE_SUCCESS - * The signature is valid - * \retval T_COSE_ERR_SIG_VERIFY - * Signature verification failed. For example, the - * cryptographic operations completed successfully but hash - * wasn't as expected. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select or a \c kid was - * not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type - * for the operation. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * The requested signing algorithm is not supported. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Out of heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_CORRUPTION_DETECTED. - */ -enum t_cose_err_t -t_cose_crypto_verify(int32_t cose_algorithm_id, - struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c hash_to_verify, - struct q_useful_buf_c signature); - -#ifndef T_COSE_DISABLE_EDDSA - -/** - * \brief Perform public key signing for EdDSA. - * - * The EdDSA signing algorithm (or more precisely its PureEdDSA - * variant, used in COSE) requires two passes over the input data. - * This requires the whole to-be-signed structure to be held in - * memory and given as an argument to this function, rather than - * an incrementally computed hash. - * - * \param[in] signing_key Indicates or contains key to sign with. - * \param[in] tbs The bytes to sign. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \retval T_COSE_SUCCESS - * Successfully created the signature. - * \retval T_COSE_ERR_SIG_BUFFER_SIZE - * The \c signature_buffer too small. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * EdDSA signatures are not supported. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select was not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Insufficient heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_CORRUPTION_DETECTED. - * - * This is called to do public key signing. The implementation will - * vary from one platform / OS to another but should conform to the - * description here. - * - * The contents of signing_key is usually the type that holds - * a key for the cryptographic library. - * - * See the note in the Detailed Description (the \\file comment block) - * for details on how \c q_useful_buf and \c q_useful_buf_c are used - * to return the signature. - * - */ -enum t_cose_err_t -t_cose_crypto_sign_eddsa(struct t_cose_key signing_key, - struct q_useful_buf_c tbs, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature); - -/** - * \brief Perform public key signature verification for EdDSA. - * - * The EdDSA signing algorithm (or more precisely its PureEdDSA - * variant, used in COSE) requires two passes over the input data. - * This requires the whole to-be-signed structure to be held in - * memory and given as an argument to this function, rather than - * an incrementally computed hash. - * - * \param[in] verification_key The verification key to use. - * \param[in] kid The COSE kid (key ID) or \c NULL_Q_USEFUL_BUF_C. - * \param[in] tbs The data to be verified. - * \param[in] signature The COSE-format signature. - * - * The key selected must be of the correct type for EdDSA - * signatures. - * - * \retval T_COSE_SUCCESS - * The signature is valid - * \retval T_COSE_ERR_SIG_VERIFY - * Signature verification failed. For example, the - * cryptographic operations completed successfully but hash - * wasn't as expected. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select or a \c kid was - * not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type - * for the operation. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * EdDSA signatures are not supported. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Out of heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_CORRUPTION_DETECTED. - */ -enum t_cose_err_t -t_cose_crypto_verify_eddsa(struct t_cose_key verification_key, - struct q_useful_buf_c kid, - struct q_useful_buf_c tbs, - struct q_useful_buf_c signature); -#endif /* T_COSE_DISABLE_EDDSA */ - -#ifdef T_COSE_USE_PSA_CRYPTO -#include "psa/crypto.h" - -#elif T_COSE_USE_OPENSSL_CRYPTO -#include "openssl/evp.h" - -#elif T_COSE_USE_B_CON_SHA256 -/* This is code for use with Brad Conte's crypto. See - * https://github.com/B-Con/crypto-algorithms and see the description - * of t_cose_crypto_hash - */ -#include "sha256.h" -#endif - - -/** - * The context for use with the hash adaptation layer here. - * - * Hash implementations for this porting layer are put into two - * different categories. - * - * The first can be supported generically without any dependency on - * the actual hash implementation in this header. These only need a - * pointer or handle for the hash context. Usually these are - * implemented by a service, system API or crypto HW that runs in a - * separate context or process. They probably allocate memory - * internally. These can use context.ptr or context.handle to hold the - * pointer or handle to the hash context. - * - * The second sort of hash implementations need more than just a - * pointer or handle. Typically these are libraries that are linked - * with this code and run in the same process / context / thread as - * this code. These can be efficient requiring no context switches or - * memory allocations. These type require this header be modified for - * the #include which defines the hash context and so this struct - * includes that context as a member. This context is allocated on the - * stack, so any members added here should be small enough to go on - * the stack. USE_B_CON_SHA256 is an example of this type. - * - * The actual implementation of the hash is in a separate .c file - * that will be specific to the particular platform, library, - * service or such used. - */ -struct t_cose_crypto_hash { - - #ifdef T_COSE_USE_PSA_CRYPTO - /* --- The context for PSA Crypto (MBed Crypto) --- */ - - /* psa_hash_operation_t actually varied by the implementation of - * the crypto library. Sometimes the implementation is inline and - * thus the context is a few hundred bytes, sometimes it is not. - * This varies by what is in crypto_struct.h (which is not quite - * a public interface). - * - * This can be made smaller for PSA implementations that work inline - * by disabling the larger algorithms using PSA / MBed configuration. - */ - psa_hash_operation_t ctx; - psa_status_t status; - - #elif T_COSE_USE_OPENSSL_CRYPTO - /* --- The context for OpenSSL crypto --- */ - EVP_MD_CTX *evp_ctx; - int update_error; /* Used to track error return by SHAXXX_Update() */ - int32_t cose_hash_alg_id; /* COSE integer ID for the hash alg */ - - #elif T_COSE_USE_B_CON_SHA256 - /* --- Specific context for Brad Conte's sha256.c --- */ - SHA256_CTX b_con_hash_context; - - #else - /* --- Default: generic pointer / handle --- */ - - union { - void *ptr; - uint64_t handle; - } context; - int64_t status; - #endif - -}; - - -/** - * The size of the output of SHA-256. - * - * (It is safe to define these independently here as they are - * well-known and fixed. There is no need to reference - * platform-specific headers and incur messy dependence.) - */ -#define T_COSE_CRYPTO_SHA256_SIZE 32 - -/** - * The size of the output of SHA-384 in bytes. - */ -#define T_COSE_CRYPTO_SHA384_SIZE 48 - -/** - * The size of the output of SHA-512 in bytes. - */ -#define T_COSE_CRYPTO_SHA512_SIZE 64 - - -/** - * The maximum needed to hold a hash. It is smaller and less stack is needed - * if the larger hashes are disabled. - */ -#if !defined(T_COSE_DISABLE_ES512) || !defined(T_COSE_DISABLE_PS512) - #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA512_SIZE -#else - #if !defined(T_COSE_DISABLE_ES384) || !defined(T_COSE_DISABLE_PS384) - #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA384_SIZE - #else - #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA256_SIZE - #endif -#endif - - -/** - * \brief Start cryptographic hash. Part of the t_cose crypto - * adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context that - * will be initialized. - * \param[in] cose_hash_alg_id Algorithm ID that identifies the - * hash to use. This is from the - * [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml) - * - * \retval T_COSE_ERR_UNSUPPORTED_HASH - * The requested algorithm is unknown or unsupported. - * - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * Some general failure of the hash function - * - * \retval T_COSE_SUCCESS - * Success. - * - * This initializes the hash context for the particular algorithm. It - * must be called first. A \c hash_ctx can be reused if it is - * reinitialized. - * - * \ref T_COSE_INVALID_ALGORITHM_ID may be passed to this function, in which - * case \ref T_COSE_ERR_UNSUPPORTED_HASH must be returned. - * - * Other errors can be returned and will usually be propagated up, but hashes - * generally don't fail so it is suggested not to bother (and to reduce - * object code size for mapping errors). - */ -enum t_cose_err_t -t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id); - - -/** - * \brief Feed data into a cryptographic hash. Part of the t_cose - * crypto adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context in which - * accumulate the hash. - * \param[in] data_to_hash Pointer and length of data to feed into - * hash. The pointer may by \c NULL in which - * case no hashing is performed. - * - * There is no return value. If an error occurs it is remembered in \c - * hash_ctx and returned when t_cose_crypto_hash_finish() is called. - * Once in the error state, this function may be called, but it will - * not do anything. - * - * This function can be called with \c data_to_hash.ptr NULL and it - * will pretend to hash. This allows the same code that is used to - * produce the real hash to be used to return a length of the would-be - * hash for encoded data structure size calculations. - */ -void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf_c data_to_hash); - - -/** - * \brief Finish a cryptographic hash. Part of the t_cose crypto - * adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context. - * \param[in] buffer_to_hold_result Pointer and length into which - * the resulting hash is put. - * \param[out] hash_result Pointer and length of the - * resulting hash. - * - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * Some general failure of the hash function. - * \retval T_COSE_ERR_HASH_BUFFER_SIZE - * The size of the buffer to hold the hash result was - * too small. - * \retval T_COSE_SUCCESS - * Success. - * - * Call this to complete the hashing operation. If the everything - * completed correctly, the resulting hash is returned. Note that any - * errors that occurred during t_cose_crypto_hash_update() are - * returned here. - * - * See \ref useful_buf_use for details on how \c q_useful_buf and - * \c q_useful_buf_c are used to return the hash. - * - * Other errors can be returned and will usually be propagated up, but - * hashes generally don't fail so it is suggested not to bother (and - * to reduce object code size for mapping errors). - */ -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf buffer_to_hold_result, - struct q_useful_buf_c *hash_result); - - - -/** - * \brief Indicate whether a COSE algorithm is ECDSA or not. - * - * \param[in] cose_algorithm_id The algorithm ID to check. - * - * \returns This returns \c true if the algorithm is ECDSA and \c false if not. - * - * This is a convenience function to check whether a given - * integer COSE algorithm ID uses the ECDSA signing algorithm - * or not. - * - */ -static bool -t_cose_algorithm_is_ecdsa(int32_t cose_algorithm_id); - -/** - * \brief Indicate whether a COSE algorithm is RSASSA-PSS or not. - * - * \param[in] cose_algorithm_id The algorithm ID to check. - * - * \returns This returns \c true if the algorithm is RSASSA-PSS - * and \c false if not. - * - * This is a convenience function to check whether a given - * integer COSE algorithm ID uses the RSASSA-PSS signing algorithm - * or not. - * - */ -static bool -t_cose_algorithm_is_rsassa_pss(int32_t cose_algorithm_id); - - - - -/* - * Inline implementations. See documentation above. - */ - -/** - * \brief Look for an integer in a zero-terminated list of integers. - * - * \param[in] cose_algorithm_id The algorithm ID to check. - * \param[in] list zero-terminated list of algorithm IDs. - * - * \returns This returns \c true if an integer is in the list, \c false if not. - * - * Used to implement t_cose_algorithm_is_ecdsa() and in the future - * _is_rsa() and such. - * - * Typically used once in the crypto adaptation layer, so defining it - * inline rather than in a .c file is OK and saves creating a whole - * new .c file just for this. - */ -static inline bool -t_cose_check_list(int32_t cose_algorithm_id, const int32_t *list) -{ - while(*list) { - if(*list == cose_algorithm_id) { - return true; - } - list++; - } - - return false; -} - -static inline bool -t_cose_algorithm_is_ecdsa(int32_t cose_algorithm_id) -{ - /* The simple list of COSE alg IDs that use ECDSA */ - static const int32_t ecdsa_list[] = { - COSE_ALGORITHM_ES256, -#ifndef T_COSE_DISABLE_ES384 - COSE_ALGORITHM_ES384, -#endif -#ifndef T_COSE_DISABLE_ES512 - COSE_ALGORITHM_ES512, -#endif - 0}; /* 0 is a reserved COSE alg ID and will never be used */ - - return t_cose_check_list(cose_algorithm_id, ecdsa_list); -} - -static inline bool -t_cose_algorithm_is_rsassa_pss(int32_t cose_algorithm_id) -{ - /* The simple list of COSE alg IDs that use RSASSA-PSS */ - static const int32_t rsa_list[] = { -#ifndef T_COSE_DISABLE_PS256 - COSE_ALGORITHM_PS256, -#endif -#ifndef T_COSE_DISABLE_PS384 - COSE_ALGORITHM_PS384, -#endif -#ifndef T_COSE_DISABLE_PS512 - COSE_ALGORITHM_PS512, -#endif - 0}; /* 0 is a reserved COSE alg ID and will never be used */ - - return t_cose_check_list(cose_algorithm_id, rsa_list); -} - - -#ifdef __cplusplus -} -#endif - -#endif /* __T_COSE_CRYPTO_H__ */ diff --git a/3rdparty/internal/t_cose/src/t_cose_parameters.c b/3rdparty/internal/t_cose/src/t_cose_parameters.c deleted file mode 100644 index c175abb891b1..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_parameters.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * t_cose_parameters.c - * - * Copyright 2019-2020, Laurence Lundblade - * Copyright (c) 2021, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#include "t_cose_parameters.h" -#include "t_cose_standard_constants.h" -#include "qcbor/qcbor_spiffy_decode.h" - - -/** - * \file t_cose_parameters.c - * - * \brief Implementation of COSE header parameter decoding. - * - */ - - -/** - * \brief Add a new label to the end of the label list. - * - * \param[in] item Data item to add to the label list. - * \param[in,out] label_list The list to add to. - * - * \retval T_COSE_SUCCESS If added correctly. - * \retval T_COSE_ERR_TOO_MANY_PARAMETERS Label list is full. - * \retval T_COSE_ERR_PARAMETER_CBOR The item to add doesn't have a label - * type that is understood - * - * The label / key from \c item is added to \c label_list. - */ -static inline enum t_cose_err_t -add_label_to_list(const QCBORItem *item, struct t_cose_label_list *label_list) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 16 8 - * TOTAL 16 8 - */ - /* Stack use: 16 bytes for 64-bit */ - enum t_cose_err_t return_value; - uint_fast8_t n; - - /* Assume success until an error adding is encountered. */ - return_value = T_COSE_SUCCESS; - - if(item->uLabelType == QCBOR_TYPE_INT64) { - /* Add an integer-labeled parameter to the end of the list */ - for(n = 0; label_list->int_labels[n] != LABEL_LIST_TERMINATOR; n++); - if(n == T_COSE_PARAMETER_LIST_MAX) { - /* List is full -- error out */ - return_value = T_COSE_ERR_TOO_MANY_PARAMETERS; - goto Done; - } - label_list->int_labels[n] = item->label.int64; - - } else if(item->uLabelType == QCBOR_TYPE_TEXT_STRING) { - /* Add a string-labeled parameter to the end of the list */ - for(n = 0; !q_useful_buf_c_is_null(label_list->tstr_labels[n]); n++); - if(n == T_COSE_PARAMETER_LIST_MAX) { - /* List is full -- error out */ - return_value = T_COSE_ERR_TOO_MANY_PARAMETERS; - goto Done; - } - label_list->tstr_labels[n] = item->label.string; - - } else { - /* error because label is neither integer or string */ - /* Should never occur because this is caught earlier, but - * leave it to be safe and because inlining and optimization - * should take out any unneeded code - */ - return_value = T_COSE_ERR_PARAMETER_CBOR; - } - -Done: - return return_value; -} - - -/** - * \brief Indicate whether label list is clear or not. - * - * \param[in,out] list The list to check. - * - * \return true if the list is clear. - */ -inline static bool -is_label_list_clear(const struct t_cose_label_list *list) -{ - return list->int_labels[0] == 0 && - q_useful_buf_c_is_null_or_empty(list->tstr_labels[0]); -} - - -/** - * \brief Decode the parameter containing the labels of parameters considered - * critical. - * - * \param[in,out] decode_context Decode context to read critical - * parameter list from. - * \param[out] critical_labels List of labels of critical - * parameters. - * - * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED Undecodable CBOR. - * \retval T_COSE_ERR_TOO_MANY_PARAMETERS More critical labels than this - * implementation can handle. - * \retval T_COSE_ERR_PARAMETER_CBOR Unexpected CBOR data type. - */ -static inline enum t_cose_err_t -decode_critical_parameter(QCBORDecodeContext *decode_context, - struct t_cose_label_list *critical_labels) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * QCBORItem 56 52 - * local vars 32 16 - * TOTAL 88 68 - */ - QCBORItem item; - uint_fast8_t num_int_labels; - uint_fast8_t num_tstr_labels; - enum t_cose_err_t return_value; - QCBORError cbor_result; - - /* Assume that decoder has been entered into the parameters map */ - - /* Find and enter the array that is the critical parameters parameter */ - QCBORDecode_EnterArrayFromMapN(decode_context, COSE_HEADER_PARAM_CRIT); - - cbor_result = QCBORDecode_GetAndResetError(decode_context); - if(cbor_result == QCBOR_ERR_LABEL_NOT_FOUND) { - /* Critical paratmeters parameter doesn't exist */ - return_value = T_COSE_SUCCESS; - goto Done; - } else if(cbor_result != QCBOR_SUCCESS) { - return_value = T_COSE_ERR_CRIT_PARAMETER; - goto Done; - } - - if(critical_labels == NULL) { - /* crit parameter occuring in non-protected bucket */ - return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED; - goto Done; - } - - num_int_labels = 0; - num_tstr_labels = 0; - - while(1) { - cbor_result = QCBORDecode_GetNext(decode_context, &item); - if(cbor_result == QCBOR_ERR_NO_MORE_ITEMS) { - /* successful exit from loop */ - break; - } - if(cbor_result != QCBOR_SUCCESS) { - return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED; - goto Done; - } - - if(item.uDataType == QCBOR_TYPE_INT64) { - if(num_int_labels >= T_COSE_PARAMETER_LIST_MAX) { - return_value = T_COSE_ERR_CRIT_PARAMETER; - goto Done; - } - critical_labels->int_labels[num_int_labels++] = item.val.int64; - } else if(item.uDataType == QCBOR_TYPE_TEXT_STRING) { - if(num_tstr_labels >= T_COSE_PARAMETER_LIST_MAX) { - return_value = T_COSE_ERR_CRIT_PARAMETER; - goto Done; - } - critical_labels->tstr_labels[num_tstr_labels++] = item.val.string; - } else { - return_value = T_COSE_ERR_CRIT_PARAMETER; - goto Done; - } - } - - /* Exit out of array back up to parameters map */ - QCBORDecode_ExitArray(decode_context); - - if(is_label_list_clear(critical_labels)) { - /* Per RFC 8152 crit parameter can't be empty */ - return_value = T_COSE_ERR_CRIT_PARAMETER; - goto Done; - } - - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - -/** - * Public function. See t_cose_parameters.h - */ -enum t_cose_err_t -check_critical_labels(const struct t_cose_label_list *critical_labels, - const struct t_cose_label_list *unknown_labels) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 24 12 - * TOTAL 24 12 - */ - enum t_cose_err_t return_value; - uint_fast8_t num_unknown; - uint_fast8_t num_critical; - - /* Assume success until an unhandled critical label is found */ - return_value = T_COSE_SUCCESS; - - /* Iterate over unknown integer parameters */ - for(num_unknown = 0; unknown_labels->int_labels[num_unknown]; num_unknown++) { - /* Iterate over critical int labels looking for the unknown label */ - for(num_critical = 0; - critical_labels->int_labels[num_critical]; - num_critical++) { - if(critical_labels->int_labels[num_critical] == unknown_labels->int_labels[num_unknown]) { - /* Found a critical label that is unknown to us */ - return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER; - goto Done; - } - } - /* Exit from loop here means all no unknown label was critical */ - } - - /* Iterate over unknown string labels */ - for(num_unknown = 0; !q_useful_buf_c_is_null(unknown_labels->tstr_labels[num_unknown]); num_unknown++) { - /* iterate over critical string labels looking for the unknown param */ - for(num_critical = 0; !q_useful_buf_c_is_null(critical_labels->tstr_labels[num_critical]); num_critical++) { - if(!q_useful_buf_compare(critical_labels->tstr_labels[num_critical], - unknown_labels->tstr_labels[num_unknown])){ - /* Found a critical label that is unknown to us */ - return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER; - goto Done; - } - } - /* Exit from loop here means all no unknown label was critical */ - } - -Done: - return return_value; -} - - -struct cb_context { - struct t_cose_label_list *unknown_labels; - enum t_cose_err_t return_value; -}; - -/** - * \brief Add unknown parameter to unknown labels list - * - * \param[in] pCallbackCtx Callback context. - * \param[in] pItem The data item for the unknown parameter. - * - * \returns On failure to add to the list (because it is full) this returns - * \ref QCBOR_ERR_CALLBACK_FAIL to signal an error in traversal. - * The error details is in \c context->return_value. - * - * This gets called through QCBORDecode_GetItemsInMapWithCallback() on - * any parameter that is not recognized. (Maybe someday this will call - * out further to allow t_cose to handle custom parameters). - */ -static QCBORError header_parameter_callback(void *pCallbackCtx, const QCBORItem *pItem) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 16 8 - * TOTAL 16 8 - */ - struct cb_context *context = (struct cb_context *)pCallbackCtx; - enum t_cose_err_t result; - - if(pItem->uLabelType == QCBOR_TYPE_INT64 && - pItem->label.int64 == COSE_HEADER_PARAM_CRIT) { - /* header parameters that are not processed through the - * call to QCBORDecode_GetItemsInMapWithCallback show up - * here, but are not unknown header parameters. There is - * only one: COSE_HEADER_PARAM_CRIT - */ - result = T_COSE_SUCCESS; - } else { - /* Add an unknown header parameter to the list or unknowns */ - result = add_label_to_list(pItem, context->unknown_labels); - } - - context->return_value = result; - - if(result == T_COSE_SUCCESS) { - return QCBOR_SUCCESS; - } else { - return QCBOR_ERR_CALLBACK_FAIL; - } -} - - -/** - * \brief Parse some COSE header parameters. - * - * \param[in] decode_context The QCBOR decode context to read from. - * \param[out] parameters The parsed parameters being returned. - * \param[out] critical_labels The parsed list of critical labels if - * parameter is present. - * \param[out] unknown_labels The list of labels that were not recognized. - * - * \retval T_COSE_SUCCESS The parameters were decoded - * correctly. - * \retval T_COSE_ERR_PARAMETER_CBOR CBOR is parsable, but not the - * right structure (e.g. array - * instead of a map) - * \retval T_COSE_ERR_TOO_MANY_PARAMETERS More than - * \ref T_COSE_PARAMETER_LIST_MAX - * parameters. - * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED The CBOR is not parsable. - * \retval T_COSE_ERR_NON_INTEGER_ALG_ID The algorithm ID is not an - * integer. This implementation - * doesn't support string algorithm - * IDs. - * \retval T_COSE_ERR_BAD_CONTENT_TYPE Error in content type parameter. - * \retval T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER A label marked critical is - * present and not understood. - * - * No header parameters are mandatory. Which parameters were present - * or not is indicated in \c returned_parameters. It is OK for there - * to be no parameters at all. - * - * The first item to be read from the decode_context must be the map - * data item that contains the parameters. - */ -enum t_cose_err_t -parse_cose_header_parameters(QCBORDecodeContext *decode_context, - struct t_cose_parameters *parameters, - struct t_cose_label_list *critical_labels, - struct t_cose_label_list *unknown_labels) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 32 16 - * header_items 336 312 - * MAX (GetItemsInMapWithCallback+CB 432 316 - * decode_critical 88 68) 432 316 - * TOTAL 768 628 - */ - enum t_cose_err_t return_value; - QCBORError qcbor_result; - struct cb_context callback_context = {unknown_labels, 0}; - - /* Get all the non-aggregate headers in one fell swoop with - * QCBORDecode_GetItemsInMapWithCallback(). - */ -#define ALG_INDEX 0 -#define KID_INDEX 1 -#define IV_INDEX 2 -#define PARTIAL_IV_INDEX 3 -#define CONTENT_TYPE 4 -#define END_INDEX 5 - QCBORItem header_items[END_INDEX+1]; - - QCBORDecode_EnterMap(decode_context, NULL); - - header_items[ALG_INDEX].label.int64 = COSE_HEADER_PARAM_ALG; - header_items[ALG_INDEX].uLabelType = QCBOR_TYPE_INT64; - header_items[ALG_INDEX].uDataType = QCBOR_TYPE_INT64; - - header_items[KID_INDEX].label.int64 = COSE_HEADER_PARAM_KID; - header_items[KID_INDEX].uLabelType = QCBOR_TYPE_INT64; - header_items[KID_INDEX].uDataType = QCBOR_TYPE_BYTE_STRING; - - header_items[IV_INDEX].label.int64 = COSE_HEADER_PARAM_IV; - header_items[IV_INDEX].uLabelType = QCBOR_TYPE_INT64; - header_items[IV_INDEX].uDataType = QCBOR_TYPE_BYTE_STRING; - - header_items[PARTIAL_IV_INDEX].label.int64 = COSE_HEADER_PARAM_PARTIAL_IV; - header_items[PARTIAL_IV_INDEX].uLabelType = QCBOR_TYPE_INT64; - header_items[PARTIAL_IV_INDEX].uDataType = QCBOR_TYPE_BYTE_STRING; - - header_items[CONTENT_TYPE].label.int64 = COSE_HEADER_PARAM_CONTENT_TYPE; - header_items[CONTENT_TYPE].uLabelType = QCBOR_TYPE_INT64; - header_items[CONTENT_TYPE].uDataType = QCBOR_TYPE_ANY; - - header_items[END_INDEX].uLabelType = QCBOR_TYPE_NONE; - - /* This call takes care of duplicate detection in the map itself. - * - * COSE has the notion of critical parameters that can't be - * ignored, so the callback has to be set up to catch items in - * this map that are not handled by code here. - */ - QCBORDecode_GetItemsInMapWithCallback(decode_context, - header_items, - &callback_context, - header_parameter_callback); - qcbor_result = QCBORDecode_GetError(decode_context); - if(qcbor_result == QCBOR_ERR_CALLBACK_FAIL) { - return_value = callback_context.return_value; - goto Done; - } else if(qcbor_result != QCBOR_SUCCESS) { - if(QCBORDecode_IsNotWellFormedError(qcbor_result)) { - return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED; - } else { - return_value = T_COSE_ERR_PARAMETER_CBOR; - } - goto Done; - } - - /* The following few clauses copy the parameters out of the - * QCBORItems retrieved into the returned parameters - * structure. - * - * Duplicate detection between protected and unprotected parameter - * headers is performed by erroring out if a parameter has already - * been filled in. - * - * Much of the type checking was performed by - * QCBORDecode_GetItemsInMapWithCallback() but not all so the rest - * is done here. - */ - - /* COSE_HEADER_PARAM_ALG */ - if(header_items[ALG_INDEX].uDataType != QCBOR_TYPE_NONE) { - if(critical_labels == NULL) { - /* Algorithm parameter must be protected */ - return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED; - goto Done; - } - if(header_items[ALG_INDEX].val.int64 == COSE_ALGORITHM_RESERVED || - header_items[ALG_INDEX].val.int64 > INT32_MAX) { - return_value = T_COSE_ERR_NON_INTEGER_ALG_ID; - goto Done; - } - parameters->cose_algorithm_id = (int32_t)header_items[ALG_INDEX].val.int64; - } - - /* COSE_HEADER_PARAM_KID */ - if(header_items[KID_INDEX].uDataType != QCBOR_TYPE_NONE) { - if(q_useful_buf_c_is_null(parameters->kid)) { - parameters->kid = header_items[KID_INDEX].val.string; - } else { - return_value = T_COSE_ERR_DUPLICATE_PARAMETER; - goto Done; - } - } - - /* COSE_HEADER_PARAM_IV */ - if(header_items[IV_INDEX].uDataType != QCBOR_TYPE_NONE) { - if(q_useful_buf_c_is_null(parameters->iv)) { - parameters->iv = header_items[IV_INDEX].val.string; - } else { - return_value = T_COSE_ERR_DUPLICATE_PARAMETER; - goto Done; - } - } - - /* COSE_HEADER_PARAM_PARTIAL_IV */ - if(header_items[PARTIAL_IV_INDEX].uDataType != QCBOR_TYPE_NONE) { - if(q_useful_buf_c_is_null(parameters->partial_iv)) { - parameters->partial_iv = header_items[PARTIAL_IV_INDEX].val.string; - } else { - return_value = T_COSE_ERR_DUPLICATE_PARAMETER; - goto Done; - } - } - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - /* COSE_HEADER_PARAM_CONTENT_TYPE */ - if(header_items[CONTENT_TYPE].uDataType == QCBOR_TYPE_TEXT_STRING) { - if(!q_useful_buf_c_is_null_or_empty(parameters->content_type_tstr)) { - return_value = T_COSE_ERR_DUPLICATE_PARAMETER; - goto Done; - } - parameters->content_type_tstr = header_items[CONTENT_TYPE].val.string; - } else if(header_items[CONTENT_TYPE].uDataType == QCBOR_TYPE_INT64) { - if(header_items[CONTENT_TYPE].val.int64 < 0 || - header_items[CONTENT_TYPE].val.int64 > UINT16_MAX) { - return_value = T_COSE_ERR_BAD_CONTENT_TYPE; - goto Done; - } - if(parameters->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) { - return_value = T_COSE_ERR_DUPLICATE_PARAMETER; - goto Done; - } - parameters->content_type_uint = (uint32_t)header_items[CONTENT_TYPE].val.int64; - } else if(header_items[CONTENT_TYPE].uDataType != QCBOR_TYPE_NONE) { - return_value = T_COSE_ERR_BAD_CONTENT_TYPE; - goto Done; - } -#endif - - /* COSE_HEADER_PARAM_CRIT */ - return_value = decode_critical_parameter(decode_context, critical_labels); - - QCBORDecode_ExitMap(decode_context); - -Done: - return return_value; -} diff --git a/3rdparty/internal/t_cose/src/t_cose_parameters.h b/3rdparty/internal/t_cose/src/t_cose_parameters.h deleted file mode 100644 index 02b70e9e2bd8..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_parameters.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * t_cose_parameters.h - * - * Copyright 2019-2020, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef t_cose_parameters_h -#define t_cose_parameters_h - -#include -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose/t_cose_common.h" -#include "qcbor/qcbor.h" - - - - -/** - * \file t_cose_parameters.h - * - * \brief A list of COSE parameter labels, both integer and string. - * - * It is fixed size to avoid the complexity of memory management and - * because the number of parameters is assumed to be small. - * - * On a 64-bit machine it is 24 * PARAMETER_LIST_MAX which is 244 - * bytes. That accommodates 10 string parameters and 10 integer parameters - * and is small enough to go on the stack. - * - * On a 32-bit machine: 16 * PARAMETER_LIST_MAX = 176 - * - * This is a big consumer of stack in this implementation. Some - * cleverness with a union could save almost 200 bytes of stack, as - * this is on the stack twice. - */ -struct t_cose_label_list { - /* Terminated by value LABEL_LIST_TERMINATOR */ - int64_t int_labels[T_COSE_PARAMETER_LIST_MAX+1]; - /* Terminated by a NULL_Q_USEFUL_BUF_C */ - struct q_useful_buf_c tstr_labels[T_COSE_PARAMETER_LIST_MAX+1]; -}; - - -/* - * The IANA COSE Header Parameters registry lists label 0 as - * "reserved". This means it can be used, but only by a revision of - * the COSE standard if it is deemed necessary for some large and good - * reason. It cannot just be allocated by IANA as any normal - * assignment. See [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). It is thus - * considered safe to use as the list terminator. - */ -#define LABEL_LIST_TERMINATOR 0 - - -/** - * \brief Clear a label list to empty. - * - * \param[in,out] list The list to clear. - */ -inline static void clear_label_list(struct t_cose_label_list *list) -{ - memset(list, 0, sizeof(struct t_cose_label_list)); -} - - - - -enum t_cose_err_t -check_critical_labels(const struct t_cose_label_list *critical_labels, - const struct t_cose_label_list *unknown_labels); - - - -enum t_cose_err_t -parse_cose_header_parameters(QCBORDecodeContext *decode_context, - struct t_cose_parameters *returned_parameters, - struct t_cose_label_list *critical_labels, - struct t_cose_label_list *unknown_labels); - - -/** - * \brief Clear a struct t_cose_parameters to empty - * - * \param[in,out] parameters Parameter list to clear. - */ -static inline void clear_cose_parameters(struct t_cose_parameters *parameters) -{ -#if COSE_ALGORITHM_RESERVED != 0 -#error Invalid algorithm designator not 0. Parameter list initialization fails. -#endif - -#if T_COSE_UNSET_ALGORITHM_ID != COSE_ALGORITHM_RESERVED -#error Constant for unset algorithm ID not aligned with COSE_ALGORITHM_RESERVED -#endif - - /* This clears all the useful_bufs to NULL_Q_USEFUL_BUF_C - * and the cose_algorithm_id to COSE_ALGORITHM_RESERVED - */ - memset(parameters, 0, sizeof(struct t_cose_parameters)); - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - /* The only non-zero clear-state value. (0 is plain text in CoAP - * content format) */ - parameters->content_type_uint = T_COSE_EMPTY_UINT_CONTENT_TYPE; -#endif -} - -#endif /* t_cose_parameters_h */ diff --git a/3rdparty/internal/t_cose/src/t_cose_short_circuit.c b/3rdparty/internal/t_cose/src/t_cose_short_circuit.c deleted file mode 100644 index 675edb7c2b98..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_short_circuit.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * t_cose_short_circuit.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose_short_circuit.h" -#include "t_cose_standard_constants.h" -#include "t_cose_crypto.h" - -/** - * \file t_cose_short_circuit.h - * - * \brief Functions used to compute and verify short-circuit signatures. - * - * These signatures don't use any cryptographic algorithm and don't - * provide any security guarantees at all. They are provided for - * demonstration purposes, and will not be used unless explicitly - * enabled by users of the library. - * - */ - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - -/** - * See documentation in t_cose_short_circuit.h - */ -enum t_cose_err_t -short_circuit_sig_size(int32_t cose_algorithm_id, size_t *sig_size) -{ - *sig_size = cose_algorithm_id == COSE_ALGORITHM_ES256 ? T_COSE_EC_P256_SIG_SIZE : - cose_algorithm_id == COSE_ALGORITHM_ES384 ? T_COSE_EC_P384_SIG_SIZE : - cose_algorithm_id == COSE_ALGORITHM_ES512 ? T_COSE_EC_P512_SIG_SIZE : - 0; - - return sig_size == 0 ? T_COSE_ERR_UNSUPPORTED_SIGNING_ALG : T_COSE_SUCCESS; -} - - -/** - * See documentation in t_cose_short_circuit.h - */ -enum t_cose_err_t -short_circuit_sign(int32_t cose_algorithm_id, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - /* approximate stack use on 32-bit machine: local use: 16 bytes - */ - enum t_cose_err_t return_value; - size_t array_indx; - size_t amount_to_copy; - size_t sig_size; - - return_value = short_circuit_sig_size(cose_algorithm_id, &sig_size); - - /* Check the signature length against buffer size */ - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - if(sig_size > signature_buffer.len) { - /* Buffer too small for this signature type */ - return_value = T_COSE_ERR_SIG_BUFFER_SIZE; - goto Done; - } - - /* Loop concatening copies of the hash to fill out to signature size */ - for(array_indx = 0; array_indx < sig_size; array_indx += hash_to_sign.len) { - amount_to_copy = sig_size - array_indx; - if(amount_to_copy > hash_to_sign.len) { - amount_to_copy = hash_to_sign.len; - } - memcpy((uint8_t *)signature_buffer.ptr + array_indx, - hash_to_sign.ptr, - amount_to_copy); - } - signature->ptr = signature_buffer.ptr; - signature->len = sig_size; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - -/** - * See documentation in t_cose_short_circuit.h - */ -enum t_cose_err_t -t_cose_crypto_short_circuit_verify(struct q_useful_buf_c hash_to_verify, - struct q_useful_buf_c signature) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 24 12 - * TOTAL 24 12 - */ - struct q_useful_buf_c hash_from_sig; - enum t_cose_err_t return_value; - - hash_from_sig = q_useful_buf_head(signature, hash_to_verify.len); - if(q_useful_buf_c_is_null(hash_from_sig)) { - return_value = T_COSE_ERR_SIG_VERIFY; - goto Done; - } - - if(q_useful_buf_compare(hash_from_sig, hash_to_verify)) { - return_value = T_COSE_ERR_SIG_VERIFY; - } else { - return_value = T_COSE_SUCCESS; - } - -Done: - return return_value; -} - -#else /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - -/* So some of the build checks don't get confused by an empty object file */ -void t_cose_short_circuit_placeholder() -{} - - -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - diff --git a/3rdparty/internal/t_cose/src/t_cose_short_circuit.h b/3rdparty/internal/t_cose/src/t_cose_short_circuit.h deleted file mode 100644 index ddcc52abb1be..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_short_circuit.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * t_cose_short_circuit.h - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_SHORT_CIRCUIT_H__ -#define __T_COSE_SHORT_CIRCUIT_H__ - -#include -#include "t_cose/q_useful_buf.h" -#include "t_cose/t_cose_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \file t_cose_short_circuit.h - * - * \brief Functions used to compute and verify short-circuit signatures. - * - * These signatures don't use any cryptographic algorithm and don't - * provide any security guarantees at all. They are provided for - * demonstration purposes, and will not be used unless explicitly - * enabled by users of the library. - * - */ - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - -/** - * \brief Compute the size of a short-circuit signature. - * - * \param[in] cose_algorithm_id Algorithm ID. This is used only to make - * the short-circuit signature the same size - * as the real signature would be for the - * particular algorithm. - * \param[out] sig_size The returned size in bytes. - * - * \return An error code or \ref T_COSE_SUCCESS. - */ -enum t_cose_err_t -short_circuit_sig_size(int32_t cose_algorithm_id, size_t *sig_size); - -/** - * \brief Create a short-circuit signature - * - * \param[in] cose_algorithm_id Algorithm ID. This is used only to make - * the short-circuit signature the same size - * as the real signature would be for the - * particular algorithm. - * \param[in] hash_to_sign The bytes to sign. Typically, a hash of - * a payload. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This creates the short-circuit signature that is a concatenation of - * hashes up to the expected size of the signature. This is a test - * mode only has it has no security value. This is retained in - * commercial production code as a useful test or demo that can run - * even if key material is not set up or accessible. - */ -enum t_cose_err_t -short_circuit_sign(int32_t cose_algorithm_id, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature); - -/** - * \brief Verify a short-circuit signature - * - * \param[in] hash_to_verify Pointer and length of hash to verify. - * \param[in] signature Pointer and length of signature. - * - * \return This returns one of the error codes defined by \ref - * t_cose_err_t. - * - * See t_cose_sign1_sign_init() for description of the short-circuit - * signature. - */ -enum t_cose_err_t -t_cose_crypto_short_circuit_verify(struct q_useful_buf_c hash_to_verify, - struct q_useful_buf_c signature); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/3rdparty/internal/t_cose/src/t_cose_sign1_sign.c b/3rdparty/internal/t_cose/src/t_cose_sign1_sign.c deleted file mode 100644 index 18c8f9209ded..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_sign1_sign.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * t_cose_sign1_sign.c - * - * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose/t_cose_sign1_sign.h" -#include "qcbor/qcbor.h" -#include "t_cose_standard_constants.h" -#include "t_cose_crypto.h" -#include "t_cose_util.h" -#include "t_cose_short_circuit.h" - - -#if !(defined(QCBOR_1_1) || QCBOR_VERSION_MAJOR >= 2 || (QCBOR_VERSION_MAJOR == 1 && QCBOR_VERSION_MINOR >= 1)) -/* The OpenBytes API we use was only added in 1.1. */ -#error t_cose requires QCBOR 1.1 or greater -#endif - - -/** - * \file t_cose_sign1_sign.c - * - * \brief This implements t_cose signing - * - * Stack usage to sign is dependent on the signing alg and key size - * and type of hash implementation. t_cose_sign1_finish() is the main - * user of stack It is 384 for \ref COSE_ALGORITHM_ES256 and 778 for - * \ref COSE_ALGORITHM_ES512. - */ - - -/* - * Cross-check to make sure public definition of algorithm - * IDs matches the internal ones. - */ -#if T_COSE_ALGORITHM_ES256 != COSE_ALGORITHM_ES256 -#error COSE algorithm identifier definitions are in error -#endif - -#if T_COSE_ALGORITHM_ES384 != COSE_ALGORITHM_ES384 -#error COSE algorithm identifier definitions are in error -#endif - -#if T_COSE_ALGORITHM_ES512 != COSE_ALGORITHM_ES512 -#error COSE algorithm identifier definitions are in error -#endif - -#if T_COSE_ALGORITHM_PS256 != COSE_ALGORITHM_PS256 -#error COSE algorithm identifier definitions are in error -#endif - -#if T_COSE_ALGORITHM_PS384 != COSE_ALGORITHM_PS384 -#error COSE algorithm identifier definitions are in error -#endif - -#if T_COSE_ALGORITHM_PS512 != COSE_ALGORITHM_PS512 -#error COSE algorithm identifier definitions are in error -#endif - -/** - * \brief Makes the protected header parameters for COSE. - * - * \param[in] cose_algorithm_id The COSE algorithm ID to put in the - * header parameters. - * \param[in,out] cbor_encode_ctx Encoding context to output to. - * - * \return The pointer and length of the encoded protected - * parameters is returned, or \c NULL_Q_USEFUL_BUF_C if this fails. - * This will have the same pointer as \c buffer_for_parameters, - * but the pointer is conts and the length is that of the valid - * data, not of the size of the buffer. - * - * The protected parameters are returned in fully encoded CBOR format as - * they are added to the \c COSE_Sign1 message as a binary string. This is - * different from the unprotected parameters which are not handled this - * way. - */ -static inline struct q_useful_buf_c -encode_protected_parameters(int32_t cose_algorithm_id, - QCBOREncodeContext *cbor_encode_ctx) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 16 8 - * QCBOR (guess) 32 24 - * TOTAL 48 32 - */ - struct q_useful_buf_c protected_parameters; - - QCBOREncode_BstrWrap(cbor_encode_ctx); - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_AddInt64ToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_ALG, - cose_algorithm_id); - QCBOREncode_CloseMap(cbor_encode_ctx); - QCBOREncode_CloseBstrWrap2(cbor_encode_ctx, false, &protected_parameters); - - return protected_parameters; -} - - -/** - * \brief Add the unprotected parameters to a CBOR encoding context - * - * \param[in] me The t_cose signing context. - * \param[in] kid The key ID. - * \param[in] cbor_encode_ctx CBOR encoding context to output to - * - * \returns An error of type \ref t_cose_err_t. - * - * The unprotected parameters added by this are the kid and content type. - * - * In the case of a QCBOR encoding error, T_COSE_SUCCESS will be returned - * and the error will be caught when \c QCBOR_Finish() is called on \c - * cbor_encode_ctx. - */ -static inline enum t_cose_err_t -add_unprotected_parameters(const struct t_cose_sign1_sign_ctx *me, - const struct q_useful_buf_c kid, - QCBOREncodeContext *cbor_encode_ctx) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * QCBOR (guess) 32 24 - * TOTAL 32 24 - */ - - QCBOREncode_OpenMap(cbor_encode_ctx); - - if(!q_useful_buf_c_is_null_or_empty(kid)) { - QCBOREncode_AddBytesToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_KID, - kid); - } - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE && - me->content_type_tstr != NULL) { - /* Both the string and int content types are not allowed */ - return T_COSE_ERR_DUPLICATE_PARAMETER; - } - - - if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) { - QCBOREncode_AddUInt64ToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - me->content_type_uint); - } - - if(me->content_type_tstr != NULL) { - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - me->content_type_tstr); - } -#else - (void)me; /* avoid unused parameter warning */ -#endif - - QCBOREncode_CloseMap(cbor_encode_ctx); - - return T_COSE_SUCCESS; -} - - -/* - * Semi-private function. See t_cose_sign1_sign.h - */ -enum t_cose_err_t -t_cose_sign1_encode_parameters_internal(struct t_cose_sign1_sign_ctx *me, - bool payload_is_detached, - QCBOREncodeContext *cbor_encode_ctx) -{ - enum t_cose_err_t return_value; - struct q_useful_buf_c kid; - - if (!signature_algorithm_id_is_supported(me->cose_algorithm_id)) { - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - /* Add the CBOR tag indicating COSE_Sign1 */ - if(!(me->option_flags & T_COSE_OPT_OMIT_CBOR_TAG)) { - QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1); - } - - /* Get started with the tagged array that holds the four parts of - * a cose single signed message */ - QCBOREncode_OpenArray(cbor_encode_ctx); - - /* The protected parameters, which are added as a wrapped bstr */ - me->protected_parameters = encode_protected_parameters(me->cose_algorithm_id, cbor_encode_ctx); - - /* The Unprotected parameters */ - /* Get the kid because it goes into the parameters that are about - * to be made. */ - kid = me->kid; - - if(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG) { -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - if(q_useful_buf_c_is_null_or_empty(kid)) { - /* No kid passed in, Use the short-circuit kid */ - kid = get_short_circuit_kid(); - } -#else - return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED; - goto Done; -#endif - } - - return_value = add_unprotected_parameters(me, kid, cbor_encode_ctx); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - if(!payload_is_detached) { - QCBOREncode_BstrWrap(cbor_encode_ctx); - } - - /* Any failures in CBOR encoding will be caught in finish when the - * CBOR encoding is closed off. No need to track here as the CBOR - * encoder tracks it internally. - */ - -Done: - return return_value; -} - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -/** - * \brief Compute the short-circuit signature for a COSE_Sign1 message. - * - * \param[in] me The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of payload to sign. - * \param[in] buffer_for_signature Pointer and length of buffer to output to. - * \param[out] signature Pointer and length of the resulting signature. - * - * \returns An error of type \ref t_cose_err_t. - * - * This function does not actually perform any kind of cryptographic - * signature, and should only be used as a test mode. - * - * If \c buffer_for_signature contains a \c NULL pointer, this function - * will compute the necessary size, and set \c signature accordingly. - */ -static inline enum t_cose_err_t -sign1_sign_short_circuit(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_signature, - struct q_useful_buf_c *signature) -{ - enum t_cose_err_t return_value; - - Q_USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE); - struct q_useful_buf_c tbs_hash; - - /* Create the hash of the to-be-signed bytes. Inputs to the - * hash are the protected parameters, the payload that is - * getting signed, the cose signature alg from which the hash - * alg is determined. The cose_algorithm_id was checked in - * t_cose_sign1_init() so it doesn't need to be checked here. - */ - return_value = create_tbs_hash(me->cose_algorithm_id, - me->protected_parameters, - aad, - payload, - buffer_for_tbs_hash, - &tbs_hash); - if (return_value) { - goto Done; - } - - if (buffer_for_signature.ptr == NULL) { - /* Output size calculation. Only need signature size. */ - signature->ptr = NULL; - return_value = short_circuit_sig_size(me->cose_algorithm_id, &signature->len); - } else { - /* Perform the a short circuit signing */ - return_value = short_circuit_sign(me->cose_algorithm_id, - tbs_hash, - buffer_for_signature, - signature); - } - -Done: - return return_value; -} -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - -#ifndef T_COSE_DISABLE_EDDSA -/** - * \brief Compute an EDDSA signature for a COSE_Sign1 message. - * - * \param[in] me The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of payload to sign. - * \param[in] buffer_for_signature Pointer and length of buffer to output to. - * \param[out] signature Pointer and length of the resulting signature. - * - * \returns An error of type \ref t_cose_err_t. - * - * Unlike other algorithms, EDDSA signing requires two passes over the - * to-be-signed data, and therefore cannot be performed incrementally. - * This function serializes the to-be-signed bytes and uses the crypto - * adapter to compute the signature over them. An auxiliary buffer, - * used to store the to-be-signed bytes, must have previously been - * configured by calling the \ref t_cose_sign1_sign_set_auxiliary_buffer - * function. - * - * If \c buffer_for_signature contains a \c NULL pointer, this function - * will compute the necessary size, and update \c signature accordingly. - */ -static inline enum t_cose_err_t -sign1_sign_eddsa(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_signature, - struct q_useful_buf_c *signature) -{ - enum t_cose_err_t return_value; - struct q_useful_buf_c tbs; - - /* Serialize the TBS data into the auxiliary buffer. - * If auxiliary_buffer.ptr is NULL this will succeed, computing - * the necessary size. - */ - return_value = create_tbs(me->protected_parameters, - aad, - payload, - me->auxiliary_buffer, - &tbs); - if (return_value == T_COSE_ERR_TOO_SMALL) { - /* Be a bit more specific about which buffer is too small */ - return_value = T_COSE_ERR_AUXILIARY_BUFFER_SIZE; - } - if (return_value) { - goto Done; - } - - /* Record how much buffer we actually used / would have used, - * allowing the caller to allocate an appropriately sized buffer. - * This is particularly useful when buffer_for_signature.ptr is - * NULL and no signing is actually taking place yet. - */ - me->auxiliary_buffer_size = tbs.len; - - if (buffer_for_signature.ptr == NULL) { - /* Output size calculation. Only need signature size. */ - signature->ptr = NULL; - return_value = t_cose_crypto_sig_size(me->cose_algorithm_id, - me->signing_key, - &signature->len); - } else if (me->auxiliary_buffer.ptr == NULL) { - /* Without a real auxiliary buffer, we have nothing to sign. */ - return_value = T_COSE_ERR_NEED_AUXILIARY_BUFFER; - } else { - /* Perform the public key signing over the TBS bytes we just - * serialized. - */ - return_value = t_cose_crypto_sign_eddsa(me->signing_key, - tbs, - buffer_for_signature, - signature); - } - -Done: - return return_value; -} -#endif /* T_COSE_DISABLE_EDDSA */ - -/** - * \brief Compute a signature for a COSE_Sign1 message, following the - * general procedure which works for most algorithms. - * - * \param[in] me The t_cose signing context. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of payload to sign. - * \param[in] buffer_for_signature Pointer and length of buffer to output to. - * \param[out] signature Pointer and length of the resulting signature. - * - * \returns An error of type \ref t_cose_err_t. - * - * The message's to-be-signed bytes are hashed incrementally using the - * chosen algorithm's digest function, and the result is signed by the - * crypto adapter. - * - * This function does not support short-circuit signing or EDDSA - * signatures, which require a special procedure. See - * \ref sign1_sign_short_circuit and \ref sign1_sign_eddsa. - * - * If \c buffer_for_signature contains a \c NULL pointer, this function - * will compute the necessary size, and update \c signature accordingly. - */ -static inline enum t_cose_err_t -sign1_sign_default(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_signature, - struct q_useful_buf_c *signature) -{ - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE); - struct q_useful_buf_c tbs_hash; - - /* Create the hash of the to-be-signed bytes. Inputs to the - * hash are the protected parameters, the payload that is - * getting signed, the cose signature alg from which the hash - * alg is determined. The cose_algorithm_id was checked in - * t_cose_sign1_init() so it doesn't need to be checked here. - */ - return_value = create_tbs_hash(me->cose_algorithm_id, - me->protected_parameters, - aad, - payload, - buffer_for_tbs_hash, - &tbs_hash); - if (return_value) { - goto Done; - } - - if (buffer_for_signature.ptr == NULL) { - /* Output size calculation. Only need signature size. */ - signature->ptr = NULL; - return_value = t_cose_crypto_sig_size(me->cose_algorithm_id, - me->signing_key, - &signature->len); - } else { - /* Perform the public key signing */ - return_value = t_cose_crypto_sign(me->cose_algorithm_id, - me->signing_key, - tbs_hash, - buffer_for_signature, - signature); - } - -Done: - return return_value; -} - -/* - * Semi-private function. See t_cose_sign1_sign.h - */ -enum t_cose_err_t -t_cose_sign1_encode_signature_aad_internal(struct t_cose_sign1_sign_ctx *me, - struct q_useful_buf_c aad, - struct q_useful_buf_c detached_payload, - QCBOREncodeContext *cbor_encode_ctx) -{ - enum t_cose_err_t return_value; - QCBORError cbor_err; - /* Pointer and length of the completed signature */ - struct q_useful_buf_c signature; - /* Pointer and length of the buffer for the signature */ - struct q_useful_buf buffer_for_signature; - struct q_useful_buf_c signed_payload; - - if(q_useful_buf_c_is_null(detached_payload)) { - QCBOREncode_CloseBstrWrap2(cbor_encode_ctx, false, &signed_payload); - } else { - signed_payload = detached_payload; - } - - /* Check that there are no CBOR encoding errors before proceeding - * with hashing and signing. This is not actually necessary as the - * errors will be caught correctly later, but it does make it a - * bit easier for the caller to debug problems. - */ - cbor_err = QCBOREncode_GetErrorState(cbor_encode_ctx); - if(cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) { - return_value = T_COSE_ERR_TOO_SMALL; - goto Done; - } else if(cbor_err != QCBOR_SUCCESS) { - return_value = T_COSE_ERR_CBOR_FORMATTING; - goto Done; - } - - /* The signature gets written directly into the output buffer. - * The matching QCBOREncode_CloseBytes call further down still needs do a - * memmove to make space for the CBOR header, but at least we avoid the need - * to allocate an extra buffer. - */ - QCBOREncode_OpenBytes(cbor_encode_ctx, &buffer_for_signature); - - /* Sign the message using the appropriate procedure, depending on - * the flags and algorithm. - */ -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - if (me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG) { - return_value = sign1_sign_short_circuit(me, - aad, - signed_payload, - buffer_for_signature, - &signature); - } else -#endif -#ifndef T_COSE_DISABLE_EDDSA - if (me->cose_algorithm_id == COSE_ALGORITHM_EDDSA) { - return_value = sign1_sign_eddsa(me, - aad, - signed_payload, - buffer_for_signature, - &signature); - } else -#endif - { - return_value = sign1_sign_default(me, - aad, - signed_payload, - buffer_for_signature, - &signature); - } - - if (return_value) - goto Done; - - /* Add signature to CBOR and close out the array */ - QCBOREncode_CloseBytes(cbor_encode_ctx, signature.len); - QCBOREncode_CloseArray(cbor_encode_ctx); - - /* The layer above this must check for and handle CBOR encoding - * errors CBOR encoding errors. Some are detected at the start of - * this function, but they cannot all be deteced there. - */ -Done: - return return_value; - -} - - -/* - * Semi-private function. See t_cose_sign1_sign.h - */ -enum t_cose_err_t -t_cose_sign1_sign_aad_internal(struct t_cose_sign1_sign_ctx *me, - bool payload_is_detached, - struct q_useful_buf_c payload, - struct q_useful_buf_c aad, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 8 4 - * encode context 168 148 - * QCBOR (guess) 32 24 - * max(encode_param, encode_signature) 224-1316 216-1024 - * TOTAL 432-1524 392-1300 - */ - QCBOREncodeContext encode_context; - enum t_cose_err_t return_value; - - /* -- Initialize CBOR encoder context with output buffer -- */ - QCBOREncode_Init(&encode_context, out_buf); - - /* -- Output the header parameters into the encoder context -- */ - return_value = t_cose_sign1_encode_parameters_internal(me, - payload_is_detached, - &encode_context); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - if(payload_is_detached) { - /* -- Output NULL but the payload -- */ - /* In detached content mode, the output COSE binary does not - * contain the target payload, and it should be derivered - * in another channel. - */ - QCBOREncode_AddNULL(&encode_context); - } else { - /* -- Output the payload into the encoder context -- */ - /* Payload may or may not actually be CBOR format here. This - * function does the job just fine because it just adds bytes to - * the encoded output without anything extra. - */ - QCBOREncode_AddEncoded(&encode_context, payload); - } - - /* -- Sign and put signature in the encoder context -- */ - if(!payload_is_detached) { - payload = NULL_Q_USEFUL_BUF_C; - } - return_value = t_cose_sign1_encode_signature_aad_internal(me, - aad, - payload, - &encode_context); - if(return_value) { - goto Done; - } - - QCBORError cbor_err = QCBOREncode_GetErrorState(&encode_context); - if(cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) { - return_value = T_COSE_ERR_TOO_SMALL; - goto Done; - } else if(cbor_err != QCBOR_SUCCESS) { - return_value = T_COSE_ERR_CBOR_FORMATTING; - goto Done; - } - - /* -- Close off and get the resulting encoded CBOR -- */ - if(QCBOREncode_Finish(&encode_context, result)) { - return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED; - goto Done; - } - -Done: - return return_value; -} - diff --git a/3rdparty/internal/t_cose/src/t_cose_sign1_verify.c b/3rdparty/internal/t_cose/src/t_cose_sign1_verify.c deleted file mode 100644 index c332089c9984..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_sign1_verify.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * t_cose_sign1_verify.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#include "qcbor/qcbor_decode.h" -#ifndef QCBOR_SPIFFY_DECODE -#error This t_cose requires a version of QCBOR that supports spiffy decode -#endif -#include "qcbor/qcbor_spiffy_decode.h" -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose_crypto.h" -#include "t_cose_util.h" -#include "t_cose_parameters.h" -#include "t_cose_short_circuit.h" - - - -/** - * \file t_cose_sign1_verify.c - * - * \brief \c COSE_Sign1 verification implementation. - */ - - -/** - * \brief Check the tagging of the COSE about to be verified. - * - * \param[in] me The verification context. - * \param[in] decode_context The decoder context to pull from. - * - * \return This returns one of the error codes defined by \ref - * t_cose_err_t. - * - * This must be called after decoding the opening array of four that - * starts all COSE message that is the item that is the content of the - * tags. - * - * This checks that the tag usage is as requested by the caller. - * - * This returns any tags that enclose the COSE message for processing - * at the level above COSE. - */ -static inline enum t_cose_err_t -process_tags(struct t_cose_sign1_verify_ctx *me, QCBORDecodeContext *decode_context) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 20 16 - * TOTAL 20 16 - */ - uint64_t uTag; - uint32_t item_tag_index = 0; - int returned_tag_index; - - /* The 0th tag is the only one that might identify the type of the - * CBOR we are trying to decode so it is handled special. - */ - uTag = QCBORDecode_GetNthTagOfLast(decode_context, item_tag_index); - item_tag_index++; - if(me->option_flags & T_COSE_OPT_TAG_REQUIRED) { - /* The protocol that is using COSE says the input CBOR must - * be a COSE tag. - */ - if(uTag != CBOR_TAG_COSE_SIGN1) { - return T_COSE_ERR_INCORRECTLY_TAGGED; - } - } - if(me->option_flags & T_COSE_OPT_TAG_PROHIBITED) { - /* The protocol that is using COSE says the input CBOR must - * not be a COSE tag. - */ - if(uTag == CBOR_TAG_COSE_SIGN1) { - return T_COSE_ERR_INCORRECTLY_TAGGED; - } - } - /* If the protocol using COSE doesn't say one way or another about the - * tag, then either is OK. - */ - - - /* Initialize auTags, the returned tags, to CBOR_TAG_INVALID64 */ -#if CBOR_TAG_INVALID64 != 0xffffffffffffffff -#error Initializing return tags array -#endif - memset(me->auTags, 0xff, sizeof(me->auTags)); - - returned_tag_index = 0; - - if(uTag != CBOR_TAG_COSE_SIGN1) { - /* Never return the tag that this code is about to process. Note - * that you can sign a COSE_SIGN1 recursively. This only takes out - * the one tag layer that is processed here. - */ - me->auTags[returned_tag_index] = uTag; - returned_tag_index++; - } - - while(1) { - uTag = QCBORDecode_GetNthTagOfLast(decode_context, item_tag_index); - item_tag_index++; - if(uTag == CBOR_TAG_INVALID64) { - break; - } - if(returned_tag_index > T_COSE_MAX_TAGS_TO_RETURN) { - return T_COSE_ERR_TOO_MANY_TAGS; - } - me->auTags[returned_tag_index] = uTag; - returned_tag_index++; - } - - return T_COSE_SUCCESS; -} - - -/** - * \brief Map QCBOR decode error to COSE errors. - * - * \param[in] qcbor_error The QCBOR error to map. - * - * \return This returns one of the error codes defined by - * \ref t_cose_err_t. - */ -static inline enum t_cose_err_t -qcbor_decode_error_to_t_cose_error(QCBORError qcbor_error) -{ - if(qcbor_error == QCBOR_ERR_TOO_MANY_TAGS) { - return T_COSE_ERR_TOO_MANY_TAGS; - } - if(QCBORDecode_IsNotWellFormedError(qcbor_error)) { - return T_COSE_ERR_CBOR_NOT_WELL_FORMED; - } - if(qcbor_error != QCBOR_SUCCESS) { - return T_COSE_ERR_SIGN1_FORMAT; - } - return T_COSE_SUCCESS; -} - - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -/** - * \brief Verify the short-circuit signature of a COSE_Sign1 message. - * - * \param[in] me The t_cose signature verification context. - * \param[in] parameters The previously decoded parameters from the message. - * \param[in] protected_parameters Full, CBOR encoded, protected parameters. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of the message's payload. - * \param[in] signature Pointer and length of the message's signature. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This function always succeeds if the \ref T_COSE_OPT_DECODE_ONLY - * flag is set. - * - * No actual cryptographic algorithm is used, and a successful - * verification does not provide any security guarantees. To avoid - * accidental bypass of signature verification, the \ref T_COSE_OPT_ALLOW_SHORT_CIRCUIT - * flag must be set in the verification context. - */ -static inline enum t_cose_err_t -sign1_verify_short_circuit(struct t_cose_sign1_verify_ctx *me, - const struct t_cose_parameters *parameters, - struct q_useful_buf_c signature, - struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload) -{ - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE); - struct q_useful_buf_c tbs_hash; - - if(me->option_flags & T_COSE_OPT_DECODE_ONLY) { - return_value = T_COSE_SUCCESS; - goto Done; - } - - if(!(me->option_flags & T_COSE_OPT_ALLOW_SHORT_CIRCUIT)) { - return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG; - goto Done; - } - - /* -- Compute the TBS hash -- */ - return_value = create_tbs_hash(parameters->cose_algorithm_id, - protected_parameters, - aad, - payload, - buffer_for_tbs_hash, - &tbs_hash); - if(return_value) { - goto Done; - } - - return_value = t_cose_crypto_short_circuit_verify(tbs_hash, signature); - -Done: - return return_value; -} -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - - -#ifndef T_COSE_DISABLE_EDDSA -/** - * \brief Verify the EDDSA signature from a COSE_Sign1 message. - * - * \param[in] me The t_cose signature verification context. - * \param[in] parameters The previously decoded parameters from the message. - * \param[in] protected_parameters Full, CBOR encoded, protected parameters. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of the message's payload. - * \param[in] signature Pointer and length of the message's signature. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * Unlike other algorithms, EDDSA verification requires two passes over - * the to-be-signed data, and therefore cannot be performed incrementally. - * This function serializes the to-be-signed bytes and uses the crypto - * adapter to verify the signature. An auxiliary buffer, used to store - * the to-be-signed bytes, must have previously been configured by - * calling the \ref t_cose_sign1_verify_set_auxiliary_buffer function. - * - * Signature verification is skipped if the \ref T_COSE_OPT_DECODE_ONLY - * flag is set. This mode can however be used to determine the - * necessary size for the auxiliary buffer. - */ -static enum t_cose_err_t -sign1_verify_eddsa(struct t_cose_sign1_verify_ctx *me, - const struct t_cose_parameters *parameters, - struct q_useful_buf_c signature, - struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload) -{ - enum t_cose_err_t return_value; - struct q_useful_buf_c tbs; - - /* We need to serialize the Sig_structure (rather than hashing it - * incrementally) before signing. We do this before checking for - * the DECODE_ONLY option, as this allows the caller to discover - * the necessary buffer size (create_tbs supports a NULL - * auxiliary_buffer, and we record the size the structure would - * have occupied). - */ - return_value = create_tbs(protected_parameters, - aad, - payload, - me->auxiliary_buffer, - &tbs); - if (return_value == T_COSE_ERR_TOO_SMALL) { - /* Be a bit more specific about which buffer is too small */ - return_value = T_COSE_ERR_AUXILIARY_BUFFER_SIZE; - } - if (return_value) { - goto Done; - } - - /* Record how much buffer we actually used / would have used, - * allowing the caller to allocate an appropriately sized buffer. - * This is particularly useful in DECODE_ONLY mode. - */ - me->auxiliary_buffer_size = tbs.len; - - if(me->option_flags & T_COSE_OPT_DECODE_ONLY) { - return_value = T_COSE_SUCCESS; - goto Done; - } - - if (me->auxiliary_buffer.ptr == NULL) { - return_value = T_COSE_ERR_NEED_AUXILIARY_BUFFER; - goto Done; - } - - return_value = t_cose_crypto_verify_eddsa(me->verification_key, - parameters->kid, - tbs, - signature); - -Done: - return return_value; -} -#endif /* T_COSE_DISABLE_EDDSA */ - - -/** - * \brief Verify the signature from a COSE_Sign1 message, following - * the general process which work for most algorithms. - * - * \param[in] me The t_cose signature verification context. - * \param[in] parameters The previously decoded parameters from the message. - * \param[in] protected_parameters Full, CBOR encoded, protected parameters. - * \param[in] aad The Additional Authenticated Data or \c NULL_Q_USEFUL_BUF_C. - * \param[in] payload Pointer and length of the message's payload. - * \param[in] signature Pointer and length of the message's signature. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This function always succeeds if the \ref T_COSE_OPT_DECODE_ONLY - * flag is set. - * - * Short-circuit signing or EDDSA signatures, which require a special - * procedure, are not supported. See \ref sign1_sign_short_circuit and - * \ref sign1_sign_eddsa. - */ -static enum t_cose_err_t -sign1_verify_default(struct t_cose_sign1_verify_ctx *me, - const struct t_cose_parameters *parameters, - struct q_useful_buf_c signature, - struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload) -{ - enum t_cose_err_t return_value; - Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE); - struct q_useful_buf_c tbs_hash; - - if(me->option_flags & T_COSE_OPT_DECODE_ONLY) { - return_value = T_COSE_SUCCESS; - goto Done; - } - - /* -- Compute the TBS hash -- */ - return_value = create_tbs_hash(parameters->cose_algorithm_id, - protected_parameters, - aad, - payload, - buffer_for_tbs_hash, - &tbs_hash); - if(return_value) { - goto Done; - } - - /* -- Call crypto adapter to verify the signature -- */ - return_value = t_cose_crypto_verify(parameters->cose_algorithm_id, - me->verification_key, - parameters->kid, - tbs_hash, - signature); - -Done: - return return_value; -} - - -/* - * Semi-private function. See t_cose_sign1_verify.h - */ -enum t_cose_err_t -t_cose_sign1_verify_internal(struct t_cose_sign1_verify_ctx *me, - struct q_useful_buf_c cose_sign1, - struct q_useful_buf_c aad, - struct q_useful_buf_c *payload, - struct t_cose_parameters *returned_parameters, - bool is_dc) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 80 40 - * Decode context 312 256 - * Hash output 32-64 32-64 - * header parameter lists 244 176 - * MAX(parse_headers 768 628 - * process tags 20 16 - * check crit 24 12 - * create_tbs_hash 32-748 30-746 - * crypto lib verify 64-1024 64-1024) 768-1024 768-1024 - * TOTAL 1724-1436 1560-1272 - */ - QCBORDecodeContext decode_context; - struct q_useful_buf_c protected_parameters; - enum t_cose_err_t return_value; - struct q_useful_buf_c signature; - struct t_cose_label_list critical_parameter_labels; - struct t_cose_label_list unknown_parameter_labels; - struct t_cose_parameters parameters; - struct q_useful_buf_c signed_payload; - QCBORError qcbor_error; -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - struct q_useful_buf_c short_circuit_kid; -#endif - - clear_label_list(&unknown_parameter_labels); - clear_label_list(&critical_parameter_labels); - clear_cose_parameters(¶meters); - -#if QCBOR_VERSION_MAJOR >= 2 - const int decode_config = QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS; -#else - const int decode_config = QCBOR_DECODE_MODE_NORMAL; -#endif - - /* === Decoding of the array of four starts here === */ - QCBORDecode_Init(&decode_context, cose_sign1, decode_config); - - /* --- The array of 4 and tags --- */ - QCBORDecode_EnterArray(&decode_context, NULL); - return_value = qcbor_decode_error_to_t_cose_error(QCBORDecode_GetError(&decode_context)); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - return_value = process_tags(me, &decode_context); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* --- The protected parameters --- */ - QCBORDecode_EnterBstrWrapped(&decode_context, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &protected_parameters); - if(protected_parameters.len) { - return_value = parse_cose_header_parameters(&decode_context, - ¶meters, - &critical_parameter_labels, - &unknown_parameter_labels); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - } - QCBORDecode_ExitBstrWrapped(&decode_context); - - /* --- The unprotected parameters --- */ - return_value = parse_cose_header_parameters(&decode_context, - ¶meters, - NULL, - &unknown_parameter_labels); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* --- The payload --- */ - if(is_dc) { - signed_payload = *payload; - QCBORItem tmp; - QCBORDecode_GetNext(&decode_context, &tmp); - if (tmp.uDataType != QCBOR_TYPE_NULL) { - return_value = T_COSE_ERR_CBOR_FORMATTING; - goto Done; - } - /* In detached content mode, the payload should be set by - * function caller, so there is no need to set the payload. - */ - } else { - QCBORDecode_GetByteString(&decode_context, &signed_payload); - } - - /* --- The signature --- */ - QCBORDecode_GetByteString(&decode_context, &signature); - - /* --- Finish up the CBOR decode --- */ - QCBORDecode_ExitArray(&decode_context); - - /* This check make sure the array only had the expected four - * items. It works for definite and indefinte length arrays. Also - * makes sure there were no extra bytes. Also that the payload - * and signature were decoded correctly. */ - qcbor_error = QCBORDecode_Finish(&decode_context); - return_value = qcbor_decode_error_to_t_cose_error(qcbor_error); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* === End of the decoding of the array of four === */ - - - if((me->option_flags & T_COSE_OPT_REQUIRE_KID) && q_useful_buf_c_is_null(parameters.kid)) { - return_value = T_COSE_ERR_NO_KID; - goto Done; - } - - if (!(me->option_flags & T_COSE_OPT_UNKNOWN_CRIT_ALLOWED)) { - return_value = check_critical_labels(&critical_parameter_labels, - &unknown_parameter_labels); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - } - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - short_circuit_kid = get_short_circuit_kid(); - if(!q_useful_buf_compare(parameters.kid, short_circuit_kid)) { - return_value = sign1_verify_short_circuit(me, ¶meters, signature, protected_parameters, aad, signed_payload); - goto Done; - } -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - -#ifndef T_COSE_DISABLE_EDDSA - if (parameters.cose_algorithm_id == COSE_ALGORITHM_EDDSA) { - return_value = sign1_verify_eddsa(me, ¶meters, signature, protected_parameters, aad, signed_payload); - goto Done; - } -#endif - - return_value = sign1_verify_default(me, ¶meters, signature, protected_parameters, aad, signed_payload); - -Done: - if (return_value == T_COSE_SUCCESS) - { - if(returned_parameters != NULL) { - *returned_parameters = parameters; - } - if(!is_dc && payload != NULL) { - *payload = signed_payload; - } - } - - return return_value; -} - diff --git a/3rdparty/internal/t_cose/src/t_cose_standard_constants.h b/3rdparty/internal/t_cose/src/t_cose_standard_constants.h deleted file mode 100644 index 8307145ce5de..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_standard_constants.h +++ /dev/null @@ -1,451 +0,0 @@ -/* - * t_cose_standard_constants.h - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_STANDARD_CONSTANTS_H__ -#define __T_COSE_STANDARD_CONSTANTS_H__ - -/** - * \file t_cose_standard_constants.h - * - * \brief Constants from COSE standard and IANA registry. - * - * This file contains constants identifiers defined in - * [COSE (RFC 8152)](https://tools.ietf.org/html/rfc8152) and - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * They include algorithm IDs and other constants. - * - * Many constants in the IANA registry are not included here yet as - * they are not needed by t_cose. They can be added if they become - * needed. - * - * This file is not part of the t_cose public interface as it contains - * lots of stuff not needed in the public interface. The parts that - * are needed in the public interface are also defined as \ref - * T_COSE_ALGORITHM_ES256 and related (there is a pre processor cross - * check to make sure they don't get defined differently in - * t_cose_sign1_sign.c). - */ - - -/* --------------- COSE Header parameters ----------- - * https://www.iana.org/assignments/cose/cose.xhtml#header-parameters - */ - -/** - * \def COSE_HEADER_PARAM_ALG - * - * \brief Label of COSE parameter that indicates an algorithm. - * - * The algorithm assignments are found in the IANA registry here - * https://www.iana.org/assignments/cose/cose.xhtml#algorithms - * Signing algorithms are identified as combinations of the - * public key algorithm, padding mode and hash. This must be - * a protected header. They may be string or integers. This - * implementation only support integer IDs. - */ -#define COSE_HEADER_PARAM_ALG 1 - - -/** - * \def COSE_HEADER_PARAM_CRIT - * - * \brief Label of COSE parameter listing critical header parameters - * - * The contents is an array of header parameter labels, either string or - * integer. The implementation must know how to process them or it is - * an error. - */ -#define COSE_HEADER_PARAM_CRIT 2 - - -/** - * \def COSE_HEADER_PARAM_CONTENT_TYPE - * - * \brief Label of COSE parameter with the content type - * - * Either an integer CoAP content type or a string MIME type. This is - * the type of the data in the payload. - */ -#define COSE_HEADER_PARAM_CONTENT_TYPE 3 - - -/** - * \def COSE_HEADER_PARAM_KID - * - * \brief CBOR map label of COSE parameter that contains a kid (key ID). - * - * The kid is a byte string identifying the key. It is optional and - * there is no required format. They are not even required to be - * unique. - */ -#define COSE_HEADER_PARAM_KID 4 - - -/** - * \def COSE_HEADER_PARAM_IV - * - * \brief CBOR map label of parameter that contains an initialization - * vector. - * - * A binary string initialization vector. - * - * This implementation only parses this. - */ -#define COSE_HEADER_PARAM_IV 5 - - -/** - * \def COSE_HEADER_PARAM_PARTIAL_IV - * - * \brief CBOR map label of parameter containing partial - * initialization vector. - * - * A binary string partial initialization vector. - * - * This implementation only parses this. - */ -#define COSE_HEADER_PARAM_PARTIAL_IV 6 - - -/** - * \def COSE_HEADER_PARAM_COUNTER_SIGNATURE - * - * \brief CBOR map label of parameter that holds one or more counter signature. - * - * Counter signatures can be full \c COSE_Sign1, \c COSE_Signature and - * such messages. This implementation doesn't support them. - */ -#define COSE_HEADER_PARAM_COUNTER_SIGNATURE 6 - - - - - -/* ------------ COSE Header Algorithm Parameters -------------- - * https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters - * - * None of these are defined here yet, as they are not needed by t_cose yet. - */ - - - - -/* ------------- COSE Algorithms ---------------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#algorithms - */ - -/** - * This is defined as reserved by IANA. This implementation uses it to - * mean the end of a list of algorithm IDs or an unset algorithm ID. - */ -#define COSE_ALGORITHM_RESERVED 0 - - -/** - * \def COSE_ALGORITHM_ES256 - * - * \brief Indicates ECDSA with SHA-256. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA with SHA-256. - * - * RFC 8152 section 8.1 suggests, but does not require, that this - * algorithm identifier only be used with keys based on the P-256 - * curve (also known as prime256v1 or secp256r1). - * - * See https://tools.ietf.org/search/rfc4492 and https://tools.ietf.org/html/rfc8152 - */ -#define COSE_ALGORITHM_ES256 -7 - -/** - * \def COSE_ALGORITHM_EDDSA - * - * \brief Indicates EDDSA. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate EDDSA. - * - * Keys using either the edwards25519 or edwards448 curves can be used - * with this algorithm. - * - * See https://tools.ietf.org/search/rfc8032 and https://tools.ietf.org/html/rfc8152 - */ -#define COSE_ALGORITHM_EDDSA -8 - -/** - * \def COSE_ALGORITHM_ES384 - * - * \brief Indicates ECDSA with SHA-384. - * - * See discussion on \ref COSE_ALGORITHM_ES256. - * - * RFC 8152 section 8.1 suggests, but does not require, that this - * algorithm identifier be used only with keys based on the P-384 - * curve (also known as secp384r1). - */ -#define COSE_ALGORITHM_ES384 -35 - -/** - * \def COSE_ALGORITHM_ES512 - * - * \brief Indicates ECDSA with SHA-512. - * - * See discussion on \ref COSE_ALGORITHM_ES256. - * - * RFC 8152 section 8.1 suggests, but does not require, that this - * algorithm identifier be used only with keys based on the P-521 - * curve (also known as secp521r1) - */ -#define COSE_ALGORITHM_ES512 -36 - -/** - * \def COSE_ALGORITHM_PS256 - * - * \brief Indicates RSASSA-PSS with SHA-256. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate RSASSA-PSS with SHA-256. - * - * See https://tools.ietf.org/search/rfc8230 and https://tools.ietf.org/html/rfc8152 - */ -#define COSE_ALGORITHM_PS256 -37 - -/** - * \def COSE_ALGORITHM_PS384 - * - * \brief Indicates RSASSA-PSS with SHA-384. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate RSASSA-PSS with SHA-384. - * - * See https://tools.ietf.org/search/rfc8230 and https://tools.ietf.org/html/rfc8152 - */ -#define COSE_ALGORITHM_PS384 -38 - -/** - * \def COSE_ALGORITHM_PS512 - * - * \brief Indicates RSASSA-PSS with SHA-512. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate RSASSA-PSS with SHA-512. - * - * See https://tools.ietf.org/search/rfc8230 and https://tools.ietf.org/html/rfc8152 - */ -#define COSE_ALGORITHM_PS512 -39 - -/** - * \def COSE_ALGORITHM_SHA_256 - * - * \brief Indicates simple SHA-256 hash. - * - * This is not used in the t_cose interface, just used internally. - */ -#define COSE_ALGORITHM_SHA_256 -16 - -/** - * \def COSE_ALGORITHM_SHA_384 - * - * \brief Indicates simple SHA-384 hash. - * - * This is not used in the t_cose interface, just used internally. - */ -#define COSE_ALGORITHM_SHA_384 -43 - -/** - * \def COSE_ALGORITHM_SHA_512 - * - * \brief Indicates simple SHA-512 hash. - * - * This is not used in the t_cose interface, just used internally. - */ -#define COSE_ALGORITHM_SHA_512 -44 - - - - -/* ---------- COSE Key Common Parameters -------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters - */ - -/** - * \def COSE_KEY_COMMON_KTY - * - * \brief Label for data item containing the key type. - * - * In a \c COSE_Key, label that indicates the data item containing the - * key type. - */ -#define COSE_KEY_COMMON_KTY 1 - -/** - * \def COSE_KEY_COMMON_KID - * - * \brief Label for data item containing the key's kid. - * - * In a \c COSE_Key, label that indicates the data item containing the - * kid of this key. - */ -#define COSE_KEY_COMMON_KID 2 - - - - -/* ---------- COSE Key Type Parameters -------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters - * - * These are not used by this implementation. - */ - -/** - * \def COSE_KEY_PARAM_CRV - * - * \brief Label for data item indicating EC curve. - * - * In a \c COSE_Key that holds an EC key of either type \ref - * COSE_KEY_TYPE_EC2 or \ref COSE_KEY_TYPE_OKP this labels the data - * item with the EC curve for the key. - */ -#define COSE_KEY_PARAM_CRV -1 - -/** - * \def COSE_KEY_PARAM_X_COORDINATE - * - * \brief Label for data item that is an X coordinate of an EC key. - * - * In a \c COSE_Key that holds an EC key, this is label that indicates - * the data item containing the X coordinate. - * - * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref - * COSE_KEY_TYPE_OKP. - */ -#define COSE_KEY_PARAM_X_COORDINATE -2 - -/** - * \def COSE_KEY_PARAM_Y_COORDINATE - * - * \brief Label for data item that is a y coordinate of an EC key. - * - * In a COSE_Key that holds an EC key, this is label that indicates - * the data item containing the Y coordinate. - * - * This is used only for key type \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_KEY_PARAM_Y_COORDINATE -3 - -/** - * \def COSE_KEY_PARAM_PRIVATE_D - * - * \brief Label for data item that is d, the private part of EC key. - * - * In a \c COSE_Key that holds an EC key, this is label that indicates - * the data item containing the Y coordinate. - * - * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref - * COSE_KEY_TYPE_OKP. - */ -#define COSE_KEY_PARAM_PRIVATE_D -4 - - - - -/* ---------- COSE Key Types -------------------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-type - */ - -/** - * \def COSE_KEY_TYPE_OKP - * - * \brief Key type is Octet Key Pair - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is some sort of - * key pair represented by some octets. It may or may not be an EC - * key. - */ -#define COSE_KEY_TYPE_OKP 1 - -/** - * \def COSE_KEY_TYPE_EC2 - * - * \brief Key is a 2-parameter EC key. - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is an EC key - * specified with two coordinates, X and Y. - */ -#define COSE_KEY_TYPE_EC2 2 - -/** - * \def COSE_KEY_TYPE_SYMMETRIC - * - * \brief Key is a symmetric key. - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is a symmetric - * key. - */ -#define COSE_KEY_TYPE_SYMMETRIC 4 - - - - -/* ----------- COSE Elliptic Curves --------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves - */ - -/** - * \def COSE_ELLIPTIC_CURVE_P_256 - * - * \brief Key type for NIST P-256 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-256 curve, also known as - * secp256r1. - * - * This key type is always \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_ELLIPTIC_CURVE_P_256 1 - -/** - * \def COSE_ELLIPTIC_CURVE_P_384 - * - * \brief Key type for NIST P-384 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-384 curve, also known as - * secp384r1. - * - * This key type is always \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_ELLIPTIC_CURVE_P_384 2 - -/** - * \def COSE_ELLIPTIC_CURVE_P_521 - * - * \brief Key type for NIST P-521 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-521 curve, also known as - * secp521r1. - */ -#define COSE_ELLIPTIC_CURVE_P_521 3 - - - - -/* ------- Constants from RFC 8152 --------- - */ - -/** - * \def COSE_SIG_CONTEXT_STRING_SIGNATURE1 - * - * \brief This is a string constant used by COSE to label \c - * COSE_Sign1 structures. See RFC 8152, section 4.4. - */ -#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1" - - -#endif /* __T_COSE_STANDARD_CONSTANTS_H__ */ diff --git a/3rdparty/internal/t_cose/src/t_cose_util.c b/3rdparty/internal/t_cose/src/t_cose_util.c deleted file mode 100644 index d87642652c77..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_util.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * t_cose_util.c - * - * Copyright 2019-2021, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "qcbor/qcbor.h" -#include "t_cose/t_cose_common.h" -#include "t_cose_util.h" -#include "t_cose_standard_constants.h" -#include "t_cose_crypto.h" - - -/** - * \file t_cose_util.c - * - * \brief Implementation of t_cose utility functions. - * - * These are some functions common to signing and verification, - * primarily the to-be-signed bytes hashing. - */ - -/* - * Public function. See t_cose_util.h - */ -bool signature_algorithm_id_is_supported(int32_t cose_algorithm_id) -{ - return (cose_algorithm_id == COSE_ALGORITHM_ES256) -#ifndef T_COSE_DISABLE_ES384 - || (cose_algorithm_id == COSE_ALGORITHM_ES384) -#endif -#ifndef T_COSE_DISABLE_ES512 - || (cose_algorithm_id == COSE_ALGORITHM_ES512) -#endif -#ifndef T_COSE_DISABLE_PS256 - || (cose_algorithm_id == COSE_ALGORITHM_PS256) -#endif -#ifndef T_COSE_DISABLE_PS384 - || (cose_algorithm_id == COSE_ALGORITHM_PS384) -#endif -#ifndef T_COSE_DISABLE_PS512 - || (cose_algorithm_id == COSE_ALGORITHM_PS512) -#endif -#ifndef T_COSE_DISABLE_EDDSA - || (cose_algorithm_id == COSE_ALGORITHM_EDDSA) -#endif - ; -} - -/* - * Public function. - * - * This is declared in t_cose_common.h, but there is no t_cose_common.c, - * so this little function is put here.*/ -bool -t_cose_is_algorithm_supported(int32_t cose_algorithm_id) -{ - return t_cose_crypto_is_algorithm_supported(cose_algorithm_id); -} - -/* - * Public function. See t_cose_util.h - */ -int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id) -{ - /* If other hashes, particularly those that output bigger hashes - * are added here, various other parts of this code have to be - * changed to have larger buffers, in particular - * \ref T_COSE_CRYPTO_MAX_HASH_SIZE. - */ - /* ? : operator precedence is correct here. This makes smaller - * code than a switch statement and is easier to read. - */ - return cose_algorithm_id == COSE_ALGORITHM_ES256 ? COSE_ALGORITHM_SHA_256 : -#ifndef T_COSE_DISABLE_ES384 - cose_algorithm_id == COSE_ALGORITHM_ES384 ? COSE_ALGORITHM_SHA_384 : -#endif -#ifndef T_COSE_DISABLE_ES512 - cose_algorithm_id == COSE_ALGORITHM_ES512 ? COSE_ALGORITHM_SHA_512 : -#endif -#ifndef T_COSE_DISABLE_PS256 - cose_algorithm_id == COSE_ALGORITHM_PS256 ? COSE_ALGORITHM_SHA_256 : -#endif -#ifndef T_COSE_DISABLE_PS384 - cose_algorithm_id == COSE_ALGORITHM_PS384 ? COSE_ALGORITHM_SHA_384 : -#endif -#ifndef T_COSE_DISABLE_PS512 - cose_algorithm_id == COSE_ALGORITHM_PS512 ? COSE_ALGORITHM_SHA_512 : -#endif - T_COSE_INVALID_ALGORITHM_ID; -} - -/* - * Public function. See t_cose_util.h - */ -enum t_cose_err_t -create_tbs(struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_tbs, - struct q_useful_buf_c *tbs) -{ - QCBOREncodeContext cbor_context; - QCBOREncode_Init(&cbor_context, buffer_for_tbs); - - QCBOREncode_OpenArray(&cbor_context); - QCBOREncode_AddSZString(&cbor_context, COSE_SIG_CONTEXT_STRING_SIGNATURE1); - QCBOREncode_AddBytes(&cbor_context, protected_parameters); - QCBOREncode_AddBytes(&cbor_context, aad); - QCBOREncode_AddBytes(&cbor_context, payload); - QCBOREncode_CloseArray(&cbor_context); - - QCBORError cbor_err = QCBOREncode_Finish(&cbor_context, tbs); - if (cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) { - return T_COSE_ERR_TOO_SMALL; - } else if (cbor_err != QCBOR_SUCCESS) { - return T_COSE_ERR_CBOR_FORMATTING; - } else { - return T_COSE_SUCCESS; - } -} - -/** - * \brief Hash an encoded bstr without actually encoding it in memory - * - * @param hash_ctx Hash context to hash it into - * @param bstr Bytes of the bstr - * - * If \c bstr is \c NULL_Q_USEFUL_BUF_C, a zero-length bstr will be - * hashed into the output. - */ -static void hash_bstr(struct t_cose_crypto_hash *hash_ctx, - struct q_useful_buf_c bstr) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * buffer_for_encoded 9 9 - * useful_buf 16 8 - * hash function (a guess! variable!) 16-512 16-512 - * TOTAL 41-537 23-529 - */ - - /* make a struct q_useful_buf on the stack of size QCBOR_HEAD_BUFFER_SIZE */ - Q_USEFUL_BUF_MAKE_STACK_UB (buffer_for_encoded_head, QCBOR_HEAD_BUFFER_SIZE); - struct q_useful_buf_c encoded_head; - - encoded_head = QCBOREncode_EncodeHead(buffer_for_encoded_head, - CBOR_MAJOR_TYPE_BYTE_STRING, - 0, - bstr.len); - - /* An encoded bstr is the CBOR head with its length followed by the bytes */ - t_cose_crypto_hash_update(hash_ctx, encoded_head); - t_cose_crypto_hash_update(hash_ctx, bstr); -} - - -/* - * Public function. See t_cose_util.h - */ -/* - * Format of to-be-signed bytes used by create_tbs_hash(). This is - * defined in COSE (RFC 8152) section 4.4. It is the input to the - * hash. - * - * Sig_structure = [ - * context : "Signature" / "Signature1" / "CounterSignature", - * body_protected : empty_or_serialized_map, - * ? sign_protected : empty_or_serialized_map, - * external_aad : bstr, - * payload : bstr - * ] - * - * body_protected refers to the protected parameters from the main - * COSE_Sign1 structure. This is a little hard to to understand in the - * spec. - */ -enum t_cose_err_t create_tbs_hash(int32_t cose_algorithm_id, - struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_hash, - struct q_useful_buf_c *hash) -{ - /* Aproximate stack usage - * 64-bit 32-bit - * local vars 8 6 - * hash_ctx 8-224 8-224 - * hash function (a guess! variable!) 16-512 16-512 - * TOTAL 32-748 30-746 - */ - enum t_cose_err_t return_value; - struct t_cose_crypto_hash hash_ctx; - int32_t hash_alg_id; - - /* Start the hashing */ - hash_alg_id = hash_alg_id_from_sig_alg_id(cose_algorithm_id); - if (hash_alg_id == T_COSE_INVALID_ALGORITHM_ID) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - /* Don't check hash_alg_id for failure. t_cose_crypto_hash_start() - * will handle error properly. It was also checked earlier. - */ - return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id); - if(return_value) { - goto Done; - } - - /* - * Format of to-be-signed bytes. This is defined in COSE (RFC - * 8152) section 4.4. It is the input to the hash. - * - * Sig_structure = [ - * context : "Signature" / "Signature1" / "CounterSignature", - * body_protected : empty_or_serialized_map, - * ? sign_protected : empty_or_serialized_map, - * external_aad : bstr, - * payload : bstr - * ] - * - * sign_protected is not used with COSE_Sign1 since there is no - * signer chunk. - * - * external_aad allows external data to be covered by the - * signature, but may be a NULL_Q_USEFUL_BUF_C in which case a - * zero-length bstr will be correctly hashed into the result. - * - * Instead of formatting the TBS bytes in one buffer, they are - * formatted in chunks and fed into the hash. If actually - * formatted, the TBS bytes are slightly larger than the payload, - * so this saves a lot of memory. - */ - - /* Hand-constructed CBOR for the array of 4 and the context string. - * \x84 is an array of 4. \x6A is a text string of 10 bytes. */ - t_cose_crypto_hash_update(&hash_ctx, Q_USEFUL_BUF_FROM_SZ_LITERAL("\x84\x6A" COSE_SIG_CONTEXT_STRING_SIGNATURE1)); - - /* body_protected */ - hash_bstr(&hash_ctx, protected_parameters); - - /* external_aad */ - hash_bstr(&hash_ctx, aad); - - /* payload */ - hash_bstr(&hash_ctx, payload); - - /* Finish the hash and set up to return it */ - return_value = t_cose_crypto_hash_finish(&hash_ctx, - buffer_for_hash, - hash); -Done: - return return_value; -} - - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -/* This is a random hard coded kid (key ID) that is used to indicate - * short-circuit signing. It is OK to hard code this as the - * probability of collision with this ID is very low and the same as - * for collision between any two key IDs of any sort. - */ - -static const uint8_t defined_short_circuit_kid[] = { - 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, - 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, - 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, - 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6}; - -static struct q_useful_buf_c short_circuit_kid; - -/* - * Public function. See t_cose_util.h - */ -struct q_useful_buf_c get_short_circuit_kid(void) -{ - short_circuit_kid.len = sizeof(defined_short_circuit_kid); - short_circuit_kid.ptr = defined_short_circuit_kid; - - return short_circuit_kid; -} - -#endif diff --git a/3rdparty/internal/t_cose/src/t_cose_util.h b/3rdparty/internal/t_cose/src/t_cose_util.h deleted file mode 100644 index da529a6bd487..000000000000 --- a/3rdparty/internal/t_cose/src/t_cose_util.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * t_cose_util.h - * - * Copyright 2019-2021, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#ifndef __T_COSE_UTIL_H__ -#define __T_COSE_UTIL_H__ - -#include -#include "t_cose/q_useful_buf.h" -#include "t_cose/t_cose_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \file t_cose_util.h - * - * \brief Utility functions used internally by the t_cose implementation. - * - */ - - -/** - * This value represents an invalid or in-error algorithm ID. The - * value selected is 0 as this is reserved in the IANA COSE algorithm - * registry and is very unlikely to ever be used. (It would take am - * IETF standards-action to put it to use). - */ -#define T_COSE_INVALID_ALGORITHM_ID COSE_ALGORITHM_RESERVED - -/** - * \brief Check whether a signature algorithm is valid and supported - * by the library. - * - * \param[in] cose_algorithm_id A COSE signature algorithm identifier. - * - * \return \c true if the algorithm is supported. - * - * What algorithms are supported can change as more algorithms are - * added to the library, and depend on the build configuration. Even - * if a signature algorithm is supported by the t_cose library and - * this function returns true, using an algorithm can fail for other - * reasons, for example if the crypto adapter does not support it. - * - */ -bool signature_algorithm_id_is_supported(int32_t cose_algorithm_id); - -/** - * \brief Return hash algorithm ID from a signature algorithm ID - * - * \param[in] cose_algorithm_id A COSE signature algorithm identifier. - * - * \return \c T_COSE_INVALID_ALGORITHM_ID when the signature algorithm ID - is not known, or if the signature algorithm does not have - an associated hash algorithm (eg. EDDSA). - * - * This works off of algorithm identifiers defined in the - * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml). - * Corresponding local integer constants are defined in - * t_cose_standard_constants.h. - * - * COSE signing algorithms are the combination of public key - * algorithm, hash algorithm and hash size and imply an appropriate - * key size. They are simple integers making them convenient for - * direct use in code. - * - * This function returns an identifier for only the hash algorithm - * from the combined identifier. - * - * If the needed algorithm identifiers are not in the IANA registry, - * they can be added to it. This will take some time and work. It is - * also fine to use algorithms in the COSE proprietary space. - */ -int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id); - - -/** - * \brief Create the hash of the to-be-signed (TBS) bytes for COSE. - * - * \param[in] cose_algorithm_id The COSE signing algorithm ID. Used to - * determine which hash function to use. - * \param[in] protected_parameters Full, CBOR encoded, protected parameters. - * \param[in] aad Additional Authenitcated Data to be - * included in TBS. - * \param[in] payload The CBOR-encoded payload. - * \param[in] buffer_for_hash Pointer and length of buffer into which - * the resulting hash is put. - * \param[out] hash Pointer and length of the - * resulting hash. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * \retval T_COSE_ERR_SIG_STRUCT - * Most likely this is because the protected_parameters passed in - * is larger than \c T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS. - * \retval T_COSE_ERR_UNSUPPORTED_HASH - * If the hash algorithm is not known. - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * In case of some general hash failure. - * - * The input to the public key signature algorithm in COSE is a CBOR - * encoded structure containing the protected parameters algorithm ID - * and a few other things. These are known as the to-be-signed or "TBS" - * bytes. The exact specification is in [RFC 8152 section - * 4.4](https://tools.ietf.org/html/rfc8152#section-4.4). - * - * Most algorithms use a hash of these bytes, which this function - * computes incrementally. If the entire TBS structure is needed - * (for signing with EdDSA for example), the \ref create_tbs function - * can be used instead. - * - * \c aad can be \ref NULL_Q_USEFUL_BUF_C if not present. - */ -enum t_cose_err_t create_tbs_hash(int32_t cose_algorithm_id, - struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_hash, - struct q_useful_buf_c *hash); - -/** - * Serialize the to-be-signed (TBS) bytes for COSE. - * - * \param[in] protected_parameters Full, CBOR encoded, protected parameters. - * \param[in] aad Additional Authenitcated Data to be - * included in TBS. - * \param[in] payload The CBOR-encoded payload. - * \param[in] buffer_for_tbs Pointer and length of buffer into which - * the resulting TBS bytes is put. - * \param[out] tbs Pointer and length of the - * resulting TBS bytes. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * \retval T_COSE_ERR_TOO_SMALL - * The output buffer is too small. - * \retval T_COSE_ERR_CBOR_FORMATTING - * Something went wrong formatting the CBOR. - * - * The input to the public key signature algorithm in COSE is a CBOR - * encoded structure containing the protected parameters algorithm ID - * and a few other things. These are known as the to-be-signed or "TBS" - * bytes. The exact specification is in [RFC 8152 section - * 4.4](https://tools.ietf.org/html/rfc8152#section-4.4). - * - * \c aad can be \ref NULL_Q_USEFUL_BUF_C if not present. - */ -enum t_cose_err_t create_tbs(struct q_useful_buf_c protected_parameters, - struct q_useful_buf_c aad, - struct q_useful_buf_c payload, - struct q_useful_buf buffer_for_tbs, - struct q_useful_buf_c *tbs); - - - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - -/** - * Size of the key returned by get_short_circuit_kid(). It is always - * this size. - */ -#define T_COSE_SHORT_CIRCUIT_KID_SIZE 32 - - -/** - * \brief Get the special kid for short-circuit signing. - * - * \returns Buffer with the kid. - * - * This always returns the same kid. It always indicates short-circuit - * signing. It is OK to hard code this kid value as the probability of - * collision with this ID is extremely low and the same as for - * collision between any two key IDs (kids) of any sort. - * - * This always returns a pointer to the same memory as the result - * returned by this never changes. - * - * This is the value of the kid. - * - * 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, - * 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, - * 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, - * 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6 - * - */ -struct q_useful_buf_c get_short_circuit_kid(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __T_COSE_UTIL_H__ */ diff --git a/3rdparty/internal/t_cose/t-cose-logo.png b/3rdparty/internal/t_cose/t-cose-logo.png deleted file mode 100644 index 6b8c70699701e6bcea32f15d5481eb137e64d1ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68555 zcmc$`cRZE<|38k%F~UJc_A%q&9D8RRWQD9_bL{NBg~YKFj!`I~NI3S+R>)on8Ofd{ zA@#ky-k;CsReAsZ{<)oVJJ&habv?&p-XG%Ug=^JGt25;M|N&HzGu)PF<7x^@hWmpyL7f8>JnU zyb6dfGF($ZUy<@A9h?jQs`%{^t2s#AvwQ<^ydfW}FDoiX+0(SQJ3_sX=4HK31NWtk z8h@Fi;M^~H;vbLw29JMz!F@9IF5@k+ZYWM%LH9wyn#W{8f+kHd;X)fe443HpJ^?X3 zHylnTe=YY{x`ibn`cCUoS>@r;;V<=Q#S}#xoQDLSNjhvik@Z(_nl)KdX)nnqgoiX` zbqigkQF7sk!Bvzoy8lHappbagagVG7P zVk|X|EIV2WAJs~+M2%LZy{cujc%MRADUiOaiOqgB#9nyUa%(kVdiBc}l?pCF(G+$L zVq>dj zI=uK=;JD(Gg^rWK~8I)Tqf(^`^td4^b9zhW@cP!C9p> z4Qg_-*RAPR`x+Quxv^W8eS7(ESBIv+tNNRJoN}}EX}Nm$^>qq8+_o2-532*vzHDN* zsX2P@*up;ChKq+GRmwDPce|6rO*swH6I?s(#7 z1|g>CcUL*znwW=}!Dk;|I}LbTDgjrf;?B((V##|EODKrz8BPMhA>mnkgFB`m_rT|y z=ux|6b~;ZRq1OXKM4Nd({p3xf@|%mo^l6bF*(h0OLov({kwb=pBr8W#Gm1U1X!+JlRBUk{3eYcOy+$Gk`S_1=^f zg#rboqADGl9+fD;>V~H6P*HqvlY>l6QRsmS2YCua-BzHIu2|8Kogu~brtHBbFFMJH z$I6WlOy7hS&>m9-CZl++h$`~ys`^0tR3sgt*^##tz6{elUN=b+P<0-b@)4Yg%9S5_ zHZ|<_m0l_wSCh~NC6+1O(^HSc!^Ezjyjv8fThI%s=8TRJ_sOBRq+jp1GzH{T{SSfh0<5LDisYS_jXetss&8|rGKzk79 z7BP1?LsH&wNP*85od#GxQ>{{DfW@hfz#q`&T`^s_l(DudUhD*^ls7|e!;2%UBdRle z9{XgCD+OsxvYDo~ywUxnS(#?0QpUB*#=>sNb%Txk_SfrVY4YlL$~UvLj1}H1I2D=| zeAT&Jd|99S4oviZwzfIq)l;$C+Pb?smK$qp(;N6}n&T;J(DCAt_vPLytF435*=+C9 zdkXDF(yCXg&8x*`_-8bva&~T#KXVw3U+-T({F?eT_-kDw=^VUK#{B6H-kixC*Ia+& z&>>F{SrB7OaZq8hLe!9=57w!1TwoABAyhP|^{>9jfkJH1` zy%O&NFrKgWb(h_^dVFjTGVc#u9k?{GIdH^<;bNppd3!rmCAFW+T~jqHIx9|-PwObl zLO9gDM<`x|4`ymN>EbuVDDE$s=O{N85`TRCORKKRvq%*p6@w%x*oG0wc*g|fEh?$o zFP?SC5drC-Q#jHABLe zAA35udQ_aM-W8464^O@oo2VV|%iA`WE@Ap0Fy;2jyvh7^OU)VnX~VZG-(E}UFiw-9 zVh+ikGtEm#Nft?mZBK7~AAdU@yQ;r2zTnfFwZpg})7db1TtYH(fBW`A<@=R~d>b2^ zyne5ITh^i*j~mox#hQE*xf00e_?gVbPokyYFzz(u3NT(HhDy>_)&yVkObwPz_4J2#Gd>D zi^7fqfkJR(Zj$#k?rU{6vz=BStitwc7j`HNZ~DEdW1D*__VmYa<1nGMpLIt?jN;NP?E_YqmdhKG_=XGdn0WAdlJ&b#cQi)n$WY%^Pql`Xf0}=YErYFYL`MV(ft+< zQFD|ikv~-qr31%LkrWBICu+N^S1nh~JM|W~@WbbvyJ}%Ml)06V6~7Yi5}_JdEkS<1 zS9050L5P!$uRCfs-0vRw$aTsnJsf$c)~DG&nbR)vDm*vgkic8-*tp~v-!BCWSM@@%?ZiQpbnwp!( z&c^KX!1h4rgP`uGOLsi;qWIqP1g5a0z83wZrJ&ee7WuT}Ye%T^r~Iw_&f7{(5!E)0 z6JL$Tnrz)FiH(mE+UPg!zxLa#NMA*x;_?fpK^F6ZJUQu>*LO3b(#A2(Iay*~7NGZx zM~!Lin+7eUPSu?B*ZsZsBqJrayRW zrK=kFPQ=(n+O4+k|0w$W=;=yBzqHZ!SJRab>u)z6oRkb3G#N3J3YedHyo(amayEA6 zn`$)?cb$8GCvW4`X7OhFW|Q;M9TTx>cVxq2r^z@4I_zW=?n4 z((-jLYAEh=OcPAhB+1liW@;f)C%V&RmAb)?u>;^^flQY&+tL0>} z8*Wlv68i6>MBce=xYLOH*V$J4Ffre)ZxMZQIIL|GHsjm%`R2Cn@-x09-Q;u@1}Tf6 zkSAJ`lm3w1uFh{x+jZKvqylSfP^zoN(|QhJNhimjoCepI9U_MqB^d&~?MZ%X`1~bo z^^w4L3yH7syMi%NXHt&@PApv-s6C2noXw`N{ZBKr&0^~hz8K6;e3@D*_chmU3Hzcl znYi<)S*WLW{aC&-mN>y?QUtjTmQqxvd;2o

})D04H+j)0;>U8ogEvnHN>V|oXYo;R8`xNtJS6Zs^!^er+RF8*; z7d}6Inp~mU?S?xnrZnbUf(8ZOb2n%asIRf_Q`{qPIvF1F`r&oC1QgPi@#O|?IC(6y zN#2J!Anu5>L#o+pY2ok!#~>Vh+-o=lz!5I+mcwQEzhf0#9-K@6{Eml%6XS$~|3BB< z0zS|G9suw2d;arz>0vYuA@Ge7cn3Ve``@cCbv(KBzsI->z&RWRJtZ|Y;8V}W%g)Zt z+tJ-8I_fA2_<_jdrm;5;4h`q|8&~Z%#~v{Lq?10<2dSkgW#jHDU~TJ;vJ(h!^*A2~ zMF0T@J% zn3a`P#>>`T>NY~X3e4O0fSkK3`M!Ea?$U-3J6aC-cf7WRi;PmfIZr=a1 zEntI!=Vt`r0x-e<8ymP)=KNPF9j5?07bL>T6`&a~hn%FCkjy{VUpVvcjQ_dQz}wDC z$=wyW(MRrIqW{m$zn}d3#($I6T1n{1bTl$np$~l;GgVO7ZorYkWzdh{ptKXB8c7qdU5Ox#luWkDnjC63X7s;fjlEPY=z9 z_vZG<%Od?S5UEld1b39xlRpNBi8UfB31d=cVm{}aXMPm=>X*#?jW7K#0t7AXTLX@T zK7MSHW$)f|D1^b1Ln4w zm~BP=eFlb0V*T+FmlfV$FB|1H#emZ6546sIpW(7%+Y0_KTQ3D6LCFT*rzoupC!tZH z=xcunAZM7GlLFWB6`6Ui8Ar3W{&C7dF8KGsK5R z^_Db*V*lD6@D*SN;s1ZkAQ_&mbDLA|$MBnmXPX!P7Ygh>*u_OuM0Qu)3~>6J2c7Hy zA!H^Cxkwh-F8TZZy*VA=wArO4tqaVKDAWSj>Qq-=K6pXao~X1b)?Y4o^=^&wm6V7I z^0fNZnZ-o`Bh3Y*bsHyySM!3e2oS^`~E#P zECQDb&|%nckSAqFfoep^m(TAI&3@Y^jX{TZz#T`k-r5kUiz-vC3J`?M1ze{){*6~r zF_W`{c0{AuXZ?0#$gx-Ba+36D%h9|k{$AWwKFX2yi!7D}c2s4{XWego7H4gIx7_k| z?qHsD-eAs+jKRl}dJss!=Hx4<&gd&n#|JB%g9mAk=PnFlMFUXP0XM$%3}n4B^4)Sa z5BrmHDDOs|fLXncSw6VurBV4U(^?m`&8c$1<$JO!0hlXGTYobbrg6R${7G%UDA;~q zI^TNV3g3E1H%a$N@Xl<5nnJVvyX`Fo5u()0b`jPJVPmzg~k zv}i^mcHdVyj1}uWr~Hsje@z3n-+H>kw=QzKOgAu+CVbzg2J}R0QPU_QZAV? z{>R2ZKJymCcc9Rduj?q>u$_ig$`oun$XqV5+Vw-NkR*-GJO<1biq4YjxLI{n0zVPB~_(w8udjKqFl!b?1@vX8Q7a)up)TN8+SIJ4h4Jj~>jGKsWl2+hS* zWnFL;0}lb&%xh~TvhKlSj|4Y!Yv)2~tjzLbx0WSl^Tb_e^dWg_sAxxgkFhQ!O=qYW z`obV>j6_J#5w1X-RVBNj9Z@SFY*>8u5G?*OO(LJjI>@{fSjuNAHMI5Y)7Y)lHG|`s zo#nL0-50l%^bei6Q`BpD^pC}07%Tj}SSs!~PJmaCvQdy-5B@S`;?)2^6O=*1T$yjN zC}ZKrk^YY^?27aOuq*ORU3@+UCj`D=o=OK^0!7a?vsQ-3ubH6Ef;N%jZnMZJn1+3v z3XTT8UecsNYsTLKXoa^8Xg^uVqbT=jbHl?#EBkwLep^Uz8wh3g^zfJi+KLSGyg%RQ z>kRJTGb)4H+`o>$&#+lZSEl!^_HXW=>!n0R;*$Pb%Hpl2z-9Z!kQFcbOCev^Mtr{S zEiPS4j2FQ(R>-IIUyF^6MG>jcQC;Op&fM-arq}jwGGrF~+jO=*zlQEg^`>3@1^>&s;Zix~oLiyAJQ*)$7J;Viz z|0TyNN>E?~0c{7_;0r~BBwXRznZ`Z?S<5}@8W^cZ^d267T+&of%Fmw%L2-2!TBH zhd7gT);;(d3lGUPV0o$#A-%7F3mrXJ>F543{xSu`Wxg{0CE&x~BWV8Pkb+^#TT3Sc z;*m$YA1!+bEnCgrU1PcrRkk`y$HA~BRUxKc#`c!2YN=M#5)CBe$`&RmIrdmA#G$44vRaQ$*q9@n;BQ;+QCH+Vmk?56 zKLU)CCrzVZfJKS7sB<$1w}(g(S!*T)2J0`IUzB+z4qzKNrZkpZJsrde6!w#jJ;bV> z8gdBO(1!PF3xPaFJk)392eJ5zX|vBu*9ltX0)w`u6?>DEt>8Z&Ct2h*GKS2(!v?h$<#D=^28m6|-UY86 zeJ&7$n|jZ0aoQ)!0jjw~rH;1ldKu+f4YD}{kXbNQ)lK)j>0GW_?KD?>p;U+N=8{oG zB*z6*9I*&QcsuRa7UM;cU~9(imtC*Auv~9vYF$mSpmNhXfmbFqcSeO6Uv3!Q8d&}> z=&~Ik&rUnF(VDQsAT`^-)(A5Cks@`?*2iimy;ufuH|R&Y9(5?zY)B)F=+5M$Z>c-~ zC3vC(_$@1Oz;A6IXJ5Ma^X#;rbX44Z{xO%CuLPc9Bn=-7%og(N>?lK|uA%n;86fr}nI#5B{h<7m#`GB(7J zs2`SR@{msDdru`a>d{T93;yKtKbmVtU9_e0L&%!OCJIZo%$s;K_c|<)rb>k!edxp) z1y3<90(a813hRCi`&)kh$MWcc*!2NzFpN3{MRzAn?;7+)E3r`X!il9gIT0Csh zIto}zhfo5tmbEPP%LP;L9~4d<~gceoWZ-sfjYkkC5y5DU9yx?f?B2I2*| z^em;SHBLl?=C!h6M3>-4S{2YTFTa8r*Qg1mm+T{$mwe^L?Cttrf5Yr>qJeB6a)hR^ z1$f5Dg?#tGlIBVImV`KGx|8uCu-EQaeCy@J1E#TI>M_sWK0%lq3Zag%(DI9hcR&+} zg6vhsyjUY+pKIp{7+PbHXe{ZnRHAPtEESnvKY=hwU{JxQ!ctSw8$op$wNXWtHWvS7 zBu#*7GC92orj!*Kf|ddpD}Y;i0JrGu6<^T>#TxdZZlE&Y9cXL&40}p`xw@!R5yh;t zPn!mYrDK~HjnW(dmHi#YyvYSdk$1tb(bkaVnAid;PM_eb9M*}`b|J8(40va~8hgTd zMAHRGM-PoEywt|Vq`a|t=z_sz4c@bdcUS9>RdL{mnH6}(^bik_jw0{Jma;#{GJ9!? zUP`Z=Rw1SGj90-~=1OGkQ6CUf%+g7E_X@LGk_(l?h-a-`{abcn5g!0e{1|QPM}#&n zeO<3EY>32IPpa9lL^d$zdnE2cZuXwUzZAhkQaM_4s*qMC-^`REt6LAc@?TuABao1p zMHCK+MDc*1#)H&=gKngJGn@F zALugym-jtav-jKURoEkscPiwtUHB$s7rA?O?sBXQXd8Sz``8X;cvY5YNGcG5!fGti ze$X5V&wS0&?oTFjNzWf6S&pj{Spfk&?i%e$WQael-uQOGTWDI@pJQt}wHNA954D`k z$+D=&1 zbAVoSxn+3$za)D^05{~8KdP4cz^?dh8O1XM7j`r#8PX>ZYm5)4asqRr0dmsy+!+WX zLiKU2O;>_{!aOmv&y0mqMIc#g7k$d`c}U_fmYS!m_=FPNN%_b`y+Z7&9xc{|-KX5L zDObR()E?7gaIGH}nThR0FNNWy+AY!~f_kJ9U=~=Ea_kx7uFT)8ft8)(>go`1+mw5O z^Hh0y))O%Hq(_j-2y90`DMY;7NRf0($DVK%DXgLD?}RVzJC&ULyyWD#6(%sM`MCQ# zAe3yASChXq{tb8&qycCUEiI3yA4xq@GQ^UiVjIaT=hSsOKdn&CfrG825+%B&q|fdL z?nFke2qgAbw<>AM&PC!&F44Y(fnUNpkf)7In?8RFCY{4MlzJt&&pQ&YBkQ}NPd^p! zp-jgf>8Wl1kXP9(RZVqG9i-RXr)S{Fg35eb$#XQYF1-FVYi#|~+td|34fM(hmRCt* z!#)HC0o2QF6zw?#;a9xC!ZsgZqOrg<{#b1c!af)?fq^%drmEPM!j{BUy4GcnW*_l) z`=_6QEYsBpC_8vr;0bGmW)Q{i4Xe3)80&YuOxnVjn5)-tThDVbK=Pv6t{>wiP+(2( z_qT_~rOG@{*GVN;URCBJLPmp2kZztST)7gS5T+Yp%>~X6dAoqcZbDOBqwXwg4(7OD zc^R~!&xE#8hK_jR@y9wQEz{M;CR~{ZAY^uCCeLQQrYR`C?1H4j&QsHIfT~eARC zl{<|goZ24g4uKft1fAv8SY_m-aqM^)SLH)il^?ls=32Sk_12T%8PI+sMbAmRX{}j- z|JJmwS(V+@q+{Q(|1v(1)Yz$-;Edwru{*Q-Auwr$;KP{a&t`&KkkQ!7n^dY^85nuj z5({6rwCIZ7XRJ+c+`{Bhj4v~zc37>!$1?M#(Ve-bc!I`Fx|O219Q(gh0ygph^~Dk& zbJwfub$a)wB#^6oU#cDWWDGK#EqZUyqCn;7I$ICFen-ZWx|-Ab`!mnCplu-UkXC8T z-NU-5c@6J0f{>X9jGIL9T;RW0Y@it8!Q!t-oeh_U7^1Ff@Vkv7@Zme7AloG6$3k*+ zb#|>^G;ANeX{C#UkqN8o$r)O64UQh&zkVY+AZ&oT1qiJvv#Lo*L<|=*pJ#keS_!(4 z!o)xTt(G&n3VzSQ!A)RCQ#R#prai#*PGa#AAz8uM=~0HO*$YWbGw3#8?gjvRY_Ir| z?u}77i9%v}7QBOyoEf^(E91$;HgFUbo1krf0Nv1G?#q+eMPe@|!ZiVJJ2X5@`GC{( zo->dy(}31xZy&FXJc~v9(&5HG;IumHR*#pMc%Ec?6(eCsziDf_GnIC@RW*dUdCix1 zjV=miXXD#*Un9b+jkLY-@v>x#Ttp}~^lCaNw z4ALpB>e~KLM|)(~vyZyIBbsEivIJ=XF!mR z)oR#hd=tMZnzH{U;i`Q{X^`adCwm(>obsL3;0ROt?_`uTJ2M+ z>gl&_KH-}-EfYv*HVB>7ZF`z){H)bf-IBe{G@*Ekud#7&d zkKo=43J6-=@BsP>1PEaa56>*2^~BjCBu8t6EFl#MtLZn{lDkSqr&T~UL|n|$ex-mp z5aBED!zgD~(#Iz#Pg^^IheO*9CO*9Wkltfs?`>9h@c7S!V0=0N;Bia^h_6gy@ig#l z+7lHswXehVL{Nu|F)RZ80U>AAC*Tf7Z8@_t@zNo;sYknlcnq7~vR#cQS8pE*HMe-+ zkB14@n9Ev*1`8NH5t8sLI$6Eln*2vh9#IS681e@&JZp6hXusljO;kP<0RwB4MdIV9 z8q1!nJ?r**8LDT;Q%K1;2kp>nxSf?^vYd1rMVYb-no?>Z%h8t2tD_Z+5SyvD;PMIC zh0X_eIsCShWp#k(;rz)r(TcbvFo6N&eQ*~Ny@|{Ag#e(&21__ZV0I?HXOsCUSf1w&FeGXW&Uhlqh`g+Pi(w zB9IToyg^#`5Pl3jnj6D!?9)585HQD^rNXu>%hHT}V1*4d&Pd$N_}vIp_y9z!8?FVy zb4>*PCJ?K~Q=FsmtVQDqHe_r9c)rR(8@r&g_#{NPlr@N)N$N2fi<~~!Qb$LEgdsB~ zL3SRfT+`YHhSq2HiN_s#^KbwK|lijdtE(V=V!< zr^SO*NXyL{DqT`M!9#XskBX#s8>_bTTFf_fE(>ZsA;)V?J_-K>{e2>KV4{FFt$Xqdr|sE1n{QIs zWB1$fp%s)AnkZj@Glg1@#I7DWP7=*niXE^dDQuyRTLSh`;7PPK0_M~=B(WgsJel?u z>ruyrVp3u4KVaB=9#Z&HKv2s{4BuyW&X2{{Vs;iI_oyRh>Nm2s;hX#;FZJk4UAv2& zG4Y&q3JILzad-!;;l~4Djn>ot0z+a-Iu~!oNZPtJ5?TRjwuE$Jff1?8&M-Uh;d_n- zL@GBiifOr!s9NDk*sogMnEpSCt`W!Q)|I@)18Qj6fMAh)d>=5aYRdu3QHGR612iq6 zr{5rv*iS;mR~1eTfD|t{!GK;jbZ?=Z@|lK6q>)-`u zh>$=Fb6^C7{L-8fjN6f3b4=5UZqA>urA-l7 z5Hp1@K4Fyv6&6GV?imS{H0-9EKQ~+rPXxSn(L_U%y>7tg)ns#`5Az_DS zRtQm>`_Cv011$tx@hIETW-?&vEM%guMF~ZqWT))QQ}k&965m60>yDzhMP;c;P06gD zy52ljHg9U^C+|N1Y=rK4NqvZ>;kJ*-MjIZpdA)O{X1+Hx;!>z+PT<4vCEio&RR*j$aKXlzOUs(;v-_h#(CQC;Y{5w>!(m&6by{FX5 z2_B`mhWt>0&#oU^*~)ecB@bgo#)1qXc$Y>LICShWRK^MgYMV@{?u%}rKM)3DE1Mw{ zqt|Gg!_H1_*Y;I`V!vj5ZnVI#deJKlYNP_`$*bZgYnR_OHd9r9Vjc}G2)QA){nO8iZRRJ zyyZiR!T~3Q%l|ld%Ynd$&}>#j#oSWvWeWg{rzI+X2LhK=8reQ}NSJ4=eIyjxSzkd3 zl}C6x2{fppkpblvZ>fsSn|18@Rtt%kiDvokkPzQ}aN3uVk zLr&DUOhD>3()e6d@zB)YxmO=99JdyyT* zLlcW5{{)4rQoYoZ;E`BX0Kc)q?tw--o4o>epsf%|_yjaoefgRINQ#K;9<+9%T3{ZD zr)#G0`Q@oC#EeupBK~j>h|WwkcBG?VN32I2N0N}NV7W>9A?3fpAjx@jMDuBVdO0pm zl*~F#zWbUgBI=C^A8t5Ic@Nd1%&~BbH)D;*gp*Pt2`x&la4(n-5_6!Y^y8*2kWZ^O z(v#~@vXOG|R2ytWgFM_9uC$%SaAv-dz4?ig=!ozX)c71Zb@t{Y1kbLga=PbIL@>F+ zKue+nUVf$>>3#^R@lObB#deN=Bc&kt5pg`-x8rYibEbff$;5pROUH(I--++?Fp_?_9&Xj=U(?yqEX&pTTRz zFyJ#!9dTpz@zj^jMH-_TR`i6?k#9Yl>%5A7WO3j@2wyVi ze+G&YoVN*`KCL37M1^lrfxD59J+WL!7iv?hr;h9O<0irODxq$oz- z0hiXt-cfNdjBB2pPpCEeyO*VSu#~EFL15c|tJ{xpstmgH{!oHEpVwuqZ+^&FtT-;D+pq}?OjirF}r`5>TsSGmQ8d1f})2J8l4v_Us-jk3Oy1%#+qn|a4iNrZa|_NSYk=wDw)A$>vHTlv|>SI0kNHDE^N&=-C%h||N4~# zFd!4rJw-~|wkSwwADR;nfy*Xeu&nKnck710Q$!RT9!Jo}zR;&W{>il7Tu-1Q(`&NK z_>ti&3xm=&3Op|+fY?-cwq0i$!K2o@794*$-sI19`OJ$OnB^K6kTX?{1`l&NbF_dr&onP z2?@}N+e1-NJap44A{1aDpaBDM;G_xb)hj}X^-5-jgZ3czX}OzkF0POsahHuY7qklv z{N%aiJIk8USZ+Xm#EY@A__RkEvuX{rciDY*Y?tGR_L2cnu<&l+3kSWF39hq~ApL z?3F(45e0a^Kc1Qh1?_BnzI41+e|&q(kn5$z)1Sqsi2LW2 z1bJp!M?`cK%upP`2UZ9#j3>LnbQkF3nazGrOK>kv0L4KLw#PVjiA3I)w}=u{RK!E} z21w4}Z{SrG&k+U^9G+C*P=PxJqy}Z<=(zZEHO}fAa#Q>C0}o8v;v>}Nz7`8&n#b8b z$CmZGOpO;WubRA07XG~k7NG#7&)lBGzF>vGDnRUUD}HfS-NZesDFFCFgWExPky1Y> zNj)ElXknBaAwaq4e&-TI$9>s4r)7s75O;SJQ%~rxX{=2uRpWZ=nB=-yjqHcQzGsY+ zfq|Xg;d_aORtWf!F!uVIjJ|~)^YcGCw&Xtm-hlzMOq^KpfMSxv*k|6;hD%5w;6trz zH$j>!A|g`i)a7L-%UGKBY4vs?(Ku1pX^|6?QE+M7?921S1qx}`b;`&5@~q0Z1lnh9 zzPz{}ymNEw+(E{RY1M<;?+X3ku;YMpX4qj1^{w z?|bHQgVTa(NIXf$pB|u2T&8@>(z>Mt!_c$85K-7s%PJbBC1__-J1Oh~?rP%cln}IL2Umqz%{~)TuKGqP9wP7JZPrlc-ZOSbYYGw?@ zyVDd&2E$t&`VwAmS08S1nJs8V z6zrhn&?3k7c(96AeC2vS>~rRJYw{yQwD=!c71kq8?_L>yK_*sKwggT(+)^}%ZTP)| z7xW!t(Z*%h733U*>S{>^d+ zfNuY0CfdvZhwcAD84d>eO%{2gvN-ruq)vnh`gTMOy^5Aw?urm0bSJk-pCMl!u+NvM zjZu_?j4^1F(q?3cC@!W;FfdJ!*kba!-s;npZC^j>rk`U5MH|B@>JE>5A(0r)d?a2L zXTA|0T{$sC@L@nS#gLR??+da&o71e$F^savhi>=zlBn3({1pg4o2F_m(9)wxiRda3 z{Scn{WNf!0fC!<0oT>a=`;yOwCGaYz?Is536hshNcU71@le8COn>XE;anMtdE$@4* z9Z18-twa)z3jfE6&|g?YVGxz$*@sQw?H?FR%BveSp}&x zL<-t9Q!evKuOW@LKWV+B|4*Q~1|V;V;p;h@F7Ks}XW#Z1KLh%>s3*p+C+B?AF}Ino z|G4=~BV5d&Y4kI8F5Ti_w%Gt5hG#@$S=x%Wv=8DsV6uvGmla7j9-^wV`I$M`I9QxJ zzgyd9C^?hVE55B~GB8y=XlnwLx~bWt-m5TDiGD_+=-}ppb?YJ78=l#}NlG{okfpEp zV;OFj3*GRM@;%W%=Gq*2rpkRIFNz{*`JQKD(OB87z`DWuZ&M}NT)7*k&9XE2j(R8; z?^pc~Udw3)h~s`2Uj$%hQdAty2C{%c*7}$-h(*$?0J$}N zUs+vXB!OzObmWS%rbbCTuK)D&MdLJvL$MWzqtU1+HXYhZ`PxPJn|Rn}UGZZJ`RtvX z_n48FKf;a zg`77RL{(VaRO3i}Zi+taI%!(*|Gl)?HhSJHGTei<08+)mD#(wNJ=xrR23U{-Tj|?S zy0I4&((?rkU-*Tdwdgk;-Vt0GN%zQeq=XuWdxqMZPg+8|qk!t8&0`Eont_J#9?zr% zDz|-&>z!02Qdl$966na<*$qk_GhcQ7HxnB10U-Xz!Ge(5%OuPgtJ!B*(yFBT_5(y3 zg~jWzP%OomWb)JEXDrgI@bW2IjJylq^mbZ_p`H@xk*?PtER1p(@S(GHfkxHL<( zuS_IxNY=?7PSK-fqS58ynPJfi;ct5OUPzOnBypl_KjG}L%C+BcO+?{2tW<4UI*6+P z0?K$1RHg`m!shC_k4>T?#Tb3BXzDayS5lqStooQ=`ErZ92Yy#eao04>Cw54<-S$eZ z6%FhWM@<+RVF!sk86WYeblq`DD{@y@3Brq z;dz&n>Z87ztNpN4d$#B-9HK=fLWU8Im`AZy--}>5p7=s+ew8*?vFyxaHS^mN+ecn7 z{Op;h48aFWO9M#Dcc6DI^5Y4^Tf0|L@3nl7q$W>`Kt9XpMq3UOhS-@Ix46Y>6k1A^$=}ib-taICR7*T)MK*ZGBztCJ2TQ zcZbNu0wQ%A?+$se; zK{<1X7w(1>Zn_k|yadOVV#C+t|IOw{z|Y&c3r9Gu#v95U#=^KXAt?TFaeL!~2Bt1* zTv|>0QoCk|+bGavmn4xdfnk~2JPd3C@UmWPK9J@wYzaQ1iH9-c)OWv3tlnBJ)pxrQ znB!oNcUD2`jX_&Q^SMk{JRR6dV*UKy*({$W%7sIfbG%+8B*kMP( zK(KO?5CRvRz==$?-=7`9VCUw_p3UXTN&ib=Iu0N?pfI|Xc7Npo+5qS}pF|nQ0PcW- zYCVCkdJg=2jAiqM`=(5fD}A?4vme)+j=3D#YxRxnQA{)}xQSqU$H>;}1Kv*@*lJ&o z(tI>HN%%ebw^ssEref760~)>A=KbuRsuGoX8&&G&aLfI_E!Pef5A~a-z4vMH z9aNuE?mnwmq6&P<#-{l*Kyv_)RK_cK)mOknB+=}9l7&TVL{g?TFF)uberqj>C_FDG zfn53a(?s=Ybkm!P%v@}qOP7&vRF6088dxwKek&<|7rGy`>?>N>D>8WfvxBLiP{oeT zm7dBWxKvqgo(-c)O!$oIJZ*EpQbQ{3(=+ubwz8_*AUj?m_Z64lcsY{80Cg#Fg|RC27HK<(ih2eGNE$@so$h$b# zZLU?v4|V-3%PPQge0wq`3QVrPl{H!^>dw5mAu~gbTy~?#@p{`FnYc9CWQW;j_D}3@ zv)XqX01h#==q!z@uD=IzqIcu2>rrD-=JOAQaoTlfw=8Aw9e0nbpYLQGr(pvek2U`l zH>(f;f{<6dS{La}^1qSe5LMPHUCLQS<($JANNvNEHl$gPwv@Zl$&Er6IHOnvw0kQC zzLI)VA{m>pnxDOXpgym9zs`|wW|`g$Uh-49^=}P5qWiqS&CLHisZ#3A zjA4ok6&O1prHPn^_|&{>j4B^psuTzZ0>3oTO!vYv)4DPQ0?4gd=TK=dz5FuaH&B&1 z>C4nIXgtM}8^VyO4OusBFW@6z={mGn3HrFirt@0carr=It~q_Dd2{e!VC}uN+HmNT zm8AxgyyD*wzq}ye4zBp1Vj4^dB|bkzXOin0NKG?=6TU0^fPu&CG6l>VMH*iDbiovQ zy9-A(qGwn(I3ZEMLuqMZZnK$_W#*42OO5qPyZg#QW-QeEgG@!t8K$)5S`s9HhB-*C zw7)>kjk~SQ2@f7MOpB*4S9fd4yK0zH9geQg2k-I^C0cM{^_h2={=`H;j8?A^tl~K_ z4xS9-=k9i|6);V<{3^A8!9ej9xrikz7 z>jmplC%hqD!o^n_bGS~OSS)VtL6$o1lblC1z~bK*U8yMRbS^q*oLK%k!X@9tyV0=F zDo^?a5}TpAIa#K$DPF35{#@h`ImUX2Wa)Njm`c+`h~IB&LI$XbfEj0WqipL-Bn{7LKj1j>ST?$m8ba`pD zo@*>R6khgwAF|aT5bQg|-ePjVR0{Pi^;0?vmenG!t@vr2gea8{imm4VKdQdMt?4i9 z+Xe)slnwz2NkO`%q_jv&NsCBH*QU}fH5!!e?i$@N0RhQLHv`5PgT*_a_j<4A_x=I9 zcCPb1=iKp$`^(nH`6_cq)bYwdFQ+gQg2%O5B*mdta8|n^!E73uC6)A$Svon6NlL`| ztaiXZRvz9%{gUDz?yo7$O-`z%Kr6?;j%Y~E&F`W1j{M(!c+T+epQj#r0_{dpE|o8> zk(_nfwzcsB$2JTEQA<>&D6_BDo!NH-w*~3k z*-u6Erl>^tDSPV1H||#sZyGnG_xV!&>MRJjd%s}dNSdC%PpSVOxhp38E|eNd`~T^J z-@E_g3+As-^cV+567%tQXHbxyMqjc|mmbg79_N>Rwe9I7)D;SsJw&Yh**^Wk*;fM; z?2065E<2SS)=(we2J%w^uxn?{f2W3v=fE&-M(c<6mw@?F9{tkgF%dzo=NDS9JfO|ro=Jqv^0)80FK7^XC087z zKJN|L`5XAZN9z5p;D5<+Fh|~fzUMBDfuF-kQa5oG?j@cdX44IJnp6`i58q;I-6rqS zYI994wz%8WTE~{%)mUEl;t{aWn*nZZ4BY8WZOY4zAhucL>#F#`%Q5%wzg51h-Ssv6 z%QZ2^nIoW8GVp1pt+`=y^*6RubkyE_Z}Hf$c;=r@hI^-nzq!S2+7b3ofZD$~FyWE>Ep4`1aZh@_#qzpl(dKkO zUFfE!j1@@{^TE&37=ISmOu~z6{54%x!_aE3mWCra^3L&#W8IbF)2;LT z%kz*Tk7Hy1LfI8X{GI?pq{xgrxtmAle#r^<#rKO^JatrY%n``pvyePpk93IZ==YV? z*B^ZP6N82a((1UZHi16J8~wMxdXHd7(DIc>aH@Y}D8BfgIyHe)Vkxb&bmJWyGl=Q4 z7&50mc>Ir~9m-d1-(8vOFw;nO9e7d703(LOZdm_t@DqD7S>!msJip!K*ga$|kAl&o+T@ewfQ zze#sAfBHhe0BFX(xN)Ir=L`AIdLI8TS>_=SXXpVq8PnZ$6oyTbKPGc_a}5Jhok0PSFiKiS`BJ5RJLySJ#(4SxuPVjd*WUm_ zJQ127RAeS>N#f>3%baPUQwRBKKlae;ntluYK4F{@?n&FNNp>wju~U`;&3-|YkJ-m; zPp(iKQ;q55+`30La>*LWe+Ohjyuh;8{5Hu?xMDYq6II?X{m0kbNaHhWkY;%E!b?^)rPQj9I8;6;+h3PV3BTOJ4G!eO7{JR* zn68@S-PxublC8A?Gg$u}3X=v&5fuY4k|tzcctEC3 z(`m0N%J+bqk@v5JLcN8?WnHr5-1qx;Ug+leKLP=I?fho{w~BBf(8vNA6M0`T8+e`k z;j*SzIUn`!Yq6T(nUK%>7B}n7uXnI0QNrmpSm*VyV9GJYE9zleg~4YK({CxVGA7Bf z`|;1;dw=MR`0Ky!^{`Ak)#g_4lkWP#%lGVp(@OF-VZKVA=HTW)i4(WKq46Qlm-_uz zuh0Vy9bK+XOIgj6l)^g6yRqMld+DY$Hzl)GNBahBD4p7N{3UqEEX-MOSgE)Hadov%I{leKjh0^VwUkvjtCGnWRY&qr>RM_av!=M zNRY`|lME`v6pr`YQAxi6&A9WlkFv>m$#C!iqJoX*0NPan>DZMbaCxK&p~bIfP@~BL z)t=*O{CkY)5i8c-O)g7j{!57i_)~279Gqx}8p@Fa`!PB6A8(HCCxkKy`jwqoPV2qm zP|74Pm}%exy`k!J?}zOM3pzP2L*5$I^Fm_}HbNrzhplIIEd<(A7VM?TDB6|yyCdFP zh;-A;9U6T?$eJ~gjHiC#FKbbG!SvN3*6YqwDBbnr^TRRTaZ>T)Aa)2hW|b#CZYr^^ z?MN>N&Hv2O+L(sWUO0UoNvR>6M_2AM1Ai?GEy5zCbXb=(Z)`)iQlnDOf;{*38$A>3 zaze9?4$wXqtL>@9DPwT$@-vONl-8p^7LDvWRg&L?R5PpHP75u@mZ4^&EUfeO+^=22 zsj6YaM@gMO&gyemTc;nQmV=DicB*7ua_t;5+h>9>rk$69exD{URe-vn;m`_9r3DFgAb;P=5AqNfDWsUseT-BJ#= zABr6)ePEq2uSH-W?$WPwQd<*#Ex=1 zPi9Rh@I{x$wM(;t$FvgC_74s9^;;TtoRy3xGmb~rFTY~Ww!g|&_g5hqr-L)a3$pzP z4Y_n`^2}>`p(74g`(evb=URBHUMsV9aUVJqy|ygaFm$?X`C0;jpm;TRxij%_M?3fz zkCdGSuQyG$PU;l@^e8WO z!UuwRGevd}U*H({WCZgfZu0lsIV&YJmlpN_T+j3FP(&$Nh^rAhRmh|2*^8m@yU-gD zW&)hv!RE{5yC?n;)yY2)6FOJ$zQRdXRDqtaE@$bFl9r=8WIlkpyX>-+Lv@B49lFN- zkV!Ll5|WZy_jkfaxA2Dxn-{%GFGNhwIx0@erbXs$%V9at6v1msIL?MUFz!e0Ip*xF z31iQArARkF{R}*vWZo-m_b#el?c_U}6ne$iQ$ zekvZG&Sz#hwN!HSPVXt7fs@N!^HazT+i+uvLD0>~LzS*;ObB{eFav_jkN*+vx9$ zKyX zWFSf}zKY!FL%;m|Fp}*`EY7%U+N^j~pE+0-?#@G64iC=_631@sK)%bLoUg8{o0>~} zOL6h7MdVqQ%lny}EM*u>Gn>fT%{;2Bu;sa>MlXZM4J-MnuFm<7SYmZu;;KKHmm0HK zHZkgU$aKmM%`Oc1o81Dhpn#{*d!3e-1Re#@F(s3m=+Bn&U1_1kEz4RL7kmmjJ#gT5 z`%F3NP|XtY_qJoJxjUa(5N^wEh846wvqvtEw)K~W?gC~j^iUun+##dwH2{v&+Dm~3 zSoj|%gwF({VTrmVzCW3y0;(`wLK{9@sI5`b+>R{&hthjnoZ7xB!_#PI-ua|lMqJR} z<}#*CT0ISxGQvf+n1ygN6<>v!03`a2j{f9?gZXzJG0{9D1eTj(Oyo~#7(=QPeD?}S`436X_yyq6jf(M*0F<0qxn|6FMH-1-5O7^vY( zv*?`=x0AP1Z|P~4Z$AbOrITTAHwnKM0GT0zcug5#*j8vEN)D;-4hiY2!ywEW zctK|>v&sdTJdy9F){SH#-@1Xu;KRz#{V<=oXFu;3lJSp@)v4-f?*P>2zL{wuUu>Tq zumUZvwuP?i&g(u2SVYae<`0Hnuj}o}nPBA8bH_3z{@yB7;L$6K=!v+oV0Btt<${DI z4FMq{%@Y!`XRm8F0|I#~XPD>!cvT&sGF>>Cn`JXWU z<(IwZqlx)y^_N^cb4=1Tha6Pas!2x+-r`dBZ@xa{1v4rUz=^J)sI4MkTv@ee#63*( z7!pBsQ@iEM8JaGyV(&0MMzXo3(gQJlM*jBTAM){hVb}o zv;5s+V4))3XbTU?nHA5CwD9T=GUKo|&SPB@vZ|o3r|f_Dg1Y8_3Y^2)ra_sjY}!?zU@yog&D z<{-lO_A{+``HU{~UCSI6<6Flwxg&V4&La+1Emq9*YBI$9&FQ_Xh%+Irii?<|?D_d^ z5DIdjETjoT&>wWBBq2l6$Iy5~8Rsi$Y5L*17P=(-eU-xd!sSHoeYaYde zQ>J8bJ?2%{TcoeP1Q?*oExx(4L|BnnRTL@l_aVEn6Yl<8IWlN7|6_fmfb+^VZ>~*> zp^!t@Qs@3|Q#|akRz@hJB&F`ShJ=#H(16WOK%B;&ul)lYULL!5zQl_4mCo2vF9~s) zWviC{mF?v{T%LnuszDlpX^+Db-&ESJa&9)*EhG!uLB>m|G)8q)FAQn?$9N?Uc>RD# z0J!oy0C@y^m)*yHHHJX-bV4_qE3%Vq4$vv9(gQVZS8l%@h+G#WwJ~3byVch-f3#5XwZ=&x%ct> z*SwGXhgv4Yh+9_rAkg9_KFp|7BnTgExjZ}&86EsjZMLMwth-EG>&E`2mUt#1B~x^E z>ZbncO+!F&o+PbwWz10@yCzZgByWOecCmEj;+)rb>9iX~MFhdtiZO;5Y$s{!WEQ(K zoz@e{RrBS}`MBHtQ;XSXZVUMlWd^5bdrbKol3~O3J#ZqSC|~(Y^B%bj?Y1*M_zxkY zowtyCvop?sy@&vIh=5X<)nC7FPgKYd3f)#wH)#I)1Y#o3=g9Fv(n$h(DU<84`$~>9 zBA8t2vCjUWMDoghm#wI!+MB79Jn4JMh5@|pW@kG##)hC$!mDyygIP+gFPO*#-{(iy zUEP6mH;_2fpu>+i$Y-uzpjfr85o5&zlewuJFBVB@m4=Cg)J&s&{77wT2f za5|x`SXVkYJJCqMk7bTd%w~_`9^MajJxz-!E&<=ikM6@PuR$9KRxSJn;Id6t@iZgB zrTA4A6ZL!S65ui)qgMW6jqM=0Ln#NMh34FJsvkI$u{eM1XrLj)3c^*N(XGk;{8NI% zjc?;}JF2fff#NB1o;H0jB1qr|ykXD2gJz=*#jQ=D&`f0_x0qBEJuc z^UF>H>)r|j(>(e6?lY`f27|nsw03?tr5Mn?sxYbNObkdd zskV9MJaZEtis}T!%LKJW2x@h+cbb4r3e{ok#+(jM9qmw+{%2CRd%-sMOY+_zu*uO- zU5m7oIxeEZ&0l-x&*CqVIqkO8pCv7Ol;%PqF>T71A1*pB3sHD4f1Mm+r(g4sUl<2d z{2AtK-)mtMd1(aUU&*|_p&^VxI{-3qdNgjS2-1NjIDX;GbpvPG8K~UrkFN9^$Nf;; zV!%e0{h`EQ9g`pg01;lamg+!wJw2p@m6mBETdvr@MMhY&U(ceQ_GKSlHRv1hOU!9F zJdS=O7`;^Ilx$W&zY|WELx!f!h%+M7vKzu`9T1!U84hB)IW7$&pY!wLGrG4v(jt3(NxI>r39wxE`P>orDaC=1 z`>wBH*c74Z?QSsfn$MPSufLk%{T$nO<@PtLAz33|4nP}x1iv|<(~7A^Lks;(nqC1> zTIN??_e`ws&PlwY3?#OWJ&pD=l}s67w^22SlvZt8&~Z4glJy%L)Jkz`;5zFOiOKXl zteA^8NXH7+Mp3VQZDf)+ZmIdfH|{w(N+9sXP~BW*5L5RARZb(V?7Ge$!5!=h;xWV2qY z;fQTrjssvF;M%OC1V7Du4qK5eSd3b^PS)ME0TRM{|{EL9|_j$y} z+8eYt&Ce2E`Zv+|#Ff)v?2Oux@P*Hyt1U_Cz`kUH0xgCa@B{ac4Y2Tm{zUi<{GlbzKpG?krRwNMljmW5wntKND-s|Ne_I5WV+!aY6^Ysw$Cm=oGngNn zaGUrkgz7c^0CY({(+oMe>(L{=A?(UabDw1rY^ z58MzU$xx_9xQ@aJ!9@91Tl_}rp5K#LhZu(kuR5%-VGZ6Zi-}?^s=#GQ^wH(poVDZ< zwtKY|#zP7f^U&5MsS}xA3bHV3H*ANSBAG`ZfBw>G^fTttt8!M%(zz)sj+m-}sxd{l z$&+QTgtF|RDNPp|GI`7^=lYA1gGa|?EOHFIr5&VpgaIQMwV2r+g|dsOTidtlzuzlvV#4meOee6xAtcq;nX-2IgQ6ExWLg!m;`4 z*cC*x9KH)TNREHQH}{@}JxIP3BP03^0tjxyw;Ezqc2THU*a^~3MC3w>Uz^YxR{S6V zWFm0nayaKdv`VsnR~7j6YT)g_rb&!tK~h;9?=2Ism6zcx$-H;-0UK*CD@{u{$G5dF zJaK|kD{%x;C%^qIfBEx{ekZFeekj9nFJX?BF!ZN|^d249IP@R<$ex$>2kfA>_i|G@ zv)2q&${(kSq4L`slytOcIlX?{Om=WJ@WzfmY^xCyFtlTWTldH<|NTifKhZM94*avL zV0l#2Es`tw6B<6z(ODth?m=0%nLA$G_>rVqrp{E1Rr~F{KsCQH)|gV&s;;6Qy?~bR z1OMeFXU^LEX6IIls6I~aX~Ywlg6sJ645MbQiWUPRdTsmsJ^*ORwRmGk(37R2bjOZq z5zmdEk|=UTpY`Y@7K$fQ%n41G5K5dYTs#C~90I`)uy9laSP2UXgoOY3=xIm^RI2!4 z9Ik3|L!|Zr4TILUBDZ0<667b>>^D{a zdgBvz;N1v5R722~eyhx3@L{B-p^S22CR4o|65a~(VBzSfp;_ZV!!mMx=UEGa{9>>z zr>^-}%dP;QD_GZ&sVdOW(LxD(3GdL}C=Ddu*!Ukp62@0MC?!}QBSPrkp@i(O`Lk5swCai?~BSY5hbFTIvmI?MCT z-j59`0m3LBtB~43GMn1Bs*Oh6DY6{|0W7`HL?g9HF*OXV>@-N~b&s0v<}F#(2!)*b ze;y*`&!NmhIc1Y~&09Laxf(#BD9+1ewCBDj(mGc3V!+|ML)3DsV0ZZ{7X!f5|!!g(f3DRmu z^Ea{RBmcaGSgGdBtI7rpbAwHnDzB69QO3N76pyso5BPUFLvl;@G%TSusJdH{E8Gj| z_);~cvz4k0IIV)|K+RjyT=O*fA(ACICB!NR8u1|0BM5i%fevWLr|3cXWj4da$whpS zEH)KmQZe$}{s`~dwUs#|vE{1ROb^7#!ABG>N6eIgW#@0JWZ&nXUeC;7p~$Ya+M!RB zE{JUgg$2Up{ZhfZyZnBlN11^w#vnP;Rb_&mK_<0g=GBlw-&6S(Au1E@X_M?{ZYxUC zFf$=tn?iTQ(;8UMok2p+oB{f%YKkEfs!?p0Atl+zM&6r}s)_+WZ?ec`QWV`^*z${7 zPj!g5d4ztjzA)n*h|^brI8(+Sq0-XguTEsw7Abo_KiKgJr*+q2o0D2XIP<#xa^#-0 z95yUzF78{nug1eHd=(MMslGa@9JM8fkq478_e7OU_|^PPJ|D?dseH2T7Nk<6D-E(X zia&CEEZ~a`sB=13m|(ze{#4xKMvz8o7$N@rax|7+9{d8zM8Uv~PSYUZkrVZpE-5X- zb#nu9aj?g4nLj)s=W+y*!RK^sg#+ErV4+Qm4x?fj3@UI`@x(PO$*$4M=s~p^>DpSY zptTMSeXGg_mzIM!A-A&`N_@!8{OOL6by{32yCKuWxq5NR#(J%S2ECa?w(GLw#-I1n z>;J6S9^cI29vmASt{-?o7YtOTs8^CJ_Q(CA^h_cF2W{0wVd#7O%B~_LCk~x@| z*n&{95frU9{Oe{(`;qg-{wYOAp%x+!Q`G!&{EltqT_^9YMQM063a*V-Rrp1R*;$T6 z6Ho3-SbkQ6cqPHH+Zzb+YmK%zwn~mN88w3`=Gvj_B;8U71BYzj{BChv?rZ!$GbDA= zyj64#v($xeazHIvUgGA9kORS-uyzir)iWPfb=Q$xjgQw?sz~&;59~}}Z#IC%u~Ur8 zJpZQfzZ=^GG0!)JbiS)5bThsB4ess_JC0n+-(l0}B8@8FC<*yfyBWB^HBDb!A7v`a z?8SB76PoalkG-|DZ&GZkv?w^%^!)2>qS2=SVvzI+*1JVDG#1)-=bqL}C?nx`fy3C| zKjx}3&dIH8ucs4CVx5|K`Bz_oHi0phE#)zyCYR^c_}g`(TWJnSw4ccgUOuU}WCNFq zrm!~ev}vQ2fR>j6Q?Aiwg$G;vf#*y5Fv#~M;~x|jxloUnPe8gg=;^4~J9ef|-FGAm zc1)zFh+$b4TWqukv)(DLA6fV8K*F@Cit2{ykOg{0v#m*xY5`95EJ*f{;Ga~#GsOtH zKH57kj1JwDMC<@RTwk$H=2!#pSXicE_$jt<@$Que7fQ$iRSp3Q?xY6wwcvCEa5>G6 zHdnK(7;d!DPwW@vOLHArsk;B!$56Lxl+ltH!2(6AMNd9k{I2xp7NQrXBGzfOb)VwZ z->4=bB6paf@$P}1`g;u;WKPS^=Qeglv>Y-g#RRjiQE(lCelGJc&4&*#x8+4`JbLH6 zMpWhC>weVYmH%G@}m@Q1qOz~Tbh3br- zXF0^kpFdT^@8_WF{Z%eAnS=wb+_UL5CUtn#e5Ayo&0ChipTI!;*Sh8prrM&GMuqz2 zf_wV@;yd2nv=Td?^(Rg3#=`Y&zPWDE=cgaqy+v88Ofn`j0Fv}a9GJ}>_g${(mVlt( zwKkR9Vbm#PnEENRbS7ZT0jJoGw@BNOxJ-wmj~m$WaRQ!~1G0jbK7fnr%_X5vsk!7=vv-=;HpC@5bei6F!Yco5K>|1EHibQy`3htJ-`OtRyFY z|CEPYzf$mMC!SWv6^K0uo4cn8Mo!9_%n@1xoD6D z9a4B7R9J=fF!UAZ{v&&vlqE3`_^6F;WeCB-W$K7+m}OcXx;8lm>_Ou4;*!liWY_p`$}6TZ1LMv0loB zy0IFrnzdv}ZMz1~sG!HD0Q{BIl+}ETm5EEuqk3&3npZJ}Bt1~y53S}G2CXmByV*IP z!**!LYUDW!gzJ4RpWIteEdfNIn%G$`ABXC0)%?D+dSLf{_+GCuw9>4|#t+eHm{N$? zlD*WL@~RKH3whS&y)|1)+KN%Y9pO%4eyVMWmUP2)rpWGcpp}Ds`RAyClQC^W^^&&e zEx0YTwmw>U2X@o!M>(>_Ree8YpJE{Y9X?-?fddnsd!>K1;Da~Ve&cR!g-enwTe2ZW z!I;sv7Xa6tuq2BP57iE<@FtwlDlYDPBshH3`MJvx-i{za!(UyJlf{ZXPBF>P9fnaJ z`!>bQAW&gLb;_3mLM*(lM&kc>>WS3Bv>QN{z@&Fiu&>L|%@B=_cHDO>+o*^(U;!&h zm-C~?sSE}9)x*!Y`D^ZYe8T#s5bS{X@80rfX#uyc9>^+cGAVCL^(tr3Y8Z$5p?~YU zRQSjPFGIra#6qf#KJ|R$oFSP*OK2;*`9ie z7)T*hUh^L0>*8}JGT-3?sbKeUwTDy_q$CKTW`!;}nksDit1F|rfa4-eyV$rJTR>yr z5Gcr_P0iBgW_7NUMZ^_oI{+dRgsd{}Q_2Z-Ya#}*n}&>u>2&&%N|)cAL%aahZc z6Ak_ljSZn`08KCHFE`Kg-+PLe>mn7e!#&t;?>v@SkcJj{M4{J#actA>J03j7kaRk- zF{+;yspD z{mDdjF{PPaereAQGlqYWPKz4)fA@kmR^(o70My{if1XhZJj?cZ=}LAL z12Zx(JGK&xGGK#O;)Jq4iVs86{+4nWSnPanp-Z?zHGHD9Z#rfTI&dw<7HbccLtA*o zpHokL6ey0N#D})ws+WZmfX9t6qb@(WPOHTwe<*ENny;V+-Pa3{B%^D zIA;uxO)TggzwL6+*_59;_1KviiKd;VCVE&zF4rlMz3t-_2gQ?eH5KB|Zo^3MYHVI|O96SAE>y^y}3IvhT}*L&;sC+bV3Bqt(tm5EcvQIMS!9 zA8Y`z0Z@j5V++#aWl&qYOkZ1#ZI6?F;)OY;tt zknFmvK4{h?B)ex_mA5sxsfA-2Ll^SV9pCwdr5pWKn^zqTy3m3)ax42!$ZH)zdhf7V zSEc#Dm}af_StNfMVwIC?>x@I)DdX7W^@M|(4o=arc8S`yfzPeeV7x)Mvqu^uPX8>- zEeSv-za9+nRte9T0j?V$OQ+672b8b4Ib*TS2XqD#{h{ z`$9lILBHQ^wbDjfW3(lmnh$OExR5=%=G!Y=#k4gcv)C4>3{p)KUIbhiZcC}-H;~4=MMMd|7B0C7&2q-3(Do{a+#5hBf7;$4p0I&t2 zf<^wCJQbQh%YlN}u-oDCSr^`1beyrj&M_bZmUt`zhUzp3W5dTPq6Bfg_6@`Ho5%2@{5Ha!iNjp6Uoowx+nG62%91rhVM$%pHhoei* zApX98q7YB^-2t1E@;13~24?QKUgb1dW6f|%PZo?en?F6_ol4{JaRd(Cd+do#R$aNW zmm-TW4&5lQ3NG^z-@;780-yW?6Dwt1$K1>hAtq_yRi9a)yMf)9x>*Lz&8+w|GQWCb zJ@t397qhqyi#wW=3sNEZQHAM8esd5^mCV>Pv(B&~Z7*g6<)?Zxm;=`_F$U5_Mj+~F zuRff7r`{|JLmG&)9Y3*jN1d(9c^z>5an0l7l4Wf@I0F$C{O95cs0`F7cqPxTD}Q zZ^Ny>4A{v}lq}nDSX&CJXdZHI=V+1>ux7{tG|FIn9;%HSgXE)8U(e}=r!TKFXJo?l z=@m>)eOZ3njqyU6fbJHZI|-OXhuL%f)pz;?h8=B7>+Y`A&B5t!#Dj7SW277K*YVj3 z*=5p2i^a}ItaEj_SJxviDiB_BTs3sWyXk9YeogM-Dj4U{Y<{zl+8Fk42f5TAuNNh0 z*{#!PePXU1ngZAzF%}Qjn@fOLGZ{)sg6g?kawCNHW5x3%5$vuhh?&`7wkolMSUW$6oNnwXGynbW%C`MC+KnHI!+3Q{ zL+f~p4+39W6n{GdNtIaOqhzbH+@pj>VRozEW%d|7hGHkL22=bLnjX(Ov`%h;JmPlX z)htjv4JDf9V9LW`COp@VE8ecd_@ls%WH_NHamj<6U2beG-$U=90BGB*RtTn?z8drs zJ%136=OZ9-iLukmcBm zWN04t0J)RtT7qIl;>Uf0eEiY3+s7Ikkvlr_*z|K&7?zgw3{%;P$~gzKUU56x;5uD6 zPLd%n+VS{l7)GnjKidJcj|Q1E$#Znm@_wkRSRUv6O+Zdt@D`|P+F}rHwA!*n!@E-> zf`Fagk|>f+jezx`E5&o^dq)*i^$fxOLvCMn7G?>a`VE?294zvvdWKrwhy1PLx2Fg$ z5XJ$GU+pLa8Hf4lhTG9mj=R!OuO$q2T?Q!QeEFB|pE9J(HEb@@(~cvZDxSjxxr5kx zA-GPT!g$&CYLWhF?N-Hi1$>W?Cu(-!*`DMw^97o(k%xo9k^np$V-zY!eK2ws1<1jlj*N{tn>D=(Mb3Mr9 zV}m+w(k@FN_B~+l^Y--Cc`yN^**mmTl7^0bIE|ktzmh|@1}VFcFK#9r?nAN9Q{4mt zET7j-!?uL?LG7po&y(@e1PJhWH&RyjceMlUUOOV@#5uGXxXH0M0m6R0>xToLWp)V% zjgfYBRBB}Mqta!6?nCf103AzdZ&|>*SvXV(*A37X8t!wT;e8Z+Lap-xns`y<3})NHldoGbs@c+LYN`-1BDlq%Nw!HXn6kv>-Z ziqE47X|3TOJ!f#qb?|wf{gq!(@y4IH#uKB*r{@1WBIR-2Bl1|R$roJ zp67w^-hErxlPr2v+kyQ=qHVA7oFNt=T7K%ff85?abAk6=Rj$8mzj15D_FJB!JuQ#R z2F+}`@pLjS%KAL~{ojdO3O?u2SrF5WmDd=}`=Sh*bK1?MoIh z6t=AU9m4RdsnKcv%I0)^zy*gvyAUQH#?^iz%s|Z9{V2a4SZ3MkFe+m^OraBk=IQQC z-2A*z_7pQiO4|l$+y4lF!P354;Qalo*eK7!MYns|9+WsY-*V)Fglx!_+{kMA+aDjm z$~u4cMD}7vwUt!9fU+1+0Rs4pt_HOB`7FOG{u#=H=z5|$KasUH8L-RNyp1Ja6DW0=u5tTjeAL-ZSPN7)yLu~t5j~9r@MgAsnU4(qI zJ$kIzP4R*1&i7l2H;5iEY;xvPSZBrEmKOY7CRs3c8DdN4_}uoAIf3d-I6mHAaw2KF zHlu^>rYf(j+uxTu5j|G*6XFO}u~YEXG0ZHe@_RHoCq9hC{K>UN?;1V5@T+&qw+>tR z^obN7R$Ud=CjQv55|I~oX)}q)=BDYd%To?1x zJ=DR{5*A?<-WtRe11-p!RZ=);!_*F~+$9Gb{#0WqxV&ebW^f%n24CvHFErpb&WDES zyhmtt1Y;h|CcnTQ8wp+q2iWZ;W*`9q_=XjqgX!s!CzQZ>odyd>}K-ztsOThRpb~%I^J~cvYT5eMCzxF6iE@bb@v_d^O3hiy88?D#RoIR z@u?wkw6{cEmRnBJOk6eI1aZ#SQ<+XO@gID-1HoP_aPHX_-v z>5ib}zzlt1k@J^)7@J?|Q;r0=k5HkIW7Q|;VlN-0yjL$4d_$_cPD5V$y+m8~D3sqT zm5(xZ_d0QpV($9nR-Y$a1W<> zNHu*5#>F#9L_ZeSx1rPGLGbH6CcF#)t6wis!BCbhl}NAxhg3m6pam)39Ee;TU$Qg< zG6a4&D{REWfmd!mzcxqG6_Kq7K~L9eU^N$3ND$ve&E3MPhV?NZqUczXPtiV_Tzh9rLdjJ0Wzzg`cAsx3D259vf zAu>}Jx7(#iAl89C&CP{e`ndF*J@)E@y^wzvIR^+iUdom3N2YlHiEtSyGdQ+%ZCjY| z^HAeD5;DiBFX9EKK~Q;I%lMk~W|n0Ox%l+Vu29buuI>;tFbeoEHnEaY3|v5dKW*h} zs}CiHJwI?H*IM1kU1u#g;i5c_IubY#VWga7n7Y4VLp9t_$v*xx(Pp8}4);>sY*VujLQa~XKzwhEbu{LA}zk@ES z+RXe^Pr3rXU#(R(w+C4ImlmdTMS^E=(_5&NH?OW$7x1IiS?ggJOCmFQte+=^R>B|g z6yxSC(2zQ~{PAY|QM#jF2B%2G3G#)qSjJB%e)9!x;8JJlftM#o@5HnUgH*0c2xEbF z8XddbSF(J=;gGiiwR!B>-lzT5iE4Jz^6e6L$i5CL{HTtJQi^BIF%=T2U{D*O?5ePq&6mic89Qb!f;ESGhO2MUxdyY{WB~Hdcs3tv09VA(x2kQ=ST})dm}fo1%4~*-%a#~> z7GuMfYK1Kw`#AXN$1nGg1Y-tn;H)O^%;{n$+k0Zsd$-(K=b5JF*?_N=q@D~gy;eWi zyNnp>QI#1K&@Vuz4YjSEUn;du1DUtvfJFHwWeg9VZ4cLD@H+fc@?o6s((k@Nqx@1u zo1TQuTXDt5J#Yti$(uHxGA*%q98@fkpN z|AouWRDK zIO%K^Sv5hQx9M?X#}95Q{y3$GxNg~w>x%2)pBwu8gKHevR*_rT%;8$b@_^EU{az7W zUm0_*HB$uXdVDQ^Q=)a}bGjewIpG1SbMpB#%uV?3k9wJ0XA1fO-;pohNs#Omx|ERe z-h5a|DPS;dQWoVbTdNOkMGD zZR32IrY+%sA)OVZwIO=o2FdZyTYCFi=SADyv!7Tpwmv?k&+k4GLMkhRQ`zR@b3lR#wn;m_0{KN9hu)x&lwzWixnnfBY#`-wO(xl$HMp~epBw+VnI`4D`om%T|dcbCqCAKRN!FS`v#L=AFVL!FYPi;qg#00 z-5L6O!fyxwOrN>G4B2o?DbPF2mdVN80D2BFTOXy@-FsLxBQ?y&`L@-yrB5-UQkJYR z#j^G1u0=*#KP6XG$P*fO`7a&Z7UK&@k{w-B*DV9V1aU7rR8TEYb|aLwbCdbEWH+}f zCdix%32FRbgYjRCbg>OK2^VZOAGc^2#vaYiw;)-kGX@%GaO-Eme&8d}6-z+W7VPi> zh9!68@PYaX&)|$4(L>}co0H2RQ1ehrEz9~OhFU*=Anl3Z#%Z+xrWnpG*QtJkErh9p zdUA1KLtR?PS+4H`4eQyZZ}A-bR8PcAjb)=jEtULcaxVFeceswGH&>_3K5a`509LNK zyEHejR4K-PYClC5jQ=<>CXFO|HKUCYzrXQ##xkcLJrr8=`R21%8{&Sc&L)3y3d`F! zltl28?d5&6p$zLfa+f15`V#KvY){flQFIX zlfF`lRerZz^?|fsm8O@9?9Kcin%*)X%C2kwz62zsK~j(g=@6tD=@z9MX(gqb5$VpM zLj|Nkx*6&2l5UW01{h}Me{#Ri`;m{cIroa=_^q|KxfXbfP&!7)a{*mi_QOFCyFDCh zs3vagAAJ`vqV@@)v^lK*Nvnj!HUuTOq$u*Vd__0vEAfU(;_$vCt8X!d>pyDq0!}5v zsijx@82q^@yD8k!b3k4^`1?`HE}l!u3rG#-1e29^2K!OyRqODx^{>Q~ ze!sV~DUdHngRN&ksZ}3#X74}Wh?)D9@f!O_`l-e&)&pJm1^j|Fbo?3Wvv;nhR1)CyF=UhP&ir(6VOlk=k~0U=ap+hE-- zGrwEQ*PZ1GUa92TYp#^UmAuFb&H2cpB-3(*+A)Is*Gdr?YMHNrWLFvcpB!cI2Rp%M z-5-i^ISocgX!{CWH{~yevBdj0bz&7{MkL2oTrzXx!uP%E9w-N?fhHMrLEm+0wJdq( zmFBzuLD<|dx1fQ<=hGM()8+QtcFn!Bm^Gpx;qCnLG&isFy=;*kZ< z5;%sK&(X|HDXT;6=pc~+zO9JHjP08&!O3G*OZ`(;w%)yEPIx&k@h>)VH=lLqzM3co z$3O`EN4X}F8CPFLwm>Bvk>5>G+LVkjr3}f+Zed>;ChCblN|rmlD3D9=<6`5CET@oB z3IMiU2hHlIQlmK2u(dF0Nw+TE2S$JtYJtZA_xj=~_EiXslvZv>YENvv*0z%8>RXpX zlucxGLTTMenfPQN{vvs1iBTAZd*q-4`9ba{k|jzuvDMH%?&=nk(Em_s5x+(EI=qG} zocf}9eO^7!r}rHqL>2h@XJQR_TCaf)rgJJeUTuBWGu}7Vf3V?nc)U874k!adS+gep z(5%4oQ-OVOJqI|?RC1-i=hQwc#vUByI1EasNW3{ek%}1`V8f>B#y#DNez_uPIdv8Fz%KibTUR zue;0rHus*3cb-fYCygdi?Y;;G1j24a;p5pzmp5=WZ`jV*&Utiqaf`B!? zSh1E2$M$6QE-rJKXfFFPf#GA&f1`}qq!hAC0W~DxNT05@yDljdYg>76eY>hr&`9;K@yP~_Wy%bc zXyMx1#F_lpDNvyIwZ$GA1Jw8c&jEe>ZX^Q(x9T2;FE^A;>W@NW1?Af^&ovX}QmrQI zpEw>z%@j%oe}2EY4X?f-CI?wAa`WifSx?uSl7U{^=%;fcV@>sye-R3ssiS?kg z0aHvhSG*DCmKoFf=@Z)+0F%sXI;=doLcigqV#58~^qBSkv`h{%bA%Qv%6`+47aOa5 z_aNy1F!H}|(2emeG#rDGEEFKZqS`|~#P?OL#+_p`j-)>&w!zza1;I`R4^hV3pG(fu zqMq)rP!KcGUi@T!F5Gaz+cGFhmj3!`_SwCeF{=I*_|Vlk3iWAH zLBzkGcA3}}&*|;(wC(Uc;?P!-sh6nE!Xx(GH*ob0NT*yk&*e{GMcLR%CJE3h;~P5` z%lKV?V(2QS637s=#im3vdGQ3B&TfJxVSVGLO88Uj7)9xX7oE}}*XS>)xoL`3ZTC~K zWy2uYw(?pd_pI$NRzyi{P6&kP`ROy$trVHKyZk_W zz6)s8{u?09hPBX$%8O*ES&=))fQaumLfvrnxL`gk@7Ah@{(_5b^Dhj6SqMH4Q?e!HK(kvwgtGP7M6k@*~f zUM;>dI>mgA4R8o7^#3i$N>X2cR66@@-u;l<0=)VMw?nOo-O|Gra-s(MB9`+pp8=))(|Q37vf3LV&u|sSV%`SE2`dnndGtu64(2uXe#&goe3LH&@r1HHD}T;j-R7PI(@HL zI*XOua@c^9W~4u;JmTzle6T^lYnj2DPrmnQAGKA(K=6)Kgv+z#RNEIxLgftZ*jsE4 zQUo&CEH`$I)XpSs!)kwNI}kS~bcFB}aCcxf+^d>0;53@|+4J?ipdm8Ud)1kB1z3Fe z%L9V60JGL_t=qiuEzvLUYWx2-IxjZ$XHA74ww>j*ys-PVP|;{*a!0}2JX2v<%R|I! z7WBhL`~d8N03=Xkx9ly6E;%xwck>G88?6z}td{+gNT6@e8?<_`Cx0k9VI?uwioKC6 zTL8xZ&(Gu6IP+OiUVn<>f zM*41pc%y1L5qn1e1-Kr{Y@XwYr{1qyxMTNz zP%*V~-87l-xX9Sopa-$ttr@$BLRugYSa}GwUwoEr`+y<^SwYny4f@}gUGyWMNmt=R z_XnpmfyGM(4hl2fIZPsEAbT6uEi;y#q7j2wXyGsLPk(KcyX3NG{7-|l!+!fM9FJ-5iK~cUyfXVl zO=eOaa=1*wM&m_%PKZnHOE%mfQS;}+8s$G3#EfM^2g_(;)>JA(xllK_(YQlN%yycPf7G(lQA=i-$Hc-|cJG*^fNyo};hrxS=R6;!zKjqp_CrtPb# zB(*d!hyg=V^DgED5G8&Qv!9r{>K$yF3t1e;^tGM-=~D4)k`c_|@ESKw7=4tNX|svd z7l7Dl3B4`r;s|P(#}8ta|BpmMUx^fuyrMCyUo9SyY~-!^<+Xb5j!bYcl6~Tuu#gs1 z`$bBC8+je_CcBQEr6Z7}gIIMkl4cX!W zcDp+Pf#+E#YSkjhA7=R)PndD;?ZpuqhtPx!>XbD?v_OuN*Vz9;w}*SdL%)BVn8k}M z$EFqv)VuBtc>Anq)uOp8|1>0t(j2>;=epHcaTL~yt<*su7NuqC5=A#wzp|r@c1)q~ z0*VY9N+v^#FR-nR7KQH%#r>`A%0WQ8)^cH`?Om=7pFw z!2b}gjCmL+cBF^en}b3-Sa0pyKm0?t0w0`$cL!S1ps7^1eLH#>IHjzaF+x6#D1M8r z^(o$*@)8^08)nB}34$)P*U%OPcOj3;Z&XTuBdDGt|e`D`m^gs*aa>NbGFObKbSRN(5w|g&~T?yOo zOFz=k>>1Xfq^C}*#!6PE!#ez?0Y_8MZ2vb~5=>aPMGhHD<43y)uESkVEoaI9Kqmd6gbBHbp@tx_ZHD9*wR03k$#33YzLaql{Eg?fX~G+nDEYy1;)OOw7P2(Q1O=;t4nuZ>H%X z)cu+zEWNI=}u!`D|WCP7c z-QQfU=?N!qE{%YJl{(+HUPToT@fKmoy4pNkQH)h1vS( zdKfdGU*uh5mKyReF6kz#r!DF1C)TxB`a?~}dm9sGjA^p-^g}yNmWr);0Vho&Ej$73 zhKrNcd%34`Q5AS+LoZPDF06%4C-!t}O9AHNlC95?6jBcntyh!%{&%gaOXWK7HMPF7 zR%_+AxlZi~8&K$t80_jHbm}w;2HYfjgFv$rt5?{fq>@Q7XQvCY17{y(!uod(PZIoAT?30^cs309rgfhZLHeNbLUuuXOUcmnCwSV;^wwVT3-U0S(7pep%}uE(`XLv#-hFb> zPX~KD9cG=H=-+|!-*zZigR1uAVK<{Wzs<0(5ZrODAWSO21<5{nEGcRpTv`J8h`-mW zfumOgdZ-b~agM1MU-*fC#cGQodqu1a0zpkA&9;kD;X3mu?FFg9Iqbd3Ogp+F;*CX1 zQ_U!~R}jG5lLl-)3FlP_@Y|44D!`+fmwDTd!IEusy*6~6=4kqxnwHdj;EN>9orS~Z z7Oh-*uuF8Xi&{=AJQGS0{^IP6A8(j_1tRise)2L!r!V zWnlF?=FV`$h29{B?t~KkFfN#PROR3Smu_h~0C?ZDRh#T#?@`0c^^0cZ;eJh*uoeXojqKs=D}x`>URN#qD9amr4X?15x?Q0+IX>o85_xl zT|d;O3l*|r6?^vN7j@2O*-|Ylg^)uGf6+mUAV?$&dA^z7u@IP&m)sKCA>Y~S`p#LL?`ZJmzqsQ zuz5wy{@d%ZbKfLEvUvIGe7DHO@av*Cz1<{|a7a;pb7$`Q>YL?8`^IPb&P_sM@;58$ zH%vG1O%;*y_Eq1$eFhTvH8u@%U(JIe7C4O;sZDQpJhPBUw=fw1PY!o4F}(Gg4DmjS z_33zU=_K=zR&4v+PorEBf_dC7gUbs=5FR%|S}$gJRkQ2e+_srk2%Xwjxb>^cCs40a z=fK&d+#aSo^T<4}d$89)=SgvVATy64>%1LT+0=cN&K4d=Ka% zi8t=&rNc!h23h>Dp-}8HLa@^nGr!a7o#kw;LwQcxcoOBuHlG z#r}mSgDv54Vdo`7U^TbQL6`eqIOSgr(!M`N)VAhHqoGYp9X?@)T1A9Z3|O((egzJB zJ%$^9`7=gw!6lkz;(oC&P6J(!CS7WBkoPI7fv2Y6Jx8;^afiYl7bBhjYWl!k--Avz zlcC=y=Z{7fFU{6qUn#Nuba%CXpxZs(wA{C>2+;Ty{OVvMkW+*(jj-52jF&j~F6ON+ z;x^6pPL&F*st#U!S*&oH#u7uWmjier#%$}u>Zv&N3bm%*8&6@I(Y#`;*@f>Iht-F> zUH})(jsB0PvP#H@Setgfg5Rcclr_U5Pw#XXMnv1Rc2{CE0|&#lHvrwGkhn-f95HVFr>jYTlN@-s6aAP;<0Oeuu( z7k{ysZpi?{HFm)J=fUOQ0#JXB*AG9x>sFy|GkdQj2W8LBy&_?DJBT&BcrANRx59*p zm+h4j)3v(D-VL<-Y~y5p`dvBKG*z3BnFFOU>%o+l1V|B^e@okO_%u4(XhY-n3ws-f{We6@J@z+=IZK!*t4V}m|10dW#n*3Xsk;M@0^&j_Q6kx<6pZ`p z-rpmB`HV;BsiL12MHTJ(q<>WQA zL68O-v3QyYTInH=>`D57x|F(qb>ATHb5rb)uC4U<6Iu)U0~#PG71uiI6JQ4+6-_G zFMNNN*$4vZ*WpQI6haMPqstJpyBf>W-Ew2T)LyBsm@k`O@%1`y_tsQD#$&FI46RMx z8rj{m4csW((tIQ_kJn2^0aDTWvzbUb1G&K8NW`_%qm%aWXS3aGsrn55izbm&As~Yd zP(D%Ov+Lp~wrO{$i1<>*ufi&sVA}VKY*?@9DK14*C@#f)ya)BW!O~SdG_1p5_9_r2 zzGpBd;gB&};PBDH37gkyj@qF_0Hi!@fogHI)B-F1+D$URF#XTx!EaZ3%C&4)A&@W9 z^?Kc**y{spe^0kg3M4(_U%DR;*H*SHN^%|->)yie3*uOMRiWNBFT}sRO)LJdya1I` zP8>H(_emXjj9MRDY5@=Hs~D&kw$~q+c=czCp1eyWf+ELi3XVg87no6ig=n_u$LkeE zW6)e{J3?e>Fz#T1iZ|_9uFpQNBHwX#e&7~DkV+E20s5x;AHIE-a!tAayb?Sm46M*X zwdG+XyAL-@&W(#n1;PK0svpHi0Sx+1m5{_ZM&e2eVw*M@t2lf8niFhvcmMhp!dQ;OAl(-?k zW!Yn5=v(d;a@UYWp0JJFi~mpR7b1SoDDi26UIPz;T}HNJ_@j#ipP<2K3!RqkfWDi? z02TRT1TZ()54uaK$5K@c#BQo24R5N{Tj@!=D83QR-G%W5E!G^C=CL(e>PGUtns^YL#wC+Gpcf2h_9=TCifWGaysPi^^_Z9I|mdnV3hy8Djf`<-EC@%ugOn_bM@zkKujO5nR^hMCoyTs?U^@~IGhe-`e zZ)y)w9TP%-P-gOI;DMCEjE{K49iDSso%#3YRk}O8#Zm>2ktMGMeqzJLnLMY3Qi{Qz zhZ3laJwfO1p};LaVw3PXF$SG;iK5|t0yMRpXHS$Emat3g1gAbIeW{4#Q>YQSeIL#Y z`1(`$F*ernA&Fhya(ru7qXWb4(d?D3&NvblF59Hs;ay_$vSq;IgV(e6%#~?x!q`=S>qg*V{Yt%5Z z#HU|lrEFe4RNABzAWGi_th|QFQFa^9_z-Qpu522TZ1hf4OG|JYm{G!Z?(#9J%gj)_ z6HOrs?J|Bg^;M-#1SQinvnKPq2R*0!Td6e(GI>dT&>^XG|IOjuPUEVp865bmd(B8x z53KUV5C5RAoVNn63Z6kyPR-U(Ut2E**><+R)tO{EYa@X^5|o4Vm^Yh43g`Q2^mV|u zEk^+$)Acp*NaCS+*)gjA4>*J?|E`?S{zwXtlo z*!PQljQRQlDe1Hw-*=F}!4+rF8+$VkbosJk!y@~TT56OEHyAp)vxTFk zOT%WM!$`+y^{_J{@Vxo2l95dec znQw;vX+Y7hTdipG(|`CUYyf|CLk$|+E38F)q(20oHrpoOP^7Ja2NHKPfMqd%o2pNs z7;9s@rq3(Vv+{C|PkhdMyL>J93ir~cQ1(G680hk|*PjAM|G3gS(LGbZ(2>(O25yz& zPF@4t>7)+f2>)q!FuIEW=;ZuN{jO;?reypcWVJb1K*}Vviw9^B_6+aGkCQ3G>AOA^ z|7J~>45o_Lr--2qE~m8*Vz_Ss^KH}Vd>;7nvUHNDir36FgIB>E&8SHU^6sJCx0Zqz zLndp)TlOt8am{L-HClEE@m#cfr$(HX3yfkD+^hG_C2KhIv=UHMxTx3YLt+V^R(#R< z==x_3ytBR)(o|hzd+n@&^taLV6k58L%AfO_l83r+&P64b3pV)gC=Z!=Yd0zFEMt*9 z)0T##7CY#?^44lE4R=jBhZmf35N*Y|pbhe>=OwLZ_^HQNs3rv2M_yyAVAPDH=Wx&Z z^a5;v+I&9`G6OdH-=VPfmA+d-ZL!lI%@Mt#1Kf-qOWk?lbbnX+Aalu=r0-*x1b@`oshpn-Cx+CuIL!j*E~HNbeliQ z$FLG$J-B1#8eI(nzXBfxuU0_$O3mClJq)@}P(dxpN^Qg~d}b@D9oq`LT$eqG>d#9+ zQ&HYmECD`~yf@sa*UqR>n^$F1i;7Qk+9SsU)};X=)bPo4{)?Ywq)5LQ+C3z^>7ejj zTF6&dGxewsdb3EkDDY_%xB#W{0IX7vJ$DFwHgv;|P{$AG1zc-1NK)=gr|iG1kVmcojiEEG^wiVCere zKcd^?xoz_}*n8>tWNgn2yQkp~T6%7^liJ@zvl!M!_N4V`28sXCDnrcrYT&^w=C=$$ zrO8e(tYxwWnB`3_;fqIcG-&} zx>r1UXA_-dt27Vc1)?3bmQ#GTg0UZ^^Lf z$sFZFtnn+T6G{aQX)V3;BGvD637v>c=brFBj(L14=DRs7Cs7o0F?7jPYFeP6f&l)J zZH&!zNv9{LY7Ykrhr)!pK;=uq0@ysmxl9IA<#14%6P20;@GJDM6aQl9F+S%VTj|Yn z+mwmfz})IZo$rq~AsRA@<6F1yC}1mll|Gs?yhb1GLQ}(Q@U6OD2M+hs?L+23vsdl; zHT--t3cB{20Xw7`O{iAXkEBPwuzU$cg>`cJE(M|AS_C!jbc4s*VS_iywa?aYr-^N5fm5;VtC@PW6i^6++{)+8V(mqwa*zS~NOOT_3^o>- z;fa}IWV1;^fXqoi^cCBUo>;+=QZq)7Qoy)mnm-ISy`5s~|FxU-NjQo5L#c~ONMx|! zro>xc{*KTnVy8G*S5zb7O)!TF{2UnTcO zSx)Le#>5@8uk3`n@>-@&p9k!8k1X_q$JD9b)Mb?ZNSODt9$z|L@y+^l6HczH0BOiOj zrqQ32zmg5{h~=9vCUNU|2lqYd_gIDr#oX_=cXam)7j*bL$fAcHCs8`TkF3-tDR(KF zo{~7r7WnWkg75Hqb5-h*eM@0>_3eFf>j_bLdTvxQ4s*dPHABcUM-H~_#hQs+vqSa_ zNs?DG1!Q0_!`r}aB4gwpa&>NPQ=X>AZoz1A7G|NY?G*&k2-q`GR z>-;I30iw8BmW$BsDNk4?k_}x}eKZ7I-8M$N^sETAF+>0d&)wQ1*3M#`Bk<7{;v1h8 z$?3z*R}t|y!YkVOWySn{LJGjui%}poKEz0Tjn(%#;n{0`d5)0}QPFI<)VA!W29!X- z{D}sGK7ukXilwXN*PAixPJzn%_nWhHM~zOlSbw!*7zDUdo@J`&~A$p3I?t z=ELlYg7EX`rOrEmU6*|*T4oPJB_gior_D1W?)-;hfNGI5y#RCfS+mjrZ`#oFH)qCO zkrb=OXU{PHnjMnT(c|po4GPh5MQW}t+jr^1@@jr1DaM{SWgxQQd99}|bWtCw2W7)r zF5hM9dZh9OT=9ENcE@`Y9X_5IX`u;nvxhX(#;+`N%2@-t$ovi5*i26%k?dNvFJQp`q3(uudk--U+UT|MH=|P zsUiN04#b9+;!)xH`qPKU{pUc&v8wK%*qZ^qWUYd3C0mum3BJLZrp%(N)JM7fJ;q-d zY{qgDbM1V{d%N_j_Io#;ITYmIXOWp)QGKkKD?P%x50thE&nco6*LbhX@0fWibq>m` zwNwFNGvcYW`8Vp0ncFfP*tGbmr?4cGmqDy3W^avK%jolZD`DGf2F^r` zXPHU@{4rf%k?EI2rNM5j2;cS7X|)4z(PaKIEKZ^epJ*1L;7LgZABz(&3GXFGS36P&|c9rPo?nWB;jO~a>vcOPw=Y%+pDUM}tF6~3gdVc}~4e69m4TS{Nd8Ti| zM}wwsmZ}!Zm*8Rl(WQ6ixpw~)CH{IP6PEZ4+I*`H+f5Qi6hI=&91CZ%J?xs_V5rEy z1*Z7BXdE5c3%dQ)zHA9z`5YC|%}^R8AWNCk{e#SQ&MGhN79?RU(6;lIy+1B@jbx1e zftUaelkCyIb~ml=(GRKw7hHnfCfJsXKsA<3+M(m<_QPNg6#7YK(eK@?fX5^uIGD5q zqLXKx|GmOPYX0P)-ye^%ZHN5CFArI_AV}OY=n6Ay^)m_KLe~MwJq3rF#d~$<* z`{$Saw=FNB4!f~T;Z1pN!@`x6Xjews%ALh^cY}myc^*5no3RoKHvZBvhiv7`jN>Z_ z~%* zI}gs_L3I#LYmFII)J3|{W#>IJs$!VXVB8}1H{&^E7!ddaIFH!5aD2TFf}r8zDyY|V zE1fylk?1C;9I*4s2I{m9crGP->#QXA+?b@fiogMA(CRNRb;DbTI2AH)gOBHfj2wxF zee;e3DzonDPLr>ot2OiYRPfW&xCNi0n$1DZFYjXmO@9`VX{lbpCiY}Ad*M(pc|BC~ zEWSUlTu>+h+l<$ce&?44GGLH{67}ntM>ija^8VT%h#$o97(AbP*9SsyEF^*$10Lwx ziaAOI8b7R^twN+(JQVpBwT z)k!Z3v69SmB6Wj5)-Up~_wfcGRkh)dr~&)P zylMC#pPemnW7mN!3Bm8&hWuvr&exAgrLw_2B`^6PhA>fx_bfVvnvFJI`M9o1^fTY$ zS8p$y-mwu5zZ0TPw`sdgg2RlQ9P8C}{Py=^K|WJgA0WuC{u`qGGex=U=jZyz%N&yg zvNhhvBL+^A_OSXOX<=6faLW7PszS%ldr6)t$f{qt`dXil7$>!FH+$2XVAc-Z_1pHr z;@aAEP>(Zd50f%HF}7Ur4?k5YG0g0N!X|-xP^W4yhzDg#+TWT-6ChZnw=Th5&`^ok{n0nbk=nT`vppRO4_dk; zbJmJ|*p=zp|3)qVnnaA?E%^sp-FF+# zGp!D~o1gvKZd@st;R<*U&OKit_TumxyI#BY&#ebbhkwIq#;nY;tS&^_cZ7jQ%rTY% zrMMgV@sS^>&#yN8zjm=a55;oj`^wq8WBHYBY$LHF-=n8J?~KHUBfvu3d&mk_AAfqN zFyMP2v9cua8Fh_L*wnh$_HTId!(D9+b%piMiX8vJLMLR+4ohL4c05>eM*HTL)W;ar z-FR}^Q8#aTGI8ACmbIf6u||gGzmu#HNqwc|bS)1ynuBYB}D02DWI!+mL#H z%F)fYp&!^P&&6GgU1&TV0Zn!^=s!e;CGcL8sp~Uh1=mG#;yL7+?%F&Hd4g%dpK>e! z=OBNA$sU__*s!^4P(o0`YyIc``ctB-ObA0Cjf-JnUz%bQ%5Pn|>Y3VdZnumDB7`UV zte>R=X^|gt-ZSqvq#>|@KNrvPdl^3P%$b!;Gm2jB;n?h} z<~`WX+8lE4S5Ey7=UU-rKE0!lmfh{Lk7;kK{(WW?FNd&eb%jz$?O#RxtzG{mxA9iG zwZNjcX$9I!d?6gmL-O3`^AdLVmR6`eQm?h%V{w9??sX??N!&v@k7&7+{ym` zT>xn-LX1yL>uoBWnW(FO5hAa-z}ZODOK|p*&b>#)a@n_WJ>J&kfPeE!(?QJEi>jrl zYlus@P!ZcnN7kX1Y`y19$~e&yx|`gWL>-i#gK7y1V99)4Fb^Ht51Py6ZDTa`RPJYE zz|)=-mIm-FIsNknx1Gm6il#NQqa=Bxfi<}F<*1w|;4L|AbcF^=(s9H|be~uDX-$t9 zSpeQ`0u|bo<=hY>gFGW1m5n_EQ22kE?F}&LkNq3}B?e#2lOCt9<3DCff%2q}QomdZ za{3~{Vyo_dHBS>U;MZfpn5{vV=_u)E zIyGgaG7r-4_QFRxfAmOY-@5f{1=JHwfVMtR)_&+Dn7{w(=ABm7Fx6jr)v=`J4#&Y+ z3OGuyX*4!uGyE^U?WRR3a4&+mTv(3eB{DU^hJD}uuE?rML8O4Y>Djs&^x+w-=5ODp zvWHA5TjPrJ`01kKcP}M+jwM~b9brk18D%K2bkHaU&`bN@&g!k0nSxiiO`C_H@3>^#hO8m+BeaItGI^F_sJ!b3ya?tTRR$P&FqLB5?~n-0zX1;WkU9b zZ%BZtl;uUk4a^ee;V_1TCunLD+A7a*cE4g+T8pxF?H5d0LA)t>MP@kaDzSE@Xr@83@)F*7yS559Bb|1;esFG+SjSU;ilQr0iDC)#H} zcIAU#oNEfkmGgnBtFEJ+OqlH^jyZ<}6CWMsnG#xPf-9-d-C-)=Z=dWp(1|VMlaw_R zZFd?u>|;7rH>Xj;NZ9{AyNei-YIm+k+FH?Ziu8YO&}IQKf_1`miaOuT{8hF<>MnFOtWZ=ibt&zM^X2 za0E~PRs5@+FS&c8MGJ(evhFJLRhycDC;QgC<^-(uN}lf%<7kryygQVc@l z-%y3=gOYUGRJ3?s=Yo zh9S|@g3p;jYU3yX&pi2Mn~Oi25Z5d{Waj*En1j@VttjF}9A{MK7@wjJO6`}YaracI zAuy<9f4mplQA6~S;}zw+?0`Rc+^W~8*6Wq#njVYx7^ay~)=EqSxJ)Ww`MM~e-TOYv zsyKiU8bCs_Q8!$T!cX3L%>*9~Cwsz2HM#99bURGX+s z)W;nWDxFXYU(yVnYpe6%N!87!Se@qk3})`MyQ3xcpBEeQ%FFTRNQl+c9NvDd zy6T*LNd2->4fM8EbtP(hD|TZ||Jb?Cf4Su!E*qpGwd&evkjeuIZrcbOxiEmj zt4QVw* ziC=z2>{t#~W_`4HIT{Sajop&6B-bGfQXE1o%-Z+K3RC%{G&l$l(qba&T>G#L>z*gIchlk3Md<+j$G@(}ga#U(8K050bY9ueuBe zu-rP&HpZK|L9=4oW#u_U>()|Nu?;n<7ZN-j%&(&;k7PnoJk`dChfU!^cI`B&&sLKt zsNXhm#xdw6skvDT<_qw}5!lw>0%Tz8C?~RVleNDZ@#XcbZlsS+eZNml|CYVQD>Smt ztdR4bnx0~=^hd&$5{+`Ot45#{up;6*0`A3TTIn-gKzpYB=mmdN{B_6-^Q6BrjGVX5 zk{c=Wo6s-03(3;WnP)5mDCjMfbh#oH9>nDw9p| zDyLGUwMZOmk83O`h*$lbm-xT5kynyINlVP{{M!pM{Gi5^cW%-d8WO!M=H2SII_w@5 z)8kq~hQlyt;gzEk3f!Tm6EBJ%GW&fu%&M-6PMcfd3YfZ)La4&*)6C0n@J`3Z`8vd~ z+@d4*VH-nlfZvt-=^$4B?BQCP5Ugw&9$BqSC5I{&= zL}O5H=@%==hA_l0o(hq)D;{T{lazmOy}PG2_FagnTMDWx@|zXPVvp zL=FpaV7VfkUt8A~E^nh)ZTWDO$h{>ZS*Xqn`}uu06_@;f}2+Lsp-P2 z_Z}7Tmq%ppc6_HJ+;utSUvTjtuQ9vh_n<{^{w#{8Cht;|v1ELxq`F*z7JSiz;;L>7 z@W)JTtS!ZjF7gLV&$M`h>9!|N`aaD~6{@ytQ|c)FkFM~?epM3kUM9pqb~xw<7lC%n zbR40Xl5aKXZ+-2{1hjneSZcxX1k8R6Aw*y^%;lwz-f43juu@E^R@B{uuOQctxieSd zS&##(SG$rd5|#@un2>oFTGnSxX#X|%UI5gdXLIWMStBU-Kf7;>mFQuHUiJk+_TW`0=2rlEt5=c&oNhWP>N z0xI{d`fX0whUwb0EhJayU986Gmf)GJZw1Lmmaba{7AIEaFVsbO(Z1{TrjiMt(?rH4 z46!SqNpu6)+9KC~!^77xKYzL43_4>{z;pI-ki5g6yzCLj3HP;$Xg;5U$$9%q>E@H6 zNv;7)cS@oK|CmsLf0yXoeP~7OSNGorl-0kpb1~(lyLs1gOVX&eE7>tzAf{h2bedfF z2R}2gDmSYclzm|htrRWu6;*6VY7N{S38MwSvNgR1hG=W-HDgkQJVT~E{`g~Tt#_x3 z#m2+S`@V|2Q)i2#t9iGYh)i-Os1zN5CapJYMs7Lu*xv*q`d=WoU;1suhD56HSjTV| z^SN04~_Q~YdOlryK(9LjOT*&jY%#LXK?Sjj(?$9!#~%Gf6T z^=@^vu?21#sLc0#cyS$r+~hgR5Q5s4gt?m`Zl!+g&z_}m*Ck*=8$EM8GnudZKB4Nn zKn6a<3~Mb9=<+%USdstWHH2SS)$1mP%7W`KV>{TG#_jM*+!6)fWdqt;F|N4X{{ z`-&ck*ZejzG0YKzd{};Au4ig&S?3rnJ;mIQ$zulR$=p=j3*oU?TJgCTX`1L-i}CyO zek#UPQTG`oBF%AdT$vyz^C@TPG+(8-3ZsN8lr_2ja^Uy;bL*#}EH$)xNA zXyxm?FIt3^_5vNfqZ@6DGHlQ|@V(9R0cwzu7uvB*f{ezNf9w;p z-@OvzX8lv9Tj@HS%6pk)KEph1E?A!PIE}$i6oF&DY*tO#KKf?q79C;%DYm0rg|8zB zm%oML`h(}Wll93bb+dg^DL3EcGISQZGZ6#h2A8yZ?Bo730w+ZjT<&16@M#kI9Xz=RsX##ul3Y5mB>5XV8ly$GM2m9Y17%tv82CMIL zK>2KGEkG{4gVx?aUlT5`-4ItQYmD;}Gj-jW z8>OXt2$V-27I+`G)CZ2z+lPwkvt`%M>Z?zWJq|5OqVY=?n7PGcK!oa(S=BGFU@jt> zEL;J803m?Gx)>@ zmInYx)-@~EnNg0mV?=-7T995G;!^SJHN$=+{EH&{NA!kabTCryTa;i>ua?u*2c@9a z^@!%xeGMuxxpD=Kd9K<2*WOn}McH=mE20i1B`ICLgoJ?74bn(=Bi-FdqjW2&bR#+R z&`2vWL*vje(hURr9{ha$-uK{t_&@txi?uwNJN9$!eeZqmy|4SIMTI3l;IauZf9Sxv zS$(#yee+Nu>t~zGRG}WWc9t?WkY9NNwE9eA&0imOLnf|oC|{AUp3It?u&RelT1HK9 zK)IIA5}#hz`>C)hloZ61;#M%uoin6l&28lo0i9R9Ww?6PX74mp&751DS7m2)c@~+f zrmzC5aliRLfk-c!le4R+sl9)yn6bei|KT-NJ!y)g?Z*&8ki>^r1KV_|#c&XjOPYZ< z@-M=AHDUUnaSK!Igw}Jm#}a92tWLdFeb@N~up;=c`^Ty{_%ZHDIV0N}A_`_t&yt@q z3nqX9&({$S)F#sGOy8Hd+8l{mR=}YQa&e@2hH|Cfm6b74 zZSLRf&ih9Ctkl7DjbyW+ImpncuackB_(U&MJr*Z3>u;{hXH@l|EtTs7&ns2gTIc+} zD9`xZo$9r@;dm5k3;l9^nhYTlzW8aeWNYS)h1=%8Hs0SpR=0Pv7WlAfbXutMV|}5{ zD|3kkXvF#l1KmU!BrjE0lfi2kCZ{NLo!5Lg=LK+*;Nkuyg}Rv=XEYI|{LI{s{o(bN zCpKPG{X?mJwaZ|kM;vR~Gd)&4PWfHQ&PsY@vQzPQT>irC{i?}<_5#Sx#vH24&P0=$ z7x>1V0V%4+(=SlA$w`Gg@UsJ5bT<4~YcZiD)pP7syMz;%!5*IBMyN+BCKNcR0E<$H zqL0HOmv76#>#ZLC0PV{oFhTN}4(T9zsNL1zLwNSQOJ(!<$+}l9-E}_iU`P}kQGed zl;>wtKX9DPnGrw@+})mk%#v6d?T{cQkYVW8ikIXY5=>mF&y(EFw-^Q73o1&02B+*w zM}~c?2Vgrq3_r2!blIzlypFE#%aM#k-sLC=u$gj=@lqO>7G^%q;-PAn_K8O^CB{g$ zl;%H|!i!3)U8~V*Nqg9tr|&a5X8dITdNSXk*}*U%*i_K;uS|=g(6S3Ox>drQfe~3p zPF}Rn`Sw&jOC14O9geF8_NzMnEjqPYQi>+DtSBxg_~z%5&t}69xEt0tkhmG!Q=gJlEgUUUoL0^=o22+U5#MXIQfg(69*7o9?`OvrN0q}H^3HoU&fK_1wutE zh?lCpiCe{%q)8BEPT8Q=m$ZUd8EO&jYd|xo+~$F>v#%#+K9YD$!B9q&Y+(t!c6A-} z#0d?4oO+_1-m(9mlV zAS>}`Oh!Om(U8GV(c@!bQK8POLEP|0y9d|{k0(ek^$sWGPa`jPu!~=KUIKJ43caA7 z7U^?v3U(YM%{%Bx-LVEK6ZmjC$I7W|Jjd!Y<#qyfLEI-;Q&HPhvg$Rv5d-g64nJL5 zy`t5ERsct}>Y6&ee$ zXKro~xU{K}zHw>ZVL=3*x=4pS>ABK|`raVhF6TN|nd#(eEfk|+*EQ{cmO;FBvkb_+ zt1V3?I`2>RwV4Ge7Go1H@UG+qk*zqmk(os+9?O&ZbFGop$MJYikomum%YGJokFko<6YPX zgLn7UQHC^R&aB#w_3SA4#xIq=F4PM*Z9h7#XHnQ!)PAOxs_mjhL6&ttW=qEQ$B6tH z{hgm$^{6UB3Xf$Ibo)qh7?A^rC!zc9sR3~tP~$@xpn>>#27jv)UFZ9r2OSqcJ)R@c z_4()lm`$`2f2nfyc>OsdKxA=vUYO!U1`IpfFVC?`dU6tZ9XtVFjTMALeW`T2t$G`z z)4<;6E+1E)J|fvlE4Vq{YWsKz|DNqcnFt}MbH;%qdaPY@V}#2czcyTt&KREHF4(1N z$V@4?+(xyHTcu@ly@?tI6a6f(A~Ba1S`8xQ#I+$h@8LA=@=o0PXQ?rea>q3XAXSl1 zi*u@aL5!y<%_iYF^nt^GrtI>e4Q0qr=Pzr(S?xO~rqHBAlQDw*pi&D%K1&OG=(F{= zI3uK2g%<`rwo2NV@&=MRbx`Z_)=>uvUf#n=t%Kv=;2}hu13D{XXz+w%7xOfP*g=cG)W!Qyrs`2QP7sN2U*y ziT`rSM7#M$JWv{-v+xwWxR43(Y&2GK9KY2(uhIHRgWPI+ICrnIZOm~Sf`??b3c#0q zb7lBOc>P`QL-lv&UX`ZY7fm0lW7+R1-uq>PqTfuD!VgI0gF|1?%o!0Rym3c%zbA?3 zdGObx%#5w>k3d^?2a}*!`53nOwpj?z5<95{f8`V{aB2D%ZlLR8ke(P9b!S&N_Nm5) z@yosHo$TWqORqg+jORn#SIt^CQRCli^SgSCmn?8xFpU|{CCO*x!X%w1R9O-W4h!}X zyfKcA z@uVy^qB&A{z57k(b&|2TB#nSVuEST(H*G#67&|TD6z&eP5M?gDd)G;lI`PO9jT=f5 z-my%#_G|lQco%7P#mwM@sl$+)FpW@NvNO;?!@GR$9}MgTDwc?`tO62k8ooE? zaQ>;MUdG{>*I+9fVs&G&=fe7D;ePF8EH#8I4+HHfb_TDSq)xdMQDiC*Sou|)3aAQK zG&kuom249UA6R&VOEWB{HU*zl$JFT#G}Wd)8XPCYE7gQ!w#`eHr$r}5(1xtg!TdMu z(PEpp}Tw1%sM zj}AcJl+LgKQ3-?=$*cfSGT_e%`)=X96zN^_=A-ZYoB?09part)a3zOVG`^h`^->L4 z+m$o5(ICx8Bm5RhCBA-E{LxxUd@Jti+>$Z*oN;(Vf{%CzbQ z!2iWXxXH}A6I_NRg_S1M^16Oql%`B^8J^WPfD0*wk6mdk(h5E*(-0rvO~hsq6Mq|z zl8RWWeZQJNcgCmd8D&ZR9ay!+ybsOy17E@=nlVGAzLhakpe@^po^JS%^d>RR5ET2o z4oe`_aVZp>z{~LCS||JLj?7;-@)h}58j06y)dt89neNVpiw=e=_I#%mmO3JN6<*dU zx)&5o<3Zs_2STJ@C|LQ1Kbmy20LXLBdUT?m6N`mlgM>xl~ z=LAL3MpYcY3ck0jRd%eo>_N&PF13VfsMl+=|x z^d!Z#&uU`gE!?L|Oyx_n#LE(&%=;+q!d_*-7{H|!P!!X^b430h21~Q>J1clg{iJiB ztBL5$h;y~$l=8mtTu}R^V56hbUPKbwb9!8b2v8wC4e+*<_~ zE&AB`p&c(N{Li8RSu5Xc5q(%E2azj1f!^V ztAL)@gsci8jWD57i%wiNx+gi21Ds<<5j=>%Nh-ooP#cp01C$Fq>&({B#E1+hd-C$j;+K}u zI)T)++)6qAjkR8E;th9lP94ym1bDDW*}g_?Htt*I!ZV$!vEe;84w&H6gr!MJRP~dV z{X*6=BRGOFLu{Uo%<~L-H6PRUs=*I<8uR*{>YgN*4$UkN)eBzg!I&27oWVReoX@;aph1;NP;;SC*Lt9e)kkB zxlWS1;uc7>dBiX&{eg#;Bn+o?+@m3Od2HSNHqsuzeVasc-@KU)y5js;_sP(VzmSS( z(E4!t`Xv)(&4B*MCsg9GNJ-1FV9(OWI+LH4{THEqbtkgqu>?+f+pVUfGg5bUE_!Eo zf%=&B=EAk%({(}<7NyXR3$*6gAX0o;mH;A?pMp2Xs4znrVlgN39r3Lvtsx!*-;872 z@+p&-X{+7+2F+T%L8cJO_ZLUZ)rvRT)T*PbcqVm5@w)HfGS~`kXI-A>uUgM8&`f** zTK_v7$}9uBJkBAPMJ&0WV#1^iUucq`Xg$hqwXB+e(++G_0xKmuCtl~k7oZhOa_O1bA2Fl*v=%QI;As^u@WUf4B$TU`CJxjdm z9FW~MC_B(b>SF4s)!eI`f=3C!y4W7_i4hI*AZtBW#&Yc92&PZV`MTZ)Yr%O zh`#gad+oS?$*vWtw7X2?Jv4SJs{3J}#DWUtn8ny-25dXQ$gUn(ngepc?`2G1#jKRk z$1-|zC6g0neX2fzMuTcuA+v$L;kq1Ih_^n^Wh}ik!Rl_;8qKqxw0Jkq%GI8(11#c= z$5!yRKa~zbI00{G@(>@U~|-o*2a11m{omL+wM3zQ^kxd(fJl zcd|DwM6pq1wP$PxnQA620E< zcrPRq(A_|8_Mt6pXEg1}_AZXmQt(CzDOZA#G`m%CJPZ9mOLmOv^47-3g5k@HM;1Hd zPS#rdum^!|V(;T0iTg&2O+Gk`QTZ%1)l6LH0@c!Obq/QA_#g5Lsxi$hpvw<`Cy z`kc)`dBAG`8B%%gcHMGhaK{pdPO|FM%@}5+v9uf_tho~H>n)50b4WMeE!#0u9NrR% zkKu?&l31~XllFIF2bI~lY`T=x-Mzc^jUMx8(sdD*wEyZN(oB0Yi+WBrh`KY*bPOJG zS+9u}W$splagrAEs05fp=##NZi|hjg|Y`h8vv?oE|t7H&NOC)Q(f3=0q!AIheG@s;{vbO_3r5#M0^ zyKnwG_G`PCr|-I(_A0sy6$f=$g#P2l|6Uh6s&yc6JFfF-ZpDh-OY-^9O8Rj`ks<5j zWn41(wi@?+I)kSp+J(mZBq+xsRQ9uJ{&T(5CB$FFNTWKKpa}Oab1^lP&f9C(S3=yDCL!x2Yy6nOEWPc??51rN(PmK`nL8Pk|3@i6}v@5Y#hI>mT zzSRP(VGKUg3_D$BPwvKtH~Utpx2P$jbjxLQAa65yycF)$hvjb{(xhH36RAO6ZgC*@5eIcX%;E= z@liEy{Qk#gTBjr$o9u~hpqk!%{2di(QNGeN_Zh=w#mm`N>Te)W()b#6F^&fGAuX1< zpJSD~Qu-?_Qbu+;{EYxIo{4OZko(h;OBlGlcTz~ZI@uUtJxdO#b1c~Z{R}|T2L(W8 zok(NH_-io|rKm}znu^iA_16idC1W^7YTVS_(&43$7Yp z0{EmsaZ0BTaPqNdhDZk`-=S>{ZSRfY*_11r3_okTzCc|62!4E3=E24hLhl1%+FbRE zGWz@gix(&mqeW9}cJ&`0-Cp=xLvE9jBM|@=N3=@cq%dX`^(8KuT%Q#S8#kHct@K;vcR*TSQbFgEWR*to z0&fueY>Ep=>b?Xxg4pgeJOTl#5zhjA2)?ovaJg^Kb#&0@)vkZ8q2<Z8X%XVG>e+d(5#f_L{_xkQ$rZP({ z9@Y>~`|5(bvxvvVl6aWk51rPn$&Z9G^L23yHg^bt+*=v`Od+YF)x?xo??j8VPydEO z_bn8NNw}_Hy(i$W;`DuLDWl`heKk?OXEd)3x zxPdAGk2+E|jRk4Gyx4Jki%d_1%Lu7d_GW8|a4u;y7mrXJj`(|RL{T`Ng_Y%?$xX!Z))^-=UQ4ZD$S^r^>-yV9pN;7Xb zb{^3+Q}?&}-_Ea(1|UzrxPJC88v$+B7s@f&2)8On3Cc_SlzTZC9ihbHA-u0+dt++XTIfTH`U4Az7CsVw7vSnV=S*dYp z!?ukfTs{E)Q8tLNvUgr%di*Lsch9cJ^!lI5=E`s@?Sh%1B9{Gb?G^dw0g)4z*jAHNS29I+Uw8#7ny$v{$lq)ESB~59B#ol&PSY%alqB z$McGyNP=Q~+ICVSwVX*=EcNgx(UgHuV&=^?7H1l1m=*5WM)l5s3eNGx7ecOrz(>d94K*$5v*g2qQMUufoIzZ zM=r_;dm=AmfP;<7-s&IUo|YD{_whD`k*m?~_{NOCvi0dYw63PGXfI9X#}m7#ZMiN{ zCI-qbSD#`A5(mc25aJo;bw~$Iv!c~8(5CmGL@U*Je5sziiVkn}opsleY1rZf^TYn*X+Nr!qZq(r`xsbb$edLPOmEG_~V z9#vht!g6-v_9YQK0i*V}ogLQ@>to&+&X`x@zZwMov3()HxQsm1jI5JDr9zQ?K!rl) z4e>tS>U5VaBMBp>B`_y<;($@af8&X4weSxU;Xr*~S9mfLANCXzX8SH=#bfVBhkr9& zy^PrNxk4q%Y%*g|DSUr|=lyCQ@}B}>N39kIP~onnBTqo}I!fy=5)tw=pq;5LXT?65Bu2Q0FE{>q9J8YyyaJYgO{|MfPlbbz64Xa`x0qeUsE%&9$@qlG z0Bo;cdfeF)A;GtRS8XDSc{f&ME^Eg6)h0WR{={eH016J1kSDy(d8w$k56m2Ie9tA= zk2a23es{G!^AFYel_rb=tp}I(=sZBNi^q&c0k#e2wt;$Du``WHNAS+n(2*xb#*BTd z1-zEpaFMx!CC8bzxQl8+pkl2AFZwpmlMprjW&ctSOyI$nF%R57{&BF3Kx(nTX}ZNx zOI#vCrGQR#uPVDN!_`Fb>!m2rb%sbY#q(}{7xP*4R(_DqpVKyBB6kD1lqc&$w>asDt@h%m#app=Id74d`BtD^)BUua*PI=kmw3ZnVx%h9n15}GsI$~V_Hp#mE)0B}5ey93u zXc{z816&Cv6NUWFRy1SEo<8=Vw<7Xdb^0`Dz3kBTzEcm6x}ukO`2MA zm;sA>z|~YAQIc>!D;E#zd{QusmzH2HViD%SWj_L3I4)LT1#$u20X(e^q7_U5L=T4e zLqZ*8xKeykkzIw$?{}?&$wJn%{ZZd{P5tX=4ih=KH5C-9kyY}jNpXaA}$w9P)RIFaoa6n|Y!s72q=q{KdEgr&)( zm!{abn@kD`{r5(u9s?UmH!%_7mimN8^J&*oV_HfEtkIdn^)MxmdcaAmV%f)U5x^S_ z4!(*V^O^D4`>VIqt+uftPAu~@XaTob)+HECWK}%?iXMSlc;L~IMAmvu z$K|92XOn+84nSkct>-|B+w35VO7)CP`t7tX0NxN{ah)>SFw8@FH03HWrhUc}7XQjt z$DRdl$OY}EV@;X)&pShbM?^C0m#9Fo)NLUBk9BiB1rF)-ngte^B+lCvs&oBj_i|x1 z^|a$oy_%R0>~`^=>ya|D?;gXpLzf#Hd&Q|Lgq<~I$pQJQe^w6HkYTq8jz=jqF6(73 zU;X+okbk1Rbu~ib1Ra=Asd!2rMALm(-UctaM-s7}gw?vv=6@hg7JEN{wW#*V?ekEI zPHafw-K%OKWTJ>nyMKyd!46Exz3L&7s%@4%g$`Iq96K>6QGH>m4#j19XENRkMAmz<_SYYZ2Mr_VE7~&7T?p zXM1k$*rJgL)r95=J~@)QInEfgcjK_T<5SLX!F@-QHa18~6ldb>8sOq)yUUHr{wYY{ zFJ6kBEab^YE`1vZbI6y1OC5fN*-d%aQQFmL=BBlak82h~=Ie}V?+C)~ZS>k3?5B+b zbLg3S>G=lnNq2mYTT922Z}dJ|1llk(jQAxSmWaQ-a~A~_ghS=1g%Y%9938&UQXujq zXx#N#1|8AVK<#;nh11Ybt1opL^Zy-CytRp2UXffG5KU_bwbu|WKu?2n;Gu+n&-WynA~)59>czRm8JJb_sPyMRfs zEm)3Ll28cbozwK;bZ#@=Xl-a6UU3?LyxzMYTvO@|eA?=fN%~ME*?sqDZSz2U_Zl-o z9y$9+#lJ?jzn$0G!J4M7vB@+&%3GiR8TlnM6$qjou;?F#@)Yf<`ub#aRpr-UG^4)-{<{Q#OatE&4H?Qsx-u!!qh{T#Zum z`J+Y5-{LzW0=3+pxcWbAA$-fs^RjTNu@Px#d86e1!ufA7i2R7g0ChU}f?R*#pyEYv z9;SawpUtZg@Z2*pz>8u2!4f=5eWXu$fC4ZG<^ z)N1p`{#OW*_&6bKBQr0_KZ%5XaD6uWkz`~y*v00k5^~MQ=9N=B+JHjf&Up{HS(vQ| zc38{`z|NS>#WzU3>)t55lZ@c~5Aa3awzJ+9^-PUAkfZ+g0FL@;2y?x)6Ri`1JQ!>N zb(-EVPn3U$RT^fuoh?Ofj%4z`!XC7)l)q!oZHxaKm-Wx6Kn^~>`tuwpgH#zL@D^R3 zK_G`7YacDN#`TEuiwKH+r=xv1@MzHJI+Y&q^X6wDFljy7Z!FFd;)H+&+bVX517Cm& zt%LTiE>G82_m}$)#cQ@QJNq&Q;P;5WI)n&c{;WBNZp<-c(!;@7RQ^BaVS;}U!TA^` zWE5w-xc9MT*WM!Ab=J;8GyimTX?8aRTiY^)u|#Bv`5i> zk6+DHV;LB0eZJ$o+>s(Jc^d8=r=fe=&MNNlx1ynrh>G9{Jya_sQ=-D|zgW)>SkwMN z8Gv*eNVr1(N|1yKuj;KQ2YW1dS$G5Q6tA;qgq!=FucnRzk#v;z;-`Wq-qqr-2 zb`Vv^JWm_eA?zzUvOz0%qlv`bOj@reGh#e=i0$8Q z#m&EA9jJ;9>MTT^@O^^fMFp)X94&YX5&r0ZeZKD1&r&sdg1X?d+qyaH0Lg5-+-YW< zZG5AHv#`L^O!HeZ?Lq)hvSUnBrKm)CcCq~rR{FnR2IGg!>e{ej_4cyWVs(DR9Z8_l ztGVG`dt%|}_4mAT06+}4;2!(*RG`%EdKg+GK?o-^3jmrHee&NhG)jF-)gmW#o{#r+ z{PW=xxbXFv>9yaUlJFH*9cO2#a!pvBgJ6t^x!+-XS&P&rq7stTcCl5;3xYX>*w_w( zVmS-EWq&K%1_4fp&uZ;#l87Mp#pZb7t4gJTuIjDvuv~O`w;^xLKyT}#hm^kT!W=WI zxqZYhTj~B|U_lw-Z>fAKN=A4yL^|z)9Lz&^=bK-SqFeCq64+aWh5mqtofLI7VqN6M z3Z*U5`mT>;GDe<)DEFs+YXV4*3HU}TSm4O{r*U!Vi|C60Rkwlv&DH5ST-&QIVe|}T z7jkp$dU>+FnW!Z65qN->W4^)P)Elu4UVE5R$9cVMSj_zQU^qOA0Cp6=?#t1~X~PA0 zFZ!3Cj^{2?DBM0#djvBKP(bVYNOD4=LuCy=4^KZ6Tk_#&X?jGuXcr{HN(V_z0{ z%m0=MPdTtP9ntM@LQ4lXMXG`8$eXqg2FNQDZy+i<`q2^0$k{cTC75o|;>mGTN1?OM z{I=fIk-|@YLjg3x;wa__MeFsF);NX>w841)R$bIbn!pO@s=n7?;8==lh2|u^>9^g> zeHB~K7fVSQ3J2_EG2f<%PYlM!0Yh6(+2~m1$Vay<9R0y#1gtRqrNhWw9tiG;yd(K6 zYC+_meS6vgQmpIentI>%%6#+9;TWy{i6gT zpmb6iTfF?o0r;W-fIEG8t0V@u=!@zkR7`2htluHzuo>QB$|Gk`l>``TIvfk_YkyC# z>$=@(^}?-sM14Tzc!gk}qyyNmVppiNjcqiOWC6Vcty$Zd-?e$A`1_#yWM%F#q%vr) z6mmhP3t`gv+h~F?0cF7E*5mU@K_M7`b}Et&p03J_eY`({=_KZq67nOd6<~C?EPk!` z2Ca|LW;FS5^)lrRqKz6VGHei%6yM<2py^30TlW*F!V2{@MyWyIbnA>N9&Venfkh2h43z?5K;~ zS~B~&CL8!un@3%($DRc1?DA{4mHmN9J+M~?8v*@c8xV`Q4!3?-9l9)I<@5r2`}Am; zgP6kr69~4S1S@ld5)`>q%v89w1)R@M7V2mkS_>om>`JcN__iArYxEb@*DWD6F?DZ> zQx90&Y+O3+>tQKF8yY``F&$E7DoNmF%y-uHwB7wYj%#9IZQOs3xRd*+@NIzPTo2ds z-n0&mb!?&6R$f_32rS@cUH!w==}i{!Tr^L|OLzl{xR=J|PB<@*b$ zGpMs6Q!n;dgYARtd|FT(GYj=ChGwetW2~YP=1%&=f96pHK=d^Fo-U!Kxbl;f85?^< zo^QFqWU=;q$h6K(HF}%drEBOadMDb5y6}40n@4lQ{>iW=!G)8n95AyhLj=?vI(W5O zg=DZfvIeSD9Yt7T zcCSkgm~?k4{nWSWJ8I`EN_&7HQh1?8%JoDa4W4rUAubfaO_zQcuE(5e~3`Z^^n-mKI+cR<225~6B< zyET8NS7dxG`d8sJLD&r6v0L*NbiZtzRqp<(j;0s6oR@ics@(mBB#UN!3k}}S4I_2P z1$W52;#J*f8)DjxrK9d@*q*;M{jKh0oj#&=kk`iRvRo5>vVC(i@0h%Mv9J~3vprc5 zQ(iu6Q|Y3qyY5>QkWcocKC^mP2CMTOd7ccdNidlEbxMgi70hs%2#g=hF8Ui;wwH2 zU4vP-pABxAr8ATMvlYO)|FL35V8t$a`UHWw?YfU`;FU4kx@`BBoC6GJIR&9!x)(Z> zCh_#JgWd{@a?^o7UJI*)2u>T0xuMwGc5RT_2Vpx;f{;-Yu8iQ{;SzhrTPlH_sZGF% zEW{}yfvaYSss8bwL;+M?v|9gP{?D+w3P(LK+nP>Q01h+>( zAmC;+j4CkyJ>DbuZjM*(EmyFk9++;jQ&rV{%4;4YajnV+0ipY`i!8E$t9DdJHS5~NkxeYF{7aW E1MF!|o&W#< diff --git a/3rdparty/internal/t_cose/t_cose.xcodeproj/project.pbxproj b/3rdparty/internal/t_cose/t_cose.xcodeproj/project.pbxproj deleted file mode 100644 index 9f50be993a31..000000000000 --- a/3rdparty/internal/t_cose/t_cose.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1028 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 51; - objects = { - -/* Begin PBXBuildFile section */ - 0F8B2FEF2345A33A00A22349 /* t_cose_make_test_messages.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */; }; - 0F91057A2321878F00008572 /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E721CB9A2362ABA400C7FD56 /* t_cose_make_openssl_test_key.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9823628E9E00C7FD56 /* t_cose_make_openssl_test_key.c */; }; - E721CB9B2362AC2A00C7FD56 /* t_cose_sign_verify_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9423628D2600C7FD56 /* t_cose_sign_verify_test.c */; }; - E72FB01D231ADAA8000970FE /* run_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E72FB01C231ADAA8000970FE /* run_tests.c */; }; - E730E60B23612DAB00175CE0 /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E730E60C23612DAB00175CE0 /* run_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E72FB01C231ADAA8000970FE /* run_tests.c */; }; - E730E61123612DAB00175CE0 /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E730E61223612DAB00175CE0 /* t_cose_make_test_messages.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */; }; - E730E61323612DAB00175CE0 /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E730E61523612DAB00175CE0 /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = E730E60723612D2B00175CE0 /* sha256.c */; }; - E730E61623612DAB00175CE0 /* t_cose_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E7F70AC52270DFAE007CE07F /* t_cose_test.c */; }; - E730E61823612DAB00175CE0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E7B226CB8400040613B /* main.c */; }; - E730E61923612DAB00175CE0 /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E730E62123612E3900175CE0 /* t_cose_test_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36EA4226CBB570040613B /* t_cose_test_crypto.c */; }; - E73BF6D723AFFB4100DF5C36 /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E73BF6DB23AFFB4100DF5C36 /* t_cose_psa_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E73CDAD223AD4E6D00D262E0 /* t_cose_psa_crypto.c */; }; - E73BF6DC23AFFB4100DF5C36 /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E73BF6DE23AFFB4100DF5C36 /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E73BF6E023AFFB4100DF5C36 /* t_cose_basic_example_psa.c in Sources */ = {isa = PBXBuildFile; fileRef = E73BF6D223AFFA6500DF5C36 /* t_cose_basic_example_psa.c */; }; - E73BF6E323AFFB4100DF5C36 /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = E730E60723612D2B00175CE0 /* sha256.c */; }; - E73BF6E723AFFB4100DF5C36 /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E73BF70723B07ACF00DF5C36 /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E73BF70B23B07ACF00DF5C36 /* t_cose_openssl_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36EA3226CBB570040613B /* t_cose_openssl_crypto.c */; }; - E73BF70D23B07ACF00DF5C36 /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E73BF70F23B07ACF00DF5C36 /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E73BF71523B07ACF00DF5C36 /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E73BF71D23B07AE400DF5C36 /* t_cose_basic_example_ossl.c in Sources */ = {isa = PBXBuildFile; fileRef = E73BF6F023B07AB200DF5C36 /* t_cose_basic_example_ossl.c */; }; - E73CDAAE23A7316700D262E0 /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E73CDAB023A7316700D262E0 /* t_cose_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E7F70AC52270DFAE007CE07F /* t_cose_test.c */; }; - E73CDAB223A7316700D262E0 /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E73CDAB623A7316700D262E0 /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E73CDAB823A7316700D262E0 /* t_cose_sign_verify_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9423628D2600C7FD56 /* t_cose_sign_verify_test.c */; }; - E73CDAB923A7316700D262E0 /* t_cose_make_psa_test_key.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9123628B5F00C7FD56 /* t_cose_make_psa_test_key.c */; }; - E73CDABA23A7316700D262E0 /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = E730E60723612D2B00175CE0 /* sha256.c */; }; - E73CDABC23A7316700D262E0 /* t_cose_make_test_messages.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */; }; - E73CDABD23A7316700D262E0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E7B226CB8400040613B /* main.c */; }; - E73CDABE23A7316700D262E0 /* run_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E72FB01C231ADAA8000970FE /* run_tests.c */; }; - E73CDABF23A7316700D262E0 /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E73CDAD423AD4F3900D262E0 /* t_cose_psa_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E73CDAD223AD4E6D00D262E0 /* t_cose_psa_crypto.c */; }; - E73FDFC528B6BB32002CF0CC /* t_cose_short_circuit.c in Sources */ = {isa = PBXBuildFile; fileRef = E73FDFC328B6BB32002CF0CC /* t_cose_short_circuit.c */; }; - E73FDFC628B6BB62002CF0CC /* t_cose_short_circuit.c in Sources */ = {isa = PBXBuildFile; fileRef = E73FDFC328B6BB32002CF0CC /* t_cose_short_circuit.c */; }; - E73FDFC728B6BB63002CF0CC /* t_cose_short_circuit.c in Sources */ = {isa = PBXBuildFile; fileRef = E73FDFC328B6BB32002CF0CC /* t_cose_short_circuit.c */; }; - E74FFBBA263BAB38003B66FF /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E74FFBB8263BAB0D003B66FF /* libcrypto.a */; }; - E772026F23CAEC84006E966E /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E772027123CAEC84006E966E /* t_cose_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E7F70AC52270DFAE007CE07F /* t_cose_test.c */; }; - E772027323CAEC84006E966E /* t_cose_psa_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E73CDAD223AD4E6D00D262E0 /* t_cose_psa_crypto.c */; }; - E772027423CAEC84006E966E /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E772027623CAEC84006E966E /* t_cose_parameters.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F9105792321878F00008572 /* t_cose_parameters.c */; }; - E772027823CAEC84006E966E /* t_cose_sign_verify_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9423628D2600C7FD56 /* t_cose_sign_verify_test.c */; }; - E772027923CAEC84006E966E /* t_cose_make_psa_test_key.c in Sources */ = {isa = PBXBuildFile; fileRef = E721CB9123628B5F00C7FD56 /* t_cose_make_psa_test_key.c */; }; - E772027A23CAEC84006E966E /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = E730E60723612D2B00175CE0 /* sha256.c */; }; - E772027B23CAEC84006E966E /* t_cose_make_test_messages.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */; }; - E772027C23CAEC84006E966E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E7B226CB8400040613B /* main.c */; }; - E772027D23CAEC84006E966E /* run_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E72FB01C231ADAA8000970FE /* run_tests.c */; }; - E772027E23CAEC84006E966E /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E7C960A627F7569E00FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960A727F7569F00FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960A827F756A000FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960AA27F756A100FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960AB27F756A200FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960AC27F756A300FB537C /* libqcbor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7C960A527F7569500FB537C /* libqcbor.a */; }; - E7C960B527FC97A800FB537C /* libmbedcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E751F9F027E1F90F00EBA5FA /* libmbedcrypto.a */; }; - E7C960B627FC97AF00FB537C /* libmbedcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E751F9F027E1F90F00EBA5FA /* libmbedcrypto.a */; }; - E7E36E7C226CB8400040613B /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E7B226CB8400040613B /* main.c */; }; - E7E36E90226CB9460040613B /* t_cose_util.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E89226CB9460040613B /* t_cose_util.c */; }; - E7E36E91226CB9460040613B /* t_cose_sign1_verify.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */; }; - E7E36E93226CB9460040613B /* t_cose_sign1_sign.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */; }; - E7E36EA5226CBB570040613B /* t_cose_openssl_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E36EA3226CBB570040613B /* t_cose_openssl_crypto.c */; }; - E7F70AC62270DFAE007CE07F /* t_cose_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E7F70AC52270DFAE007CE07F /* t_cose_test.c */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - E730E61C23612DAB00175CE0 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E73BF6EA23AFFB4100DF5C36 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E73BF71823B07ACF00DF5C36 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E73CDAC223A7316700D262E0 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E772028123CAEC84006E966E /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - E7E36E76226CB8400040613B /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_make_test_messages.c; sourceTree = ""; }; - 0F8B2FE9233C3DD600A22349 /* t_cose_make_test_messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_make_test_messages.h; sourceTree = ""; }; - 0F9105782321878F00008572 /* t_cose_parameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = t_cose_parameters.h; sourceTree = ""; }; - 0F9105792321878F00008572 /* t_cose_parameters.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = t_cose_parameters.c; sourceTree = ""; }; - E71D9E8E231C930B00A21F7F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - E71D9ECA23341D8200A21F7F /* t_cose_standard_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_standard_constants.h; sourceTree = ""; }; - E721CB9123628B5F00C7FD56 /* t_cose_make_psa_test_key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_make_psa_test_key.c; sourceTree = ""; }; - E721CB9423628D2600C7FD56 /* t_cose_sign_verify_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_sign_verify_test.c; sourceTree = ""; }; - E721CB9523628D2700C7FD56 /* t_cose_sign_verify_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_sign_verify_test.h; sourceTree = ""; }; - E721CB9723628E0B00C7FD56 /* t_cose_make_test_pub_key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_make_test_pub_key.h; sourceTree = ""; }; - E721CB9823628E9E00C7FD56 /* t_cose_make_openssl_test_key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_make_openssl_test_key.c; sourceTree = ""; }; - E72EC9EC242E74EE006D3DD3 /* t_cose_sign1_sign.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = t_cose_sign1_sign.h; path = t_cose/t_cose_sign1_sign.h; sourceTree = ""; }; - E72EC9ED242E74EE006D3DD3 /* t_cose_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = t_cose_common.h; path = t_cose/t_cose_common.h; sourceTree = ""; }; - E72EC9EE242E74EE006D3DD3 /* t_cose_sign1_verify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = t_cose_sign1_verify.h; path = t_cose/t_cose_sign1_verify.h; sourceTree = ""; }; - E72EC9EF242E74EE006D3DD3 /* q_useful_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = q_useful_buf.h; path = t_cose/q_useful_buf.h; sourceTree = ""; }; - E72FB01B231ADAA8000970FE /* run_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = run_tests.h; sourceTree = ""; }; - E72FB01C231ADAA8000970FE /* run_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = run_tests.c; sourceTree = ""; }; - E730E60623612D2B00175CE0 /* sha256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sha256.h; path = b_con_hash/sha256.h; sourceTree = ""; }; - E730E60723612D2B00175CE0 /* sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha256.c; path = b_con_hash/sha256.c; sourceTree = ""; }; - E730E62023612DAB00175CE0 /* t_cose_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_test; sourceTree = BUILT_PRODUCTS_DIR; }; - E73BF6D223AFFA6500DF5C36 /* t_cose_basic_example_psa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_basic_example_psa.c; sourceTree = ""; }; - E73BF6EE23AFFB4100DF5C36 /* t_cose_basic_example_psa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_basic_example_psa; sourceTree = BUILT_PRODUCTS_DIR; }; - E73BF6F023B07AB200DF5C36 /* t_cose_basic_example_ossl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = t_cose_basic_example_ossl.c; sourceTree = ""; }; - E73BF71C23B07ACF00DF5C36 /* t_cose_basic_example_openssl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_basic_example_openssl; sourceTree = BUILT_PRODUCTS_DIR; }; - E73CDAC623A7316700D262E0 /* t_cose_psa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_psa; sourceTree = BUILT_PRODUCTS_DIR; }; - E73CDAD223AD4E6D00D262E0 /* t_cose_psa_crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_psa_crypto.c; sourceTree = ""; }; - E73FDFC328B6BB32002CF0CC /* t_cose_short_circuit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_short_circuit.c; sourceTree = ""; }; - E73FDFC428B6BB32002CF0CC /* t_cose_short_circuit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_short_circuit.h; sourceTree = ""; }; - E7489C9F259F8B4B0004634C /* qcbor_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_encode.h; path = ../../../../../usr/local/include/qcbor/qcbor_encode.h; sourceTree = ""; }; - E7489CA0259F8B4B0004634C /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = ../../../../../usr/local/include/qcbor/qcbor_common.h; sourceTree = ""; }; - E7489CA1259F8B4B0004634C /* qcbor_spiffy_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_spiffy_decode.h; path = ../../../../../usr/local/include/qcbor/qcbor_spiffy_decode.h; sourceTree = ""; }; - E7489CA2259F8B4B0004634C /* qcbor_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_decode.h; path = ../../../../../usr/local/include/qcbor/qcbor_decode.h; sourceTree = ""; }; - E7489CA3259F8B4B0004634C /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = ../../../../../usr/local/include/qcbor/qcbor_private.h; sourceTree = ""; }; - E7489CA4259F8B4B0004634C /* qcbor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor.h; path = ../../../../../usr/local/include/qcbor/qcbor.h; sourceTree = ""; }; - E7489CA5259F8B4B0004634C /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = ../../../../../usr/local/include/qcbor/UsefulBuf.h; sourceTree = ""; }; - E74FFBB8263BAB0D003B66FF /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = /Users/lgl/Code/t_cose/master/../../../../../usr/local/lib/libcrypto.a; sourceTree = ""; }; - E751F9DE27E1F85000EBA5FA /* crypto_se_driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_se_driver.h; path = ../../../../../usr/local/include/psa/crypto_se_driver.h; sourceTree = ""; }; - E751F9DF27E1F85000EBA5FA /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = ../../../../../usr/local/include/psa/crypto.h; sourceTree = ""; }; - E751F9E027E1F85000EBA5FA /* crypto_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_platform.h; path = ../../../../../usr/local/include/psa/crypto_platform.h; sourceTree = ""; }; - E751F9E127E1F85000EBA5FA /* crypto_struct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_struct.h; path = ../../../../../usr/local/include/psa/crypto_struct.h; sourceTree = ""; }; - E751F9E227E1F85000EBA5FA /* crypto_driver_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_driver_common.h; path = ../../../../../usr/local/include/psa/crypto_driver_common.h; sourceTree = ""; }; - E751F9E327E1F85000EBA5FA /* crypto_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_config.h; path = ../../../../../usr/local/include/psa/crypto_config.h; sourceTree = ""; }; - E751F9E427E1F85000EBA5FA /* crypto_builtin_composites.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_builtin_composites.h; path = ../../../../../usr/local/include/psa/crypto_builtin_composites.h; sourceTree = ""; }; - E751F9E527E1F85000EBA5FA /* crypto_sizes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_sizes.h; path = ../../../../../usr/local/include/psa/crypto_sizes.h; sourceTree = ""; }; - E751F9E627E1F85000EBA5FA /* crypto_accel_driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_accel_driver.h; path = ../../../../../usr/local/include/psa/crypto_accel_driver.h; sourceTree = ""; }; - E751F9E727E1F85000EBA5FA /* crypto_extra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_extra.h; path = ../../../../../usr/local/include/psa/crypto_extra.h; sourceTree = ""; }; - E751F9E827E1F85000EBA5FA /* crypto_entropy_driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_entropy_driver.h; path = ../../../../../usr/local/include/psa/crypto_entropy_driver.h; sourceTree = ""; }; - E751F9E927E1F85000EBA5FA /* crypto_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_types.h; path = ../../../../../usr/local/include/psa/crypto_types.h; sourceTree = ""; }; - E751F9EA27E1F85000EBA5FA /* crypto_driver_contexts_composites.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_driver_contexts_composites.h; path = ../../../../../usr/local/include/psa/crypto_driver_contexts_composites.h; sourceTree = ""; }; - E751F9EB27E1F85000EBA5FA /* crypto_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_compat.h; path = ../../../../../usr/local/include/psa/crypto_compat.h; sourceTree = ""; }; - E751F9EC27E1F85000EBA5FA /* crypto_driver_contexts_primitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_driver_contexts_primitives.h; path = ../../../../../usr/local/include/psa/crypto_driver_contexts_primitives.h; sourceTree = ""; }; - E751F9ED27E1F85000EBA5FA /* crypto_builtin_primitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_builtin_primitives.h; path = ../../../../../usr/local/include/psa/crypto_builtin_primitives.h; sourceTree = ""; }; - E751F9EE27E1F85000EBA5FA /* crypto_values.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypto_values.h; path = ../../../../../usr/local/include/psa/crypto_values.h; sourceTree = ""; }; - E751F9F027E1F90F00EBA5FA /* libmbedcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedcrypto.a; path = ../../../../../usr/local/lib/libmbedcrypto.a; sourceTree = ""; }; - E772028523CAEC84006E966E /* t_cose_psa_noss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_psa_noss; sourceTree = BUILT_PRODUCTS_DIR; }; - E7C960A527F7569500FB537C /* libqcbor.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqcbor.a; path = ../../../../../usr/local/lib/libqcbor.a; sourceTree = ""; }; - E7E36E78226CB8400040613B /* t_cose_openssl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = t_cose_openssl; sourceTree = BUILT_PRODUCTS_DIR; }; - E7E36E7B226CB8400040613B /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; - E7E36E89226CB9460040613B /* t_cose_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_util.c; sourceTree = ""; }; - E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_sign1_verify.c; sourceTree = ""; }; - E7E36E8C226CB9460040613B /* t_cose_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_util.h; sourceTree = ""; }; - E7E36E8D226CB9460040613B /* t_cose_crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_crypto.h; sourceTree = ""; }; - E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_sign1_sign.c; sourceTree = ""; }; - E7E36EA3226CBB570040613B /* t_cose_openssl_crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_openssl_crypto.c; sourceTree = ""; }; - E7E36EA4226CBB570040613B /* t_cose_test_crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_test_crypto.c; sourceTree = ""; }; - E7F70AC42270DFAE007CE07F /* t_cose_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t_cose_test.h; sourceTree = ""; }; - E7F70AC52270DFAE007CE07F /* t_cose_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = t_cose_test.c; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - E730E61A23612DAB00175CE0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E7C960A627F7569E00FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73BF6E823AFFB4100DF5C36 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E7C960AA27F756A100FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73BF71623B07ACF00DF5C36 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E7C960AB27F756A200FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73CDAC023A7316700D262E0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E7C960B527FC97A800FB537C /* libmbedcrypto.a in Frameworks */, - E7C960A827F756A000FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E772027F23CAEC84006E966E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E7C960B627FC97AF00FB537C /* libmbedcrypto.a in Frameworks */, - E7C960AC27F756A300FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E7E36E75226CB8400040613B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E74FFBBA263BAB38003B66FF /* libcrypto.a in Frameworks */, - E7C960A727F7569F00FB537C /* libqcbor.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - E730E605235E0B1800175CE0 /* QCBOR Interface */ = { - isa = PBXGroup; - children = ( - E7489CA0259F8B4B0004634C /* qcbor_common.h */, - E7489CA2259F8B4B0004634C /* qcbor_decode.h */, - E7489C9F259F8B4B0004634C /* qcbor_encode.h */, - E7489CA3259F8B4B0004634C /* qcbor_private.h */, - E7489CA1259F8B4B0004634C /* qcbor_spiffy_decode.h */, - E7489CA4259F8B4B0004634C /* qcbor.h */, - E7489CA5259F8B4B0004634C /* UsefulBuf.h */, - ); - name = "QCBOR Interface"; - sourceTree = ""; - }; - E73CDAA123A082A500D262E0 /* examples */ = { - isa = PBXGroup; - children = ( - E73BF6F023B07AB200DF5C36 /* t_cose_basic_example_ossl.c */, - E73BF6D223AFFA6500DF5C36 /* t_cose_basic_example_psa.c */, - ); - path = examples; - sourceTree = ""; - }; - E751F9DD27E1F81000EBA5FA /* PSA Interface */ = { - isa = PBXGroup; - children = ( - E751F9E627E1F85000EBA5FA /* crypto_accel_driver.h */, - E751F9E427E1F85000EBA5FA /* crypto_builtin_composites.h */, - E751F9ED27E1F85000EBA5FA /* crypto_builtin_primitives.h */, - E751F9EB27E1F85000EBA5FA /* crypto_compat.h */, - E751F9E327E1F85000EBA5FA /* crypto_config.h */, - E751F9E227E1F85000EBA5FA /* crypto_driver_common.h */, - E751F9EA27E1F85000EBA5FA /* crypto_driver_contexts_composites.h */, - E751F9EC27E1F85000EBA5FA /* crypto_driver_contexts_primitives.h */, - E751F9E827E1F85000EBA5FA /* crypto_entropy_driver.h */, - E751F9E727E1F85000EBA5FA /* crypto_extra.h */, - E751F9E027E1F85000EBA5FA /* crypto_platform.h */, - E751F9DE27E1F85000EBA5FA /* crypto_se_driver.h */, - E751F9E527E1F85000EBA5FA /* crypto_sizes.h */, - E751F9E127E1F85000EBA5FA /* crypto_struct.h */, - E751F9E927E1F85000EBA5FA /* crypto_types.h */, - E751F9EE27E1F85000EBA5FA /* crypto_values.h */, - E751F9DF27E1F85000EBA5FA /* crypto.h */, - ); - name = "PSA Interface"; - sourceTree = ""; - }; - E7E36E6F226CB8400040613B = { - isa = PBXGroup; - children = ( - E71D9E8E231C930B00A21F7F /* README.md */, - E73CDAA123A082A500D262E0 /* examples */, - E7E36E7B226CB8400040613B /* main.c */, - E7E36E82226CB9460040613B /* inc */, - E7E36E86226CB9460040613B /* src */, - E7E36EA2226CBA540040613B /* crypto_adapters */, - E7F70AC32270DF90007CE07F /* test */, - E730E605235E0B1800175CE0 /* QCBOR Interface */, - E751F9DD27E1F81000EBA5FA /* PSA Interface */, - E7F70AB22270D989007CE07F /* Frameworks */, - E7E36E79226CB8400040613B /* Products */, - ); - sourceTree = ""; - }; - E7E36E79226CB8400040613B /* Products */ = { - isa = PBXGroup; - children = ( - E7E36E78226CB8400040613B /* t_cose_openssl */, - E730E62023612DAB00175CE0 /* t_cose_test */, - E73CDAC623A7316700D262E0 /* t_cose_psa */, - E73BF6EE23AFFB4100DF5C36 /* t_cose_basic_example_psa */, - E73BF71C23B07ACF00DF5C36 /* t_cose_basic_example_openssl */, - E772028523CAEC84006E966E /* t_cose_psa_noss */, - ); - name = Products; - sourceTree = ""; - }; - E7E36E82226CB9460040613B /* inc */ = { - isa = PBXGroup; - children = ( - E72EC9EF242E74EE006D3DD3 /* q_useful_buf.h */, - E72EC9ED242E74EE006D3DD3 /* t_cose_common.h */, - E72EC9EC242E74EE006D3DD3 /* t_cose_sign1_sign.h */, - E72EC9EE242E74EE006D3DD3 /* t_cose_sign1_verify.h */, - ); - path = inc; - sourceTree = ""; - }; - E7E36E86226CB9460040613B /* src */ = { - isa = PBXGroup; - children = ( - E73FDFC328B6BB32002CF0CC /* t_cose_short_circuit.c */, - E73FDFC428B6BB32002CF0CC /* t_cose_short_circuit.h */, - E71D9ECA23341D8200A21F7F /* t_cose_standard_constants.h */, - E7E36E89226CB9460040613B /* t_cose_util.c */, - E7E36E8A226CB9460040613B /* t_cose_sign1_verify.c */, - 0F9105782321878F00008572 /* t_cose_parameters.h */, - 0F9105792321878F00008572 /* t_cose_parameters.c */, - E7E36E8C226CB9460040613B /* t_cose_util.h */, - E7E36E8D226CB9460040613B /* t_cose_crypto.h */, - E7E36E8E226CB9460040613B /* t_cose_sign1_sign.c */, - ); - path = src; - sourceTree = ""; - }; - E7E36EA2226CBA540040613B /* crypto_adapters */ = { - isa = PBXGroup; - children = ( - E73CDAD223AD4E6D00D262E0 /* t_cose_psa_crypto.c */, - E7E36EA4226CBB570040613B /* t_cose_test_crypto.c */, - E7E36EA3226CBB570040613B /* t_cose_openssl_crypto.c */, - E7F70AAC2270D650007CE07F /* b_con_hash */, - ); - path = crypto_adapters; - sourceTree = ""; - }; - E7F70AAC2270D650007CE07F /* b_con_hash */ = { - isa = PBXGroup; - children = ( - E730E60723612D2B00175CE0 /* sha256.c */, - E730E60623612D2B00175CE0 /* sha256.h */, - ); - name = b_con_hash; - sourceTree = ""; - }; - E7F70AB22270D989007CE07F /* Frameworks */ = { - isa = PBXGroup; - children = ( - E7C960A527F7569500FB537C /* libqcbor.a */, - E751F9F027E1F90F00EBA5FA /* libmbedcrypto.a */, - E74FFBB8263BAB0D003B66FF /* libcrypto.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - E7F70AC32270DF90007CE07F /* test */ = { - isa = PBXGroup; - children = ( - E72FB01B231ADAA8000970FE /* run_tests.h */, - E72FB01C231ADAA8000970FE /* run_tests.c */, - E7F70AC42270DFAE007CE07F /* t_cose_test.h */, - E7F70AC52270DFAE007CE07F /* t_cose_test.c */, - E721CB9523628D2700C7FD56 /* t_cose_sign_verify_test.h */, - E721CB9423628D2600C7FD56 /* t_cose_sign_verify_test.c */, - 0F8B2FE9233C3DD600A22349 /* t_cose_make_test_messages.h */, - 0F8B2FE8233C3DD600A22349 /* t_cose_make_test_messages.c */, - E721CB9723628E0B00C7FD56 /* t_cose_make_test_pub_key.h */, - E721CB9823628E9E00C7FD56 /* t_cose_make_openssl_test_key.c */, - E721CB9123628B5F00C7FD56 /* t_cose_make_psa_test_key.c */, - ); - path = test; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - E730E60923612DAB00175CE0 /* t_cose_test */ = { - isa = PBXNativeTarget; - buildConfigurationList = E730E61D23612DAB00175CE0 /* Build configuration list for PBXNativeTarget "t_cose_test" */; - buildPhases = ( - E730E60A23612DAB00175CE0 /* Sources */, - E730E61A23612DAB00175CE0 /* Frameworks */, - E730E61C23612DAB00175CE0 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_test; - productName = t_cose; - productReference = E730E62023612DAB00175CE0 /* t_cose_test */; - productType = "com.apple.product-type.tool"; - }; - E73BF6D523AFFB4100DF5C36 /* t_cose_basic_example_psa */ = { - isa = PBXNativeTarget; - buildConfigurationList = E73BF6EB23AFFB4100DF5C36 /* Build configuration list for PBXNativeTarget "t_cose_basic_example_psa" */; - buildPhases = ( - E73BF6D623AFFB4100DF5C36 /* Sources */, - E73BF6E823AFFB4100DF5C36 /* Frameworks */, - E73BF6EA23AFFB4100DF5C36 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_basic_example_psa; - productName = t_cose; - productReference = E73BF6EE23AFFB4100DF5C36 /* t_cose_basic_example_psa */; - productType = "com.apple.product-type.tool"; - }; - E73BF70523B07ACF00DF5C36 /* t_cose_basic_example_openssl */ = { - isa = PBXNativeTarget; - buildConfigurationList = E73BF71923B07ACF00DF5C36 /* Build configuration list for PBXNativeTarget "t_cose_basic_example_openssl" */; - buildPhases = ( - E73BF70623B07ACF00DF5C36 /* Sources */, - E73BF71623B07ACF00DF5C36 /* Frameworks */, - E73BF71823B07ACF00DF5C36 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_basic_example_openssl; - productName = t_cose; - productReference = E73BF71C23B07ACF00DF5C36 /* t_cose_basic_example_openssl */; - productType = "com.apple.product-type.tool"; - }; - E73CDAAC23A7316700D262E0 /* t_cose_psa */ = { - isa = PBXNativeTarget; - buildConfigurationList = E73CDAC323A7316700D262E0 /* Build configuration list for PBXNativeTarget "t_cose_psa" */; - buildPhases = ( - E73CDAAD23A7316700D262E0 /* Sources */, - E73CDAC023A7316700D262E0 /* Frameworks */, - E73CDAC223A7316700D262E0 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_psa; - productName = t_cose; - productReference = E73CDAC623A7316700D262E0 /* t_cose_psa */; - productType = "com.apple.product-type.tool"; - }; - E772026D23CAEC84006E966E /* t_cose_psa_noss */ = { - isa = PBXNativeTarget; - buildConfigurationList = E772028223CAEC84006E966E /* Build configuration list for PBXNativeTarget "t_cose_psa_noss" */; - buildPhases = ( - E772026E23CAEC84006E966E /* Sources */, - E772027F23CAEC84006E966E /* Frameworks */, - E772028123CAEC84006E966E /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_psa_noss; - productName = t_cose; - productReference = E772028523CAEC84006E966E /* t_cose_psa_noss */; - productType = "com.apple.product-type.tool"; - }; - E7E36E77226CB8400040613B /* t_cose_openssl */ = { - isa = PBXNativeTarget; - buildConfigurationList = E7E36E7F226CB8400040613B /* Build configuration list for PBXNativeTarget "t_cose_openssl" */; - buildPhases = ( - E7E36E74226CB8400040613B /* Sources */, - E7E36E75226CB8400040613B /* Frameworks */, - E7E36E76226CB8400040613B /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = t_cose_openssl; - productName = t_cose; - productReference = E7E36E78226CB8400040613B /* t_cose_openssl */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - E7E36E70226CB8400040613B /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1150; - ORGANIZATIONNAME = "Laurence Lundblade"; - TargetAttributes = { - E7E36E77226CB8400040613B = { - CreatedOnToolsVersion = 9.4.1; - }; - }; - }; - buildConfigurationList = E7E36E73226CB8400040613B /* Build configuration list for PBXProject "t_cose" */; - compatibilityVersion = "Xcode 10.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = E7E36E6F226CB8400040613B; - productRefGroup = E7E36E79226CB8400040613B /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - E730E60923612DAB00175CE0 /* t_cose_test */, - E7E36E77226CB8400040613B /* t_cose_openssl */, - E73CDAAC23A7316700D262E0 /* t_cose_psa */, - E73BF6D523AFFB4100DF5C36 /* t_cose_basic_example_psa */, - E73BF70523B07ACF00DF5C36 /* t_cose_basic_example_openssl */, - E772026D23CAEC84006E966E /* t_cose_psa_noss */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - E730E60A23612DAB00175CE0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E730E60B23612DAB00175CE0 /* t_cose_sign1_verify.c in Sources */, - E730E60C23612DAB00175CE0 /* run_tests.c in Sources */, - E73FDFC528B6BB32002CF0CC /* t_cose_short_circuit.c in Sources */, - E730E62123612E3900175CE0 /* t_cose_test_crypto.c in Sources */, - E730E61123612DAB00175CE0 /* t_cose_parameters.c in Sources */, - E730E61223612DAB00175CE0 /* t_cose_make_test_messages.c in Sources */, - E730E61323612DAB00175CE0 /* t_cose_util.c in Sources */, - E730E61523612DAB00175CE0 /* sha256.c in Sources */, - E730E61623612DAB00175CE0 /* t_cose_test.c in Sources */, - E730E61823612DAB00175CE0 /* main.c in Sources */, - E730E61923612DAB00175CE0 /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73BF6D623AFFB4100DF5C36 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E73BF6D723AFFB4100DF5C36 /* t_cose_sign1_verify.c in Sources */, - E73BF6DB23AFFB4100DF5C36 /* t_cose_psa_crypto.c in Sources */, - E73BF6DC23AFFB4100DF5C36 /* t_cose_util.c in Sources */, - E73BF6DE23AFFB4100DF5C36 /* t_cose_parameters.c in Sources */, - E73BF6E023AFFB4100DF5C36 /* t_cose_basic_example_psa.c in Sources */, - E73BF6E323AFFB4100DF5C36 /* sha256.c in Sources */, - E73BF6E723AFFB4100DF5C36 /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73BF70623B07ACF00DF5C36 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E73BF70723B07ACF00DF5C36 /* t_cose_sign1_verify.c in Sources */, - E73BF70B23B07ACF00DF5C36 /* t_cose_openssl_crypto.c in Sources */, - E73BF71D23B07AE400DF5C36 /* t_cose_basic_example_ossl.c in Sources */, - E73BF70D23B07ACF00DF5C36 /* t_cose_parameters.c in Sources */, - E73BF70F23B07ACF00DF5C36 /* t_cose_util.c in Sources */, - E73BF71523B07ACF00DF5C36 /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E73CDAAD23A7316700D262E0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E73CDAAE23A7316700D262E0 /* t_cose_sign1_verify.c in Sources */, - E73CDAB023A7316700D262E0 /* t_cose_test.c in Sources */, - E73CDAD423AD4F3900D262E0 /* t_cose_psa_crypto.c in Sources */, - E73FDFC728B6BB63002CF0CC /* t_cose_short_circuit.c in Sources */, - E73CDAB223A7316700D262E0 /* t_cose_util.c in Sources */, - E73CDAB623A7316700D262E0 /* t_cose_parameters.c in Sources */, - E73CDAB823A7316700D262E0 /* t_cose_sign_verify_test.c in Sources */, - E73CDAB923A7316700D262E0 /* t_cose_make_psa_test_key.c in Sources */, - E73CDABA23A7316700D262E0 /* sha256.c in Sources */, - E73CDABC23A7316700D262E0 /* t_cose_make_test_messages.c in Sources */, - E73CDABD23A7316700D262E0 /* main.c in Sources */, - E73CDABE23A7316700D262E0 /* run_tests.c in Sources */, - E73CDABF23A7316700D262E0 /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E772026E23CAEC84006E966E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E772026F23CAEC84006E966E /* t_cose_sign1_verify.c in Sources */, - E772027123CAEC84006E966E /* t_cose_test.c in Sources */, - E772027323CAEC84006E966E /* t_cose_psa_crypto.c in Sources */, - E772027423CAEC84006E966E /* t_cose_util.c in Sources */, - E772027623CAEC84006E966E /* t_cose_parameters.c in Sources */, - E772027823CAEC84006E966E /* t_cose_sign_verify_test.c in Sources */, - E772027923CAEC84006E966E /* t_cose_make_psa_test_key.c in Sources */, - E772027A23CAEC84006E966E /* sha256.c in Sources */, - E772027B23CAEC84006E966E /* t_cose_make_test_messages.c in Sources */, - E772027C23CAEC84006E966E /* main.c in Sources */, - E772027D23CAEC84006E966E /* run_tests.c in Sources */, - E772027E23CAEC84006E966E /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E7E36E74226CB8400040613B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E7E36E91226CB9460040613B /* t_cose_sign1_verify.c in Sources */, - E72FB01D231ADAA8000970FE /* run_tests.c in Sources */, - E721CB9A2362ABA400C7FD56 /* t_cose_make_openssl_test_key.c in Sources */, - E7E36EA5226CBB570040613B /* t_cose_openssl_crypto.c in Sources */, - 0F91057A2321878F00008572 /* t_cose_parameters.c in Sources */, - E73FDFC628B6BB62002CF0CC /* t_cose_short_circuit.c in Sources */, - 0F8B2FEF2345A33A00A22349 /* t_cose_make_test_messages.c in Sources */, - E7E36E90226CB9460040613B /* t_cose_util.c in Sources */, - E721CB9B2362AC2A00C7FD56 /* t_cose_sign_verify_test.c in Sources */, - E7F70AC62270DFAE007CE07F /* t_cose_test.c in Sources */, - E7E36E7C226CB8400040613B /* main.c in Sources */, - E7E36E93226CB9460040613B /* t_cose_sign1_sign.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - E730E61E23612DAB00175CE0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "FRAMEWORK_SEARCH_PATHS[arch=*]" = ""; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - T_COSE_ENABLE_HASH_FAIL_TEST, - T_COSE_DISABLE_SIGN_VERIFY_TESTS, - T_COSE_USE_B_CON_SHA256, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E730E61F23612DAB00175CE0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( - T_COSE_USE_B_CON_SHA256, - T_COSE_DISABLE_SIGN_VERIFY_TESTS, - T_COSE_ENABLE_HASH_FAIL_TEST, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - E73BF6EC23AFFB4100DF5C36 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = T_COSE_USE_PSA_CRYPTO; - HEADER_SEARCH_PATHS = ""; - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../mbed-crypto/library"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E73BF6ED23AFFB4100DF5C36 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - HEADER_SEARCH_PATHS = ""; - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../mbed-crypto/library/"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - E73BF71A23B07ACF00DF5C36 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( - T_COSE_USE_OPENSSL_CRYPTO, - "DEBUG=1", - ); - HEADER_SEARCH_PATHS = ""; - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../openssl/openssl-1.1.1b"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E73BF71B23B07ACF00DF5C36 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = T_COSE_USE_OPENSSL_CRYPTO; - HEADER_SEARCH_PATHS = ""; - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../openssl/openssl-1.1.1b"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - E73CDAC423A7316700D262E0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = T_COSE_USE_PSA_CRYPTO; - GCC_WARN_SHADOW = YES; - GCC_WARN_SIGN_COMPARE = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E73CDAC523A7316700D262E0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CODE_SIGN_STYLE = Automatic; - GCC_WARN_SHADOW = YES; - GCC_WARN_SIGN_COMPARE = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - E772028323CAEC84006E966E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( - T_COSE_USE_PSA_CRYPTO, - T_COSE_DISABLE_SHORT_CIRCUIT_SIGN, - ); - "HEADER_SEARCH_PATHS[arch=*]" = ( - "../../mbed-crypto/include", - ../../QCBOR/master/inc, - ); - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../mbed-crypto/library"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E772028423CAEC84006E966E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - "HEADER_SEARCH_PATHS[arch=*]" = "../../mbed-crypto/include"; - "LIBRARY_SEARCH_PATHS[arch=*]" = "../../mbed-crypto/library/"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - E7E36E7D226CB8400040613B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = NO; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - inc, - /usr/local/include, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = /usr/local/lib; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - E7E36E7E226CB8400040613B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = NO; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - inc, - /usr/local/include, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = /usr/local/lib; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - }; - name = Release; - }; - E7E36E80226CB8400040613B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( - T_COSE_USE_OPENSSL_CRYPTO, - "DEBUG=1", - ); - HEADER_SEARCH_PATHS = ( - inc, - /usr/local/include, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - E7E36E81226CB8400040613B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CODE_SIGN_STYLE = Automatic; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = T_COSE_USE_OPENSSL_CRYPTO; - HEADER_SEARCH_PATHS = ( - inc, - /usr/local/include, - ); - LIBRARY_SEARCH_PATHS = /usr/local/lib; - "LIBRARY_SEARCH_PATHS[arch=*]" = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - E730E61D23612DAB00175CE0 /* Build configuration list for PBXNativeTarget "t_cose_test" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E730E61E23612DAB00175CE0 /* Debug */, - E730E61F23612DAB00175CE0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E73BF6EB23AFFB4100DF5C36 /* Build configuration list for PBXNativeTarget "t_cose_basic_example_psa" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E73BF6EC23AFFB4100DF5C36 /* Debug */, - E73BF6ED23AFFB4100DF5C36 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E73BF71923B07ACF00DF5C36 /* Build configuration list for PBXNativeTarget "t_cose_basic_example_openssl" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E73BF71A23B07ACF00DF5C36 /* Debug */, - E73BF71B23B07ACF00DF5C36 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E73CDAC323A7316700D262E0 /* Build configuration list for PBXNativeTarget "t_cose_psa" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E73CDAC423A7316700D262E0 /* Debug */, - E73CDAC523A7316700D262E0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E772028223CAEC84006E966E /* Build configuration list for PBXNativeTarget "t_cose_psa_noss" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E772028323CAEC84006E966E /* Debug */, - E772028423CAEC84006E966E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E7E36E73226CB8400040613B /* Build configuration list for PBXProject "t_cose" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E7E36E7D226CB8400040613B /* Debug */, - E7E36E7E226CB8400040613B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E7E36E7F226CB8400040613B /* Build configuration list for PBXNativeTarget "t_cose_openssl" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E7E36E80226CB8400040613B /* Debug */, - E7E36E81226CB8400040613B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = E7E36E70226CB8400040613B /* Project object */; -} diff --git a/3rdparty/internal/t_cose/test/keys/README.txt b/3rdparty/internal/t_cose/test/keys/README.txt deleted file mode 100644 index 6c8bd31442a1..000000000000 --- a/3rdparty/internal/t_cose/test/keys/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -To list curves: - - openssl ecparam -list_curves - -To generate an ECDSA key: - - openssl ecparam -genkey -name secp384r1 -out k.pem - -To print out the ECDSA key: - - openssl ec -in k.pem -noout -text - - -https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html -https://superuser.com/questions/1103401/generate-an-ecdsa-key-and-csr-with-openssl diff --git a/3rdparty/internal/t_cose/test/keys/prime256v1.pem b/3rdparty/internal/t_cose/test/keys/prime256v1.pem deleted file mode 100644 index 5e72622dd895..000000000000 --- a/3rdparty/internal/t_cose/test/keys/prime256v1.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN EC PARAMETERS----- -BggqhkjOPQMBBw== ------END EC PARAMETERS----- ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIPG3FCNDQC87XecxXqiU+dpc9QP/eTijfKFOsDKGmIRQoAoGCCqGSM49 -AwEHoUQDQgAEN6tllV+uBGZnPDopNKNPLw7Cs+7CJBmFV5mPwEv0srSV2XmPJTnJ -DX0QKzu72n/L2w6bWNThrS5hUI2nX4Smew== ------END EC PRIVATE KEY----- diff --git a/3rdparty/internal/t_cose/test/keys/secp384r1.pem b/3rdparty/internal/t_cose/test/keys/secp384r1.pem deleted file mode 100644 index eccd31025752..000000000000 --- a/3rdparty/internal/t_cose/test/keys/secp384r1.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQAIg== ------END EC PARAMETERS----- ------BEGIN EC PRIVATE KEY----- -MIGkAgEBBDAD3xT0uKQ/2Kt1pgRr0rXqpv0QsrID/Yp415Ft4gqiQes37D1MaT0j -uitPbltm9X+gBwYFK4EEACKhZANiAAS92cP4GMnO8+EeLUDndb6ze8N2aY1xln+T -M3pOAy3/sRtQUGfd20IUtW2bzsWRd+zNirBfUJdZM7mnONkMCwfrlRlWfvkHWAfP -dxOfwf6FYIhRNhE2gGEj7cc1zloD6OQ= ------END EC PRIVATE KEY----- diff --git a/3rdparty/internal/t_cose/test/keys/secp521r1.pem b/3rdparty/internal/t_cose/test/keys/secp521r1.pem deleted file mode 100644 index d3aa0c745c79..000000000000 --- a/3rdparty/internal/t_cose/test/keys/secp521r1.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQAIw== ------END EC PARAMETERS----- ------BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIARdLRQ5Q1+rMzscbItTTwlpOWrWTV9TXWX2jyoWBlkLsV/VMi/Jek -FsOVdF5yx8hRmMCSGrO46S3ZAbWkIVmtrG2gBwYFK4EEACOhgYkDgYYABADk0lMX -WhQxH8LdSHaHcMtJsHvRXTJ765iqM+YM0BgbF/uPHL8H28hlL/W3tEUsCC4GhsD6 -uAiQccvFNxAdNEuUwgHmQk86GNpPIOyr+8hLhGfCF81nBV+l3sf7GuhwgjAsGBPK -pLexzyjZRnfkhvtLMXCX6TB6vbnVAYd3mj0eaCwSPA== ------END EC PRIVATE KEY----- diff --git a/3rdparty/internal/t_cose/test/run_tests.c b/3rdparty/internal/t_cose/test/run_tests.c deleted file mode 100644 index ecbb1b54e686..000000000000 --- a/3rdparty/internal/t_cose/test/run_tests.c +++ /dev/null @@ -1,319 +0,0 @@ -/*============================================================================== - run_tests.c -- test aggregator and results reporting - - Copyright (c) 2018-2022, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/30/18 - =============================================================================*/ - -#include "run_tests.h" -#include "qcbor/UsefulBuf.h" -#include -#include - -#include "t_cose_test.h" -#include "t_cose_sign_verify_test.h" - - -/* - Test configuration - */ - -typedef int_fast32_t (test_fun_t)(void); -typedef const char * (test_fun2_t)(void); - - -#define TEST_ENTRY(test_name) {#test_name, test_name, true} -#define TEST_ENTRY_DISABLED(test_name) {#test_name, test_name, false} - -typedef struct { - const char *szTestName; - test_fun_t *test_fun; - bool bEnabled; -} test_entry; - -#ifdef STRING_RETURNING_TESTS -typedef struct { - const char *szTestName; - test_fun2_t *test_fun; - bool bEnabled; -} test_entry2; - - -static test_entry2 s_tests2[] = { -}; -#endif - -static test_entry s_tests[] = { - TEST_ENTRY(sign1_structure_decode_test), - -#ifndef T_COSE_DISABLE_SIGN_VERIFY_TESTS - /* Many tests can be run without a crypto library integration and - * provide good test coverage of everything but the signing and - * verification. These tests can't be run with signing and - * verification short circuited. They must have a real crypto - * library integrated. */ - TEST_ENTRY(sign_verify_basic_test), - TEST_ENTRY(sign_verify_make_cwt_test), - TEST_ENTRY(sign_verify_sig_fail_test), - TEST_ENTRY(sign_verify_get_size_test), - TEST_ENTRY(sign_verify_known_good_test), - TEST_ENTRY(sign_verify_unsupported_test), - TEST_ENTRY(sign_verify_bad_auxiliary_buffer), -#endif /* T_COSE_DISABLE_SIGN_VERIFY_TESTS */ - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - /* These tests can't run if short-circuit signatures are disabled. - * The most critical ones are replicated in the group of tests - * that require a real crypto library. Typically short-circuit - * signing is only disabled for extreme code size savings so these - * tests are typically always run. - */ - TEST_ENTRY(bad_parameters_test), - TEST_ENTRY(crit_parameters_test), -#ifndef T_COSE_DISABLE_CONTENT_TYPE - TEST_ENTRY(content_type_test), -#endif - TEST_ENTRY(all_header_parameters_test), - TEST_ENTRY(cose_example_test), - TEST_ENTRY(short_circuit_signing_error_conditions_test), - TEST_ENTRY(short_circuit_self_test), - TEST_ENTRY(short_circuit_self_detached_content_test), - TEST_ENTRY(short_circuit_decode_only_test), - TEST_ENTRY(short_circuit_make_cwt_test), - TEST_ENTRY(short_circuit_verify_fail_test), - TEST_ENTRY(tags_test), - TEST_ENTRY(get_size_test), - TEST_ENTRY(indef_array_and_map_test), - -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST - TEST_ENTRY(short_circuit_hash_fail_test), -#endif /* T_COSE_DISABLE_HASH_FAIL_TEST */ -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - - -}; - - - -/** - \brief Convert number to ASCII string, similar to sprint - - \param [in] nNum The 32-bit integer to convert. - \param [in] StringMem The buffer to output to. - - \return POinter to NULL-terminated string with result or "XXX" on failure. - - Convert a number up to 999999999 to a string. This is so sprintf doesn't - have to be linked in so as to minimized dependencies even in test code. - - StringMem should be 12 bytes long, 9 for digits, 1 for minus and - 1 for \0 termination. - */ -static const char *NumToString(int32_t nNum, UsefulBuf StringMem) -{ - const int32_t nMax = 1000000000; - - UsefulOutBuf OutBuf; - UsefulOutBuf_Init(&OutBuf, StringMem); - - if(nNum < 0) { - UsefulOutBuf_AppendByte(&OutBuf, '-'); - nNum = -nNum; - } - if(nNum > nMax-1) { - return "XXX"; - } - - bool bDidSomeOutput = false; - for(int32_t n = nMax; n > 0; n/=10) { - int32_t nDigitValue = nNum/n; - if(nDigitValue || bDidSomeOutput){ - bDidSomeOutput = true; - UsefulOutBuf_AppendByte(&OutBuf, (uint8_t)('0' + nDigitValue)); - nNum -= nDigitValue * n; - } - } - if(!bDidSomeOutput){ - UsefulOutBuf_AppendByte(&OutBuf, '0'); - } - UsefulOutBuf_AppendByte(&OutBuf, '\0'); - - return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr; -} - - -/* - Public function. See run_test.h. - */ -int RunTestsTCose(const char *szTestNames[], - OutputStringCB pfOutput, - void *poutCtx, - int *pNumTestsRun) -{ - // int (-32767 to 32767 according to C standard) used by conscious choice - int nTestsFailed = 0; - int nTestsRun = 0; - UsefulBuf_MAKE_STACK_UB(StringStorage, 12); - -#ifdef STRING_RETURNING_TESTS - - test_entry2 *t2; - const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2); - - for(t2 = s_tests2; t2 < s_tests2_end; t2++) { - if(szTestNames[0]) { - // Some tests have been named - const char **szRequestedNames; - for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { - if(!strcmp(t2->szTestName, *szRequestedNames)) { - break; // Name matched - } - } - if(*szRequestedNames == NULL) { - // Didn't match this test - continue; - } - } else { - // no tests named, but don't run "disabled" tests - if(!t2->bEnabled) { - // Don't run disabled tests when all tests are being run - // as indicated by no specific test names being given - continue; - } - } - const char * szTestResult = (t2->test_fun)(); - nTestsRun++; - if(pfOutput) { - (*pfOutput)(t2->szTestName, poutCtx, 0); - } - - if(szTestResult) { - if(pfOutput) { - (*pfOutput)(" FAILED (returned ", poutCtx, 0); - (*pfOutput)(szTestResult, poutCtx, 0); - (*pfOutput)(")", poutCtx, 1); - } - nTestsFailed++; - } else { - if(pfOutput) { - (*pfOutput)( " PASSED", poutCtx, 1); - } - } - } -#endif - - - test_entry *t; - const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry); - - for(t = s_tests; t < s_tests_end; t++) { - if(szTestNames[0]) { - // Some tests have been named - const char **szRequestedNames; - for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { - if(!strcmp(t->szTestName, *szRequestedNames)) { - break; // Name matched - } - } - if(*szRequestedNames == NULL) { - // Didn't match this test - continue; - } - } else { - // no tests named, but don't run "disabled" tests - if(!t->bEnabled) { - // Don't run disabled tests when all tests are being run - // as indicated by no specific test names being given - continue; - } - } - - int32_t nTestResult = (int32_t)(t->test_fun)(); - nTestsRun++; - if(pfOutput) { - (*pfOutput)(t->szTestName, poutCtx, 0); - } - - if(nTestResult) { - if(pfOutput) { - (*pfOutput)(" FAILED (returned ", poutCtx, 0); - (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0); - (*pfOutput)(")", poutCtx, 1); - } - nTestsFailed++; - } else { - if(pfOutput) { - (*pfOutput)( " PASSED", poutCtx, 1); - } - } - } - - if(pNumTestsRun) { - *pNumTestsRun = nTestsRun; - } - - if(pfOutput) { - (*pfOutput)( "SUMMARY: ", poutCtx, 0); - (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0); - (*pfOutput)( " tests run; ", poutCtx, 0); - (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0); - (*pfOutput)( " tests failed", poutCtx, 1); - } - - return nTestsFailed; -} - - -/* - Public function. See run_test.h. - */ -static void PrintSize(const char *szWhat, - uint32_t uSize, - OutputStringCB pfOutput, - void *pOutCtx) -{ - UsefulBuf_MAKE_STACK_UB(buffer, 20); - - (*pfOutput)(szWhat, pOutCtx, 0); - (*pfOutput)(" ", pOutCtx, 0); - (*pfOutput)(NumToString((int32_t)uSize, buffer), pOutCtx, 0); - (*pfOutput)("", pOutCtx, 1); -} - - - - -#include "t_cose/t_cose_sign1_sign.h" /* For struct size printing */ -#include "t_cose/t_cose_sign1_verify.h" /* For struct size printing */ -#include "t_cose_crypto.h" /* For struct size printing */ - - -/* - Public function. See run_test.h. - */ -void PrintSizesTCose(OutputStringCB pfOutput, void *pOutCtx) -{ - // Type and size of return from sizeof() varies. These will never be large - // so cast is safe. - PrintSize("sizeof(struct t_cose_sign1_ctx)", - (uint32_t)sizeof(struct t_cose_sign1_sign_ctx), - pfOutput, pOutCtx); - PrintSize("sizeof(struct t_cose_signing_key)", - (uint32_t)sizeof(struct t_cose_key), - pfOutput, pOutCtx); - PrintSize("sizeof(struct t_cose_crypto_hash)", - (uint32_t)sizeof(struct t_cose_crypto_hash), - pfOutput, pOutCtx); - PrintSize("sizeof(struct t_cose_parameters)", - (uint32_t)sizeof(struct t_cose_parameters), - pfOutput, pOutCtx); - PrintSize("sizeof(struct t_cose_sign1_verify_ctx)", - (uint32_t)sizeof(struct t_cose_sign1_verify_ctx), - pfOutput, pOutCtx); - (*pfOutput)("", pOutCtx, 1); -} diff --git a/3rdparty/internal/t_cose/test/run_tests.h b/3rdparty/internal/t_cose/test/run_tests.h deleted file mode 100644 index 1fa4975f9fff..000000000000 --- a/3rdparty/internal/t_cose/test/run_tests.h +++ /dev/null @@ -1,69 +0,0 @@ -/*============================================================================== - run_tests.h -- test aggregator and results reporting - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created 9/30/18 - =============================================================================*/ - -/** - @file run_tests.h -*/ - -/** - @brief Type for function to output a text string - - @param[in] szString The string to output - @param[in] pOutCtx A context pointer; NULL if not needed - @param[in] bNewline If non-zero, output a newline after the string - - This is a prototype of a function to be passed to RunTests() to - output text strings. - - This can be implemented with stdio (if available) using a straight - call to fputs() where the FILE * is passed as the pOutCtx as shown in - the example code below. This code is for Linux where the newline is - a \\n. Windows usually prefers \\r\\n. - - @code - static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) - { - fputs(szString, (FILE *)pOutCtx); - if(bNewLine) { - fputs("\n", pOutCtx); - } - } - @endcode -*/ -typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline); - - -/** - @brief Runs the T_COSE tests. - - @param[in] szTestNames An argv-style list of test names to run. If - empty, all are run. - @param[in] pfOutput Function that is called to output text strings. - @param[in] pOutCtx Context pointer passed to output function. - @param[out] pNumTestsRun Returns the number of tests run. May be NULL. - - @return The number of tests that failed. Zero means overall success. - */ -int RunTestsTCose(const char *szTestNames[], - OutputStringCB pfOutput, - void *pOutCtx, - int *pNumTestsRun); - - -/** - @brief Print sizes of encoder / decoder contexts. - - @param[in] pfOutput Function that is called to output text strings. - @param[in] pOutCtx Context pointer passed to output function. - */ -void PrintSizesTCose(OutputStringCB pfOutput, void *pOutCtx); - diff --git a/3rdparty/internal/t_cose/test/t_cose_make_openssl_test_key.c b/3rdparty/internal/t_cose/test/t_cose_make_openssl_test_key.c deleted file mode 100644 index 5b567c193071..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_make_openssl_test_key.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * t_cose_make_openssl_test_key.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose_make_test_pub_key.h" /* The interface implemented here */ - -#include "openssl/err.h" -#include "openssl/evp.h" -#include "openssl/x509.h" - - - -/* - * RFC 5915 format EC private key, including the public key. These - * are the same key as in t_cose_make_psa_test_key.c - * - * They are made by: - * - * openssl ecparam -genkey -name prime256v1 | sed -e '1d' -e '$d' | base64 --decode | xxd -i - * - * See also: - * https://stackoverflow.com/ - * questions/71890050/ - * set-an-evp-pkey-from-ec-raw-points-pem-or-der-in-both-openssl-1-1-1-and-3-0-x/ - * 71896633#71896633 - */ - -static const unsigned char ec256_key_pair[] = { - 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xd9, 0xb5, 0xe7, 0x1f, 0x77, - 0x28, 0xbf, 0xe5, 0x63, 0xa9, 0xdc, 0x93, 0x75, 0x62, 0x27, 0x7e, 0x32, - 0x7d, 0x98, 0xd9, 0x94, 0x80, 0xf3, 0xdc, 0x92, 0x41, 0xe5, 0x74, 0x2a, - 0xc4, 0x58, 0x89, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, - 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x40, 0x41, 0x6c, - 0x8c, 0xda, 0xa0, 0xf7, 0xa1, 0x75, 0x69, 0x55, 0x53, 0xc3, 0x27, 0x9c, - 0x10, 0x9c, 0xe9, 0x27, 0x7e, 0x53, 0xc5, 0x86, 0x2a, 0xa7, 0x15, 0xed, - 0xc6, 0x36, 0xf1, 0x71, 0xca, 0x32, 0xf1, 0x76, 0x43, 0x54, 0x96, 0x15, - 0xe5, 0xc8, 0x34, 0x0d, 0x43, 0x32, 0xdd, 0x13, 0x77, 0x8a, 0xec, 0x87, - 0x15, 0x76, 0xa3, 0x3c, 0x26, 0x08, 0x6c, 0x32, 0x0c, 0x9f, 0xf3, 0x3f, - 0xc7 -}; - -static const unsigned char ec384_key_pair[] = { - 0x30, 0x81, 0xa4, 0x02, 0x01, 0x01, 0x04, 0x30, 0x63, 0x88, 0x1c, 0xbf, - 0x86, 0x65, 0xec, 0x39, 0x27, 0x33, 0x24, 0x2e, 0x5a, 0xae, 0x63, 0x3a, - 0xf5, 0xb1, 0xb4, 0x54, 0xcf, 0x7a, 0x55, 0x7e, 0x44, 0xe5, 0x7c, 0xca, - 0xfd, 0xb3, 0x59, 0xf9, 0x72, 0x66, 0xec, 0x48, 0x91, 0xdf, 0x27, 0x79, - 0x99, 0xbd, 0x1a, 0xbc, 0x09, 0x36, 0x49, 0x9c, 0xa0, 0x07, 0x06, 0x05, - 0x2b, 0x81, 0x04, 0x00, 0x22, 0xa1, 0x64, 0x03, 0x62, 0x00, 0x04, 0x14, - 0x2a, 0x78, 0x91, 0x06, 0x9b, 0xbe, 0x43, 0xa9, 0xe8, 0xd2, 0xa7, 0xbd, - 0x03, 0xdf, 0xc9, 0x12, 0x62, 0x66, 0xb7, 0x84, 0xe3, 0x33, 0x4a, 0xf2, - 0xb5, 0xf9, 0x5e, 0xe0, 0x3f, 0xe5, 0xc7, 0xdc, 0x1d, 0x56, 0xb3, 0x9f, - 0x30, 0x6f, 0x97, 0xba, 0x00, 0xd8, 0xcf, 0x41, 0xea, 0x95, 0x5f, 0xeb, - 0x55, 0x62, 0xab, 0x7c, 0xb7, 0x58, 0xd0, 0xe8, 0xde, 0xcf, 0x64, 0x69, - 0x32, 0x50, 0xb3, 0x06, 0x70, 0xb0, 0xbc, 0x84, 0xcb, 0xa7, 0x1f, 0x2f, - 0x1b, 0xf6, 0xad, 0x54, 0x56, 0x0a, 0x75, 0x83, 0xe1, 0xcf, 0xb6, 0x12, - 0x2e, 0x0a, 0xde, 0xf9, 0xaa, 0x37, 0x64, 0x1a, 0x51, 0x1c, 0x27 -}; - -static const unsigned char ec521_key_pair[] = { - 0x30, 0x81, 0xdc, 0x02, 0x01, 0x01, 0x04, 0x42, 0x00, 0x4b, 0x35, 0x4d, - 0xa4, 0xab, 0xf7, 0xa5, 0x4f, 0xac, 0xee, 0x06, 0x49, 0x4a, 0x97, 0x0e, - 0xa6, 0x5f, 0x85, 0xf0, 0x6a, 0x2e, 0xfb, 0xf8, 0xdd, 0x60, 0x9a, 0xf1, - 0x0b, 0x7a, 0x13, 0xf7, 0x90, 0xf8, 0x9f, 0x49, 0x02, 0xbf, 0x5d, 0x5d, - 0x71, 0xa0, 0x90, 0x93, 0x11, 0xfd, 0x0c, 0xda, 0x7b, 0x6a, 0x5f, 0x7b, - 0x82, 0x9d, 0x79, 0x61, 0xe1, 0x6b, 0x31, 0x0a, 0x30, 0x6f, 0x4d, 0xf3, - 0x8b, 0xe3, 0xa0, 0x07, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 0xa1, - 0x81, 0x89, 0x03, 0x81, 0x86, 0x00, 0x04, 0x00, 0x64, 0x27, 0x45, 0x07, - 0x38, 0xbd, 0xd7, 0x1a, 0x87, 0xea, 0x20, 0xfb, 0x93, 0x6f, 0x1c, 0xde, - 0xb3, 0x42, 0xcc, 0xf4, 0x58, 0x87, 0x79, 0x0f, 0x69, 0xaf, 0x5b, 0xff, - 0x72, 0x96, 0x35, 0xb9, 0x6e, 0x8a, 0x55, 0x64, 0x00, 0x44, 0xfe, 0x63, - 0x20, 0x4f, 0x65, 0x3a, 0x3a, 0x47, 0xcf, 0x3a, 0x7f, 0x60, 0x5d, 0xcb, - 0xe6, 0xb4, 0x5a, 0x57, 0x2f, 0xc8, 0x74, 0x62, 0xcf, 0x98, 0x58, 0x33, - 0x59, 0x00, 0xb9, 0xd0, 0xbc, 0x76, 0x2a, 0x37, 0x15, 0x3b, 0x9d, 0x3c, - 0x62, 0xe9, 0xcc, 0x63, 0x00, 0xab, 0x7b, 0x01, 0xb1, 0x00, 0x77, 0x02, - 0x14, 0xdb, 0x5e, 0xb8, 0xda, 0xac, 0x72, 0xf1, 0xd4, 0xa6, 0x17, 0xc5, - 0x12, 0x97, 0x95, 0x6b, 0x98, 0x0b, 0xe0, 0x19, 0xf1, 0xf6, 0xd1, 0x0c, - 0x09, 0xec, 0x1e, 0x2f, 0x51, 0x7a, 0x87, 0x71, 0x3c, 0x63, 0x25, 0x01, - 0x43, 0xc0, 0xa8, 0x52, 0x1f, 0xf9, 0x53 -}; - -static const unsigned char rsa2048_private_key[] = { -#include "t_cose_rsa_test_key.h" -}; - -static const unsigned char ed25519_private_key[] = { - 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, - 0x04, 0x22, 0x04, 0x20, 0x5f, 0xe3, 0x9b, 0x74, 0x55, 0xa0, 0x73, 0xd1, - 0x38, 0xc2, 0xe7, 0xd4, 0xe5, 0x06, 0x30, 0x52, 0x9f, 0xce, 0x7d, 0xdc, - 0xe8, 0x22, 0x80, 0x2a, 0x68, 0x5d, 0xa8, 0x99, 0x16, 0x5d, 0x44, 0x58 -}; - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -/* - * The key object returned by this is malloced and has to be freed by - * by calling free_key_pair(). This heap use is a part of - * OpenSSL and not t_cose which does not use the heap. - */ -enum t_cose_err_t make_key_pair(int32_t cose_algorithm_id, - struct t_cose_key *key_pair) -{ - enum t_cose_err_t return_value; - EVP_PKEY *pkey; - - int key_type; - const uint8_t *key_data; - long key_len; - - switch (cose_algorithm_id) { - case T_COSE_ALGORITHM_ES256: - key_type = EVP_PKEY_EC; - key_data = ec256_key_pair; - key_len = sizeof(ec256_key_pair); - break; - - case T_COSE_ALGORITHM_ES384: - key_type = EVP_PKEY_EC; - key_data = ec384_key_pair; - key_len = sizeof(ec384_key_pair); - break; - - case T_COSE_ALGORITHM_ES512: - key_type = EVP_PKEY_EC; - key_data = ec521_key_pair; - key_len = sizeof(ec521_key_pair); - break; - - case T_COSE_ALGORITHM_PS256: - case T_COSE_ALGORITHM_PS384: - case T_COSE_ALGORITHM_PS512: - key_type = EVP_PKEY_RSA; - key_data = rsa2048_private_key; - key_len = sizeof(rsa2048_private_key); - break; - - case T_COSE_ALGORITHM_EDDSA: - key_type = EVP_PKEY_ED25519; - key_data = ed25519_private_key; - key_len = sizeof(ed25519_private_key); - break; - - default: - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - /* This imports the public key too */ - pkey = d2i_PrivateKey(key_type, NULL, &key_data, key_len); - if(pkey == NULL) { - return_value = T_COSE_ERR_FAIL; - goto Done; - } - - key_pair->k.key_ptr = pkey; - key_pair->crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -void free_key_pair(struct t_cose_key key_pair) -{ - EVP_PKEY_free(key_pair.k.key_ptr); -} - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -int check_for_key_pair_leaks() -{ - /* So far no good way to do this for OpenSSL or malloc() in general - in a nice portable way. The PSA version does check so there is - some coverage of the code even though there is no check here. - */ - return 0; -} diff --git a/3rdparty/internal/t_cose/test/t_cose_make_psa_test_key.c b/3rdparty/internal/t_cose/test/t_cose_make_psa_test_key.c deleted file mode 100644 index 063d0a485904..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_make_psa_test_key.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * t_cose_make_psa_test_key.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -#include "t_cose_make_test_pub_key.h" /* The interface implemented here */ -#include "t_cose_standard_constants.h" -#include "psa/crypto.h" - - -/* - * These are the same keys as in t_cose_make_openssl_test_key.c so that - * messages made with openssl can be verified those made by mbedtls. - * These were made with openssl as detailed in t_cose_make_openssl_test_key.c. - * Then just the private key was pulled out to be put here because - * mbedtls just needs the private key, unlike openssl for which there - * is a full rfc5915 DER structure. These were pulled out of the DER - * by identifying the key with openssl asn1parse and then finding those - * bytes in the C variable holding the rfc5915 (perhaps there is a better - * way, but this works). - */ - - -#define PRIVATE_KEY_prime256v1 \ -0xd9, 0xb5, 0xe7, 0x1f, 0x77, 0x28, 0xbf, 0xe5, 0x63, 0xa9, 0xdc, 0x93, 0x75, \ -0x62, 0x27, 0x7e, 0x32, 0x7d, 0x98, 0xd9, 0x94, 0x80, 0xf3, 0xdc, 0x92, 0x41, \ -0xe5, 0x74, 0x2a, 0xc4, 0x58, 0x89 - -#define PRIVATE_KEY_secp384r1 \ - 0x63, 0x88, 0x1c, 0xbf, \ - 0x86, 0x65, 0xec, 0x39, 0x27, 0x33, 0x24, 0x2e, 0x5a, 0xae, 0x63, 0x3a, \ - 0xf5, 0xb1, 0xb4, 0x54, 0xcf, 0x7a, 0x55, 0x7e, 0x44, 0xe5, 0x7c, 0xca, \ - 0xfd, 0xb3, 0x59, 0xf9, 0x72, 0x66, 0xec, 0x48, 0x91, 0xdf, 0x27, 0x79, \ - 0x99, 0xbd, 0x1a, 0xbc, 0x09, 0x36, 0x49, 0x9c - -#define PRIVATE_KEY_secp521r1 \ -0x00, 0x4b, 0x35, 0x4d, \ -0xa4, 0xab, 0xf7, 0xa5, 0x4f, 0xac, 0xee, 0x06, 0x49, 0x4a, 0x97, 0x0e, \ -0xa6, 0x5f, 0x85, 0xf0, 0x6a, 0x2e, 0xfb, 0xf8, 0xdd, 0x60, 0x9a, 0xf1, \ -0x0b, 0x7a, 0x13, 0xf7, 0x90, 0xf8, 0x9f, 0x49, 0x02, 0xbf, 0x5d, 0x5d, \ -0x71, 0xa0, 0x90, 0x93, 0x11, 0xfd, 0x0c, 0xda, 0x7b, 0x6a, 0x5f, 0x7b, \ -0x82, 0x9d, 0x79, 0x61, 0xe1, 0x6b, 0x31, 0x0a, 0x30, 0x6f, 0x4d, 0xf3, \ -0x8b, 0xe3 - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -enum t_cose_err_t make_key_pair(int32_t cose_algorithm_id, - struct t_cose_key *key_pair) -{ - psa_key_type_t key_type; - psa_status_t crypto_result; - mbedtls_svc_key_id_t key_handle; - psa_algorithm_t key_alg; - const uint8_t *private_key; - size_t private_key_len; - psa_key_attributes_t key_attributes; - - - static const uint8_t private_key_256[] = {PRIVATE_KEY_prime256v1}; - static const uint8_t private_key_384[] = {PRIVATE_KEY_secp384r1}; - static const uint8_t private_key_521[] = {PRIVATE_KEY_secp521r1}; - static const uint8_t private_key_rsa2048[] = { -#include "t_cose_rsa_test_key.h" - }; - - /* There is not a 1:1 mapping from COSE algorithm to key type, but - * there is usually an obvious curve for an algorithm. That - * is what this does. - */ - - switch(cose_algorithm_id) { - case COSE_ALGORITHM_ES256: - private_key = private_key_256; - private_key_len = sizeof(private_key_256); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); - break; - - case COSE_ALGORITHM_ES384: - private_key = private_key_384; - private_key_len = sizeof(private_key_384); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384); - break; - - case COSE_ALGORITHM_ES512: - private_key = private_key_521; - private_key_len = sizeof(private_key_521); - key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); - key_alg = PSA_ALG_ECDSA(PSA_ALG_SHA_512); - break; - - case COSE_ALGORITHM_PS256: - private_key = private_key_rsa2048; - private_key_len = sizeof(private_key_rsa2048); - key_type = PSA_KEY_TYPE_RSA_KEY_PAIR; - key_alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256); - break; - - case COSE_ALGORITHM_PS384: - private_key = private_key_rsa2048; - private_key_len = sizeof(private_key_rsa2048); - key_type = PSA_KEY_TYPE_RSA_KEY_PAIR; - key_alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_384); - break; - - case COSE_ALGORITHM_PS512: - private_key = private_key_rsa2048; - private_key_len = sizeof(private_key_rsa2048); - key_type = PSA_KEY_TYPE_RSA_KEY_PAIR; - key_alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_512); - break; - - default: - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - - /* OK to call this multiple times */ - crypto_result = psa_crypto_init(); - if(crypto_result != PSA_SUCCESS) { - return T_COSE_ERR_FAIL; - } - - - /* When importing a key with the PSA API there are two main things - * to do. - * - * First you must tell it what type of key it is as this cannot be - * discovered from the raw data (because the import is not of a format - * like RFC 5915). The variable key_type contains - * that information including the EC curve. This is sufficient for - * psa_import_key() to succeed, but you probably want actually use - * the key. - * - * Second, you must say what algorithm(s) and operations the key - * can be used as the PSA Crypto Library has policy enforcement. - */ - - key_attributes = psa_key_attributes_init(); - - /* The type of key including the EC curve */ - psa_set_key_type(&key_attributes, key_type); - - /* Say what algorithm and operations the key can be used with/for */ - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_algorithm(&key_attributes, key_alg); - - - /* Import the private key. psa_import_key() automatically - * generates the public key from the private so no need to import - * more than the private key. With ECDSA the public key is always - * deterministically derivable from the private key. - */ - crypto_result = psa_import_key(&key_attributes, - private_key, - private_key_len, - &key_handle); - - if(crypto_result != PSA_SUCCESS) { - return T_COSE_ERR_FAIL; - } - - /* This assignment relies on MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER - * not being defined. If it is defined key_handle is a structure. - * This does not seem to be typically defined as it seems that is - * for a PSA implementation architecture as a service rather than - * an linked library. If it is defined, the structure will - * probably be less than 64 bits, so it can still fit in a - * t_cose_key. */ - key_pair->k.key_handle = key_handle; - key_pair->crypto_lib = T_COSE_CRYPTO_LIB_PSA; - - return T_COSE_SUCCESS; -} - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -void free_key_pair(struct t_cose_key key_pair) -{ - psa_destroy_key((mbedtls_svc_key_id_t)key_pair.k.key_handle); -} - - -/* - * Public function, see t_cose_make_test_pub_key.h - */ -int check_for_key_pair_leaks(void) -{ - /* The key allocation counters are private data structures, but - * they are the only way to do the valuable test for key - * deallocation leakage, so they are used. MbedTLS 3 formally - * labeled them private with a macro. */ -#if MBEDTLS_VERSION_MAJOR < 3 -#define MBEDTLS_PRIVATE(x) x -#endif - - mbedtls_psa_stats_t stats; - - mbedtls_psa_get_stats(&stats); - - return (int)(stats.MBEDTLS_PRIVATE(volatile_slots) + - stats.MBEDTLS_PRIVATE(persistent_slots) + - stats.MBEDTLS_PRIVATE(external_slots) + - stats.MBEDTLS_PRIVATE(half_filled_slots) + - stats.MBEDTLS_PRIVATE(cache_slots)); -} diff --git a/3rdparty/internal/t_cose/test/t_cose_make_test_messages.c b/3rdparty/internal/t_cose/test/t_cose_make_test_messages.c deleted file mode 100644 index 1b22867b9a26..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_make_test_messages.c +++ /dev/null @@ -1,658 +0,0 @@ -/* - * t_cose_make_test_messages.c - * - * Copyright (c) 2019-2022, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose_make_test_messages.h" -#include "qcbor/qcbor.h" -#include "t_cose_crypto.h" -#include "t_cose_util.h" - - -/** - * \file t_cose_make_test_messages.c - * - * This makes \c COSE_Sign1 messages of various sorts for testing - * verification. Some of them are badly formed to test various - * verification failures. - * - * This is essentially a hacked-up version of t_cose_sign1_sign.c. - */ - - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -/** - * \brief Create a short-circuit signature - * - * \param[in] cose_algorithm_id Algorithm ID. This is used only to make - * the short-circuit signature the same size - * as the real signature would be for the - * particular algorithm. - * \param[in] hash_to_sign The bytes to sign. Typically, a hash of - * a payload. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This creates the short-circuit signature that is a concatenation of - * hashes up to the expected size of the signature. This is a test - * mode only has it has no security value. This is retained in - * commercial production code as a useful test or demo that can run - * even if key material is not set up or accessible. - */ -static inline enum t_cose_err_t -short_circuit_sign(int32_t cose_algorithm_id, - struct q_useful_buf_c hash_to_sign, - struct q_useful_buf signature_buffer, - struct q_useful_buf_c *signature) -{ - /* approximate stack use on 32-bit machine: local use: 16 bytes - */ - enum t_cose_err_t return_value; - size_t array_index; - size_t amount_to_copy; - size_t sig_size; - - sig_size = cose_algorithm_id == COSE_ALGORITHM_ES256 ? T_COSE_EC_P256_SIG_SIZE : - cose_algorithm_id == COSE_ALGORITHM_ES384 ? T_COSE_EC_P384_SIG_SIZE : - cose_algorithm_id == COSE_ALGORITHM_ES512 ? T_COSE_EC_P512_SIG_SIZE : - 0; - - /* Check the signature length against buffer size*/ - if(sig_size == 0) { - return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - goto Done; - } - - if(sig_size > signature_buffer.len) { - /* Buffer too small for this signature type */ - return_value = T_COSE_ERR_SIG_BUFFER_SIZE; - goto Done; - } - - /* Loop concatening copies of the hash to fill out to signature size */ - for(array_index = 0; array_index < sig_size; array_index += hash_to_sign.len) { - amount_to_copy = sig_size - array_index; - if(amount_to_copy > hash_to_sign.len) { - amount_to_copy = hash_to_sign.len; - } - memcpy((uint8_t *)signature_buffer.ptr + array_index, - hash_to_sign.ptr, - amount_to_copy); - } - signature->ptr = signature_buffer.ptr; - signature->len = sig_size; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} -#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */ - - -/** - * \brief Makes various protected parameters for various tests - * - * \param[in] test_message_options Flags to select test modes. - * \param[in] cose_algorithm_id The algorithm ID to put in the parameters. - * \param[in] buffer_for_protected_parameters Pointer and length into which - * the resulting encoded protected - * parameters is put. - * - * \return The pointer and length of the protected parameters is - * returned, or \c NULL_Q_USEFUL_BUF_C if this fails. - * - * The protected parameters are returned in fully encoded CBOR format as - * they are added to the \c COSE_Sign1 as a binary string. This is - * different from the unprotected parameters which are not handled this - * way. - * - * This returns \c NULL_Q_USEFUL_BUF_C if buffer_for_protected_parameters was - * too small. See also definition of - * \c T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS. - */ -static inline struct q_useful_buf_c -encode_protected_parameters(uint32_t test_message_options, - int32_t cose_algorithm_id, - struct q_useful_buf buffer_for_protected_parameters) -{ - /* approximate stack use on 32-bit machine: - * local use: 170 - * with calls: 210 - */ - struct q_useful_buf_c protected_parameters; - QCBORError qcbor_result; - QCBOREncodeContext cbor_encode_ctx; - struct q_useful_buf_c return_value; - - if(test_message_options & T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS) { - /* An empty q_useful_buf_c */ - return (struct q_useful_buf_c){buffer_for_protected_parameters.ptr, 0}; - } - - - if(test_message_options & T_COSE_TEST_UNCLOSED_PROTECTED) { - *(uint8_t *)(buffer_for_protected_parameters.ptr) = 0xa1; - return (struct q_useful_buf_c){buffer_for_protected_parameters.ptr, 1}; - } - - QCBOREncode_Init(&cbor_encode_ctx, buffer_for_protected_parameters); - - if(test_message_options & T_COSE_TEST_BAD_PROTECTED) { - QCBOREncode_OpenArray(&cbor_encode_ctx); - QCBOREncode_AddInt64(&cbor_encode_ctx, 42); - QCBOREncode_CloseArray(&cbor_encode_ctx); - goto Finish; - } - - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_OpenMapIndefiniteLength(&cbor_encode_ctx); - } else { - QCBOREncode_OpenMap(&cbor_encode_ctx); - } - QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, - COSE_HEADER_PARAM_ALG, - cose_algorithm_id); - - if(test_message_options & T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER) { - /* This is the parameter that will be unknown */ - QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, 42, 43); - /* This is the critical labels parameter */ - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_OpenArrayIndefiniteLengthInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - } else { - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - } - QCBOREncode_AddInt64(&cbor_encode_ctx, 42); - QCBOREncode_AddInt64(&cbor_encode_ctx, 43); - QCBOREncode_AddInt64(&cbor_encode_ctx, 44); - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_CloseArrayIndefiniteLength(&cbor_encode_ctx); - } else { - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - } - - if(test_message_options & T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER) { - /* This is the parameter that will be unknown */ - QCBOREncode_AddInt64ToMap(&cbor_encode_ctx, "hh", 43); - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - QCBOREncode_AddSZString(&cbor_encode_ctx, "hh"); - QCBOREncode_AddSZString(&cbor_encode_ctx, "h"); - QCBOREncode_AddSZString(&cbor_encode_ctx, "hhh"); - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_BAD_CRIT_LABEL) { - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - QCBOREncode_AddBool(&cbor_encode_ctx, true); - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_CRIT_PARAMETER_EXIST) { - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - int i; - /* Add the maxium */ - for(i = 0; i < T_COSE_PARAMETER_LIST_MAX; i++) { - QCBOREncode_AddInt64(&cbor_encode_ctx, i + 10); - } - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST) { - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - int i; - /* One more than the maximum */ - for(i = 0; i < T_COSE_PARAMETER_LIST_MAX+1; i++) { - QCBOREncode_AddInt64(&cbor_encode_ctx, i + 10); - } - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS) { - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - int i; - /* One more than the maximum */ - for(i = 0; i < T_COSE_PARAMETER_LIST_MAX+1; i++) { - QCBOREncode_AddSZString(&cbor_encode_ctx, ""); - } - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_EMPTY_CRIT_PARAMETER) { - QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - QCBOREncode_CloseArray(&cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_KID_IN_PROTECTED) { - QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, - COSE_HEADER_PARAM_KID, - Q_USEFUL_BUF_FROM_SZ_LITERAL("kid")); - } - - if(test_message_options & T_COSE_TEST_DUP_CONTENT_ID) { - QCBOREncode_AddUInt64ToMapN(&cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - 3); - } - - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_CloseMapIndefiniteLength(&cbor_encode_ctx); - } else { - QCBOREncode_CloseMap(&cbor_encode_ctx); - } - -Finish: - qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_parameters); - - if(qcbor_result == QCBOR_SUCCESS) { - return_value = protected_parameters; - } else { - return_value = NULL_Q_USEFUL_BUF_C; - } - - return return_value; -} - - -/** - * \brief Add the unprotected parameters to a CBOR encoding context - * - * \param[in] test_message_options Flags to select test modes. - * \param[in] cbor_encode_ctx CBOR encoding context to output to. - * \param[in] kid The key ID to go into the kid parameter. - * - * No error is returned. If an error occurred it will be returned when - * \c QCBOR_Finish() is called on \c cbor_encode_ctx. - * - * The unprotected parameters added by this are the key ID plus - * lots of different test parameters. - */ -static inline void -add_unprotected_parameters(uint32_t test_message_options, - QCBOREncodeContext *cbor_encode_ctx, - struct q_useful_buf_c kid) -{ - if(test_message_options & T_COSE_TEST_UNPROTECTED_NOT_MAP) { - QCBOREncode_OpenArray(cbor_encode_ctx); - QCBOREncode_AddBytes(cbor_encode_ctx, kid); - QCBOREncode_CloseArray(cbor_encode_ctx); - return; /* skip the rest for this degenerate test */ - } - - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_OpenMapIndefiniteLength(cbor_encode_ctx); - } else { - QCBOREncode_OpenMap(cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_NOT_WELL_FORMED_1) { - QCBOREncode_AddEncoded(cbor_encode_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("xxxxxx")); - } - - /* Put in a byte string (not a text string) for the parameter label */ - if(test_message_options & T_COSE_TEST_PARAMETER_LABEL) { - QCBOREncode_AddBytes(cbor_encode_ctx, kid); - QCBOREncode_AddBytes(cbor_encode_ctx, kid); - } - - if(test_message_options & T_COSE_TEST_BAD_CRIT_PARAMETER) { - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CRIT, "hi"); - } - - if(test_message_options & T_COSE_TEST_EXTRA_PARAMETER) { - QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55); - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi"); - QCBOREncode_CloseMap(cbor_encode_ctx); - QCBOREncode_CloseArray(cbor_encode_ctx); - } - - - if(test_message_options & T_COSE_TEST_NOT_WELL_FORMED_2) { - QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55); - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi"); - /* 0xff is a break outside of anything indefinite and thus - * not-well-formed, This test used to use a 0x3d before - * spiffy decode, but spiffy decode can traverse that - * without error because it is not an - * QCBORDecode_IsUnrecoverableError(). - * Improvement: add a test case for the 3d error back in - */ - QCBOREncode_AddEncoded(cbor_encode_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("\xff")); - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 67, "bye"); - - QCBOREncode_CloseMap(cbor_encode_ctx); - QCBOREncode_CloseArray(cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_CRIT_NOT_PROTECTED) { - /* This is the critical labels parameter */ - QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, COSE_HEADER_PARAM_CRIT); - int i; - /* Add the maxium */ - for(i = 0; i < T_COSE_PARAMETER_LIST_MAX; i++) { - QCBOREncode_AddInt64(cbor_encode_ctx, i + 100); - QCBOREncode_AddSZString(cbor_encode_ctx, "xxxx"); - } - QCBOREncode_CloseArray(cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_TOO_MANY_UNKNOWN) { - int i; - for(i = 0; i < T_COSE_PARAMETER_LIST_MAX + 1; i++ ) { - QCBOREncode_AddBoolToMapN(cbor_encode_ctx, i+10, true); - } - } - - if(!q_useful_buf_c_is_null_or_empty(kid)) { - QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid); - } - - if(test_message_options & T_COSE_TEST_ALL_PARAMETERS) { - QCBOREncode_AddBytesToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_IV, - Q_USEFUL_BUF_FROM_SZ_LITERAL("iv")); - QCBOREncode_AddBytesToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_PARTIAL_IV, - Q_USEFUL_BUF_FROM_SZ_LITERAL("partial_iv")); - QCBOREncode_AddInt64ToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - 1); - /* A slighly complex unknown header parameter */ - QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55); - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi"); - QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 67, "bye"); - QCBOREncode_CloseMap(cbor_encode_ctx); - QCBOREncode_OpenArray(cbor_encode_ctx); - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_CloseMap(cbor_encode_ctx); - QCBOREncode_CloseArray(cbor_encode_ctx); - QCBOREncode_CloseArray(cbor_encode_ctx); - } - - if(test_message_options & T_COSE_TEST_TOO_LARGE_CONTENT_TYPE) { - QCBOREncode_AddInt64ToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - UINT16_MAX+1); - } - - if(test_message_options & T_COSE_TEST_DUP_CONTENT_ID) { - QCBOREncode_AddUInt64ToMapN(cbor_encode_ctx, - COSE_HEADER_PARAM_CONTENT_TYPE, - 3); - } - - if(test_message_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_CloseMapIndefiniteLength(cbor_encode_ctx); - } else { - QCBOREncode_CloseMap(cbor_encode_ctx); - } -} - - -/* - * Buffer for the protected parameters. There used to be a buffer in - * t_cose_sign1_sign_ctx but it was removed when code was improved. - * This needs to be carried between encoding the header and doing - * the signatured, so a buffer is needed. The size is that of the - * largest test protected header and some padding. - */ -static uint8_t s_protected_params[40]; - -/** - * Replica of t_cose_sign1_encode_parameters() with modifications to - * output various good and bad messages for testing verification. - */ -static enum t_cose_err_t -t_cose_sign1_test_message_encode_parameters(struct t_cose_sign1_sign_ctx *me, - uint32_t test_mess_options, - QCBOREncodeContext *cbor_encode_ctx) -{ - enum t_cose_err_t return_value; - struct q_useful_buf_c kid; - int32_t hash_alg_id; - struct q_useful_buf buffer_for_protected_parameters; - - - /* Check the cose_algorithm_id now by getting the hash alg as an early - * error check even though it is not used until later. - */ - hash_alg_id = hash_alg_id_from_sig_alg_id(me->cose_algorithm_id); - if(hash_alg_id == T_COSE_INVALID_ALGORITHM_ID) { - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - /* Add the CBOR tag indicating COSE_Sign1 */ - if(!(me->option_flags & T_COSE_OPT_OMIT_CBOR_TAG)) { - QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1); - } - - /* Get started with the tagged array that holds the four parts of - * a cose single signed message */ - if(test_mess_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_OpenArrayIndefiniteLength(cbor_encode_ctx); - } else { - QCBOREncode_OpenArray(cbor_encode_ctx); - } - - /* The protected parameters, which are added as a wrapped bstr */ - if( ! (test_mess_options & T_COSE_TEST_NO_PROTECTED_PARAMETERS)) { - buffer_for_protected_parameters = Q_USEFUL_BUF_FROM_BYTE_ARRAY(s_protected_params); - - me->protected_parameters = encode_protected_parameters(test_mess_options, - me->cose_algorithm_id, - buffer_for_protected_parameters); - QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_parameters); - } - - /* The Unprotected parameters */ - /* Get the key id because it goes into the parameters that are about - to be made. */ - if(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG) { -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - kid = get_short_circuit_kid(); -#else - return T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED; -#endif - } else { - kid = me->kid; - } - - if( ! (test_mess_options & T_COSE_TEST_NO_UNPROTECTED_PARAMETERS)) { - add_unprotected_parameters(test_mess_options, cbor_encode_ctx, kid); - } - - QCBOREncode_BstrWrap(cbor_encode_ctx); - - /* Any failures in CBOR encoding will be caught in finish when the - * CBOR encoding is closed off. No need to track here as the CBOR - * encoder tracks it internally. */ - - return_value = T_COSE_SUCCESS; - - return return_value; -} - - -/** - * Replica of t_cose_sign1_output_signature() with modifications to - * output various good and bad messages for testing verification. - */ -static enum t_cose_err_t -t_cose_sign1_test_message_output_signature(struct t_cose_sign1_sign_ctx *me, - uint32_t test_mess_options, - QCBOREncodeContext *cbor_encode_ctx) -{ - /* approximate stack use on 32-bit machine: - * 32 bytes local use - * 220 to 434 for calls dependin on hash implementation - * 32 to 64 bytes depending on hash alg (SHA256, 384 or 512) - * 64 to 260 depending on EC alg - * 348 to 778 depending on hash and EC alg - * Also add stack use by EC and hash functions - */ - enum t_cose_err_t return_value; - QCBORError cbor_err; - /* pointer and length of the completed tbs hash */ - struct q_useful_buf_c tbs_hash; - /* Pointer and length of the completed signature */ - struct q_useful_buf_c signature; - /* Pointer and length of the buffer for the signature */ - struct q_useful_buf buffer_for_signature; - /* Buffer for the tbs hash. */ - Q_USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE); - struct q_useful_buf_c signed_payload; - - QCBOREncode_CloseBstrWrap2(cbor_encode_ctx, false, &signed_payload); - - /* Check there are no CBOR encoding errors before proceeding with - * hashing and signing. This is not actually necessary as the - * errors will be caught correctly later, but it does make it a - * bit easier for the caller to debug problems. - */ - cbor_err = QCBOREncode_GetErrorState(cbor_encode_ctx); - if(cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) { - return_value = T_COSE_ERR_TOO_SMALL; - goto Done; - } else if(cbor_err != QCBOR_SUCCESS) { - return_value = T_COSE_ERR_CBOR_FORMATTING; - goto Done; - } - - /* Create the hash of the to-be-signed bytes. Inputs to the hash - * are the protected parameters, the payload that is getting signed, the - * cose signature alg from which the hash alg is determined. The - * cose_algorithm_id was checked in t_cose_sign1_init() so it - * doesn't need to be checked here. - */ - return_value = create_tbs_hash(me->cose_algorithm_id, - me->protected_parameters, - NULL_Q_USEFUL_BUF_C, - signed_payload, - buffer_for_tbs_hash, - &tbs_hash); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* The signature gets written directly into the output buffer. - * The matching QCBOREncode_CloseBytes call further down still needs do a - * memmove to make space for the CBOR header, but at least we avoid the need - * to allocate an extra buffer. - */ - QCBOREncode_OpenBytes(cbor_encode_ctx, &buffer_for_signature); - - /* Compute the signature using public key crypto. The key selector - * and algorithm ID are passed in to know how and what to sign - * with. The hash of the TBS bytes are what is signed. A buffer in - * which to place the signature is passed in and the signature is - * returned. - * - * Short-circuit signing is invoked if requested. It does no - * public key operation and requires no key. It is just a test - * mode that always works. - */ - if(!(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG)) { - /* Normal, non-short-circuit signing */ - return_value = t_cose_crypto_sign(me->cose_algorithm_id, - me->signing_key, - tbs_hash, - buffer_for_signature, - &signature); - } else { -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN - return_value = short_circuit_sign(me->cose_algorithm_id, - tbs_hash, - buffer_for_signature, - &signature); -#endif - } - - if(return_value) { - goto Done; - } - - /* Add signature to CBOR and close out the array */ - QCBOREncode_CloseBytes(cbor_encode_ctx, signature.len); - - if(test_mess_options & T_COSE_TEST_INDEFINITE_MAPS_ARRAYS) { - QCBOREncode_CloseArrayIndefiniteLength(cbor_encode_ctx); - } else { - QCBOREncode_CloseArray(cbor_encode_ctx); - } - - /* The layer above this must check for and handle CBOR encoding - * errors CBOR encoding errors. Some are detected at the start of - * this function, but they cannot all be deteced there. - */ -Done: - return return_value; -} - - -/* - * Public function. See t_cose_make_test_messages.h - */ -enum t_cose_err_t -t_cose_test_message_sign1_sign(struct t_cose_sign1_sign_ctx *me, - uint32_t test_message_options, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result) -{ - QCBOREncodeContext encode_context; - enum t_cose_err_t return_value; - - /* -- Initialize CBOR encoder context with output buffer */ - QCBOREncode_Init(&encode_context, out_buf); - - /* -- Output the header parameters into the encoder context -- */ - return_value = t_cose_sign1_test_message_encode_parameters(me, test_message_options, &encode_context); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* -- Output the payload into the encoder context -- */ - /* Payload may or may not actually be CBOR format here. This - * function does the job just fine because it just adds bytes to - * the encoded output without anything extra. - */ - QCBOREncode_AddEncoded(&encode_context, payload); - - /* -- Sign and put signature in the encoder context -- */ - return_value = t_cose_sign1_test_message_output_signature(me, - test_message_options, - &encode_context); - if(return_value) { - goto Done; - } - - /* -- Close off and get the resulting encoded CBOR -- */ - if(QCBOREncode_Finish(&encode_context, result)) { - return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED; - goto Done; - } - -Done: - return return_value; -} - diff --git a/3rdparty/internal/t_cose/test/t_cose_make_test_messages.h b/3rdparty/internal/t_cose/test/t_cose_make_test_messages.h deleted file mode 100644 index 9b86e243ba0d..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_make_test_messages.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * t_cose_make_test_messages.h - * - * Copyright (c) 2019-2022, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_MAKE_TEST_MESSAGES__ -#define __T_COSE_MAKE_TEST_MESSAGES__ - - -#include -#include -#include "qcbor/qcbor.h" -#include "t_cose/t_cose_common.h" -#include "t_cose/t_cose_sign1_sign.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * \file t_cose_make_test_messages.h - * - * \brief Create a test \c COSE_Sign1 message for testing the verifier. - * - */ - - -/** - * Various flags to pass to t_cose_test_message_sign1_sign() to - * make different types of test messages for testing verification - */ - - -/** Make test message with a bstr label, which is not allowed by - * COSE */ -#define T_COSE_TEST_PARAMETER_LABEL 0x80000000U - -/** Format of the crit parameter is made invalid */ -#define T_COSE_TEST_BAD_CRIT_PARAMETER 0x40000000 - -/** An extra parameter is added. It has nested structure to be sure - * such are skipped correctly */ -#define T_COSE_TEST_EXTRA_PARAMETER 0x20000000 - -/** The protected parameters bucked is left out of the COSE_Sign1 - * message entirely */ -#define T_COSE_TEST_NO_PROTECTED_PARAMETERS 0x10000000 - -/** The unprotected parameters bucked is left out of the COSE_Sign1 - * message entirely */ -#define T_COSE_TEST_NO_UNPROTECTED_PARAMETERS 0x08000000 - -/** Simple not-well-formed CBOR is added to the unprotected parameters - * bucket */ -#define T_COSE_TEST_NOT_WELL_FORMED_1 0x04000000 - -/** Not-well-formed CBOR nested in a map is added to the unprotected - * parameters bucket */ -#define T_COSE_TEST_NOT_WELL_FORMED_2 0x02000000 - -/** The crit parameter lists several integer critical labels and the - * labeled parameters exists and they are not understood */ -#define T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER 0x01000000 - -/** The crit parameter lists critical labels, but none of them - * occur */ -#define T_COSE_TEST_CRIT_PARAMETER_EXIST 0x00800000 - -/** Exceed the limit on number of T_COSE_PARAMETER_LIST_MAX on number - * of crit parameters this implementation can handle */ -#define T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST 0x00400000 - -/** One of the labels in the crit parameter is of the wrong type */ -#define T_COSE_TEST_BAD_CRIT_LABEL 0x00200000 - -/** The crit parameter is in the unprotected bucket */ -#define T_COSE_TEST_CRIT_NOT_PROTECTED 0x00100000 - -/** More than T_COSE_PARAMETER_LIST_MAX unknown parameters occurred */ -#define T_COSE_TEST_TOO_MANY_UNKNOWN 0x00080000 - -/** The crit parameter lists several text string critical labels and - * the labeled parameters exists and they are not understood */ -#define T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER 0x00040000 - -/** One of each type of parameter the verify handles is added, plus - * some unknown parameters */ -#define T_COSE_TEST_ALL_PARAMETERS 0x00020000 - -/** An invalid CBOR type is in the protected bucket */ -#define T_COSE_TEST_BAD_PROTECTED 0x00010000 - -/** The unprotected header bucket is an array, not a map */ -#define T_COSE_TEST_UNPROTECTED_NOT_MAP 0x00008000 - -/** A kid is added to the protected parameters and is thus a duplicate - * parameter in both protected and unprotected buckets */ -#define T_COSE_TEST_KID_IN_PROTECTED 0x00004000 - -/** The integer CoAP content type is larger than UINT16_MAX, larger - * than it is allowed */ -#define T_COSE_TEST_TOO_LARGE_CONTENT_TYPE 0x00002000 - -/** The protected parameters are not a complete map. Supposed to have - * 1 item, but has zero */ -#define T_COSE_TEST_UNCLOSED_PROTECTED 0x00001000 - -/** The content ID parameter occurs in both protected and unprotected - * bucket */ -#define T_COSE_TEST_DUP_CONTENT_ID 0x00000800 - -/** The bstr wrapped protected parameters is zero length */ -#define T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS 0x00000400 - -/** The list of critical labels parameter is empty. This is not - * allowed by COSE */ -#define T_COSE_TEST_EMPTY_CRIT_PARAMETER 0x00000200 - -/** Exceed the limit on number of T_COSE_PARAMETER_LIST_MAX on number - * of crit parameters this implementation can handle */ -#define T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS 0x00000100 - -/** Encode the COSE maps and arrays with indefinte lengths rather - * than definite. */ -#define T_COSE_TEST_INDEFINITE_MAPS_ARRAYS 0x80 - - -/** - * Replica of t_cose_sign1_sign() with modifications to output various - * good and bad messages for testing of t_cose_sign1_verify() . - * - * \c test_message_options is one of \c T_COSE_TEST_XXX - */ -enum t_cose_err_t -t_cose_test_message_sign1_sign(struct t_cose_sign1_sign_ctx *me, - uint32_t test_message_options, - struct q_useful_buf_c payload, - struct q_useful_buf out_buf, - struct q_useful_buf_c *result); - - -#ifdef __cplusplus -} -#endif - -#endif /* __T_COSE_MAKE_TEST_MESSAGES__ */ diff --git a/3rdparty/internal/t_cose/test/t_cose_make_test_pub_key.h b/3rdparty/internal/t_cose/test/t_cose_make_test_pub_key.h deleted file mode 100644 index bb3dec01e76d..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_make_test_pub_key.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * t_cose_make_test_pub_key.h - * - * Copyright 2019-2020, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose/t_cose_common.h" -#include - -/** - * \file t_cose_make_test_pub_key.h - * - * \brief This defines a simple interface to make keys for tests cases. - * - */ - - -/** - * \brief make a key pair for testing suited to algorithm - * - */ -enum t_cose_err_t make_key_pair(int32_t cose_algorithm_id, - struct t_cose_key *key_pair); - - -void free_key_pair(struct t_cose_key key_pair); - - -/** - \brief Called by test frame work to see if there were key pair or mem leaks. - - \return 0 if no leaks, non-zero if there is a leak. - */ -int check_for_key_pair_leaks(void); - - - diff --git a/3rdparty/internal/t_cose/test/t_cose_rsa_test_key.h b/3rdparty/internal/t_cose/test/t_cose_rsa_test_key.h deleted file mode 100644 index 54b3d6656b8f..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_rsa_test_key.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * t_cose_rsa_test_key.h - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - - -/** - * An RSA private key in PKCS #1 (RFC 8017) format. - * - * This was generated by: - * - * openssl genrsa 2048 | sed -e '1d' -e '$d' | base64 --decode | xxd -i - * - * This file is used whether mbedtls or OpenSSL is used. - * - * On its own, the file is not itself valid C, and must be wrapped in a variable - * definition before being included. - */ -0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, -0x9e, 0x4e, 0x3b, 0x05, 0xb4, 0x33, 0xe5, 0x49, 0x68, 0xdc, 0x64, 0xa0, -0x4e, 0x2c, 0x63, 0xd8, 0x11, 0x25, 0x7c, 0xe0, 0x63, 0xb6, 0x64, 0x89, -0x0b, 0xbd, 0xcd, 0x62, 0x30, 0xd4, 0x52, 0xa2, 0x52, 0xe0, 0x61, 0x84, -0xee, 0xf9, 0x6e, 0x14, 0x9f, 0x9e, 0x0e, 0xee, 0x67, 0x51, 0x09, 0xa9, -0x15, 0x05, 0x07, 0x17, 0x09, 0x93, 0x76, 0x87, 0x45, 0x2b, 0x89, 0xfd, -0x7c, 0xa7, 0xfa, 0xfc, 0x1b, 0x7b, 0x6e, 0xbb, 0x5f, 0xfc, 0x8a, 0xca, -0xc9, 0x14, 0xb4, 0xd0, 0xe8, 0x91, 0xb1, 0x60, 0xe8, 0x89, 0x54, 0xe0, -0x06, 0x0b, 0x59, 0xff, 0x90, 0x12, 0x34, 0x47, 0xd7, 0xbf, 0x82, 0xa8, -0x48, 0x77, 0x46, 0x56, 0x2c, 0xfb, 0x84, 0x00, 0x01, 0xdb, 0x6b, 0x14, -0xe2, 0x5a, 0xc7, 0x77, 0x3c, 0x8e, 0x48, 0x59, 0x21, 0xc6, 0x7a, 0x28, -0x17, 0x3f, 0xfa, 0xe1, 0xea, 0xc4, 0x6f, 0xa0, 0x0d, 0xf0, 0x04, 0x5a, -0x29, 0x97, 0x2e, 0x96, 0x35, 0x25, 0xba, 0x0a, 0x39, 0x51, 0x9e, 0x1d, -0x64, 0x95, 0xad, 0xc8, 0xc1, 0xa6, 0xfd, 0x61, 0xa1, 0x56, 0x40, 0x96, -0x85, 0x42, 0x83, 0x1e, 0x8f, 0xc8, 0xfa, 0x70, 0x2b, 0xea, 0xbd, 0xe6, -0x2d, 0x6f, 0x6a, 0x73, 0x00, 0x2a, 0x8f, 0x8e, 0x2c, 0x28, 0xdb, 0xc0, -0xa0, 0x23, 0x37, 0x6f, 0x67, 0xe3, 0x3d, 0x8f, 0xe6, 0x12, 0xbe, 0x8c, -0xdf, 0x67, 0xfb, 0xbf, 0xe2, 0x80, 0xd0, 0xdf, 0xe0, 0xf9, 0x68, 0xeb, -0x7f, 0x37, 0x4f, 0x17, 0xb8, 0x1e, 0x06, 0x46, 0x1a, 0x47, 0x6b, 0xd3, -0x40, 0x2c, 0x9a, 0xd1, 0xc5, 0x5c, 0xd2, 0x59, 0xad, 0x78, 0x82, 0x1b, -0x07, 0x49, 0x0e, 0x70, 0xa4, 0x69, 0x0c, 0xac, 0xf4, 0x78, 0x2e, 0x2d, -0x3e, 0x94, 0xc2, 0x3b, 0x80, 0xbc, 0x88, 0x91, 0xc9, 0xfe, 0x06, 0x1c, -0x19, 0xe3, 0x22, 0xbf, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, -0x00, 0x57, 0x8b, 0x07, 0x94, 0xc5, 0xec, 0x94, 0xf5, 0x9d, 0xa9, 0x93, -0x74, 0x1b, 0x06, 0xed, 0x48, 0x05, 0x63, 0x67, 0xc5, 0x67, 0x1e, 0xec, -0x45, 0xe5, 0x5a, 0x57, 0x03, 0xdf, 0xe0, 0xea, 0xb9, 0x9d, 0x7f, 0x3c, -0x2e, 0x99, 0x41, 0x12, 0xa1, 0x11, 0x0c, 0x05, 0x51, 0xcd, 0x8c, 0xc0, -0xfc, 0xe2, 0x04, 0xdf, 0xc0, 0xdb, 0xa8, 0xd2, 0xb9, 0x47, 0x85, 0x26, -0x50, 0x29, 0xe9, 0x73, 0x20, 0x8b, 0xca, 0x1c, 0x98, 0x3e, 0x22, 0x98, -0x56, 0x40, 0x10, 0xd5, 0x55, 0x59, 0xe7, 0x87, 0xe2, 0x01, 0x76, 0x40, -0x9b, 0x8a, 0x7c, 0x28, 0x8e, 0xed, 0x8b, 0x43, 0xa2, 0x1f, 0x2b, 0x67, -0x03, 0xcc, 0xdf, 0x38, 0xe4, 0x5b, 0x07, 0xd4, 0x1d, 0x74, 0xe9, 0x74, -0x34, 0x1e, 0x60, 0xf9, 0x41, 0x75, 0x19, 0x71, 0xe4, 0xe8, 0x8a, 0xab, -0xef, 0x13, 0xbc, 0x6b, 0xef, 0x17, 0x36, 0xfe, 0x4a, 0xf3, 0xe6, 0x17, -0x45, 0xd5, 0xfd, 0x7b, 0x82, 0xc6, 0x35, 0x72, 0x77, 0x91, 0x3d, 0x05, -0xd4, 0x00, 0xa3, 0x0d, 0xd5, 0x9a, 0x4e, 0x6b, 0xf4, 0x6f, 0xd5, 0xe9, -0x31, 0x58, 0x3e, 0x01, 0xfc, 0x7e, 0x7a, 0x80, 0x8f, 0x1e, 0x78, 0xbc, -0x31, 0x23, 0x03, 0x6a, 0x30, 0x31, 0x4e, 0xbb, 0x0e, 0x8f, 0xed, 0x26, -0x8d, 0x2d, 0x29, 0xc9, 0x83, 0xb8, 0x57, 0x39, 0x90, 0xd0, 0x43, 0x51, -0xb6, 0xf8, 0x5c, 0x20, 0xbe, 0x8e, 0x5d, 0xed, 0xde, 0x82, 0xe7, 0x0a, -0xf2, 0x7f, 0x76, 0x8c, 0x9d, 0x8a, 0x76, 0xa5, 0xb3, 0x63, 0x59, 0x4a, -0xcb, 0x90, 0x2b, 0x5f, 0xa4, 0xb9, 0x63, 0x10, 0x12, 0xaa, 0xa8, 0x87, -0xed, 0x60, 0x06, 0x2d, 0x1f, 0x0f, 0xad, 0x19, 0xde, 0xd0, 0xff, 0x6f, -0x2c, 0xc2, 0x4c, 0x9e, 0x1f, 0x89, 0xc8, 0x18, 0xa0, 0x42, 0xad, 0xa0, -0xa0, 0x37, 0x17, 0x68, 0x01, 0x02, 0x81, 0x81, 0x00, 0xcf, 0xcd, 0x4a, -0x0e, 0xcb, 0xe9, 0x19, 0x57, 0x2d, 0x42, 0x8a, 0xbf, 0xf9, 0x9b, 0xbc, -0xe1, 0x45, 0x87, 0x1c, 0xbe, 0xc4, 0x64, 0x9b, 0xbb, 0x40, 0x0c, 0xc5, -0x34, 0xbe, 0xbf, 0xcf, 0x6c, 0xc1, 0x4c, 0x5d, 0x72, 0x6b, 0x3f, 0xdf, -0x0c, 0x81, 0x7b, 0x2c, 0x30, 0xbf, 0x93, 0x49, 0x99, 0x28, 0xb1, 0x88, -0xf9, 0x76, 0x13, 0x6d, 0xe3, 0x1a, 0x85, 0xcf, 0x34, 0x77, 0x72, 0x76, -0x70, 0xe9, 0xe5, 0x5e, 0xc6, 0x1d, 0x7f, 0xec, 0x11, 0x6e, 0xf8, 0x50, -0x9d, 0xb3, 0x04, 0xd9, 0x0c, 0xc3, 0xf5, 0x40, 0x98, 0x8c, 0x77, 0x96, -0x89, 0x69, 0x10, 0xb3, 0xa8, 0x43, 0x99, 0x95, 0xc8, 0x6c, 0x21, 0x16, -0x36, 0x33, 0xf8, 0x6c, 0x4b, 0x99, 0x24, 0x64, 0x93, 0xbb, 0xbf, 0xa5, -0x3f, 0xed, 0xd4, 0x66, 0x9c, 0x3e, 0xd6, 0xf9, 0x62, 0x43, 0x41, 0xe5, -0xaf, 0xfe, 0x8e, 0x98, 0xbf, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x05, 0xfc, -0x0e, 0xaa, 0x94, 0x58, 0xbe, 0x92, 0xdb, 0x0e, 0x89, 0x30, 0x18, 0x7e, -0xa2, 0x2c, 0x5f, 0x16, 0xad, 0x9f, 0xd2, 0x4b, 0x40, 0x8d, 0x60, 0x30, -0xfa, 0x9b, 0xaa, 0xcb, 0x20, 0xcd, 0x18, 0x63, 0x1d, 0x51, 0xda, 0xb3, -0x61, 0xb1, 0xcc, 0x82, 0x45, 0x2a, 0x84, 0x82, 0x7b, 0xb5, 0xc1, 0x0c, -0xd4, 0xe5, 0xe4, 0x0f, 0x03, 0xe7, 0x92, 0x48, 0x24, 0x85, 0x4c, 0xa6, -0x02, 0xd3, 0x7b, 0xe8, 0xb8, 0x9e, 0xf4, 0x92, 0xb9, 0x55, 0x71, 0x2e, -0x80, 0x45, 0x7c, 0x80, 0x62, 0x20, 0x1b, 0x9a, 0xbb, 0x18, 0x36, 0x36, -0x5d, 0x69, 0xf0, 0xea, 0x41, 0x5c, 0x4c, 0x75, 0x5c, 0x62, 0xc9, 0x4f, -0xae, 0xb0, 0xad, 0x98, 0xc5, 0x03, 0xf2, 0xf9, 0xde, 0x1f, 0x01, 0xe9, -0x1e, 0x3d, 0xe8, 0xf8, 0x84, 0xaf, 0x49, 0x61, 0x2f, 0x4e, 0x20, 0xb4, -0x18, 0x79, 0xb3, 0xf6, 0x01, 0x02, 0x81, 0x80, 0x72, 0xe2, 0x03, 0xf7, -0x7a, 0x34, 0x3c, 0x96, 0x3d, 0xa7, 0x74, 0x1d, 0xfe, 0x59, 0x63, 0x6b, -0x07, 0x8d, 0x53, 0x0f, 0x04, 0x74, 0xba, 0xc4, 0x22, 0xfc, 0xec, 0x69, -0xe4, 0xab, 0x16, 0x7a, 0x01, 0xc3, 0xbe, 0x45, 0xeb, 0x95, 0x3c, 0x33, -0x25, 0xc2, 0x7b, 0x03, 0xd8, 0x66, 0x0d, 0x62, 0x67, 0x64, 0xff, 0x5d, -0x2b, 0x32, 0x42, 0xa6, 0x33, 0x9b, 0x96, 0x9a, 0x63, 0x0f, 0x1c, 0xfb, -0xff, 0xd3, 0x97, 0x39, 0xe0, 0x45, 0x40, 0xb5, 0xc2, 0xab, 0xf5, 0xa5, -0xb9, 0xbb, 0x0c, 0x64, 0x4a, 0x51, 0xe4, 0x8c, 0x71, 0xdc, 0x0b, 0x95, -0x9c, 0x48, 0x67, 0x8a, 0xb7, 0x14, 0xca, 0x02, 0x2c, 0x05, 0x7e, 0xca, -0x28, 0xa1, 0x46, 0xfd, 0xe4, 0x84, 0x82, 0x36, 0x4a, 0xae, 0x01, 0x25, -0xfe, 0xce, 0x56, 0x8c, 0x3b, 0x11, 0x8e, 0x7e, 0x0c, 0xc0, 0xf9, 0xc2, -0xfa, 0xf0, 0xca, 0xf1, 0x02, 0x81, 0x80, 0x61, 0x53, 0x61, 0x40, 0xe8, -0x7b, 0xf3, 0xf5, 0xd7, 0x50, 0x1e, 0xe6, 0xf3, 0xeb, 0xa5, 0x76, 0xc5, -0x72, 0x06, 0xdd, 0x4a, 0xff, 0x25, 0xb2, 0xe7, 0x5a, 0xf3, 0xd6, 0x7d, -0x4d, 0x34, 0xe5, 0xff, 0xb4, 0x85, 0xf2, 0x21, 0xe1, 0x64, 0xd8, 0x02, -0x65, 0x2f, 0x35, 0xd9, 0x4c, 0x1b, 0xda, 0x25, 0x10, 0x5c, 0x98, 0xfa, -0xc9, 0x5f, 0x7c, 0xf1, 0x5a, 0x1d, 0x4a, 0xac, 0x83, 0x5d, 0xed, 0xd7, -0x20, 0xe5, 0x39, 0x0d, 0x8a, 0xbc, 0x96, 0x65, 0x3f, 0x80, 0x97, 0x5f, -0x16, 0x0c, 0xf3, 0xeb, 0x56, 0x1b, 0x57, 0xf7, 0x73, 0x46, 0x9a, 0x43, -0xbe, 0x89, 0x09, 0x69, 0x48, 0x76, 0xe1, 0x4e, 0x23, 0x6c, 0xf2, 0x9f, -0x15, 0x63, 0x42, 0x1f, 0x00, 0x69, 0x16, 0x22, 0x9f, 0x4f, 0x79, 0x5a, -0x28, 0x23, 0xae, 0x03, 0xd4, 0x38, 0xfd, 0xe4, 0x9d, 0x89, 0x83, 0x15, -0x69, 0x6c, 0x01, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x8d, 0xfa, 0x78, 0xed, -0xb8, 0x99, 0xd3, 0xee, 0xd0, 0xbd, 0x74, 0xf3, 0x6e, 0xd1, 0xb4, 0x37, -0xc0, 0x89, 0x6c, 0xf0, 0x69, 0xbc, 0xbe, 0x5c, 0xd4, 0x6a, 0xa5, 0xba, -0x39, 0x3e, 0x68, 0x87, 0xeb, 0x35, 0x6d, 0x24, 0x3c, 0x3f, 0x11, 0xcd, -0x31, 0x60, 0x8b, 0xb6, 0x7f, 0x6c, 0x42, 0xe3, 0x8d, 0xc3, 0x90, 0x79, -0x9a, 0xba, 0x1c, 0xac, 0x72, 0x5d, 0x05, 0x8a, 0x50, 0x87, 0x34, 0x67, -0xba, 0x19, 0x2c, 0xd6, 0x9b, 0x3f, 0xd7, 0x32, 0x4f, 0x60, 0x9e, 0x19, -0x00, 0x1e, 0x29, 0xfd, 0x8f, 0xcd, 0xec, 0x75, 0xcd, 0x42, 0xcc, 0x5f, -0xad, 0x42, 0xa3, 0xf6, 0xc5, 0x5a, 0x14, 0xaa, 0x9f, 0x75, 0xe6, 0x13, -0x96, 0xdf, 0x73, 0xcd, 0xd8, 0x8b, 0x02, 0x9c, 0xeb, 0xa5, 0x2f, 0x06, -0x12, 0xc3, 0x0c, 0xf3, 0xbb, 0x9f, 0x16, 0xdb, 0xe6, 0xd2, 0x78, 0x58, -0x35, 0xb7, 0x4b diff --git a/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.c b/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.c deleted file mode 100644 index a2e1eae6b1e0..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.c +++ /dev/null @@ -1,976 +0,0 @@ -/* - * t_cose_sign_verify_test.c - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include -#include "t_cose/t_cose_sign1_sign.h" -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose_make_test_pub_key.h" -#include "t_cose_sign_verify_test.h" - -#include "t_cose_crypto.h" /* Just for t_cose_crypto_sig_size() */ - -/* These are complete known-good COSE messages for a verification - * test. The key used to verify them is made by make_key_pair(). - * It always makes the same key for both MbedTLS and OpenSSL. - * - * These were made by setting a break point in sign_verify_basic_test() - * and copying the output of the signing. - */ -static const uint8_t signed_cose_made_by_ossl_crypto_es256[] = { - 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA0, 0x47, - 0x70, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64, 0x58, - 0x40, 0xF2, 0x2B, 0xAE, 0x15, 0xA8, 0xA6, 0x7A, - 0x60, 0x6B, 0x0B, 0xEA, 0xCB, 0xB6, 0x21, 0xD0, - 0xA0, 0xAC, 0x99, 0xCE, 0x2A, 0xD3, 0xD8, 0x1F, - 0xA5, 0x25, 0x77, 0x04, 0x8C, 0x27, 0xF8, 0x7F, - 0xF2, 0x25, 0x78, 0xFA, 0xDE, 0xED, 0xB0, 0xFB, - 0xC7, 0xB3, 0x31, 0xCF, 0x4F, 0x5C, 0xC8, 0x25, - 0xDE, 0xFD, 0x2D, 0xB9, 0xF3, 0x6C, 0xD7, 0xCB, - 0x69, 0x53, 0xCB, 0x05, 0xE3, 0x60, 0xAC, 0x98, - 0xE6}; - -static const uint8_t signed_cose_made_by_psa_crypto_es384[] = { - 0xD2, 0x84, 0x44, 0xA1, 0x01, 0x38, 0x22, 0xA0, - 0x47, 0x70, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64, - 0x58, 0x60, 0x2C, 0x6C, 0x08, 0xF3, 0x36, 0x9E, - 0x35, 0x7A, 0x6B, 0xE5, 0xD6, 0x6E, 0xF9, 0x30, - 0x06, 0x2B, 0xD8, 0x73, 0xAB, 0x7E, 0x9B, 0x9D, - 0x4A, 0x30, 0xDD, 0x62, 0x75, 0xE5, 0xD6, 0x61, - 0x39, 0xF7, 0x4D, 0xC3, 0x7C, 0xF0, 0xEB, 0x58, - 0x9D, 0x78, 0xCA, 0x70, 0xD3, 0xA2, 0xF9, 0x23, - 0x85, 0xE6, 0x45, 0x18, 0x04, 0xBE, 0x9F, 0xA0, - 0xE3, 0x97, 0x4A, 0x12, 0x82, 0xF2, 0x87, 0x4F, - 0x3B, 0xF6, 0x9D, 0xC3, 0xE2, 0x99, 0xCC, 0x67, - 0x69, 0x34, 0xDB, 0x1C, 0xF4, 0xAF, 0x95, 0x83, - 0x74, 0x1B, 0x5C, 0xCD, 0xD5, 0x11, 0xC1, 0x07, - 0xE2, 0xD9, 0x3B, 0x16, 0x31, 0x5A, 0x55, 0x58, - 0x6C, 0xC9}; - -static const uint8_t signed_cose_made_by_ossl_crypto_es512[] = { - 0xD2, 0x84, 0x44, 0xA1, 0x01, 0x38, 0x23, 0xA0, - 0x47, 0x70, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64, - 0x58, 0x84, 0x01, 0x54, 0x10, 0x66, 0x49, 0x6B, - 0x8B, 0xDC, 0xB0, 0xCE, 0x03, 0x73, 0x30, 0x01, - 0x92, 0xF1, 0xE3, 0x18, 0x37, 0xF1, 0x91, 0xC1, - 0x57, 0xB5, 0x13, 0xB8, 0x30, 0x10, 0xA6, 0xA6, - 0x29, 0xDC, 0x74, 0xA0, 0x5E, 0x39, 0xC8, 0x2F, - 0x2B, 0x5D, 0x1C, 0xDB, 0x90, 0x47, 0x50, 0xA0, - 0x97, 0x47, 0x0E, 0x99, 0x66, 0x6F, 0xC4, 0xA5, - 0xBB, 0xD7, 0xF7, 0x99, 0xD3, 0x87, 0x7A, 0x1B, - 0x03, 0xCA, 0x6A, 0xDB, 0x01, 0x04, 0xB5, 0x9D, - 0xB6, 0x18, 0xE9, 0x2A, 0xD2, 0x0A, 0x32, 0x05, - 0x88, 0xDA, 0x7D, 0xB8, 0xAD, 0x7A, 0xCE, 0x5F, - 0x49, 0x1F, 0xBD, 0xF3, 0x98, 0xDE, 0x44, 0x05, - 0x38, 0xD0, 0x2C, 0x12, 0x83, 0x09, 0x7A, 0xF8, - 0xE8, 0x5F, 0xA7, 0x33, 0xA3, 0xE3, 0xE9, 0x35, - 0x11, 0x22, 0x48, 0x09, 0xA2, 0x95, 0x6C, 0x9B, - 0x97, 0xA9, 0xE9, 0xBF, 0xA8, 0x63, 0x73, 0x88, - 0x24, 0xB0, 0x84, 0x46, 0xA8, 0x90}; - -static const uint8_t signed_cose_made_by_psa_crypto_ps256[] = { - 0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x24, 0xa0, - 0x47, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x59, 0x01, 0x00, 0x41, 0x9a, 0x28, 0xe2, 0xe4, - 0x9a, 0x56, 0x90, 0xc1, 0x8c, 0xcd, 0x31, 0xd7, - 0x9c, 0x17, 0x42, 0x30, 0xfe, 0xcc, 0x33, 0x41, - 0xd7, 0xcc, 0x6a, 0x16, 0x53, 0x38, 0xd0, 0x15, - 0x31, 0x7c, 0x5c, 0x84, 0x40, 0xc7, 0xcd, 0x8e, - 0xdf, 0xc9, 0x28, 0x1c, 0xd4, 0xb0, 0xa9, 0x0f, - 0x44, 0x17, 0x50, 0x7e, 0x0e, 0xc8, 0xc5, 0xdf, - 0x6a, 0xc4, 0xbf, 0x5a, 0xdf, 0x0e, 0x0f, 0x91, - 0xfe, 0x12, 0x8d, 0x0e, 0x5b, 0x29, 0xf1, 0xc5, - 0xde, 0xbc, 0x6e, 0x61, 0xc7, 0x43, 0x64, 0x1b, - 0x0c, 0x5e, 0x9d, 0x72, 0xf6, 0x93, 0x71, 0x4c, - 0x4d, 0x67, 0xa1, 0x1c, 0xd7, 0x98, 0x5a, 0x59, - 0x1d, 0x98, 0x12, 0x63, 0x88, 0x40, 0x00, 0x9e, - 0x04, 0x9d, 0x77, 0x83, 0x39, 0xa5, 0x69, 0x83, - 0x88, 0x53, 0x38, 0xc9, 0x87, 0x04, 0xcf, 0x5a, - 0x8f, 0x77, 0x6d, 0xda, 0x14, 0x6a, 0x65, 0x2f, - 0xc3, 0xd9, 0xd7, 0x52, 0x18, 0x3f, 0x04, 0x4c, - 0x0d, 0x09, 0xf5, 0x15, 0x31, 0x7c, 0xc7, 0x95, - 0x91, 0xb2, 0x74, 0x3d, 0x31, 0xbc, 0x6a, 0x9b, - 0x49, 0x56, 0xe7, 0xe1, 0xca, 0xb1, 0xb2, 0x36, - 0x08, 0x02, 0x5d, 0xc0, 0xb7, 0xb1, 0x1e, 0x2c, - 0x5c, 0x6f, 0x74, 0x4c, 0x2f, 0x4f, 0x8a, 0xb9, - 0x9e, 0xb4, 0x36, 0xfe, 0xf4, 0xb9, 0xd2, 0x36, - 0x6a, 0xa9, 0x76, 0xdd, 0xcd, 0x37, 0x80, 0x40, - 0x02, 0x76, 0xe6, 0x61, 0xfb, 0x32, 0xa8, 0xf1, - 0x7c, 0x47, 0x7d, 0x69, 0xc1, 0x7b, 0xa3, 0x68, - 0x3c, 0xa1, 0x2c, 0x7c, 0x5c, 0x3d, 0x87, 0x15, - 0x0a, 0xee, 0xc1, 0x2a, 0x8c, 0x67, 0xb9, 0xd2, - 0x03, 0xec, 0x46, 0xc9, 0xef, 0xe1, 0xe4, 0x82, - 0x75, 0x4a, 0xf2, 0x57, 0xde, 0xac, 0x34, 0xfe, - 0x2c, 0x9d, 0xb6, 0x58, 0x5f, 0xfe, 0x67, 0x3e, - 0xb5, 0x37, 0xe2, 0xbe, 0x5d, 0x38, 0xa8, 0x64, - 0x03, 0xc0, 0xb3 -}; - -static const uint8_t signed_cose_made_by_psa_crypto_ps384[] = { - 0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x25, 0xa0, - 0x47, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x59, 0x01, 0x00, 0x5e, 0xa1, 0x14, 0xd9, 0xb9, - 0xb1, 0x6a, 0x0c, 0x17, 0x93, 0xe8, 0x94, 0x88, - 0x5e, 0x5a, 0x12, 0x30, 0x5d, 0x0b, 0x70, 0xbb, - 0xb0, 0x89, 0xad, 0x49, 0x86, 0x1e, 0xeb, 0x3e, - 0xed, 0xff, 0x07, 0x5b, 0xa9, 0x7e, 0x7e, 0xa3, - 0x2e, 0x6e, 0x1b, 0x7c, 0x9c, 0xe1, 0x22, 0xd3, - 0x5e, 0x7d, 0x0e, 0x1e, 0xfe, 0xc2, 0x03, 0x3f, - 0x03, 0xfc, 0x3a, 0xef, 0x59, 0x3f, 0xda, 0x86, - 0x46, 0xe0, 0xb0, 0xe6, 0x06, 0xa3, 0xf2, 0x48, - 0x90, 0x76, 0xff, 0x32, 0x2d, 0x44, 0xf4, 0x1c, - 0x18, 0x0e, 0x24, 0x6f, 0x8e, 0x55, 0x82, 0xf0, - 0xf5, 0x06, 0x6b, 0xab, 0xfe, 0x52, 0x81, 0x32, - 0x8a, 0xb1, 0xa2, 0xec, 0x1b, 0x07, 0x9e, 0xd6, - 0x19, 0x6b, 0x0a, 0x7e, 0x1d, 0x10, 0xad, 0xf2, - 0xb3, 0x3e, 0x3c, 0x0d, 0x23, 0x15, 0x4e, 0x2d, - 0x34, 0x59, 0x4d, 0x2d, 0x59, 0x76, 0x66, 0x40, - 0x17, 0x15, 0x84, 0x04, 0x3b, 0x37, 0x57, 0xac, - 0xab, 0x7f, 0xcc, 0x51, 0x99, 0x80, 0x31, 0x1a, - 0xd8, 0x1e, 0x63, 0x0b, 0x67, 0xd1, 0x21, 0xc3, - 0xbe, 0x33, 0x4d, 0xfd, 0x40, 0x7e, 0x04, 0x16, - 0xe8, 0x2c, 0x0b, 0xe8, 0x3c, 0x39, 0xcc, 0xcd, - 0x9a, 0x6a, 0xc6, 0x15, 0x1e, 0x49, 0xad, 0x54, - 0xee, 0x7d, 0x38, 0x47, 0x59, 0x17, 0xa5, 0xcc, - 0x03, 0x81, 0x63, 0x26, 0xd1, 0x7f, 0x4d, 0x38, - 0xf5, 0x00, 0xd5, 0x66, 0xd8, 0x53, 0x8a, 0x33, - 0x19, 0xb3, 0xcb, 0x8d, 0x65, 0x79, 0xb0, 0xe7, - 0xf4, 0xdd, 0x9a, 0x97, 0x7c, 0xb4, 0x13, 0x18, - 0x6d, 0xc6, 0x4c, 0xbc, 0xd3, 0xed, 0x8a, 0x6e, - 0x1b, 0xf0, 0x53, 0xc7, 0x71, 0x44, 0xc9, 0xf3, - 0xba, 0xaf, 0x20, 0xc5, 0x21, 0x98, 0xde, 0x71, - 0xc9, 0xa2, 0x49, 0xe4, 0xf5, 0x1d, 0x76, 0xea, - 0x6b, 0xc6, 0x74, 0xbe, 0xc6, 0xee, 0x65, 0x5d, - 0xfa, 0x81, 0x29 -}; - -static const uint8_t signed_cose_made_by_psa_crypto_ps512[] = { - 0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x26, 0xa0, - 0x47, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x59, 0x01, 0x00, 0x12, 0x53, 0xfe, 0x15, 0xda, - 0xb3, 0x01, 0x84, 0x40, 0x7b, 0x8b, 0x11, 0x0d, - 0x34, 0x40, 0x13, 0x97, 0x51, 0xa3, 0xf6, 0x53, - 0x93, 0xee, 0x98, 0xe8, 0xb7, 0x7c, 0x4a, 0x33, - 0xba, 0x90, 0xc4, 0xd9, 0x03, 0x16, 0x32, 0x55, - 0xfb, 0x64, 0x56, 0x9a, 0x65, 0x3c, 0x98, 0x8d, - 0xc4, 0xe4, 0x99, 0x79, 0xf3, 0x09, 0x88, 0x22, - 0x3e, 0x12, 0x38, 0xd0, 0xe0, 0xf2, 0xac, 0xf4, - 0x07, 0x66, 0xd4, 0x99, 0x38, 0x2c, 0x7a, 0x62, - 0x0c, 0x55, 0xbd, 0x57, 0x65, 0x5f, 0x3b, 0xe4, - 0x6a, 0xfd, 0x7c, 0x62, 0xe1, 0x7a, 0xbf, 0xe9, - 0x28, 0x9e, 0xd4, 0x03, 0x13, 0x54, 0xf4, 0x34, - 0x30, 0xe9, 0x1e, 0xec, 0xcb, 0x55, 0x23, 0xb3, - 0x2e, 0x0c, 0x1e, 0x41, 0x08, 0x04, 0x1a, 0x51, - 0x91, 0x72, 0x15, 0x78, 0x0d, 0x3c, 0x64, 0xaa, - 0x0b, 0xdc, 0x8d, 0x29, 0xc1, 0x6e, 0x89, 0x58, - 0x74, 0x2a, 0x3e, 0xf6, 0xb3, 0xab, 0x61, 0xa1, - 0x0b, 0xe9, 0x03, 0x44, 0xce, 0xb3, 0x27, 0x1c, - 0x25, 0x21, 0x59, 0x9a, 0x7b, 0x6a, 0x61, 0x1f, - 0xee, 0x3b, 0x21, 0x3b, 0x2c, 0xd9, 0x40, 0x17, - 0x5d, 0x1f, 0xee, 0x62, 0x21, 0xf4, 0x67, 0x7f, - 0xd6, 0x58, 0x2a, 0xaa, 0x75, 0xf1, 0x00, 0x26, - 0xb6, 0x04, 0x6c, 0x4d, 0xd0, 0x5a, 0x53, 0x97, - 0xc9, 0xa0, 0xb6, 0x8b, 0xf3, 0xe3, 0x2f, 0xe3, - 0x01, 0x30, 0x87, 0x89, 0xda, 0x9e, 0x4c, 0xb9, - 0x98, 0xd0, 0x0c, 0xc2, 0x92, 0x90, 0xbb, 0xb1, - 0x40, 0xe2, 0xd8, 0xd2, 0x23, 0x8b, 0x92, 0xd7, - 0x55, 0x81, 0x4a, 0xeb, 0xed, 0x08, 0xe9, 0x43, - 0xe8, 0x33, 0xa1, 0x47, 0x3c, 0x2b, 0xc1, 0xd0, - 0x69, 0x9a, 0xf9, 0x97, 0x9f, 0x2f, 0xf1, 0xab, - 0x6f, 0x6e, 0xd2, 0xb2, 0xea, 0x0b, 0xc9, 0x02, - 0xb7, 0x4d, 0x60, 0x1b, 0x3a, 0x10, 0x51, 0x20, - 0x12, 0x5c, 0x32 -}; - -static const uint8_t signed_cose_made_by_pycose_eddsa[] = { - 0xd2, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x47, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x58, - 0x40, 0x17, 0x02, 0xb0, 0xf2, 0x3f, 0x47, 0xe8, - 0x9f, 0xab, 0x39, 0xcd, 0xd3, 0xd6, 0x5a, 0x57, - 0x76, 0x37, 0xb2, 0xbc, 0x8e, 0xd1, 0xe3, 0xa9, - 0xc1, 0x4d, 0xf3, 0xbf, 0x4a, 0x93, 0x4c, 0xe7, - 0xe2, 0xa8, 0xae, 0x46, 0xb5, 0x82, 0x48, 0x79, - 0xde, 0x7b, 0x81, 0xd0, 0x25, 0xbc, 0xf8, 0x32, - 0xab, 0x41, 0x00, 0xc5, 0xd9, 0x39, 0xc7, 0xf2, - 0x07, 0x27, 0x70, 0xf3, 0x76, 0xd2, 0x8d, 0xbe, - 0x00 -}; - -struct test_case { - int32_t cose_algorithm_id; - struct q_useful_buf_c known_good_message; -}; - -/** - * List of algorithms the tests cases run over. - * - * For each algorithm, a known valid message is associated. - */ -static struct test_case test_cases[] = { - /* Annoyingly, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL doesn't work in a const-context */ - { T_COSE_ALGORITHM_ES256, { signed_cose_made_by_ossl_crypto_es256, sizeof(signed_cose_made_by_ossl_crypto_es256) } }, - { T_COSE_ALGORITHM_ES384, { signed_cose_made_by_psa_crypto_es384, sizeof(signed_cose_made_by_psa_crypto_es384) } }, - { T_COSE_ALGORITHM_ES512, { signed_cose_made_by_ossl_crypto_es512, sizeof(signed_cose_made_by_ossl_crypto_es512) } }, - { T_COSE_ALGORITHM_PS256, { signed_cose_made_by_psa_crypto_ps256, sizeof(signed_cose_made_by_psa_crypto_ps256) } }, - { T_COSE_ALGORITHM_PS384, { signed_cose_made_by_psa_crypto_ps384, sizeof(signed_cose_made_by_psa_crypto_ps384) } }, - { T_COSE_ALGORITHM_PS512, { signed_cose_made_by_psa_crypto_ps512, sizeof(signed_cose_made_by_psa_crypto_ps512) } }, - { T_COSE_ALGORITHM_EDDSA, { signed_cose_made_by_pycose_eddsa, sizeof(signed_cose_made_by_pycose_eddsa) } }, - { 0 }, /* Sentinel value with an invalid algorithm id */ -}; - -static int_fast32_t sign_verify_basic_test_alg(int32_t cose_alg) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - int32_t return_value; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - struct t_cose_key key_pair; - struct q_useful_buf_c payload; - struct t_cose_sign1_verify_ctx verify_ctx; - Q_USEFUL_BUF_MAKE_STACK_UB( auxiliary_buffer, 100); - - /* Make a key pair that will be used for both signing and verification. - */ - result = make_key_pair(cose_alg, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - - /* -- Get started with context initialization, selecting the alg -- */ - t_cose_sign1_sign_init(&sign_ctx, 0, cose_alg); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - - result = t_cose_sign1_sign(&sign_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &signed_cose); - if(result) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - /* Verification */ - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, auxiliary_buffer); - - result = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - if(result) { - return_value = 5000 + (int32_t)result; - goto Done; - } - - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"))) { - return_value = 6000; - goto Done; - } - - return_value = 0; - -Done: - /* Many crypto libraries allocate memory, slots, etc for keys */ - free_key_pair(key_pair); - - return return_value; -} - - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sign_verify_basic_test() -{ - int_fast32_t return_value; - const struct test_case* tc; - for (tc = test_cases; tc->cose_algorithm_id != 0; tc++) { - if (t_cose_is_algorithm_supported(tc->cose_algorithm_id)) { - return_value = sign_verify_basic_test_alg(tc->cose_algorithm_id); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - } - } - - return 0; -} - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sig_fail_test(int32_t cose_alg) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - QCBOREncodeContext cbor_encode; - int32_t return_value; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - struct t_cose_key key_pair; - struct q_useful_buf_c payload; - QCBORError cbor_error; - struct t_cose_sign1_verify_ctx verify_ctx; - Q_USEFUL_BUF_MAKE_STACK_UB( auxiliary_buffer, 100); - size_t tamper_offset; - - - /* Make a key pair that will be used for both signing and - * verification. - */ - result = make_key_pair(cose_alg, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, 0, cose_alg); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - QCBOREncode_AddSZString(&cbor_encode, "payload"); - - - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return_value = 3000 + (int32_t)result; - goto Done; - } - - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return_value = 4000 + (int32_t)cbor_error; - goto Done; - } - - /* tamper with the pay load to see that the signature verification fails */ - tamper_offset = q_useful_buf_find_bytes(signed_cose, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload")); - if(tamper_offset == SIZE_MAX) { - return_value = 99; - goto Done; - } - /* Change "payload" to "hayload" */ - struct q_useful_buf temp_unconst = q_useful_buf_unconst(signed_cose); - ((char *)temp_unconst.ptr)[tamper_offset] = 'h'; - - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, auxiliary_buffer); - - result = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - if(result != T_COSE_ERR_SIG_VERIFY) { - return_value = 5000 + (int32_t)result; - } - - return_value = 0; - -Done: - free_key_pair(key_pair); - - return return_value; -} - - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sign_verify_sig_fail_test() -{ - int_fast32_t return_value; - const struct test_case* tc; - for (tc = test_cases; tc->cose_algorithm_id != 0; tc++) { - if (t_cose_is_algorithm_supported(tc->cose_algorithm_id)) { - return_value = sig_fail_test(tc->cose_algorithm_id); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - } - } - return 0; -} - - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sign_verify_make_cwt_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - QCBOREncodeContext cbor_encode; - int32_t return_value; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - struct t_cose_key key_pair; - struct q_useful_buf_c payload; - QCBORError cbor_error; - struct t_cose_sign1_verify_ctx verify_ctx; - struct q_useful_buf_c expected_rfc8392_first_part; - struct q_useful_buf_c expected_payload; - struct q_useful_buf_c actual_rfc8392_first_part; - - /* -- initialize for signing -- - * No special options selected - */ - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); - - - /* -- Key and kid -- - * The ECDSA key pair made is both for signing and verification. - * The kid comes from RFC 8932 - */ - result = make_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - t_cose_sign1_set_signing_key(&sign_ctx, - key_pair, - Q_USEFUL_BUF_FROM_SZ_LITERAL("AsymmetricECDSA256")); - - - /* -- Encoding context and output of parameters -- */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - - /* -- The payload as from RFC 8932 -- */ - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com"); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944); - const uint8_t xx[] = {0x0b, 0x71}; - QCBOREncode_AddBytesToMapN(&cbor_encode, 7, - Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx)); - QCBOREncode_CloseMap(&cbor_encode); - - - /* -- Finish up the COSE_Sign1. This is where the signing happens -- */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return_value = 3000 + (int32_t)result; - goto Done; - } - - /* Finally close off the CBOR formatting and get the pointer and length - * of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return_value = (int32_t)cbor_error + 4000; - goto Done; - } - /* --- Done making COSE Sign1 object --- */ - - - /* Compare to expected from CWT RFC */ - /* The first part, the intro and protected parameters must be the same */ - const uint8_t rfc8392_first_part_bytes[] = { - 0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa1, 0x04, 0x52, 0x41, 0x73, 0x79, - 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x45, 0x43, 0x44, 0x53, 0x41, - 0x32, 0x35, 0x36, 0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70, - 0x3a, 0x2f, 0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77, - 0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x69, - 0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, - 0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0, 0x05, 0x1a, 0x56, - 0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x07, 0x42, 0x0b, - 0x71}; - expected_rfc8392_first_part = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_first_part_bytes); - actual_rfc8392_first_part = q_useful_buf_head(signed_cose, sizeof(rfc8392_first_part_bytes)); - if(q_useful_buf_compare(actual_rfc8392_first_part, expected_rfc8392_first_part)) { - return_value = -1; - goto Done; - } - - /* --- Start verifying the COSE Sign1 object --- */ - /* Run the signature verification */ - t_cose_sign1_verify_init(&verify_ctx, 0); - - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - - result = t_cose_sign1_verify(&verify_ctx, - signed_cose, /* COSE to verify */ - &payload, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ - - if(result) { - return_value = 5000 + (int32_t)result; - goto Done; - } - - /* Format the expected payload CBOR fragment */ - - /* Skip the key id, because this has the short-circuit key id */ - const size_t kid_encoded_len = - 1 + - 1 + - 1 + - strlen("AsymmetricECDSA256"); // length of short-circuit key id - - - /* compare payload output to the one expected */ - expected_payload = q_useful_buf_tail(expected_rfc8392_first_part, kid_encoded_len + 8); - if(q_useful_buf_compare(payload, expected_payload)) { - return_value = 6000; - } - /* --- Done verifying the COSE Sign1 object --- */ - - return_value = 0; - -Done: - /* Many crypto libraries allocate memory, slots, etc for keys */ - free_key_pair(key_pair); - - return return_value; -} - - -static int_fast32_t size_test(int32_t cose_algorithm_id, - struct q_useful_buf_c kid) -{ - struct t_cose_key key_pair; - struct t_cose_sign1_sign_ctx sign_ctx; - QCBOREncodeContext cbor_encode; - int32_t return_value; - enum t_cose_err_t result; - struct q_useful_buf nil_buf; - size_t calculated_size; - QCBORError cbor_error; - struct q_useful_buf_c actual_signed_cose; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - Q_USEFUL_BUF_MAKE_STACK_UB( auxiliary_buffer, 100); - struct q_useful_buf_c payload; - size_t sig_size; - - result = make_key_pair(cose_algorithm_id, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - - /* ---- Common Set up ---- */ - payload = Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"); - result = t_cose_crypto_sig_size(cose_algorithm_id, key_pair, &sig_size); - if(result) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - /* ---- First calculate the size ----- */ - nil_buf = (struct q_useful_buf) {NULL, INT32_MAX}; - QCBOREncode_Init(&cbor_encode, nil_buf); - - t_cose_sign1_sign_init(&sign_ctx, 0, cose_algorithm_id); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid); - - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return_value = 3000 + (int32_t)result; - goto Done; - } - - QCBOREncode_AddEncoded(&cbor_encode, payload); - - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return_value = 4000 + (int32_t)result; - goto Done; - } - - cbor_error = QCBOREncode_FinishGetSize(&cbor_encode, &calculated_size); - if(cbor_error) { - return_value = 5000 + (int32_t)cbor_error; - goto Done; - } - - /* ---- General sanity check ---- */ - size_t expected_min = sig_size + payload.len + kid.len; - - if(calculated_size < expected_min || calculated_size > expected_min + 30) { - return_value = -1; - goto Done; - } - - /** - * Get the expected auxiliary buffer size. For anything but EDDSA, this should be zero. - */ - size_t auxiliary_buffer_size = t_cose_sign1_sign_auxiliary_buffer_size(&sign_ctx); - if (cose_algorithm_id == T_COSE_ALGORITHM_EDDSA) { - /* TBS is a bit smaller, given it doesn't include the signature */ - expected_min = payload.len + kid.len; - if(auxiliary_buffer_size < expected_min || auxiliary_buffer_size > expected_min + 30) { - return_value = -2; - goto Done; - } - } else if (auxiliary_buffer_size != 0) { - return_value = -3; - goto Done; - } - - /* ---- Now make a real COSE_Sign1 and compare the size ---- */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, 0, cose_algorithm_id); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid); - if (auxiliary_buffer_size > 0) { - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - } - - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return_value = 6000 + (int32_t)result; - goto Done; - } - - QCBOREncode_AddEncoded(&cbor_encode, payload); - - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return_value = 7000 + (int32_t)result; - goto Done; - } - - cbor_error = QCBOREncode_Finish(&cbor_encode, &actual_signed_cose); - if(actual_signed_cose.len != calculated_size) { - return_value = -4; - goto Done; - } - - /* ---- Again with one-call API to make COSE_Sign1 ---- */\ - t_cose_sign1_sign_init(&sign_ctx, 0, cose_algorithm_id); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid); - if (auxiliary_buffer_size > 0) { - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - } - result = t_cose_sign1_sign(&sign_ctx, - payload, - signed_cose_buffer, - &actual_signed_cose); - if(result) { - return_value = 8000 + (int32_t)result; - goto Done; - } - - if(actual_signed_cose.len != calculated_size) { - return_value = -5; - goto Done; - } - - return_value = 0; - -Done: - free_key_pair(key_pair); - - return return_value; -} - - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sign_verify_get_size_test() -{ - int_fast32_t return_value; - const struct test_case* tc; - for (tc = test_cases; tc->cose_algorithm_id != 0; tc++) { - if (t_cose_is_algorithm_supported(tc->cose_algorithm_id)) { - return_value = size_test(tc->cose_algorithm_id, - NULL_Q_USEFUL_BUF_C); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - - return_value = size_test(tc->cose_algorithm_id, - Q_USEFUL_BUF_FROM_SZ_LITERAL("greasy kid stuff")); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - } - } - return 0; - -} - - -static int_fast32_t known_good_test(int cose_algorithm_id, struct q_useful_buf_c signed_message) -{ - int32_t return_value; - enum t_cose_err_t result; - struct t_cose_sign1_verify_ctx verify_ctx; - struct t_cose_key key_pair; - struct q_useful_buf_c payload; - struct t_cose_parameters parameters; - Q_USEFUL_BUF_MAKE_STACK_UB( auxiliary_buffer, 100); - - /** - * Decode the signed message once without a key, to extract - * the algorithm ID. - * - * We don't strictly need this step, since the algorithm - * is passed as an argument, but it is a nice sanity check. - */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); - result = t_cose_sign1_verify(&verify_ctx, - signed_message, - &payload, - ¶meters); - if(result) { - return_value = 1000 + (int32_t)result; - goto Done2; - } - - if (parameters.cose_algorithm_id != cose_algorithm_id) { - return_value = 2000 + (int32_t)result; - goto Done2; - } - - result = make_key_pair(cose_algorithm_id, &key_pair); - if(result) { - return_value = 3000 + (int32_t)result; - goto Done2; - } - - /** - * Some sanity check for the size of the auxiliary buffer. - * With EDDSA, it is roughly the size of the payload plus a dozen bytes. - * Otherwise it should be zero. - */ - size_t auxiliary_buffer_size = t_cose_sign1_verify_auxiliary_buffer_size(&verify_ctx); - if (cose_algorithm_id == T_COSE_ALGORITHM_EDDSA) { - size_t expected_min = payload.len; - if(auxiliary_buffer_size < expected_min || auxiliary_buffer_size > expected_min + 30) { - return_value = -1; - goto Done; - } - } else if (auxiliary_buffer_size != 0) { - return_value = -2; - goto Done; - } - - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, auxiliary_buffer); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - result = t_cose_sign1_verify(&verify_ctx, - signed_message, - &payload, - ¶meters); - if(result) { - return_value = 4000 + (int32_t)result; - goto Done; - } - - if(q_useful_buf_compare(payload, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"))) { - return_value = 5000; - goto Done; - } - - return_value = 0; - -Done: - free_key_pair(key_pair); - -Done2: - return return_value; -} - -int_fast32_t sign_verify_known_good_test(void) -{ - int_fast32_t return_value = 0; - const struct test_case* tc; - for (tc = test_cases; tc->cose_algorithm_id != 0; tc++) { - if (t_cose_is_algorithm_supported(tc->cose_algorithm_id)) { - return_value = known_good_test(tc->cose_algorithm_id, - tc->known_good_message); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - } - } - - /* Can't make signed messages and compare them to a known good - * value because signatures have a random component. They are - * never the same. There are other tests here that evaluate the - * structure of the signed messages and there tests that verify - * messages made by the signing function. */ - - return return_value; -} - -/** - * Try to sign and verify against an algorithm that is - * not supported by the current t_cose configuration - * and crypto adapter. - */ -static int_fast32_t -sign_verify_unsupported_test_alg(int32_t cose_alg, - struct q_useful_buf_c signed_message) -{ - struct t_cose_key key_pair; - int32_t return_value; - enum t_cose_err_t result; - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - Q_USEFUL_BUF_MAKE_STACK_UB( auxiliary_buffer, 100); - - result = make_key_pair(T_COSE_ALGORITHM_ES256, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - - t_cose_sign1_sign_init(&sign_ctx, 0, cose_alg); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, auxiliary_buffer); - - result = t_cose_sign1_sign(&sign_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &signed_cose); - - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, auxiliary_buffer); - result = t_cose_sign1_verify(&verify_ctx, signed_message, NULL, NULL); - if (result != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - return_value = 0; - -Done: - free_key_pair(key_pair); - return return_value; -} - -int_fast32_t sign_verify_unsupported_test(void) -{ - int_fast32_t return_value; - const struct test_case* tc; - for (tc = test_cases; tc->cose_algorithm_id != 0; tc++) { - /* Unlike other tests, this one runs only on unsupported algorithms. - * Depending on the configuration and crypto adapter, this could mean never. - */ - if (!t_cose_is_algorithm_supported(tc->cose_algorithm_id)) { - return_value = sign_verify_unsupported_test_alg(tc->cose_algorithm_id, - tc->known_good_message); - if (return_value) { - return (int32_t)(1 + tc - test_cases) * 10000 + return_value; - } - } - } - return 0; -} - -/* - * Public function, see t_cose_sign_verify_test.h - */ -int_fast32_t sign_verify_bad_auxiliary_buffer(void) -{ - enum t_cose_err_t result; - int32_t return_value; - struct t_cose_key key_pair; - const struct q_useful_buf_c known_good_message = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(signed_cose_made_by_pycose_eddsa); - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - Q_USEFUL_BUF_MAKE_STACK_UB( small_auxiliary_buffer, 5); - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c signed_cose; - - /* Only EDDSA uses the auxiliary buffer, so this test is - * meaning less if we don't support it. - */ - if (!t_cose_is_algorithm_supported(T_COSE_ALGORITHM_EDDSA)) { - return 0; - } - - result = make_key_pair(T_COSE_ALGORITHM_EDDSA, &key_pair); - if(result) { - return 1000 + (int32_t)result; - } - - /* Try to verify the message without setting up an auxiliary buffer. - * This should fail with T_COSE_ERR_NEED_AUXILIARY_BUFFER. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - result = t_cose_sign1_verify(&verify_ctx, known_good_message, NULL, NULL); - if (result != T_COSE_ERR_NEED_AUXILIARY_BUFFER) { - return_value = 2000 + (int32_t)result; - goto Done; - } - - /* Do the same again, but this time use an auxiliary buffer that is - * obviously too small. - * This time it should fail with T_COSE_ERR_AUXILIARY_BUFFER_SIZE. - */ - t_cose_sign1_verify_init(&verify_ctx, 0); - t_cose_sign1_set_verification_key(&verify_ctx, key_pair); - t_cose_sign1_verify_set_auxiliary_buffer(&verify_ctx, small_auxiliary_buffer); - result = t_cose_sign1_verify(&verify_ctx, known_good_message, NULL, NULL); - if (result != T_COSE_ERR_AUXILIARY_BUFFER_SIZE) { - return_value = 3000 + (int32_t)result; - goto Done; - } - - /* Now we try something similar, but with signing instead. */ - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_EDDSA); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - result = t_cose_sign1_sign(&sign_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &signed_cose); - if (result != T_COSE_ERR_NEED_AUXILIARY_BUFFER) { - return_value = 4000 + (int32_t)result; - goto Done; - } - - t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_EDDSA); - t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C); - t_cose_sign1_sign_set_auxiliary_buffer(&sign_ctx, small_auxiliary_buffer); - result = t_cose_sign1_sign(&sign_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &signed_cose); - if (result != T_COSE_ERR_AUXILIARY_BUFFER_SIZE) { - return_value = 5000 + (int32_t)result; - goto Done; - } - - return_value = 0; - -Done: - free_key_pair(key_pair); - - return return_value; -} diff --git a/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.h b/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.h deleted file mode 100644 index 5338604f16ee..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_sign_verify_test.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * t_cose_sign_verify_test.h - * - * Copyright 2019, 2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef t_cose_sign_verify_test_h -#define t_cose_sign_verify_test_h - -#include - - -/** - * \file t_cose_sign_verify_test.h - * - * \brief Tests that need public key crypto to be implemented - */ - - -/** - * \brief Self test using integrated crypto. - * - * \return non-zero on failure. - */ -int_fast32_t sign_verify_basic_test(void); - - -/* - * Sign some data, perturb the data and see that sig validation fails - */ -int_fast32_t sign_verify_sig_fail_test(void); - - -/* - * Make a CWT and compare it to the one in the CWT RFC - */ -int_fast32_t sign_verify_make_cwt_test(void); - - -/* - * Test the ability to calculate size of a COSE_Sign1 - */ -int_fast32_t sign_verify_get_size_test(void); - - -/* - * Test against known good messages. - */ -int_fast32_t sign_verify_known_good_test(void); - - -/* - * Test the return value when using an unsupported algorithm. - */ -int_fast32_t sign_verify_unsupported_test(void); - - -/* - * Test the return value when using a small or no auxiliary buffer. - */ -int_fast32_t sign_verify_bad_auxiliary_buffer(void); - -#endif /* t_cose_sign_verify_test_h */ diff --git a/3rdparty/internal/t_cose/test/t_cose_test.c b/3rdparty/internal/t_cose/test/t_cose_test.c deleted file mode 100644 index e514ae5df6ea..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_test.c +++ /dev/null @@ -1,1662 +0,0 @@ -/* - * t_cose_test.c - * - * Copyright 2019-2022, Laurence Lundblade - * Copyright (c) 2021, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose_test.h" -#include "t_cose/t_cose_sign1_sign.h" -#include "t_cose/t_cose_sign1_verify.h" -#include "t_cose_make_test_messages.h" -#include "t_cose/q_useful_buf.h" -#include "t_cose_crypto.h" /* For signature size constant */ -#include "t_cose_util.h" /* for get_short_circuit_kid */ - - -/* String used by RFC 8152 and C-COSE tests and examples for payload */ -#define SZ_CONTENT "This is the content." -static const struct q_useful_buf_c s_input_payload = {SZ_CONTENT, sizeof(SZ_CONTENT)-1}; - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_self_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - - - /* --- Make COSE Sign1 object --- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* No key necessary because short-circuit test mode is used */ - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &signed_cose); - if(result) { - return 1000 + (int32_t)result; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Start verifying the COSE Sign1 object --- */ - /* Select short circuit signing */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result) { - return 2000 + (int32_t)result; - } - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, s_input_payload)) { - return 3000; - } - /* This value comes from C-COSE test case sign-pass-03.json. The test - * case JSON gives the expected TBS bytes. These were then run through - * openssl dgst -sha256 -binary | hexdump -e '"\n" 8/1 "0x%01x, "'. - * - * Short-circuit signature are just the hash of the TBS bytes. They are - * twice to fake the length of a real signature. In the COSE format the - * signature is last, so this hash occurs as the last 32 bytes of a - * the encoded COSE. - * - * This is a useful test because it confirms the TBS byte calculation is - * right in comparison to C-COSE. - */ - static const uint8_t hash_of_tbs[] = { - 0x4c, 0x33, 0x63, 0xb4, 0x99, 0xe1, 0xda, 0xc4, - 0xaa, 0xfc, 0x8d, 0x69, 0x23, 0xf1, 0xca, 0x65, - 0x77, 0xdf, 0xda, 0x80, 0xda, 0x24, 0xe5, 0x4f, - 0xb9, 0x24, 0x24, 0x90, 0x64, 0x82, 0x7c, 0x88}; - - if(q_useful_buf_compare(Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(hash_of_tbs), - q_useful_buf_tail(signed_cose, signed_cose.len - 32))) { - return 4000; - } - /* --- Done verifying the COSE Sign1 object --- */ - - - /* --- Make COSE Sign1 object --- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* No key necessary because short-circuit test mode is used */ - - result = t_cose_sign1_sign_aad(&sign_ctx, - s_input_payload, - Q_USEFUL_BUF_FROM_SZ_LITERAL("some aad"), - signed_cose_buffer, - &signed_cose); - if(result) { - return 1000 + (int32_t)result; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Start verifying the COSE Sign1 object --- */ - /* Select short circuit signing */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify_aad(&verify_ctx, - /* COSE to verify */ - signed_cose, - Q_USEFUL_BUF_FROM_SZ_LITERAL("some aad"), - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result) { - return 2000 + (int32_t)result; - } - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, s_input_payload)) { - return 3000; - } - - return 0; -} - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_self_detached_content_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - - - /* --- Make COSE Sign1 object --- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* No key necessary because short-circuit test mode is used */ - - result = t_cose_sign1_sign_detached(&sign_ctx, - NULL_Q_USEFUL_BUF_C, - s_input_payload, - signed_cose_buffer, - &signed_cose); - if(result) { - return 1000 + (int32_t)result; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Start verifying the COSE Sign1 object --- */ - /* Select short circuit signing */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* The detached content */ - payload = s_input_payload; - - /* Run the signature verification */ - result = t_cose_sign1_verify_detached(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* No AAD */ - NULL_Q_USEFUL_BUF_C, - /* The detached payload */ - payload, - /* Don't return parameters */ - NULL); - if(result) { - return 2000 + (int32_t)result; - } - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, s_input_payload)) { - return 3000; - } - - /* This value comes from C-COSE test case sign-pass-03.json. The test - * case JSON gives the expected TBS bytes. These were then run through - * openssl dgst -sha256 -binary | hexdump -e '"\n" 8/1 "0x%01x, "'. - * - * Short-circuit signature are just the hash of the TBS bytes. They are - * twice to fake the length of a real signature. In the COSE format the - * signature is last, so this hash occurs as the last 32 bytes of a - * the encoded COSE. - * - * This is a useful test because it confirms the TBS byte calculation is - * right in comparison to C-COSE. - */ - static const uint8_t hash_of_tbs[] = { - 0x4c, 0x33, 0x63, 0xb4, 0x99, 0xe1, 0xda, 0xc4, - 0xaa, 0xfc, 0x8d, 0x69, 0x23, 0xf1, 0xca, 0x65, - 0x77, 0xdf, 0xda, 0x80, 0xda, 0x24, 0xe5, 0x4f, - 0xb9, 0x24, 0x24, 0x90, 0x64, 0x82, 0x7c, 0x88}; - - if(q_useful_buf_compare(Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(hash_of_tbs), - q_useful_buf_tail(signed_cose, signed_cose.len - 32))) { - return 4000; - } - - /* --- Done verifying the COSE Sign1 object --- */ - - return 0; -} - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_verify_fail_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - size_t payload_offset; - - /* --- Start making COSE Sign1 object --- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* No key necessary because short-circuit test mode is used */ - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &signed_cose); - if(result) { - return 1000 + (int32_t)result; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Start Tamper with payload --- */ - /* Find the offset of the payload in COSE_Sign1 */ - payload_offset = q_useful_buf_find_bytes(signed_cose, s_input_payload); - if(payload_offset == SIZE_MAX) { - return 6000; - } - /* Change "payload" to "hayload" */ - struct q_useful_buf temp_unconst = q_useful_buf_unconst(signed_cose); - ((char *)temp_unconst.ptr)[payload_offset] = 'h'; - /* --- Tamper with payload Done --- */ - - - /* --- Start verifying the COSE Sign1 object --- */ - - /* Select short circuit signing */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_ERR_SIG_VERIFY) { - return 4000 + (int32_t)result; - } - /* --- Done verifying the COSE Sign1 object --- */ - - - /* === AAD Verification Failure Test === */ - /* --- Start making COSE Sign1 object --- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* No key necessary because short-circuit test mode is used */ - - result = t_cose_sign1_sign_aad(&sign_ctx, - s_input_payload, - Q_USEFUL_BUF_FROM_SZ_LITERAL("some aad"), - signed_cose_buffer, - &signed_cose); - if(result) { - return 1000 + (int32_t)result; - } - /* --- Done making COSE Sign1 object --- */ - - /* --- Start verifying the COSE Sign1 object --- */ - - /* Select short circuit signing */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify_aad(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* Slightly different AAD */ - Q_USEFUL_BUF_FROM_SZ_LITERAL("home aad"), - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_ERR_SIG_VERIFY) { - return 4000 + (int32_t)result; - } - /* --- Done verifying the COSE Sign1 object --- */ - - return 0; -} - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_signing_error_conditions_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - Q_USEFUL_BUF_MAKE_STACK_UB( small_signed_cose_buffer, 15); - struct q_useful_buf_c signed_cose; - - - /* -- Test bad algorithm ID 0 -- */ - /* Use reserved alg ID 0 to cause error. */ - t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, 0); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &signed_cose); - if(result != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) { - return -1; - } - - - /* -- Test bad algorithm ID -4444444 -- */ - /* Use unassigned alg ID -4444444 to cause error. */ - t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, -4444444); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &signed_cose); - if(result != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) { - return -2; - } - - - - /* -- Tests detection of CBOR encoding error in the payload -- */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - - - QCBOREncode_AddSZString(&cbor_encode, "payload"); - /* Force a CBOR encoding error by closing a map that is not open */ - QCBOREncode_CloseMap(&cbor_encode); - - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - - if(result != T_COSE_ERR_CBOR_FORMATTING) { - return -3; - } - - - /* -- Tests the output buffer being too small -- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - small_signed_cose_buffer, - &signed_cose); - - if(result != T_COSE_ERR_TOO_SMALL) { - return -4; - } - - return 0; -} - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_make_cwt_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - QCBORError cbor_error; - - /* --- Start making COSE Sign1 object --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* Do the first part of the the COSE_Sign1, the parameters */ - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return 1000 + (int32_t)result; - } - - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com"); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944); - const uint8_t xx[] = {0x0b, 0x71}; - QCBOREncode_AddBytesToMapN(&cbor_encode, 7, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx)); - QCBOREncode_CloseMap(&cbor_encode); - - /* Finish up the COSE_Sign1. This is where the signing happens */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return 2000 + (int32_t)result; - } - - /* Finally close off the CBOR formatting and get the pointer and length - * of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return 3000 + (int32_t)cbor_error; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Compare to expected from CWT RFC --- */ - /* The first part, the intro and protected pararameters must be the same */ - const uint8_t cwt_first_part_bytes[] = {0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26}; - struct q_useful_buf_c fp = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(cwt_first_part_bytes); - struct q_useful_buf_c head = q_useful_buf_head(signed_cose, sizeof(cwt_first_part_bytes)); - if(q_useful_buf_compare(head, fp)) { - return -1; - } - - /* Skip the key id, because this has the short-circuit key id */ - const size_t kid_encoded_len = - 1 + - 1 + - 2 + - 32; // length of short-circuit key id - - /* Compare the payload */ - const uint8_t rfc8392_payload_bytes[] = { - 0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, - 0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77, - 0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, - 0x69, 0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0, - 0x05, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9, - 0xf0, 0x07, 0x42, 0x0b, 0x71}; - - struct q_useful_buf_c fp2 = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_payload_bytes); - - struct q_useful_buf_c payload2 = q_useful_buf_tail(signed_cose, - sizeof(cwt_first_part_bytes)+kid_encoded_len); - struct q_useful_buf_c pl3 = q_useful_buf_head(payload2, - sizeof(rfc8392_payload_bytes)); - if(q_useful_buf_compare(pl3, fp2)) { - return -2; - } - - /* Skip the signature because ECDSA signatures usually have a random - component */ - - - /* --- Start verifying the COSE Sign1 object --- */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result) { - return 4000 + (int32_t)result; - } - - /* Format the expected payload CBOR fragment */ - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, q_useful_buf_tail(fp2, 2))) { - return 5000; - } - /* --- Done verifying the COSE Sign1 object --- */ - - return 0; -} - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_decode_only_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - Q_USEFUL_BUF_MAKE_STACK_UB( expected_payload_buffer, 10); - struct q_useful_buf_c expected_payload; - QCBORError cbor_error; - - /* --- Start making COSE Sign1 object --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* Do the first part of the the COSE_Sign1, the parameters */ - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return 1000 + (int32_t)result; - } - - - QCBOREncode_AddSZString(&cbor_encode, "payload"); - - /* Finish up the COSE_Sign1. This is where the signing happens */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return 2000 + (int32_t)result; - } - - /* Finally close of the CBOR formatting and get the pointer and - * length of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return 3000 + (int32_t)cbor_error; - } - /* --- Done making COSE Sign1 object --- */ - - /* --- Tweak signature bytes --- */ - /* The signature is the last thing so reach back that many bytes - * and tweak so if signature verification were attempted, it would - * fail (but this is a decode-only test so it won't fail). - */ - const size_t last_byte_offset = signed_cose.len - T_COSE_EC_P256_SIG_SIZE; - struct q_useful_buf temp_unconst = q_useful_buf_unconst(signed_cose); - ((uint8_t *)temp_unconst.ptr)[last_byte_offset]++; - - - /* --- Start verifying the COSE Sign1 object --- */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); - - /* Decode-only mode so no key and no signature check. */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - - - if(result) { - return 4000 + (int32_t)result; - } - - /* Format the expected payload CBOR fragment */ - QCBOREncode_Init(&cbor_encode, expected_payload_buffer); - QCBOREncode_AddSZString(&cbor_encode, "payload"); - QCBOREncode_Finish(&cbor_encode, &expected_payload); - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, expected_payload)) { - return 5000; - } - /* --- Done verifying the COSE Sign1 object --- */ - - return 0; -} - - -/* - 18( [ - / protected / h’a10126’ / { - \ alg \ 1:-7 \ ECDSA 256 \ - }/ , - / unprotected / { - / kid / 4:’11’ - }, - / payload / ’This is the content.’, - - / signature / h’8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4 - d25a91aef0b0117e2af9a291aa32e14ab834dc56ed2a223444547e01f11d3b0916e5 - a4c345cacb36’ -] ) - - */ - -/* This comes from Appendix_C_2_1.json from COSE_C by Jim Schaad */ -static const uint8_t rfc8152_example_2_1[] = { - 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, - 0x42, 0x31, 0x31, 0x54, 0x54, 0x68, 0x69, 0x73, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2E, /* end of hdrs and payload*/ - 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D, /* Sig starts with 0x58 */ - 0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC, - 0x6B, 0x23, 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31, - 0x06, 0xC4, 0xD2, 0x5A, 0x91, 0xAE, 0xF0, 0xB0, - 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91, 0xAA, 0x32, - 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A, - 0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D, - 0x3B, 0x09, 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA, - 0xCB, 0x36}; - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t cose_example_test() -{ - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c output; - struct t_cose_sign1_sign_ctx sign_ctx; - struct q_useful_buf_c head_actual; - struct q_useful_buf_c head_exp; - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, - T_COSE_NULL_KEY, - Q_USEFUL_BUF_FROM_SZ_LITERAL("11")); - - /* Make example C.2.1 from RFC 8152 */ - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &output); - - if(result != T_COSE_SUCCESS) { - return (int32_t)result; - } - - /* Compare only the headers and payload as this was not signed - * with the same key as the example. The first 32 bytes contain - * the header parameters and payload. */ - head_actual = q_useful_buf_head(output, 32); - head_exp = q_useful_buf_head(Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8152_example_2_1), 32); - - if(q_useful_buf_compare(head_actual, head_exp)) { - return -1000; - } - - return (int32_t)result; -} - - -static enum t_cose_err_t run_test_sign_and_verify(uint32_t test_mess_options, - uint32_t verify_options) -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - - /* --- Start making COSE Sign1 object --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - result = - t_cose_test_message_sign1_sign(&sign_ctx, - test_mess_options, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &signed_cose); - if(result) { - return result; - } - /* --- Done making COSE Sign1 object --- */ - - - /* --- Start verifying the COSE Sign1 object --- */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT | verify_options); - - /* No key necessary with short circuit */ - - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - - return result; -} - - -#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -int_fast32_t all_header_parameters_test() -{ - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c output; - struct q_useful_buf_c payload; - struct t_cose_parameters parameters; - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_signing_key(&sign_ctx, - T_COSE_NULL_KEY, - Q_USEFUL_BUF_FROM_SZ_LITERAL("11")); - - result = - t_cose_test_message_sign1_sign(&sign_ctx, - T_COSE_TEST_ALL_PARAMETERS, - s_input_payload, - signed_cose_buffer, - &output); - if(result) { - return 1; - } - - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - output, - /* The returned payload */ - &payload, - /* Get parameters for checking */ - ¶meters); - - // Need to compare to short circuit kid - if(q_useful_buf_compare(parameters.kid, get_short_circuit_kid())) { - return 2; - } - - if(parameters.cose_algorithm_id != T_COSE_ALGORITHM_ES256) { - return 3; - } - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - if(parameters.content_type_uint != 1) { - return 4; - } -#endif /* T_COSE_DISABLE_CONTENT_TYPE */ - - if(q_useful_buf_compare(parameters.iv, - Q_USEFUL_BUF_FROM_SZ_LITERAL("iv"))) { - return 5; - } - - if(q_useful_buf_compare(parameters.partial_iv, - Q_USEFUL_BUF_FROM_SZ_LITERAL("partial_iv"))) { - return 6; - } - - return 0; -} -#endif - -struct test_case { - uint32_t test_option; - uint32_t verify_option; - enum t_cose_err_t result; -}; - -static struct test_case bad_parameters_tests_table[] = { - - {T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS, 0, T_COSE_ERR_UNSUPPORTED_SIGNING_ALG}, - - {T_COSE_TEST_UNCLOSED_PROTECTED, 0, T_COSE_ERR_PARAMETER_CBOR}, - -#ifndef T_COSE_DISABLE_CONTENT_TYPE - {T_COSE_TEST_DUP_CONTENT_ID, 0, T_COSE_ERR_DUPLICATE_PARAMETER}, - - {T_COSE_TEST_TOO_LARGE_CONTENT_TYPE, 0, T_COSE_ERR_BAD_CONTENT_TYPE}, -#endif /* T_COSE_DISABLE_CONTENT_TYPE */ - - {T_COSE_TEST_NOT_WELL_FORMED_2, 0, T_COSE_ERR_CBOR_NOT_WELL_FORMED}, - - {T_COSE_TEST_KID_IN_PROTECTED, 0, T_COSE_ERR_DUPLICATE_PARAMETER}, - - {T_COSE_TEST_TOO_MANY_UNKNOWN, 0, T_COSE_ERR_TOO_MANY_PARAMETERS}, - - {T_COSE_TEST_UNPROTECTED_NOT_MAP, 0, T_COSE_ERR_PARAMETER_CBOR}, - - {T_COSE_TEST_BAD_CRIT_PARAMETER, 0, T_COSE_ERR_CRIT_PARAMETER}, - - {T_COSE_TEST_NOT_WELL_FORMED_1, 0, T_COSE_ERR_CBOR_NOT_WELL_FORMED}, - - {T_COSE_TEST_NO_UNPROTECTED_PARAMETERS, 0, T_COSE_ERR_PARAMETER_CBOR}, - - {T_COSE_TEST_NO_PROTECTED_PARAMETERS, 0, T_COSE_ERR_PARAMETER_CBOR}, - - {T_COSE_TEST_EXTRA_PARAMETER, 0, T_COSE_SUCCESS}, - - {T_COSE_TEST_PARAMETER_LABEL, 0, T_COSE_ERR_PARAMETER_CBOR}, - - {T_COSE_TEST_BAD_PROTECTED, 0, T_COSE_ERR_PARAMETER_CBOR}, - - {0, 0, 0} -}; - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t bad_parameters_test() -{ - struct test_case *test; - - for(test = bad_parameters_tests_table; test->test_option; test++) { - if(run_test_sign_and_verify(test->test_option, test->verify_option) != test->result) { - return (int_fast32_t)(test - bad_parameters_tests_table + 1); - } - } - - return 0; -} - - - - -static struct test_case crit_tests_table[] = { - /* Test existance of the critical header. Also makes sure that - * it works with the max number of labels allowed in it. - */ - {T_COSE_TEST_CRIT_PARAMETER_EXIST, 0, T_COSE_SUCCESS}, - - /* Exceed the max number of labels by one and get an error */ - {T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST, 0, T_COSE_ERR_CRIT_PARAMETER}, - - /* A critical parameter exists in the protected section, but the - * format of the internals of this parameter is not the expected CBOR - */ - {T_COSE_TEST_BAD_CRIT_LABEL, 0, T_COSE_ERR_CRIT_PARAMETER}, - - /* The critical parameter includes an unknown uint label. */ - {T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER, 0, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER}, - - /* The critical parameter includes an unknown tstr label. */ - {T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER, 0, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER}, - - /* The critical parameter includes an unknown label, but criticality - * checking is disabled. - */ - {T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER, T_COSE_OPT_UNKNOWN_CRIT_ALLOWED, T_COSE_SUCCESS}, - {T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER, T_COSE_OPT_UNKNOWN_CRIT_ALLOWED, T_COSE_SUCCESS}, - - /* The critical labels list is not protected */ - {T_COSE_TEST_CRIT_NOT_PROTECTED, 0, T_COSE_ERR_PARAMETER_NOT_PROTECTED}, - - {T_COSE_TEST_EMPTY_CRIT_PARAMETER, 0, T_COSE_ERR_CRIT_PARAMETER}, - - {T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS, 0, T_COSE_ERR_CRIT_PARAMETER}, - - {0, 0, 0} -}; - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t crit_parameters_test() -{ - struct test_case *test; - - for(test = crit_tests_table; test->test_option; test++) { - if(run_test_sign_and_verify(test->test_option, test->verify_option) != test->result) { - return (int_fast32_t)(test - crit_tests_table + 1); - } - } - - return 0; -} - - -#ifndef T_COSE_DISABLE_CONTENT_TYPE -/* - * Public function, see t_cose_test.h - */ -int_fast32_t content_type_test() -{ - struct t_cose_parameters parameters; - struct t_cose_sign1_sign_ctx sign_ctx; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c output; - struct q_useful_buf_c payload; - enum t_cose_err_t result; - struct t_cose_sign1_verify_ctx verify_ctx; - - - /* -- integer content type -- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_content_type_uint(&sign_ctx, 42); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &output); - if(result) { - return 1; - } - - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - result = t_cose_sign1_verify(&verify_ctx, - output, - &payload, - ¶meters); - if(result) { - return 2; - } - - if(parameters.content_type_uint != 42) { - return 5; - } - - - /* -- string content type -- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain"); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &output); - if(result) { - return 1; - } - - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - result = t_cose_sign1_verify(&verify_ctx, - output, - &payload, - ¶meters); - if(result) { - return 2; - } - - if(q_useful_buf_compare(parameters.content_type_tstr, Q_USEFUL_BUF_FROM_SZ_LITERAL("text/plain"))) { - return 6; - } - - - /* -- content type in error -- */ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain"); - t_cose_sign1_set_content_type_uint(&sign_ctx, 42); - - - result = t_cose_sign1_sign(&sign_ctx, - Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"), - signed_cose_buffer, - &output); - if(result != T_COSE_ERR_DUPLICATE_PARAMETER) { - return 1; - } - return 0; -} -#endif /* T_COSE_DISABLE_CONTENT_TYPE */ - - -struct sign1_sample { - struct q_useful_buf_c CBOR; - enum t_cose_err_t expected_error; -}; - -static struct sign1_sample sign1_sample_inputs[] = { - /* 0. With an indefinite length string payload */ - { {(uint8_t[]){0x84, 0x40, 0xa0, 0x5f, 0x00, 0xff, 0x40}, 7}, T_COSE_ERR_SIGN1_FORMAT}, - /* 1. Too few items in unprotected header parameters bucket */ - { {(uint8_t[]){0x84, 0x40, 0xa3, 0x40, 0x40}, 5}, T_COSE_ERR_PARAMETER_CBOR}, - /* 2. Too few items in definite array */ - { {(uint8_t[]){0x83, 0x40, 0xa0, 0x40}, 4}, T_COSE_ERR_SIGN1_FORMAT}, - /* 3. Too-long signature */ - { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x4f}, 5}, T_COSE_ERR_CBOR_NOT_WELL_FORMED}, - /* 4. Too-long payload */ - { {(uint8_t[]){0x84, 0x40, 0xa0, 0x4f, 0x40}, 5}, T_COSE_ERR_CBOR_NOT_WELL_FORMED}, - /* 5. Too-long protected parameters bucket */ - { {(uint8_t[]){0x84, 0x4f, 0xa0, 0x40, 0x40}, 5}, T_COSE_ERR_CBOR_NOT_WELL_FORMED}, - /* 6. Unterminated indefinite length */ - { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40}, 6}, T_COSE_ERR_SIGN1_FORMAT}, - /* 7. The smallest legal COSE_Sign1 using indefinite lengths */ - { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40, 0xff}, 7}, T_COSE_SUCCESS}, - /* 8. The smallest legal COSE_Sign1 using definite lengths */ - { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x40}, 5}, T_COSE_SUCCESS}, - /* 9. Just one not-well-formed byte -- a reserved value */ - { {(uint8_t[]){0x3c}, 1}, T_COSE_ERR_CBOR_NOT_WELL_FORMED }, - /* terminate the list */ - { {NULL, 0}, 0 }, -}; - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t sign1_structure_decode_test(void) -{ - const struct sign1_sample *sample; - struct q_useful_buf_c payload; - enum t_cose_err_t result; - struct t_cose_sign1_verify_ctx verify_ctx; - - - for(sample = sign1_sample_inputs; !q_useful_buf_c_is_null(sample->CBOR); sample++) { - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); - - result = t_cose_sign1_verify(&verify_ctx, - sample->CBOR, - &payload, - NULL); - - if(result != sample->expected_error) { - /* Returns 100 * index of the input + the unexpected error code */ - const size_t sample_index = (size_t)(sample - sign1_sample_inputs); - return (int32_t)((sample_index+1)*100 + result); - } - } - - return 0; -} - - -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST - -/* Linkage to global variable in t_cose_test_crypto.c. This is only - * used for an occasional test in a non-threaded environment so a global - * variable is safe. This test and the hacks in the crypto code are - * never enabled for commercial deployments. - */ -extern int hash_test_mode; - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t short_circuit_hash_fail_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - enum t_cose_err_t result; - struct q_useful_buf_c wrapped_payload; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - - /* See test description in t_cose_test.h for a full description of - * what this does and what it needs to run. - */ - - - /* Set the global variable to cause the hash implementation to - * error out so this test can see what happens - */ - hash_test_mode = 1; - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &wrapped_payload); - - hash_test_mode = 0; - - if(result != T_COSE_ERR_HASH_GENERAL_FAIL) { - return 2000 + (int32_t)result; - } - - - /* Set the global variable to cause the hash implementation to - * error out so this test can see what happens - */ - hash_test_mode = 2; - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - result = t_cose_sign1_sign(&sign_ctx, - s_input_payload, - signed_cose_buffer, - &wrapped_payload); - - hash_test_mode = 0; - - if(result != T_COSE_ERR_HASH_GENERAL_FAIL) { - return 2000 + (int32_t)result; - } - - return 0; -} - -#endif /* T_COSE_ENABLE_HASH_FAIL_TEST */ - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t tags_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - struct t_cose_sign1_verify_ctx verify_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t result; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200); - struct q_useful_buf_c signed_cose; - struct q_useful_buf_c payload; - QCBORError cbor_error; - uint64_t tag; - - /* --- Start making COSE Sign1 object tagged 900(901(18())) --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - QCBOREncode_AddTag(&cbor_encode, 900); - - QCBOREncode_AddTag(&cbor_encode, 901); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* Do the first part of the the COSE_Sign1, the parameters */ - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return 1000 + (int32_t)result; - } - - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com"); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944); - const uint8_t xx[] = {0x0b, 0x71}; - QCBOREncode_AddBytesToMapN(&cbor_encode, 7, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx)); - QCBOREncode_CloseMap(&cbor_encode); - - /* Finish up the COSE_Sign1. This is where the signing happens */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return 2000 + (int32_t)result; - } - - /* Finally close off the CBOR formatting and get the pointer and length - * of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return 3000 + (int32_t)cbor_error; - } - /* --- Done making COSE Sign1 object tagged 900(901(18(0))) --- */ - - - /* --- Compare to expected from CWT RFC --- */ - /* The first part, the intro and protected pararameters must be the same */ - const uint8_t cwt_first_part_bytes[] = {0xd9, 0x03, 0x84, 0xd9, 0x03, 0x85, 0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26}; - struct q_useful_buf_c fp = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(cwt_first_part_bytes); - struct q_useful_buf_c head = q_useful_buf_head(signed_cose, sizeof(cwt_first_part_bytes)); - if(q_useful_buf_compare(head, fp)) { - return -1; - } - - /* Skip the key id, because this has the short-circuit key id */ - const size_t kid_encoded_len = - 1 + - 1 + - 2 + - 32; // length of short-circuit key id - - /* Compare the payload */ - const uint8_t rfc8392_payload_bytes[] = { - 0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, - 0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77, - 0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, - 0x69, 0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0, - 0x05, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9, - 0xf0, 0x07, 0x42, 0x0b, 0x71}; - - struct q_useful_buf_c fp2 = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_payload_bytes); - - struct q_useful_buf_c payload2 = q_useful_buf_tail(signed_cose, - sizeof(cwt_first_part_bytes)+kid_encoded_len); - struct q_useful_buf_c pl3 = q_useful_buf_head(payload2, - sizeof(rfc8392_payload_bytes)); - if(q_useful_buf_compare(pl3, fp2)) { - return -2; - } - - /* Skip the signature because ECDSA signatures usually have a random - component */ - - - /* --- Start verifying the COSE Sign1 object --- */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result) { - return 4000 + (int32_t)result; - } - - tag = t_cose_sign1_get_nth_tag(&verify_ctx, 0); - if(tag != 901) { - return -3; - } - - tag = t_cose_sign1_get_nth_tag(&verify_ctx, 1); - if(tag != 900) { - return -3; - } - - tag = t_cose_sign1_get_nth_tag(&verify_ctx, 2); - if(tag != CBOR_TAG_INVALID64) { - return -4; - } - - /* compare payload output to the one expected */ - if(q_useful_buf_compare(payload, q_useful_buf_tail(fp2, 2))) { - return 5000; - } - /* --- Done verifying the COSE Sign1 object --- */ - - - /* --- Start verifying the COSE Sign1 object, requiring tag--- */ - t_cose_sign1_verify_init(&verify_ctx, - T_COSE_OPT_ALLOW_SHORT_CIRCUIT | T_COSE_OPT_TAG_REQUIRED); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_SUCCESS) { - return 4000 + (int32_t)result; - } - - /* --- Done verifying the COSE Sign1 object --- */ - - - - /* --- Start verifying the COSE Sign1 object, prohibiting tag--- */ - t_cose_sign1_verify_init(&verify_ctx, - T_COSE_OPT_ALLOW_SHORT_CIRCUIT | T_COSE_OPT_TAG_PROHIBITED); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_ERR_INCORRECTLY_TAGGED) { - return 4000 + (int32_t)result; - } - - /* --- Done verifying the COSE Sign1 object --- */ - - - - /* --- Start making COSE Sign1 object --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - QCBOREncode_AddTag(&cbor_encode, 900); - QCBOREncode_AddTag(&cbor_encode, 901); - QCBOREncode_AddTag(&cbor_encode, 902); - QCBOREncode_AddTag(&cbor_encode, 903); - QCBOREncode_AddTag(&cbor_encode, 904); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - /* Do the first part of the the COSE_Sign1, the parameters */ - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return 1000 + (int32_t)result; - } - - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com"); - QCBOREncode_CloseMap(&cbor_encode); - - /* Finish up the COSE_Sign1. This is where the signing happens */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return 2000 + (int32_t)result; - } - - /* Finally close off the CBOR formatting and get the pointer and length - * of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return 3000 + (int32_t)cbor_error; - } - /* --- Done making COSE Sign1 object --- */ - - /* --- Start verifying the COSE Sign1 object --- */ - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_ERR_TOO_MANY_TAGS) { - return 4000 + (int32_t)result; - } - - - - /* --- Start making COSE Sign1 object tagged 900(901()) --- */ - - /* The CBOR encoder instance that the COSE_Sign1 is output into */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - QCBOREncode_AddTag(&cbor_encode, 900); - - QCBOREncode_AddTag(&cbor_encode, 901); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG | T_COSE_OPT_OMIT_CBOR_TAG, - T_COSE_ALGORITHM_ES256); - - /* Do the first part of the the COSE_Sign1, the parameters */ - result = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(result) { - return 1000 + (int32_t)result; - } - - QCBOREncode_OpenMap(&cbor_encode); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw"); - QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com"); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944); - QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944); - const uint8_t xxy[] = {0x0b, 0x71}; - QCBOREncode_AddBytesToMapN(&cbor_encode, 7, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xxy)); - QCBOREncode_CloseMap(&cbor_encode); - - /* Finish up the COSE_Sign1. This is where the signing happens */ - result = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(result) { - return 2000 + (int32_t)result; - } - - /* Finally close off the CBOR formatting and get the pointer and length - * of the resulting COSE_Sign1 - */ - cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose); - if(cbor_error) { - return 3000 + (int32_t)cbor_error; - } - /* --- Done making COSE Sign1 object tagged 900(901(18(0))) --- */ - - - - /* --- Compare to expected from CWT RFC --- */ - /* The first part, the intro and protected pararameters must be the same */ - const uint8_t cwt_first_part_bytes1[] = {0xd9, 0x03, 0x84, 0xd9, 0x03, 0x85, 0x84, 0x43, 0xa1, 0x01, 0x26}; - struct q_useful_buf_c fp1 = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(cwt_first_part_bytes1); - struct q_useful_buf_c head1 = q_useful_buf_head(signed_cose, sizeof(cwt_first_part_bytes1)); - if(q_useful_buf_compare(head1, fp1)) { - return -1; - } - - /* --- Start verifying the COSE Sign1 object, requiring tag--- */ - t_cose_sign1_verify_init(&verify_ctx, - T_COSE_OPT_ALLOW_SHORT_CIRCUIT | T_COSE_OPT_TAG_REQUIRED); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_ERR_INCORRECTLY_TAGGED) { - return 4000 + (int32_t)result; - } - - - /* --- Start verifying the COSE Sign1 object, prohibiting tag--- */ - t_cose_sign1_verify_init(&verify_ctx, - T_COSE_OPT_ALLOW_SHORT_CIRCUIT | T_COSE_OPT_TAG_PROHIBITED); - - /* No key necessary with short circuit */ - - /* Run the signature verification */ - result = t_cose_sign1_verify(&verify_ctx, - /* COSE to verify */ - signed_cose, - /* The returned payload */ - &payload, - /* Don't return parameters */ - NULL); - if(result != T_COSE_SUCCESS) { - return 4000 + (int32_t)result; - } - - /* --- Done verifying the COSE Sign1 object --- */ - - return 0; -} - - -int_fast32_t get_size_test() -{ - struct t_cose_sign1_sign_ctx sign_ctx; - QCBOREncodeContext cbor_encode; - enum t_cose_err_t return_value; - struct q_useful_buf nil_buf; - size_t calculated_size; - QCBORError cbor_error; - struct q_useful_buf_c actual_signed_cose; - Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300); - struct q_useful_buf_c payload; - - /* ---- Common Set up ---- */ - payload = Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"); - - /* ---- First calculate the size ----- */ - nil_buf = (struct q_useful_buf) {NULL, SIZE_MAX}; - QCBOREncode_Init(&cbor_encode, nil_buf); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(return_value) { - return 2000 + (int32_t)return_value; - } - - QCBOREncode_AddEncoded(&cbor_encode, payload); - - return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(return_value) { - return 3000 + (int32_t)return_value; - } - - cbor_error = QCBOREncode_FinishGetSize(&cbor_encode, &calculated_size); - if(cbor_error) { - return 4000 + (int32_t)cbor_error; - } - - /* ---- General sanity check ---- */ - size_t expected_min = 32 + payload.len + 64; - - if(calculated_size < expected_min || calculated_size > expected_min + 30) { - return -1; - } - - - - /* ---- Now make a real COSE_Sign1 and compare the size ---- */ - QCBOREncode_Init(&cbor_encode, signed_cose_buffer); - - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - - return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode); - if(return_value) { - return 2000 + (int32_t)return_value; - } - - QCBOREncode_AddEncoded(&cbor_encode, payload); - - return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode); - if(return_value) { - return 3000 + (int32_t)return_value; - } - - cbor_error = QCBOREncode_Finish(&cbor_encode, &actual_signed_cose); - if(actual_signed_cose.len != calculated_size) { - return -2; - } - - /* ---- Again with one-call API to make COSE_Sign1 ---- */\ - t_cose_sign1_sign_init(&sign_ctx, - T_COSE_OPT_SHORT_CIRCUIT_SIG, - T_COSE_ALGORITHM_ES256); - return_value = t_cose_sign1_sign(&sign_ctx, - payload, - signed_cose_buffer, - &actual_signed_cose); - if(return_value) { - return 7000 + (int32_t)return_value; - } - - if(actual_signed_cose.len != calculated_size) { - return -3; - } - - - return 0; -} - - -/* - * Public function, see t_cose_test.h - */ -int_fast32_t indef_array_and_map_test() -{ - enum t_cose_err_t return_value; - uint32_t t_opts; - - /* This makes some COSEs with - * - The main array of four indefinite length - * - The protected header parameters map indef - * - The unprotected header parameters map indef - * - The critical pamaraters array inde - */ - - /* General test with indefinite lengths */ - return_value = run_test_sign_and_verify(T_COSE_TEST_INDEFINITE_MAPS_ARRAYS, 0); - if(return_value != T_COSE_SUCCESS) { - return 1000 + (int32_t) return_value; - } - - /* Test critical parameters encoded as indefinite length */ - t_opts = T_COSE_TEST_INDEFINITE_MAPS_ARRAYS | - T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER; - return_value = run_test_sign_and_verify(t_opts, 0); - if(return_value != T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER) { - return 2000 + (int32_t) return_value; - } - - /* Another general test with indefinite lengths */ - t_opts = T_COSE_TEST_INDEFINITE_MAPS_ARRAYS | - T_COSE_TEST_ALL_PARAMETERS; - return_value = run_test_sign_and_verify(t_opts, 0); - if(return_value != T_COSE_SUCCESS) { - return 3000 + (int32_t) return_value; - } - - return 0; -} diff --git a/3rdparty/internal/t_cose/test/t_cose_test.h b/3rdparty/internal/t_cose/test/t_cose_test.h deleted file mode 100644 index 30a039220123..000000000000 --- a/3rdparty/internal/t_cose/test/t_cose_test.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * t_cose_test.h - * - * Copyright 2019-2022, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef t_cose_test_h -#define t_cose_test_h - -#include - -/** - * \file t_cose_test.h - * - * \brief Entry points for the basic t_cose_tests. - * - * These tests can be performed without any crypto library such as OpenSSL - * integrated with t_cose. - */ - - -/** - * \brief Minimal message creation test using a short-circuit signature. - * - * \return non-zero on failure. - * - * This test makes a simple COSE_Sign1 and verify it. It uses - * short-circuit signatures so no keys or even integration with public - * key crypto is necessary. - */ -int_fast32_t short_circuit_self_test(void); - - -/** - * \brief COSE detached content test using a short-circuit signature. - * - * \return non-zero on failure. - * - * This test makes a detached content COSE_Sign1 and verify it. It uses - * short-circuit signatures so no keys or even integration with public - * key crypto is necessary. - */ -int_fast32_t short_circuit_self_detached_content_test(void); - - -/** - * \brief Test where payload bytes are corrupted and sig fails. - * - * \return non-zero on failure. - * - * This test makes a simple COSE_Sign1 modifies the payload and sees that - * verification fails. It uses short-circuit signatures so no keys or - * even integration with public key crypto is necessary. - */ -int_fast32_t short_circuit_verify_fail_test(void); - - -/** - * \brief Tests error condidtions for creating COSE_Sign1. - * - * \return non-zero on failure. - * - * It uses short-circuit signatures so no keys or even integration - * with public key crypto is necessary. - */ -int_fast32_t short_circuit_signing_error_conditions_test(void); - - -/* Make a CWT and see that it compares to the sample in the CWT RFC - */ -int_fast32_t short_circuit_make_cwt_test(void); - - -/* - * Test the decode only mode, the mode where the - * headers are returned, but the signature is not - * verified. - */ -int_fast32_t short_circuit_decode_only_test(void); - - -/* -- protected header parameters not well formed CBOR -- unprotected header parameters not well formed CBOR -- unknown algorithm ID -- No algorithm ID parameter - - */ -int_fast32_t bad_parameters_test(void); - - -/* Test that makes a CWT (CBOR Web Token) - */ -int_fast32_t cose_example_test(void); - - -/* - Various tests involving the crit parameter. - */ -int_fast32_t crit_parameters_test(void); - - -/* - Check that all types of headers are correctly returned. - */ -int_fast32_t all_header_parameters_test(void); - - -/* - * Check that setting the content type works - */ -int_fast32_t content_type_test(void); - - -/* - * Check that setting the content type works - */ -int_fast32_t sign1_structure_decode_test(void); - - -#ifdef T_COSE_ENABLE_HASH_FAIL_TEST -/* - * This forces / simulates failures in the hash algorithm implementation - * to test t_cose's handling of those condidtions. This test is off - * by default because it needs a hacked version of a hash algorithm. - * It is very hard to get hash algorithms to fail, so this hacked - * version is necessary. This test will not run correctly with - * OpenSSL or Mbed TLS hashes because they aren't (and shouldn't be) hacked. - * It works only with the b_con hash bundled and not intended for - * commercial use (though it is a perfectly fine implementation). - */ -int_fast32_t short_circuit_hash_fail_test(void); - -#endif /* T_COSE_ENABLE_HASH_FAIL_TEST*/ - - - -/* - * Test tagging of COSE message - */ -int_fast32_t tags_test(void); - - -int_fast32_t get_size_test(void); - - -/* - * Test the decoding of COSE messages that use indefinite length - * maps and arrays instead of definite length. - */ -int_fast32_t indef_array_and_map_test(void); - - -#endif /* t_cose_test_h */ diff --git a/CHANGELOG.md b/CHANGELOG.md index 541d7c525af7..7c7f31e066a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added +- Added `COSEVerifier::verify_decomposed()` method that accepts pre-parsed COSE_Sign1 components (protected header, payload, signature, algorithm), bypassing envelope parsing. - Backup nodes can now be configured to automatically fetch snapshots from the primary when snapshot evidence is detected. This is controlled by the `snapshots.backup_fetch` configuration section, with `enabled`, `max_attempts`, `retry_interval`, `max_size` and `target_rpc_interface` options. Note that the target RPC interface selected must have the `SnapshotRead` operator feature enabled. - Added `ccf::IdentityHistoryNotFetched` exception type to distinguish identity-history-fetching errors from other logic errors in the network identity subsystem (#7708). - Added `ccf::describe_cose_receipt_v1(receipt)` to obtain COSE receipts with Merkle proof in unprotected header for non-signature TXs, and empty unprotected header for signature TXs (#7700). diff --git a/CMakeLists.txt b/CMakeLists.txt index 5391e8329ef1..ffbbaca4020d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,11 +173,18 @@ set(HTTP_PARSER_SOURCES ${CCF_3RD_PARTY_EXPORTED_DIR}/llhttp/llhttp.c ) +include(FetchContent) +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git + GIT_TAG a1a1aaa057a5da656c06c3d8505b767a4e941709 # v0.5.2 +) +FetchContent_MakeAvailable(Corrosion) + +include(${CCF_DIR}/cmake/cose_openssl.cmake) include(${CCF_DIR}/cmake/crypto.cmake) include(${CCF_DIR}/cmake/quickjs.cmake) -include(${CCF_DIR}/cmake/qcbor.cmake) include(${CCF_DIR}/cmake/evercbor.cmake) -include(${CCF_DIR}/cmake/t_cose.cmake) # Launcher library list(APPEND CCF_LAUNCHER_SOURCES ${CCF_DIR}/src/host/run.cpp @@ -271,8 +278,6 @@ add_ccf_static_library( LINK_LIBS http_parser ccfcrypto ccf_kv ) -target_link_libraries(ccf_endpoints PRIVATE t_cose) # For cose_auth only - # CCF task system library add_ccf_static_library( ccf_tasks @@ -633,7 +638,7 @@ if(BUILD_TESTS) crypto_test ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/test/crypto.cpp ) target_include_directories(crypto_test PRIVATE ${CCFCRYPTO_INC}) - target_link_libraries(crypto_test PRIVATE ccfcrypto t_cose) + target_link_libraries(crypto_test PRIVATE ccfcrypto) add_unit_test( cbor_test ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/test/cbor.cpp @@ -738,8 +743,13 @@ if(BUILD_TESTS) add_unit_test( cose_test ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/test/cose.cpp ) + target_link_libraries(cose_test PRIVATE ${CMAKE_THREAD_LIBS_INIT} ccfcrypto) + + add_unit_test( + cose_ffi_test ${CMAKE_CURRENT_SOURCE_DIR}/src/cose/test/cose_ffi_test.cpp + ) target_link_libraries( - cose_test PRIVATE ${CMAKE_THREAD_LIBS_INIT} ccfcrypto t_cose + cose_ffi_test PRIVATE ${CMAKE_THREAD_LIBS_INIT} ccfcrypto ) add_unit_test(pem_test ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/test/pem.cpp) diff --git a/cgmanifest.json b/cgmanifest.json index 8a3dd92f9ecd..4d3466f1d7ab 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -109,26 +109,6 @@ } } }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/laurencelundblade/QCBOR", - "commitHash": "4ace4620d549f22c1163c5b00d3ae0c0dae1d207", - "tag": "v1.5.3" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/laurencelundblade/t_cose", - "commitHash": "64fbc64dd5982a7f75834d2b9a2a8c9ba8207776", - "tag": "v1.1.3" - } - } - }, { "component": { "type": "git", diff --git a/cmake/cose_openssl.cmake b/cmake/cose_openssl.cmake new file mode 100644 index 000000000000..99f7bd5a81c4 --- /dev/null +++ b/cmake/cose_openssl.cmake @@ -0,0 +1,26 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache 2.0 License. + +corrosion_import_crate( + MANIFEST_PATH + "${CCF_DIR}/src/cose/cose_rs/Cargo.toml" + PROFILE + "release" + CRATES + "cose-rs" + CRATE_TYPES + "staticlib" +) + +# Reproducible builds: remap absolute paths in the binary. RUSTFLAGS applies to +# all crates (including dependencies), unlike +# corrosion_add_target_local_rustflags which only applies to the top crate. +corrosion_set_env_vars( + cose_rs + "RUSTFLAGS=--remap-path-prefix=${CCF_DIR}=CCF --remap-path-prefix=$ENV{HOME}/.cargo=CARGO" +) + +# What Rust, and therefore corrosion defaults to. +set(COSE_RS_LIB libcose_rs.a) + +install(FILES ${CMAKE_BINARY_DIR}/${COSE_RS_LIB} DESTINATION lib) diff --git a/cmake/crypto.cmake b/cmake/crypto.cmake index d7f190266dd7..d04258097497 100644 --- a/cmake/crypto.cmake +++ b/cmake/crypto.cmake @@ -25,7 +25,6 @@ set(CCFCRYPTO_SRC ${CCF_DIR}/src/crypto/openssl/rsa_key_pair.cpp ${CCF_DIR}/src/crypto/openssl/verifier.cpp ${CCF_DIR}/src/crypto/openssl/cose_verifier.cpp - ${CCF_DIR}/src/crypto/openssl/cose_sign.cpp ${CCF_DIR}/src/crypto/sharing.cpp ${CCF_DIR}/src/crypto/cbor.cpp ) @@ -40,7 +39,15 @@ target_compile_options(ccfcrypto PUBLIC ${COMPILE_LIBCXX}) target_link_options(ccfcrypto PUBLIC ${LINK_LIBCXX}) target_link_libraries(ccfcrypto PUBLIC crypto ssl evercbor) -target_link_libraries(ccfcrypto PRIVATE t_cose) +target_link_libraries( + ccfcrypto + PUBLIC $ + $ +) +add_dependencies(ccfcrypto cargo-build_cose_rs) +target_include_directories( + ccfcrypto PUBLIC $ +) set_property(TARGET ccfcrypto PROPERTY POSITION_INDEPENDENT_CODE ON) install( diff --git a/cmake/qcbor.cmake b/cmake/qcbor.cmake deleted file mode 100644 index cfc02ecaf61c..000000000000 --- a/cmake/qcbor.cmake +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the Apache 2.0 License. - -# Build QCBOR -set(QCBOR_DIR "${CCF_3RD_PARTY_INTERNAL_DIR}/QCBOR") -set(QCBOR_SRC "${QCBOR_DIR}/src") -set(QCBOR_SRCS - "${QCBOR_SRC}/ieee754.c" "${QCBOR_SRC}/qcbor_decode.c" - "${QCBOR_SRC}/qcbor_encode.c" "${QCBOR_SRC}/qcbor_err_to_str.c" - "${QCBOR_SRC}/UsefulBuf.c" -) - -add_library(qcbor STATIC ${QCBOR_SRCS}) - -target_include_directories( - qcbor PUBLIC $ -) - -set_property(TARGET qcbor PROPERTY POSITION_INDEPENDENT_CODE ON) -add_san(qcbor) - -install( - TARGETS qcbor - EXPORT ccf - DESTINATION lib -) diff --git a/cmake/t_cose.cmake b/cmake/t_cose.cmake deleted file mode 100644 index 47849b217109..000000000000 --- a/cmake/t_cose.cmake +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the Apache 2.0 License. - -# Build t_cose -set(T_COSE_DIR "${CCF_3RD_PARTY_INTERNAL_DIR}/t_cose") -set(T_COSE_SRC "${T_COSE_DIR}/src") -set(T_COSE_DEFS -DT_COSE_USE_OPENSSL_CRYPTO=1 - -DT_COSE_DISABLE_SHORT_CIRCUIT_SIGN=1 -) -set(T_COSE_SRCS - "${T_COSE_SRC}/t_cose_parameters.c" "${T_COSE_SRC}/t_cose_sign1_verify.c" - "${T_COSE_SRC}/t_cose_sign1_sign.c" "${T_COSE_SRC}/t_cose_util.c" - "${T_COSE_DIR}/crypto_adapters/t_cose_openssl_crypto.c" -) - -find_package(OpenSSL REQUIRED) -add_library(t_cose STATIC ${T_COSE_SRCS}) -target_compile_definitions(t_cose PRIVATE ${T_COSE_DEFS}) -target_compile_options(t_cose INTERFACE ${T_COSE_OPTS_INTERFACE}) - -target_include_directories(t_cose PRIVATE "${T_COSE_SRC}") -target_include_directories( - t_cose PUBLIC $ -) - -target_link_libraries(t_cose PUBLIC qcbor) -set_property(TARGET t_cose PROPERTY POSITION_INDEPENDENT_CODE ON) -add_san(t_cose) - -install( - TARGETS t_cose - EXPORT ccf - DESTINATION lib -) diff --git a/include/ccf/crypto/cose_verifier.h b/include/ccf/crypto/cose_verifier.h index 494d0527c777..65133d79042b 100644 --- a/include/ccf/crypto/cose_verifier.h +++ b/include/ccf/crypto/cose_verifier.h @@ -17,6 +17,11 @@ namespace ccf::crypto [[nodiscard]] virtual bool verify_detached( std::span envelope, std::span payload) const = 0; + [[nodiscard]] virtual bool verify_decomposed( + std::span phdr, + std::span payload, + std::span sig, + int64_t alg) const = 0; virtual ~COSEVerifier() = default; }; diff --git a/src/cose/cose_rs/Cargo.lock b/src/cose/cose_rs/Cargo.lock new file mode 100644 index 000000000000..ca2ca8db930f --- /dev/null +++ b/src/cose/cose_rs/Cargo.lock @@ -0,0 +1,93 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cborrs" +version = "0.1.0" +source = "git+https://github.com/project-everest/everparse.git?tag=v2026.02.25#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "cborrs-nondet" +version = "0.1.0" +source = "git+https://github.com/project-everest/everparse.git?tag=v2026.02.25#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cose-openssl" +version = "0.1.0" +dependencies = [ + "cborrs", + "cborrs-nondet", + "openssl-sys", +] + +[[package]] +name = "cose-rs" +version = "0.1.0" +dependencies = [ + "cose-openssl", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "openssl-sys" +version = "0.9.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" diff --git a/src/cose/cose_rs/Cargo.toml b/src/cose/cose_rs/Cargo.toml new file mode 100644 index 000000000000..545940a82659 --- /dev/null +++ b/src/cose/cose_rs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cose-rs" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +cose-openssl = { path = "../../../3rdparty/internal/cose-openssl" } + +[profile.release] +lto = true +codegen-units = 1 diff --git a/src/cose/cose_rs/rust-toolchain.toml b/src/cose/cose_rs/rust-toolchain.toml new file mode 100644 index 000000000000..ff100edcbbe7 --- /dev/null +++ b/src/cose/cose_rs/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.90.0" diff --git a/src/cose/cose_rs/src/lib.rs b/src/cose/cose_rs/src/lib.rs new file mode 100644 index 000000000000..d7ede67973e8 --- /dev/null +++ b/src/cose/cose_rs/src/lib.rs @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the Apache 2.0 License. + +use cose_openssl::{CborValue, EvpKey}; +use std::slice; + +// COSE/CWT header labels (matching CCF's C++ constants). +const CWT_CLAIMS: i64 = 15; +const KID: i64 = 4; +const VDS: i64 = 395; +const IAT: i64 = 6; +const ISS: i64 = 1; +const SUB: i64 = 2; +const CCF_LEDGER_SHA256: i64 = 2; + +const CCF_V1: &str = "ccf.v1"; +const TX_ID: &str = "txid"; +const TX_RANGE_BEGIN: &str = "epoch.start.txid"; +const TX_RANGE_END: &str = "epoch.end.txid"; +const EPOCH_LAST_MERKLE_ROOT: &str = "epoch.end.merkle.root"; + +unsafe fn slice_from_raw(ptr: *const u8, len: usize) -> &'static [u8] { + if ptr.is_null() || len == 0 { + &[] + } else { + unsafe { slice::from_raw_parts(ptr, len) } + } +} + +unsafe fn str_from_raw(ptr: *const u8, len: usize) -> &'static str { + let bytes = unsafe { slice_from_raw(ptr, len) }; + std::str::from_utf8(bytes).unwrap_or("") +} + +fn build_ledger_phdr(kid: &[u8], iat: i64, issuer: &str, subject: &str, txid: &str) -> CborValue { + let cwt = CborValue::Map(vec![ + (CborValue::Int(IAT), CborValue::Int(iat)), + ( + CborValue::Int(ISS), + CborValue::TextString(issuer.to_string()), + ), + ( + CborValue::Int(SUB), + CborValue::TextString(subject.to_string()), + ), + ]); + + let ccf = CborValue::Map(vec![( + CborValue::TextString(TX_ID.to_string()), + CborValue::TextString(txid.to_string()), + )]); + + CborValue::Map(vec![ + (CborValue::Int(KID), CborValue::ByteString(kid.to_vec())), + (CborValue::Int(VDS), CborValue::Int(CCF_LEDGER_SHA256)), + (CborValue::Int(CWT_CLAIMS), cwt), + (CborValue::TextString(CCF_V1.to_string()), ccf), + ]) +} + +fn build_endorsement_phdr( + iat: i64, + epoch_begin: &str, + epoch_end: &str, + previous_merkle_root: &[u8], +) -> CborValue { + let cwt = CborValue::Map(vec![(CborValue::Int(IAT), CborValue::Int(iat))]); + + let mut ccf_entries = vec![( + CborValue::TextString(TX_RANGE_BEGIN.to_string()), + CborValue::TextString(epoch_begin.to_string()), + )]; + + if !epoch_end.is_empty() { + ccf_entries.push(( + CborValue::TextString(TX_RANGE_END.to_string()), + CborValue::TextString(epoch_end.to_string()), + )); + } + + if !previous_merkle_root.is_empty() { + ccf_entries.push(( + CborValue::TextString(EPOCH_LAST_MERKLE_ROOT.to_string()), + CborValue::ByteString(previous_merkle_root.to_vec()), + )); + } + + let ccf = CborValue::Map(ccf_entries); + + CborValue::Map(vec![ + (CborValue::Int(CWT_CLAIMS), cwt), + (CborValue::TextString(CCF_V1.to_string()), ccf), + ]) +} + +/// Sign a ledger signature. +/// +/// On success, writes the output pointer and length into `out_ptr`/`out_len` +/// and returns 0. On failure returns non-zero. Caller frees with `cose_free`. +/// +/// # Safety +/// All pointer+length pairs must be valid. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_sign_ledger( + key_der_ptr: *const u8, + key_der_len: usize, + kid_ptr: *const u8, + kid_len: usize, + iat: i64, + issuer_ptr: *const u8, + issuer_len: usize, + subject_ptr: *const u8, + subject_len: usize, + txid_ptr: *const u8, + txid_len: usize, + payload_ptr: *const u8, + payload_len: usize, + out_ptr: *mut *mut u8, + out_len: *mut usize, +) -> i32 { + let result = std::panic::catch_unwind(|| unsafe { + let key_der = slice_from_raw(key_der_ptr, key_der_len); + let kid = slice_from_raw(kid_ptr, kid_len); + let issuer = str_from_raw(issuer_ptr, issuer_len); + let subject = str_from_raw(subject_ptr, subject_len); + let txid = str_from_raw(txid_ptr, txid_len); + let payload = slice_from_raw(payload_ptr, payload_len); + + let key = EvpKey::from_der_private(key_der)?; + let phdr = build_ledger_phdr(kid, iat, issuer, subject, txid); + let uhdr = CborValue::Map(vec![]); + + cose_openssl::cose_sign1(&key, phdr, uhdr, payload, true) + }); + + match result { + Ok(Ok(envelope)) => unsafe { + let mut buf = envelope.into_boxed_slice(); + *out_ptr = buf.as_mut_ptr(); + *out_len = buf.len(); + std::mem::forget(buf); + 0 + }, + _ => -1, + } +} + +/// Sign an identity endorsement. +/// +/// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be +/// null/0 if not applicable. +/// +/// # Safety +/// All pointer+length pairs must be valid. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_sign_endorsement( + key_der_ptr: *const u8, + key_der_len: usize, + iat: i64, + epoch_begin_ptr: *const u8, + epoch_begin_len: usize, + epoch_end_ptr: *const u8, + epoch_end_len: usize, + prev_root_ptr: *const u8, + prev_root_len: usize, + payload_ptr: *const u8, + payload_len: usize, + out_ptr: *mut *mut u8, + out_len: *mut usize, +) -> i32 { + let result = std::panic::catch_unwind(|| unsafe { + let key_der = slice_from_raw(key_der_ptr, key_der_len); + let epoch_begin = str_from_raw(epoch_begin_ptr, epoch_begin_len); + let epoch_end = str_from_raw(epoch_end_ptr, epoch_end_len); + let prev_root = slice_from_raw(prev_root_ptr, prev_root_len); + let payload = slice_from_raw(payload_ptr, payload_len); + + let key = EvpKey::from_der_private(key_der)?; + let phdr = build_endorsement_phdr(iat, epoch_begin, epoch_end, prev_root); + let uhdr = CborValue::Map(vec![]); + + cose_openssl::cose_sign1(&key, phdr, uhdr, payload, false) + }); + + match result { + Ok(Ok(envelope)) => unsafe { + let mut buf = envelope.into_boxed_slice(); + *out_ptr = buf.as_mut_ptr(); + *out_len = buf.len(); + std::mem::forget(buf); + 0 + }, + _ => -1, + } +} + +/// Free a buffer previously allocated by `cose_sign_*`. +/// +/// # Safety +/// `ptr` and `len` must come from a prior successful `cose_sign_*` call. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_free(ptr: *mut u8, len: usize) { + if !ptr.is_null() && len > 0 { + unsafe { + drop(Box::from_raw(slice::from_raw_parts_mut(ptr, len))); + } + } +} + +/// Verify a COSE_Sign1 from pre-parsed components. +/// +/// `alg` is the COSE algorithm integer (e.g. -7 for ES256). +/// `phdr_cbor` is the serialized CBOR protected header. +/// `payload` is the raw payload bytes (not CBOR-wrapped). +/// `sig` is the fixed-size signature. +/// +/// Returns 0 on successful verification, non-zero on failure. +/// +/// # Safety +/// All pointer+length pairs must be valid. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_verify1( + key_pub_der_ptr: *const u8, + key_pub_der_len: usize, + alg: i64, + phdr_cbor_ptr: *const u8, + phdr_cbor_len: usize, + payload_ptr: *const u8, + payload_len: usize, + sig_ptr: *const u8, + sig_len: usize, +) -> i32 { + let result = std::panic::catch_unwind(|| unsafe { + let key_der = slice_from_raw(key_pub_der_ptr, key_pub_der_len); + let phdr_cbor = slice_from_raw(phdr_cbor_ptr, phdr_cbor_len); + let payload = slice_from_raw(payload_ptr, payload_len); + let sig = slice_from_raw(sig_ptr, sig_len); + + let key = EvpKey::from_der_public(key_der)?; + + let verified = cose_openssl::cose_verify1(&key, alg, phdr_cbor, payload, sig)?; + if verified { + Ok(0i32) + } else { + Err("Signature verification failed".to_string()) + } + }); + + match result { + Ok(Ok(rc)) => rc, + _ => -1, + } +} diff --git a/src/cose/cose_rs_ffi.h b/src/cose/cose_rs_ffi.h new file mode 100644 index 000000000000..49c766fb4f71 --- /dev/null +++ b/src/cose/cose_rs_ffi.h @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the Apache 2.0 License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /// Sign a CCF ledger signature (COSE_Sign1, detached payload). + /// Returns 0 on success, non-zero on failure. + int cose_sign_ledger( + const uint8_t* key_der_ptr, + size_t key_der_len, + const uint8_t* kid_ptr, + size_t kid_len, + int64_t iat, + const uint8_t* issuer_ptr, + size_t issuer_len, + const uint8_t* subject_ptr, + size_t subject_len, + const uint8_t* txid_ptr, + size_t txid_len, + const uint8_t* payload_ptr, + size_t payload_len, + uint8_t** out_ptr, + size_t* out_len); + + /// Sign a CCF identity endorsement (COSE_Sign1, embedded payload). + /// epoch_end and prev_root may be NULL/0 if not applicable. + /// Returns 0 on success, non-zero on failure. + int cose_sign_endorsement( + const uint8_t* key_der_ptr, + size_t key_der_len, + int64_t iat, + const uint8_t* epoch_begin_ptr, + size_t epoch_begin_len, + const uint8_t* epoch_end_ptr, + size_t epoch_end_len, + const uint8_t* prev_root_ptr, + size_t prev_root_len, + const uint8_t* payload_ptr, + size_t payload_len, + uint8_t** out_ptr, + size_t* out_len); + + /// Verify a COSE_Sign1 from pre-parsed components. + /// alg: COSE algorithm integer (e.g. -7 for ES256). + /// phdr_cbor_ptr/phdr_cbor_len: serialized CBOR protected header bytes. + /// payload_ptr/payload_len: raw payload bytes (not CBOR-wrapped). + /// sig_ptr/sig_len: the fixed-size signature bytes. + /// Returns 0 on successful verification, non-zero on failure. + int cose_verify1( + const uint8_t* key_pub_der_ptr, + size_t key_pub_der_len, + int64_t alg, + const uint8_t* phdr_cbor_ptr, + size_t phdr_cbor_len, + const uint8_t* payload_ptr, + size_t payload_len, + const uint8_t* sig_ptr, + size_t sig_len); + + /// Free a buffer returned by cose_sign_*. + void cose_free(uint8_t* ptr, size_t len); + +#ifdef __cplusplus +} + +# include +# include + +/// RAII wrapper for buffers allocated by cose_sign_* FFI functions. +/// Automatically calls cose_free on destruction. +class CoseBuffer +{ + uint8_t* ptr = nullptr; + size_t len = 0; + +public: + CoseBuffer() = default; + CoseBuffer(const CoseBuffer&) = delete; + CoseBuffer& operator=(const CoseBuffer&) = delete; + + CoseBuffer(CoseBuffer&& other) noexcept : ptr(other.ptr), len(other.len) + { + other.ptr = nullptr; + other.len = 0; + } + + CoseBuffer& operator=(CoseBuffer&& other) noexcept + { + if (this != &other) + { + reset(); + ptr = other.ptr; + len = other.len; + other.ptr = nullptr; + other.len = 0; + } + return *this; + } + + ~CoseBuffer() + { + reset(); + } + + uint8_t** data() + { + return &ptr; + } + + size_t* size() + { + return &len; + } + + void reset() + { + if (ptr != nullptr) + { + cose_free(ptr, len); + ptr = nullptr; + len = 0; + } + } + + [[nodiscard]] std::vector to_vector() const + { + return {ptr, ptr + len}; + } + + [[nodiscard]] bool ok() const + { + return ptr != nullptr && len > 0; + } +}; + +inline int cose_sign_ledger( + const uint8_t* key_der_ptr, + size_t key_der_len, + const uint8_t* kid_ptr, + size_t kid_len, + int64_t iat, + const uint8_t* issuer_ptr, + size_t issuer_len, + const uint8_t* subject_ptr, + size_t subject_len, + const uint8_t* txid_ptr, + size_t txid_len, + const uint8_t* payload_ptr, + size_t payload_len, + CoseBuffer& out) +{ + return ::cose_sign_ledger( + key_der_ptr, + key_der_len, + kid_ptr, + kid_len, + iat, + issuer_ptr, + issuer_len, + subject_ptr, + subject_len, + txid_ptr, + txid_len, + payload_ptr, + payload_len, + out.data(), + out.size()); +} + +inline int cose_sign_endorsement( + const uint8_t* key_der_ptr, + size_t key_der_len, + int64_t iat, + const uint8_t* epoch_begin_ptr, + size_t epoch_begin_len, + const uint8_t* epoch_end_ptr, + size_t epoch_end_len, + const uint8_t* prev_root_ptr, + size_t prev_root_len, + const uint8_t* payload_ptr, + size_t payload_len, + CoseBuffer& out) +{ + return ::cose_sign_endorsement( + key_der_ptr, + key_der_len, + iat, + epoch_begin_ptr, + epoch_begin_len, + epoch_end_ptr, + epoch_end_len, + prev_root_ptr, + prev_root_len, + payload_ptr, + payload_len, + out.data(), + out.size()); +} + +#endif diff --git a/src/cose/test/cose_ffi_test.cpp b/src/cose/test/cose_ffi_test.cpp new file mode 100644 index 000000000000..0b8994a48bc1 --- /dev/null +++ b/src/cose/test/cose_ffi_test.cpp @@ -0,0 +1,402 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the Apache 2.0 License. +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#include "cose_rs_ffi.h" +#include "crypto/cbor.h" +#include "crypto/cose.h" +#include "crypto/openssl/ec_key_pair.h" + +#include +#include +#include + +namespace +{ + struct TestKey + { + ccf::crypto::ECKeyPair_OpenSSL kp; + std::vector priv_der; + std::vector pub_der; + + TestKey(ccf::crypto::CurveID curve = ccf::crypto::CurveID::SECP384R1) : + kp(curve), + priv_der(kp.private_key_der()), + pub_der(kp.public_key_der()) + {} + }; + + struct CoseSign1Components + { + std::span phdr; + std::optional> payload; + std::span sig; + int64_t alg; + }; + + CoseSign1Components decompose(const std::vector& envelope) + { + using namespace ccf::cbor; + auto cose = parse(envelope); + const auto& env = cose->tag_at(ccf::cbor::tag::COSE_SIGN_1); + auto phdr = env->array_at(0)->as_bytes(); + + std::optional> payload; + try + { + payload = env->array_at(2)->as_bytes(); + } + catch (const CBORDecodeError&) + { + if (env->array_at(2)->as_simple() != ccf::cbor::SimpleValue::Null) + { + throw; + } + } + + auto sig = env->array_at(3)->as_bytes(); + + auto phdr_parsed = parse({phdr.data(), phdr.size()}); + auto alg = phdr_parsed->map_at(make_signed(ccf::cose::header::iana::ALG)) + ->as_signed(); + + return {phdr, payload, sig, alg}; + } + + int verify_decoded( + const std::vector& pub_der, + const CoseSign1Components& c, + std::span payload) + { + return cose_verify1( + pub_der.data(), + pub_der.size(), + c.alg, + c.phdr.data(), + c.phdr.size(), + payload.data(), + payload.size(), + c.sig.data(), + c.sig.size()); + } +} + +TEST_CASE("cose_sign_ledger sign and verify round-trip") +{ + TestKey key; + + const std::string kid = "test-kid"; + const std::string issuer = "test-issuer"; + const std::string subject = "test-subject"; + const std::string txid = "2.42"; + const std::vector payload = {1, 2, 3, 4, 5}; + const int64_t iat = 1700000000; + + CoseBuffer buf; + auto rc = cose_sign_ledger( + key.priv_der.data(), + key.priv_der.size(), + reinterpret_cast(kid.data()), + kid.size(), + iat, + reinterpret_cast(issuer.data()), + issuer.size(), + reinterpret_cast(subject.data()), + subject.size(), + reinterpret_cast(txid.data()), + txid.size(), + payload.data(), + payload.size(), + buf); + + REQUIRE(rc == 0); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + REQUIRE(!envelope.empty()); + + auto c = decompose(envelope); + CHECK(verify_decoded(key.pub_der, c, payload) == 0); + + std::vector wrong_payload = {9, 8, 7}; + CHECK(verify_decoded(key.pub_der, c, wrong_payload) != 0); +} + +TEST_CASE("cose_sign_ledger fails with invalid key") +{ + const std::vector bad_key = {0, 1, 2, 3}; + const std::string kid = "k"; + const std::string issuer = "i"; + const std::string subject = "s"; + const std::string txid = "1.1"; + const std::vector payload = {1}; + + CoseBuffer buf; + auto rc = cose_sign_ledger( + bad_key.data(), + bad_key.size(), + reinterpret_cast(kid.data()), + kid.size(), + 0, + reinterpret_cast(issuer.data()), + issuer.size(), + reinterpret_cast(subject.data()), + subject.size(), + reinterpret_cast(txid.data()), + txid.size(), + payload.data(), + payload.size(), + buf); + + CHECK(rc != 0); + CHECK(!buf.ok()); +} + +TEST_CASE("cose_sign_endorsement sign and verify round-trip") +{ + TestKey key; + + const std::string epoch_begin = "2.1"; + const std::string epoch_end = "3.10"; + const std::vector prev_root = { + 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11}; + const std::vector payload = {10, 20, 30}; + const int64_t iat = 1700000000; + + CoseBuffer buf; + auto rc = cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + iat, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + reinterpret_cast(epoch_end.data()), + epoch_end.size(), + prev_root.data(), + prev_root.size(), + payload.data(), + payload.size(), + buf); + + REQUIRE(rc == 0); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + auto c = decompose(envelope); + CHECK(verify_decoded(key.pub_der, c, c.payload.value()) == 0); +} + +TEST_CASE("cose_sign_endorsement without optional fields") +{ + TestKey key; + + const std::string epoch_begin = "1.1"; + const std::vector payload = {42}; + const int64_t iat = 1700000000; + + CoseBuffer buf; + auto rc = cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + iat, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + + REQUIRE(rc == 0); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + auto c = decompose(envelope); + CHECK(verify_decoded(key.pub_der, c, c.payload.value()) == 0); +} + +TEST_CASE("cose_verify1 fails with wrong key") +{ + TestKey sign_key; + TestKey wrong_key; + + const std::string epoch_begin = "1.1"; + const std::vector payload = {1, 2, 3}; + + CoseBuffer buf; + cose_sign_endorsement( + sign_key.priv_der.data(), + sign_key.priv_der.size(), + 0, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + auto c = decompose(envelope); + CHECK(verify_decoded(wrong_key.pub_der, c, c.payload.value()) != 0); +} + +TEST_CASE("cose_verify1 fails with corrupted signature") +{ + TestKey key; + + const std::string epoch_begin = "1.1"; + const std::vector payload = {1, 2, 3}; + + CoseBuffer buf; + cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + 0, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + auto c = decompose(envelope); + + std::vector bad_sig(c.sig.begin(), c.sig.end()); + bad_sig[bad_sig.size() - 1] ^= 0xFF; + + auto vrc = cose_verify1( + key.pub_der.data(), + key.pub_der.size(), + c.alg, + c.phdr.data(), + c.phdr.size(), + c.payload.value().data(), + c.payload.value().size(), + bad_sig.data(), + bad_sig.size()); + CHECK(vrc != 0); +} + +TEST_CASE("cose_verify1 wrong alg fails") +{ + TestKey key; + + const std::string epoch_begin = "1.1"; + const std::vector payload = {0xCA, 0xFE}; + + CoseBuffer buf; + cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + 0, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + REQUIRE(buf.ok()); + + auto envelope = buf.to_vector(); + auto c = decompose(envelope); + + CHECK(verify_decoded(key.pub_der, c, c.payload.value()) == 0); + + auto payload_span = c.payload.value(); + auto vrc = cose_verify1( + key.pub_der.data(), + key.pub_der.size(), + -7, + c.phdr.data(), + c.phdr.size(), + payload_span.data(), + payload_span.size(), + c.sig.data(), + c.sig.size()); + CHECK(vrc != 0); +} + +TEST_CASE("CoseBuffer RAII semantics") +{ + SUBCASE("default construction") + { + CoseBuffer buf; + CHECK(!buf.ok()); + CHECK(buf.to_vector().empty()); + } + + SUBCASE("move construction") + { + TestKey key; + const std::string epoch_begin = "1.1"; + const std::vector payload = {1}; + + CoseBuffer buf; + cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + 0, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + REQUIRE(buf.ok()); + + auto vec_before = buf.to_vector(); + CoseBuffer moved(std::move(buf)); + CHECK(!buf.ok()); + CHECK(moved.ok()); + CHECK(moved.to_vector() == vec_before); + } + + SUBCASE("reset") + { + TestKey key; + const std::string epoch_begin = "1.1"; + const std::vector payload = {1}; + + CoseBuffer buf; + cose_sign_endorsement( + key.priv_der.data(), + key.priv_der.size(), + 0, + reinterpret_cast(epoch_begin.data()), + epoch_begin.size(), + nullptr, + 0, + nullptr, + 0, + payload.data(), + payload.size(), + buf); + REQUIRE(buf.ok()); + + buf.reset(); + CHECK(!buf.ok()); + } +} + +TEST_CASE("cose_free with null is safe") +{ + cose_free(nullptr, 0); + cose_free(nullptr, 100); +} diff --git a/src/crypto/cbor.cpp b/src/crypto/cbor.cpp index db3810f1f07e..c9b417feea8f 100644 --- a/src/crypto/cbor.cpp +++ b/src/crypto/cbor.cpp @@ -554,6 +554,13 @@ namespace ccf::cbor Error::DECODE_FAILED, "Failed to parse top-level cbor"); } + if (cbor_parse_size > 0) + { + throw CBORDecodeError( + Error::DECODE_FAILED, + fmt::format("Trailing {} byte(s) after CBOR item", cbor_parse_size)); + } + return consume(cbor); } diff --git a/src/crypto/openssl/cose_sign.cpp b/src/crypto/openssl/cose_sign.cpp deleted file mode 100644 index 9c1c17dff990..000000000000 --- a/src/crypto/openssl/cose_sign.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache 2.0 License. - -#include "crypto/openssl/cose_sign.h" - -#include "crypto/cbor.h" -#include "crypto/cose.h" -#include "ds/internal_logger.h" - -#include -#include -#include - -namespace -{ - std::optional key_to_cose_alg_id( - const ccf::crypto::ECPublicKey_OpenSSL& key) - { - const auto cid = key.get_curve_id(); - switch (cid) - { - case ccf::crypto::CurveID::SECP256R1: - return T_COSE_ALGORITHM_ES256; - case ccf::crypto::CurveID::SECP384R1: - return T_COSE_ALGORITHM_ES384; - default: - return std::nullopt; - } - } - - t_cose_key init_signing_key_and_set_phdr( - const ccf::crypto::ECKeyPair_OpenSSL& key, - int32_t algorithm_id, - ccf::cbor::Value& protected_headers) - { - using namespace ccf::cbor; - - bool alg_set{true}; - try - { - std::ignore = protected_headers->map_at( - ccf::cbor::make_signed(ccf::cose::header::iana::ALG)); - } - catch (const CBORDecodeError& err) - { - if (err.error_code() == Error::KEY_NOT_FOUND) - { - alg_set = false; - } - else - { - throw ccf::crypto::COSESignError( - fmt::format("Failed to parse protected header: {}", err.what())); - } - } - - if (alg_set) - { - throw ccf::crypto::COSESignError( - "Protected headers should not have alg(1) set"); - } - - auto& items = std::get(protected_headers->value).items; - items.insert( - items.begin(), - {make_signed(ccf::cose::header::iana::ALG), make_signed(algorithm_id)}); - - EVP_PKEY* evp_key = key; - t_cose_key signing_key = {}; - signing_key.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; - signing_key.k.key_ptr = evp_key; - - return signing_key; - } - - q_useful_buf_c cose_sign( - t_cose_key signing_key, - int32_t algorithm_id, - std::span phdr, - std::span payload, - std::span signature) - { - q_useful_buf_c phdr_buf{phdr.data(), phdr.size()}; - q_useful_buf_c payload_buf{payload.data(), payload.size()}; - std::vector tbs(T_COSE_CRYPTO_MAX_HASH_SIZE); - UsefulBuf buffer_for_tbs_hash{tbs.data(), tbs.size()}; - q_useful_buf_c tbs_hash{}; - - auto err = create_tbs_hash( - algorithm_id, - phdr_buf, - NULL_Q_USEFUL_BUF_C, - payload_buf, - buffer_for_tbs_hash, - &tbs_hash); - - if (err != 0) - { - throw ccf::crypto::COSESignError( - fmt::format("Failed to create TBS with err: {}", err)); - } - - UsefulBuf signature_buf{signature.data(), signature.size()}; - q_useful_buf_c out_signature{}; - err = t_cose_crypto_sign( - algorithm_id, signing_key, tbs_hash, signature_buf, &out_signature); - - if (err != 0) - { - throw ccf::crypto::COSESignError( - fmt::format("Failed to cose_sign1 with err: {}", err)); - } - - return out_signature; - } -} - -namespace ccf::crypto -{ - std::vector cose_sign1( - const ECKeyPair_OpenSSL& key, - ccf::cbor::Value protected_headers, - std::span payload, - bool detached_payload) - { - if (protected_headers == nullptr) - { - throw ccf::crypto::COSESignError("Unsupported missing protected headers"); - } - - const auto algorithm_id = key_to_cose_alg_id(key); - if (!algorithm_id.has_value()) - { - throw ccf::crypto::COSESignError("Unsupported key type"); - } - - auto signing_key = init_signing_key_and_set_phdr( - key, algorithm_id.value(), protected_headers); - - size_t sig_len{0}; - auto err = - t_cose_crypto_sig_size(algorithm_id.value(), signing_key, &sig_len); - - if (err != 0 || sig_len == 0) - { - throw ccf::crypto::COSESignError( - fmt::format("Failed to calculate signature size with err: {}", err)); - } - - std::vector signature(sig_len); - auto phdr_cbor = ccf::cbor::serialize(protected_headers); - auto signature_buf = cose_sign( - signing_key, algorithm_id.value(), phdr_cbor, payload, signature); - - if (signature_buf.ptr != signature.data()) - { - throw ccf::crypto::COSESignError(fmt::format( - "Failed to match signature address {} to pre-allocated buffer {}", - signature_buf.ptr, - (void*)signature.data())); - } - - if (signature_buf.len > signature.size()) - { - throw ccf::crypto::COSESignError(fmt::format( - "Signature size {} exceeds pre-allocated buffer size {}", - signature_buf.len, - signature.size())); - } - - signature.resize(signature_buf.len); - signature.shrink_to_fit(); - - using namespace ccf::cbor; - - std::vector cose_array; - cose_array.push_back(make_bytes(phdr_cbor)); - cose_array.push_back(make_map({})); - if (detached_payload) - { - cose_array.push_back(make_simple(SimpleValue::Null)); - } - else - { - cose_array.push_back(make_bytes(payload)); - } - cose_array.push_back(make_bytes(signature)); - - auto envelope = make_tagged( - ccf::cbor::tag::COSE_SIGN_1, make_array(std::move(cose_array))); - try - { - return serialize(envelope); - } - catch (const CBOREncodeError& err) - { - throw ccf::crypto::COSESignError(err.what()); - } - } -} diff --git a/src/crypto/openssl/cose_sign.h b/src/crypto/openssl/cose_sign.h deleted file mode 100644 index 488ee927d7e2..000000000000 --- a/src/crypto/openssl/cose_sign.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache 2.0 License. -#pragma once - -#include "crypto/cbor.h" -#include "crypto/openssl/ec_key_pair.h" - -#include -#include - -namespace ccf::crypto -{ - struct COSESignError : public std::runtime_error - { - COSESignError(const std::string& msg) : std::runtime_error(msg) {} - }; - - /* Sign a cose_sign1 payload with custom protected headers as strings, where - - key: integer label to be assigned in a COSE value - - value: string behind the label. - - Labels have to be unique. For standardised labels list check - https://www.iana.org/assignments/cose/cose.xhtml#header-parameters. - */ - std::vector cose_sign1( - const ECKeyPair_OpenSSL& key, - ccf::cbor::Value protected_headers, - std::span payload, - bool detached_payload = true); -} diff --git a/src/crypto/openssl/cose_verifier.cpp b/src/crypto/openssl/cose_verifier.cpp index 9f135ec3f403..99b35f495e65 100644 --- a/src/crypto/openssl/cose_verifier.cpp +++ b/src/crypto/openssl/cose_verifier.cpp @@ -5,7 +5,7 @@ #include "ccf/crypto/ec_public_key.h" #include "ccf/crypto/openssl/openssl_wrappers.h" -#include "crypto/openssl/cose_sign.h" +#include "cose_rs_ffi.h" #include "crypto/openssl/rsa_key_pair.h" #include "ds/internal_logger.h" #include "x509_time.h" @@ -16,74 +16,60 @@ #include #include #include -#include namespace { - std::optional extract_algorithm_from_header( - std::span cose_msg) + using CoseSign1Components = std::tuple< + std::span, // phdr + std::optional>, // payload (nullopt if detached) + std::span // sig + >; + + CoseSign1Components decompose_cose_sign1(std::span envelope) { using namespace ccf::cbor; auto cose_cbor = - rethrow_with_msg([&]() { return parse(cose_msg); }, "Parse COSE CBOR"); + rethrow_with_msg([&]() { return parse(envelope); }, "Parse COSE CBOR"); const auto& cose_envelope = rethrow_with_msg( [&]() -> auto& { return cose_cbor->tag_at(ccf::cbor::tag::COSE_SIGN_1); }, "Parse COSE tag"); - const auto& phdr_raw = rethrow_with_msg( - [&]() -> auto& { return cose_envelope->array_at(0); }, - "Parse raw protected header"); - auto phdr = rethrow_with_msg( - [&]() { return parse(phdr_raw->as_bytes()); }, "Decode protected header"); - - const int64_t alg = rethrow_with_msg( - [&]() { - return phdr->map_at(make_signed(ccf::cose::header::iana::ALG)) - ->as_signed(); - }, - "Retrieve alg from protected header"); + [&]() { return cose_envelope->array_at(0)->as_bytes(); }, + "Parse protected header"); - return alg; - } - - q_useful_buf_c buf_from_span(const std::span span) - { - return {.ptr = span.data(), .len = span.size()}; - } - - class TCOSEVerify - { - private: - EVP_PKEY* pkey = nullptr; - t_cose_key cose_key = {}; - - public: - t_cose_sign1_verify_ctx ctx = {}; - - TCOSEVerify( - std::shared_ptr pkey_, - const std::span envelope) : - pkey(*pkey_) + std::optional> payload; { - const auto alg_header = extract_algorithm_from_header(envelope); - if (!alg_header.has_value()) + const auto& payload_item = cose_envelope->array_at(2); + try { - throw std::domain_error("COSE header is missing 'alg' parameter"); + payload = payload_item->as_bytes(); } + catch (const CBORDecodeError&) + { + // as_bytes() fails when payload is CBOR null (detached) + if (payload_item->as_simple() != ccf::cbor::SimpleValue::Null) + { + throw; + } + } + } - pkey_->check_is_cose_compatible(alg_header.value()); - - cose_key.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; - cose_key.k.key_ptr = pkey; + auto sig = rethrow_with_msg( + [&]() { return cose_envelope->array_at(3)->as_bytes(); }, + "Parse signature"); - t_cose_sign1_verify_init(&ctx, T_COSE_OPT_TAG_REQUIRED); - t_cose_sign1_set_verification_key(&ctx, cose_key); - } - }; + return {phdr, payload, sig}; + } + int64_t extract_alg(std::span phdr_bytes) + { + using namespace ccf::cbor; + auto phdr = parse(phdr_bytes); + return phdr->map_at(make_signed(ccf::cose::header::iana::ALG))->as_signed(); + } } namespace ccf::crypto @@ -128,22 +114,34 @@ namespace ccf::crypto { try { - TCOSEVerify cose_verify(public_key, envelope); - q_useful_buf_c envelope_ = buf_from_span(envelope); + auto key_der = public_key->public_key_der(); + auto [phdr, payload, sig] = decompose_cose_sign1(envelope); - q_useful_buf_c authned_content_ = {}; + if (!payload.has_value()) + { + LOG_DEBUG_FMT("COSE Sign1 verification failed: payload is detached"); + return false; + } - t_cose_err_t error = t_cose_sign1_verify( - &cose_verify.ctx, envelope_, &authned_content_, nullptr); - if (error == T_COSE_SUCCESS) + auto alg = extract_alg(phdr); + auto rc = cose_verify1( + key_der.data(), + key_der.size(), + alg, + phdr.data(), + phdr.size(), + payload->data(), + payload->size(), + sig.data(), + sig.size()); + if (rc == 0) { authned_content = { - reinterpret_cast(const_cast(authned_content_.ptr)), - authned_content_.len}; + const_cast(payload->data()), payload->size()}; return true; } - LOG_DEBUG_FMT("COSE Sign1 verification failed: {}", error); + LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); } catch (const std::exception& e) { @@ -157,23 +155,59 @@ namespace ccf::crypto { try { - TCOSEVerify cose_verify(public_key, envelope); - - q_useful_buf_c envelope_ = buf_from_span(envelope); - - q_useful_buf_c payload_ = {}; - payload_.ptr = payload.data(); - payload_.len = payload.size(); + auto key_der = public_key->public_key_der(); + auto [phdr, _payload, sig] = decompose_cose_sign1(envelope); + + auto alg = extract_alg(phdr); + auto rc = cose_verify1( + key_der.data(), + key_der.size(), + alg, + phdr.data(), + phdr.size(), + payload.data(), + payload.size(), + sig.data(), + sig.size()); + if (rc == 0) + { + return true; + } - t_cose_err_t error = t_cose_sign1_verify_detached( - &cose_verify.ctx, envelope_, NULL_Q_USEFUL_BUF_C, payload_, nullptr); + LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); + } + catch (const std::exception& e) + { + LOG_DEBUG_FMT("COSE Sign1 verification failed: {}", e.what()); + } + return false; + } - if (error == T_COSE_SUCCESS) + bool COSEVerifier_OpenSSL::verify_decomposed( + std::span phdr, + std::span payload, + std::span sig, + int64_t alg) const + { + try + { + auto key_der = public_key->public_key_der(); + auto rc = cose_verify1( + key_der.data(), + key_der.size(), + alg, + phdr.data(), + phdr.size(), + payload.data(), + payload.size(), + sig.data(), + sig.size()); + if (rc == 0) { return true; } - LOG_DEBUG_FMT("COSE Sign1 verification failed: {}", error); + LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); } catch (const std::exception& e) { diff --git a/src/crypto/openssl/cose_verifier.h b/src/crypto/openssl/cose_verifier.h index 9693802cdecf..7c638747fed2 100644 --- a/src/crypto/openssl/cose_verifier.h +++ b/src/crypto/openssl/cose_verifier.h @@ -28,6 +28,11 @@ namespace ccf::crypto [[nodiscard]] bool verify_detached( std::span envelope, std::span payload) const override; + [[nodiscard]] bool verify_decomposed( + std::span phdr, + std::span payload, + std::span sig, + int64_t alg) const override; }; class COSECertVerifier_OpenSSL : public COSEVerifier_OpenSSL diff --git a/src/crypto/openssl/public_key.h b/src/crypto/openssl/public_key.h index b280a65314b1..ab6fb0d9bdd0 100644 --- a/src/crypto/openssl/public_key.h +++ b/src/crypto/openssl/public_key.h @@ -116,6 +116,15 @@ namespace ccf::crypto return key; } + [[nodiscard]] std::vector public_key_der() const + { + OpenSSL::Unique_BIO buf; + OpenSSL::CHECK1(i2d_PUBKEY_bio(buf, key)); + BUF_MEM* bptr = nullptr; + BIO_get_mem_ptr(buf, &bptr); + return {bptr->data, bptr->data + bptr->length}; + } + virtual ~PublicKey_OpenSSL() { if (key != nullptr) diff --git a/src/crypto/test/cbor.cpp b/src/crypto/test/cbor.cpp index d9a415595045..ef15d6b14370 100644 --- a/src/crypto/test/cbor.cpp +++ b/src/crypto/test/cbor.cpp @@ -1712,3 +1712,30 @@ TEST_CASE("CBOR: throw with context") expected_err.c_str(), CBORDecodeError); } + +TEST_CASE("CBOR: trailing bytes rejected") +{ + // Valid CBOR integer 42 = 0x182a + auto valid = ccf::ds::from_hex("182a"); + REQUIRE_NOTHROW(parse(valid)); + + // Append trailing byte — should be rejected + auto with_trailing = ccf::ds::from_hex("182a00"); + REQUIRE_THROWS_AS(parse(with_trailing), CBORDecodeError); + + // Valid CBOR byte string h'0102' = 0x420102 + auto valid_bstr = ccf::ds::from_hex("420102"); + REQUIRE_NOTHROW(parse(valid_bstr)); + + // Append trailing bytes + auto bstr_trailing = ccf::ds::from_hex("420102ff"); + REQUIRE_THROWS_AS(parse(bstr_trailing), CBORDecodeError); + + // Valid CBOR array [1, 2] = 0x820102 + auto valid_array = ccf::ds::from_hex("820102"); + REQUIRE_NOTHROW(parse(valid_array)); + + // Append trailing byte + auto array_trailing = ccf::ds::from_hex("82010203"); + REQUIRE_THROWS_AS(parse(array_trailing), CBORDecodeError); +} diff --git a/src/crypto/test/cose.cpp b/src/crypto/test/cose.cpp index f10b9d7f727a..6f1d6820a2eb 100644 --- a/src/crypto/test/cose.cpp +++ b/src/crypto/test/cose.cpp @@ -4,17 +4,74 @@ #include "ccf/crypto/cose.h" #include "ccf/ds/hex.h" -#include "crypto/openssl/cose_sign.h" #include "crypto/openssl/cose_verifier.h" #include "node/cose_common.h" #include #include -#include #include #include #include +// Hardcoded test vectors signed with pycose / Python cryptography (P-384). + +static const auto pub_key_der = ccf::ds::from_hex( + "3076301006072a8648ce3d020106052b81040022036200040c" + "b505681147a976cc1fcd0326e9fd76bcbf4ebd3530070406bf" + "6406501d26966ab947806afd24c02ae70bbc6b7405bf199a0e" + "c26b3eee7b487dad66af87fe1669a24d8057f387035180de09" + "5b72731a12fffccc6881abe1190e74abf25143ff"); + +static const std::vector detached_payload = { + 'p', 'a', 'y', 'l', 'o', 'a', 'd'}; +// CBOR: [1, [2, 3]] +static const auto nested_payload = ccf::ds::from_hex("8201820203"); + +// COSE_Sign1 with detached payload (cose_sign_ledger) +static const auto envelope_detached = ccf::ds::from_hex( + "d2845830a501382204436b696419018b020fa3061a6553f100" + "01636973730263737562666363662e7631a164747869646332" + "2e31a0f6586080120aea6f4df8a233aac943c9ec53d5257a78" + "17523f41c52e4ea814552d32755a2c3f0dbe6f70144ed30d93" + "cf5577b3742e258d1269b7c827bf93501f068f990940fb51b7" + "8ee9b29486e5245502cfe021983e065354a4bbaa82c9fec55c" + "0a41"); + +// COSE_Sign1 with embedded flat payload (cose_sign_endorsement) +static const auto envelope_flat = ccf::ds::from_hex( + "d2845829a30138220fa1061a6553f100666363662e7631a170" + "65706f63682e73746172742e7478696463322e31a047706179" + "6c6f616458609bd6fbeac88aaa877c2462863aea5f3da8b8e1" + "14c499da2262704263635e9e7e8b3c8eb578289e574c5e4f0a" + "26648b43031b6bb29feea3c5f0da9eaab47e8e3d3e94f75743" + "e0b08de5d05149a6a1c1822fe9956c3edff0dcf80079fbb803" + "ac14"); + +// COSE_Sign1 with embedded CBOR payload (cose_sign_endorsement) +static const auto envelope_nested = ccf::ds::from_hex( + "d2845829a30138220fa1061a6553f100666363662e7631a170" + "65706f63682e73746172742e7478696463322e31a045820182" + "02035860c9417b04245e35d3d9226886bc01c515f7a5269a46" + "58a637cce9581e9ff01e27e12021727412c15f72aa388eb068" + "c73a5da3db8190fc4bd052b1c2174ea82b1aea1224097e8eee" + "c8345675ebac854778f7f2434f653c7dea937b4104ab6b72ed"); + +struct TestEnvelope +{ + std::vector envelope; + std::vector payload; + bool detached; +}; + +static std::vector test_envelopes() +{ + return { + {envelope_detached, detached_payload, true}, + {envelope_flat, detached_payload, false}, + {envelope_nested, nested_payload, false}, + }; +} + static const std::vector keys = { 42, std::numeric_limits::min(), std::numeric_limits::max()}; @@ -26,147 +83,83 @@ static const std::vector positions = { const std::vector value = {1, 2, 3, 4}; -enum class PayloadType +static void verify_envelope( + const std::vector& envelope, + const std::vector& payload, + bool detached) { - Detached, - Flat, - NestedCBOR // Useful to test the payload transfer -}; - -struct Signer -{ - ccf::crypto::ECKeyPair_OpenSSL kp; - std::vector payload; - bool detached_payload = false; - - Signer(PayloadType type) : kp(ccf::crypto::CurveID::SECP384R1) + auto verifier = ccf::crypto::make_cose_verifier_from_key(pub_key_der); + if (detached) { - switch (type) - { - case PayloadType::Detached: - detached_payload = true; - payload = {'p', 'a', 'y', 'l', 'o', 'a', 'd'}; - break; - case PayloadType::Flat: - payload = {'p', 'a', 'y', 'l', 'o', 'a', 'd'}; - break; - case PayloadType::NestedCBOR: - { - using namespace ccf::cbor; - - std::vector arr; - arr.push_back(make_signed(1)); - - std::vector inner; - inner.push_back(make_signed(2)); - inner.push_back(make_signed(3)); - - arr.push_back(make_array(std::move(inner))); - - payload = serialize(make_array(std::move(arr))); - } - break; - } + REQUIRE(verifier->verify_detached(envelope, payload)); } - - std::vector make_cose_sign1() - { - using namespace ccf::cbor; - - std::vector phdr; - phdr.emplace_back(make_signed(300), make_bytes(value)); - phdr.emplace_back(make_signed(301), make_signed(34)); - auto phdr_map = make_map(std::move(phdr)); - - return ccf::crypto::cose_sign1(kp, phdr_map, payload, detached_payload); - }; - - void verify(const std::vector& cose_sign1) + else { - auto verifier = - ccf::crypto::make_cose_verifier_from_key(kp.public_key_pem()); - if (detached_payload) - { - REQUIRE(verifier->verify_detached(cose_sign1, payload)); - } - else - { - std::span payload_; - REQUIRE(verifier->verify(cose_sign1, payload_)); - std::vector payload_copy(payload_.begin(), payload_.end()); - REQUIRE(payload == payload_copy); - } - }; -}; + std::span authned_content; + REQUIRE(verifier->verify(envelope, authned_content)); + std::vector payload_copy( + authned_content.begin(), authned_content.end()); + REQUIRE(payload == payload_copy); + } +} TEST_CASE("Verification and payload invariant") { - for (auto type : - {PayloadType::Detached, PayloadType::Flat, PayloadType::NestedCBOR}) + for (auto& [envelope, payload, detached] : test_envelopes()) { - Signer signer(type); - auto csp = signer.make_cose_sign1(); - signer.verify(csp); + verify_envelope(envelope, payload, detached); for (const auto& key : keys) { for (const auto& position : positions) { ccf::cose::edit::desc::Value desc{position, key, value}; - auto csp_set = ccf::cose::edit::set_unprotected_header(csp, desc); + auto edited = ccf::cose::edit::set_unprotected_header(envelope, desc); - signer.verify(csp_set); + verify_envelope(edited, payload, detached); } } { - auto csp_set_empty = ccf::cose::edit::set_unprotected_header( - csp, ccf::cose::edit::desc::Empty{}); - signer.verify(csp_set_empty); + auto edited = ccf::cose::edit::set_unprotected_header( + envelope, ccf::cose::edit::desc::Empty{}); + verify_envelope(edited, payload, detached); } } } TEST_CASE("Idempotence") { - for (auto type : - {PayloadType::Detached, PayloadType::Flat, PayloadType::NestedCBOR}) + for (auto& [envelope, payload, detached] : test_envelopes()) { - Signer signer(type); - auto csp = signer.make_cose_sign1(); - for (const auto& key : keys) { for (const auto& position : positions) { ccf::cose::edit::desc::Value desc{position, key, value}; - auto csp_set_once = ccf::cose::edit::set_unprotected_header(csp, desc); + auto set_once = ccf::cose::edit::set_unprotected_header(envelope, desc); - auto csp_set_twice = - ccf::cose::edit::set_unprotected_header(csp_set_once, desc); - REQUIRE(csp_set_once == csp_set_twice); + auto set_twice = + ccf::cose::edit::set_unprotected_header(set_once, desc); + REQUIRE(set_once == set_twice); } } { - auto csp_set_empty = ccf::cose::edit::set_unprotected_header( - csp, ccf::cose::edit::desc::Empty{}); - auto csp_set_twice_empty = ccf::cose::edit::set_unprotected_header( - csp_set_empty, ccf::cose::edit::desc::Empty{}); + auto set_empty = ccf::cose::edit::set_unprotected_header( + envelope, ccf::cose::edit::desc::Empty{}); + auto set_twice_empty = ccf::cose::edit::set_unprotected_header( + set_empty, ccf::cose::edit::desc::Empty{}); - REQUIRE(csp_set_empty == csp_set_twice_empty); + REQUIRE(set_empty == set_twice_empty); } } } TEST_CASE("Check unprotected header") { - for (auto type : - {PayloadType::Detached, PayloadType::Flat, PayloadType::NestedCBOR}) + for (auto& [envelope, payload, detached] : test_envelopes()) { - Signer signer(type); - auto csp = signer.make_cose_sign1(); - using namespace ccf::cbor; for (const auto& key : keys) @@ -174,11 +167,11 @@ TEST_CASE("Check unprotected header") for (const auto& position : positions) { ccf::cose::edit::desc::Value desc{position, key, value}; - auto csp_set = ccf::cose::edit::set_unprotected_header(csp, desc); + auto edited = ccf::cose::edit::set_unprotected_header(envelope, desc); - auto edited = parse(csp_set); + auto parsed = parse(edited); const auto& uhdr = - edited->tag_at(ccf::cbor::tag::COSE_SIGN_1)->array_at(1); + parsed->tag_at(ccf::cbor::tag::COSE_SIGN_1)->array_at(1); std::vector ref; if (std::holds_alternative(position)) @@ -204,12 +197,12 @@ TEST_CASE("Check unprotected header") } { - auto csp_set_empty = ccf::cose::edit::set_unprotected_header( - csp, ccf::cose::edit::desc::Empty{}); + auto edited = ccf::cose::edit::set_unprotected_header( + envelope, ccf::cose::edit::desc::Empty{}); - auto edited = parse(csp_set_empty); + auto parsed = parse(edited); const auto& uhdr = - edited->tag_at(ccf::cbor::tag::COSE_SIGN_1)->array_at(1); + parsed->tag_at(ccf::cbor::tag::COSE_SIGN_1)->array_at(1); auto ref_map = make_map({}); diff --git a/src/crypto/test/crypto.cpp b/src/crypto/test/crypto.cpp index 1d46d60f2aef..ed57e7028968 100644 --- a/src/crypto/test/crypto.cpp +++ b/src/crypto/test/crypto.cpp @@ -18,7 +18,6 @@ #include "crypto/certs.h" #include "crypto/cose.h" #include "crypto/csr.h" -#include "crypto/openssl/cose_sign.h" #include "crypto/openssl/cose_verifier.h" #include "crypto/openssl/ec_key_pair.h" #include "crypto/openssl/rsa_key_pair.h" @@ -32,8 +31,6 @@ #include #include #include -#include -#include using namespace std; using namespace ccf::crypto; @@ -197,81 +194,6 @@ ccf::crypto::Pem generate_self_signed_cert( kp, name, {}, valid_from, certificate_validity_period_days); } -t_cose_err_t verify_detached( - EVP_PKEY* key, std::span buf, std::span payload) -{ - t_cose_key cose_key; - cose_key.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; - cose_key.k.key_ptr = key; - - t_cose_sign1_verify_ctx verify_ctx; - t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_TAG_REQUIRED); - t_cose_sign1_set_verification_key(&verify_ctx, cose_key); - - q_useful_buf_c buf_; - buf_.ptr = buf.data(); - buf_.len = buf.size(); - - q_useful_buf_c payload_; - payload_.ptr = payload.data(); - payload_.len = payload.size(); - - t_cose_err_t error = t_cose_sign1_verify_detached( - &verify_ctx, buf_, NULL_Q_USEFUL_BUF_C, payload_, nullptr); - - return error; -} - -void require_match_headers( - std::pair> kv1, - std::pair> kv2, - std::pair> kv3, - std::pair> kv4, - const std::vector& cose_sign) -{ - auto decoded = ccf::cbor::parse(cose_sign); - - const auto& as_cose = decoded->tag_at(ccf::cbor::tag::COSE_SIGN_1); - const auto& raw_phdr = as_cose->array_at(0)->as_bytes(); - - auto phdr = ccf::cbor::parse(raw_phdr); - - // 'alg' - REQUIRE_NOTHROW((void)phdr->map_at(ccf::cbor::make_signed(1))); - - if (kv1.second) - REQUIRE_EQ( - phdr->map_at(ccf::cbor::make_signed(kv1.first))->as_signed(), - *kv1.second); - else - REQUIRE_THROWS( - (void)phdr->map_at(ccf::cbor::make_signed(kv1.first))->as_signed()); - - if (kv2.second) - REQUIRE_EQ( - phdr->map_at(ccf::cbor::make_signed(kv2.first))->as_string(), - *kv2.second); - else - REQUIRE_THROWS( - (void)phdr->map_at(ccf::cbor::make_signed(kv2.first))->as_string()); - - if (kv3.second) - REQUIRE_EQ( - phdr->map_at(ccf::cbor::make_string(kv3.first))->as_signed(), - *kv3.second); - else - REQUIRE_THROWS( - (void)phdr->map_at(ccf::cbor::make_string(kv3.first))->as_signed()); - - if (kv4.second) - REQUIRE_EQ( - phdr->map_at(ccf::cbor::make_string(kv4.first))->as_string(), - *kv4.second); - else - REQUIRE_THROWS( - (void)phdr->map_at(ccf::cbor::make_string(kv4.first))->as_string()); -} - TEST_CASE("Check verifier handles nested certs for both PEM and DER inputs") { auto cert_der = ccf::crypto::raw_from_b64(nested_cert); @@ -1286,68 +1208,6 @@ TEST_CASE("Sign and verify with RSA key") } } -TEST_CASE("COSE sign & verify") -{ - std::shared_ptr kp = - std::dynamic_pointer_cast( - ccf::crypto::make_ec_key_pair(CurveID::SECP384R1)); - - std::vector payload{1, 10, 42, 43, 44, 45, 100}; - - using namespace ccf; - std::vector phdr; - - phdr.emplace_back(cbor::make_signed(35), cbor::make_signed(53)); - phdr.emplace_back(cbor::make_signed(36), cbor::make_string("thirsty six")); - phdr.emplace_back(cbor::make_string("hungry seven"), cbor::make_signed(47)); - phdr.emplace_back( - cbor::make_string("string key"), cbor::make_string("string value")); - - auto phdr_map = cbor::make_map(std::move(phdr)); - auto cose_sign = cose_sign1(*kp, phdr_map, payload); - - if constexpr (false) // enable to see the whole cose_sign as byte string - { - std::cout << "Public key: " << kp->public_key_pem().str() << std::endl; - std::cout << "Serialised cose: " << std::hex << std::uppercase - << std::setw(2) << std::setfill('0'); - for (uint8_t x : cose_sign) - std::cout << static_cast(x) << ' '; - std::cout << std::endl; - std::cout << "Raw payload: "; - for (uint8_t x : payload) - std::cout << static_cast(x) << ' '; - std::cout << std::endl; - } - - require_match_headers( - {35, 53}, - {36, "thirsty six"}, - {"hungry seven", 47}, - {"string key", "string value"}, - cose_sign); - - auto cose_verifier = - ccf::crypto::make_cose_verifier_from_key(kp->public_key_pem()); - - REQUIRE(cose_verifier->verify_detached(cose_sign, payload)); - - // Wrong payload, must not pass verification. - REQUIRE_FALSE( - cose_verifier->verify_detached(cose_sign, std::vector{1, 2, 3})); - - // Empty headers and payload handled correctly - cose_sign = cose_sign1(*kp, ccf::cbor::make_map({}), {}); - require_match_headers( - {35, std::nullopt}, - {36, std::nullopt}, - {"hungry seven", std::nullopt}, - {"string key", std::nullopt}, - cose_sign); - - REQUIRE(cose_verifier->verify_detached(cose_sign, {})); -} - TEST_CASE("COSE algorithm validation") { INFO("EC key curves must match COSE algorithm"); diff --git a/src/endpoints/authentication/cose_auth.cpp b/src/endpoints/authentication/cose_auth.cpp index 776664506c77..1a0f13c41b52 100644 --- a/src/endpoints/authentication/cose_auth.cpp +++ b/src/endpoints/authentication/cose_auth.cpp @@ -30,7 +30,15 @@ namespace ccf static constexpr auto HEADER_PARAM_MSG_CREATED_AT = "ccf.gov.msg.created_at"; - std::pair + struct DecomposedCoseSign1 + { + std::span phdr_bytes; + std::span payload; + Signature sig; + int64_t alg; + }; + + std::pair extract_governance_protected_header_and_signature( const std::vector& cose_sign1) { @@ -112,10 +120,16 @@ namespace ccf [&]() { return cose_envelope->array_at(3)->as_bytes(); }, "Parse COSE signature"); - return {parsed, signature}; + auto payload = rethrow_with_msg( + [&]() { return cose_envelope->array_at(2)->as_bytes(); }, + "Parse COSE payload"); + + DecomposedCoseSign1 decomposed{ + phdr_raw->as_bytes(), payload, signature, parsed.alg}; + return {parsed, decomposed}; } - std::pair + std::pair extract_protected_header_and_signature( const std::vector& cose_sign1, const std::string& msg_type_name, @@ -198,7 +212,13 @@ namespace ccf [&]() { return cose_envelope->array_at(3)->as_bytes(); }, "Parse COSE signature"); - return {parsed, signature}; + auto payload = rethrow_with_msg( + [&]() { return cose_envelope->array_at(2)->as_bytes(); }, + "Parse COSE payload"); + + DecomposedCoseSign1 decomposed{ + phdr_raw->as_bytes(), payload, signature, parsed.alg}; + return {parsed, decomposed}; } } @@ -227,7 +247,7 @@ namespace ccf return nullptr; } - auto [phdr, cose_signature] = + auto [phdr, decomposed] = cose::extract_governance_protected_header_and_signature( ctx->get_request_body()); @@ -245,15 +265,22 @@ namespace ccf auto verifier = ccf::crypto::make_cose_verifier_from_cert(member_cert->raw()); - std::span body = { - ctx->get_request_body().data(), ctx->get_request_body().size()}; - std::span authned_content; - if (!verifier->verify(body, authned_content)) + if (!verifier->verify_decomposed( + decomposed.phdr_bytes, + decomposed.payload, + decomposed.sig, + decomposed.alg)) { error_reason = fmt::format("Failed to validate COSE Sign1"); return nullptr; } + std::span body = { + ctx->get_request_body().data(), ctx->get_request_body().size()}; + std::span authned_content{ + const_cast(decomposed.payload.data()), + decomposed.payload.size()}; + if (gov_msg_type.has_value()) { if (!phdr.gov_msg_type.has_value()) @@ -278,7 +305,7 @@ namespace ccf return std::make_unique( authned_content, body, - cose_signature, + decomposed.sig, phdr.kid, member_cert.value(), phdr); @@ -365,7 +392,7 @@ namespace ccf return nullptr; } - auto [phdr, cose_signature] = cose::extract_protected_header_and_signature( + auto [phdr, decomposed] = cose::extract_protected_header_and_signature( ctx->get_request_body(), msg_type_name, msg_created_at_name); if (!cose::is_ecdsa_alg(phdr.alg)) @@ -382,19 +409,26 @@ namespace ccf auto verifier = ccf::crypto::make_cose_verifier_from_cert(user_cert->raw()); - std::span body = { - ctx->get_request_body().data(), ctx->get_request_body().size()}; - std::span authned_content; - if (!verifier->verify(body, authned_content)) + if (!verifier->verify_decomposed( + decomposed.phdr_bytes, + decomposed.payload, + decomposed.sig, + decomposed.alg)) { error_reason = fmt::format("Failed to validate COSE Sign1"); return nullptr; } + std::span body = { + ctx->get_request_body().data(), ctx->get_request_body().size()}; + std::span authned_content{ + const_cast(decomposed.payload.data()), + decomposed.payload.size()}; + return std::make_unique( authned_content, body, - cose_signature, + decomposed.sig, phdr.kid, user_cert.value(), phdr); diff --git a/src/node/cose_common.h b/src/node/cose_common.h index 8272154457c8..0d0754f2aee7 100644 --- a/src/node/cose_common.h +++ b/src/node/cose_common.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/src/node/history.h b/src/node/history.h index 7607c876b751..3b5c225625b6 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -6,8 +6,8 @@ #include "ccf/pal/locking.h" #include "ccf/service/tables/nodes.h" #include "ccf/service/tables/service.h" +#include "cose_rs_ffi.h" #include "crypto/cose.h" -#include "crypto/openssl/cose_sign.h" #include "crypto/openssl/ec_key_pair.h" #include "crypto/openssl/hash.h" #include "crypto/public_key.h" @@ -358,47 +358,35 @@ namespace ccf endorsed_cert); auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der()); - std::span kid_span{ - reinterpret_cast(kid.data()), kid.size()}; + auto key_der = service_kp.private_key_der(); + const auto tx_id = txid.to_str(); const auto time_since_epoch = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); - std::vector ccf_headers; - const auto tx_id = txid.to_str(); - ccf_headers.emplace_back( - cbor::make_string(ccf::cose::header::custom::TX_ID), - cbor::make_string(tx_id)); - - std::vector cwt_headers; - cwt_headers.emplace_back( - cbor::make_signed(ccf::cwt::header::iana::IAT), - cbor::make_signed(time_since_epoch)); - cwt_headers.emplace_back( - cbor::make_signed(ccf::cwt::header::iana::ISS), - cbor::make_string(cose_signatures_config.issuer)); - cwt_headers.emplace_back( - cbor::make_signed(ccf::cwt::header::iana::SUB), - cbor::make_string(cose_signatures_config.subject)); - - std::vector phdr; - phdr.emplace_back( - cbor::make_signed(ccf::cose::header::iana::KID), - cbor::make_bytes(kid_span)); - phdr.emplace_back( - cbor::make_signed(ccf::cose::header::iana::VDS), - cbor::make_signed(ccf::cose::value::CCF_LEDGER_SHA256)); - phdr.emplace_back( - cbor::make_signed(ccf::cose::header::iana::CWT_CLAIMS), - cbor::make_map(std::move(cwt_headers))); - phdr.emplace_back( - cbor::make_string(ccf::cose::header::custom::CCF_V1), - cbor::make_map(std::move(ccf_headers))); - - auto phdr_map = cbor::make_map(std::move(phdr)); - auto cose_sign = crypto::cose_sign1(service_kp, phdr_map, root_hash); + CoseBuffer cose_buf; + auto rc = cose_sign_ledger( + key_der.data(), + key_der.size(), + reinterpret_cast(kid.data()), + kid.size(), + time_since_epoch, + reinterpret_cast(cose_signatures_config.issuer.data()), + cose_signatures_config.issuer.size(), + reinterpret_cast(cose_signatures_config.subject.data()), + cose_signatures_config.subject.size(), + reinterpret_cast(tx_id.data()), + tx_id.size(), + root_hash.data(), + root_hash.size(), + cose_buf); + if (rc != 0 || !cose_buf.ok()) + { + throw std::runtime_error("cose_sign_ledger failed"); + } + std::vector cose_sign(cose_buf.to_vector()); signatures->put(sig_value); cose_signatures->put(cose_sign); diff --git a/src/node/quote.cpp b/src/node/quote.cpp index fecd2b57b62d..4db0b68cac53 100644 --- a/src/node/quote.cpp +++ b/src/node/quote.cpp @@ -345,9 +345,7 @@ namespace ccf // Verify the COSE_Sign1 signature and that the payload matches the // expected host_data. Returns the decoded protected header on success. cose::Sign1ProtectedHeader verify_ts_signature_and_payload( - const std::vector& ts_raw, - const ccf::cbor::Value& cose_array, - const HostData& host_data) + const ccf::cbor::Value& cose_array, const HostData& host_data) { const auto& phdr_raw = ccf::cbor::rethrow_with_msg( [&]() -> const ccf::cbor::Value& { return cose_array->array_at(0); }, @@ -370,8 +368,16 @@ namespace ccf auto pubk = resolve_pubkey_from_x5chain_and_issuer(h.x5chain, h.cwt.iss); auto verifier = ccf::crypto::make_cose_verifier_from_key(pubk); - std::span payload; - if (!verifier->verify(ts_raw, payload)) + + auto payload = ccf::cbor::rethrow_with_msg( + [&]() { return cose_array->array_at(2)->as_bytes(); }, + "COSE_Sign1 payload"); + auto sig_bytes = ccf::cbor::rethrow_with_msg( + [&]() { return cose_array->array_at(3)->as_bytes(); }, + "COSE_Sign1 signature"); + + if (!verifier->verify_decomposed( + phdr_raw->as_bytes(), payload, sig_bytes, h.alg)) { throw std::logic_error( "Transparent statement signature verification failed"); @@ -560,8 +566,7 @@ namespace ccf }, "COSE_Sign1 tag"); - auto phdr = - verify_ts_signature_and_payload(ts_raw, cose_array, host_data); + auto phdr = verify_ts_signature_and_payload(cose_array, host_data); auto receipt_inputs = verify_ts_receipts(ts_raw, cose_array, network_identity_subsystem); diff --git a/src/service/internal_tables_access.h b/src/service/internal_tables_access.h index 6438d363cd14..0a9998e620a1 100644 --- a/src/service/internal_tables_access.h +++ b/src/service/internal_tables_access.h @@ -16,7 +16,7 @@ #include "ccf/service/tables/virtual_measurements.h" #include "ccf/tx.h" #include "consensus/aft/raft_types.h" -#include "crypto/openssl/cose_sign.h" +#include "cose_rs_ffi.h" #include "node/ledger_secrets.h" #include "node/uvm_endorsements.h" #include "service/tables/governance_history.h" @@ -622,25 +622,11 @@ namespace ccf key_to_endorse = endorsement.endorsing_key; } - std::vector ccf_headers; auto from_txid = endorsement.endorsement_epoch_begin.to_str(); - ccf_headers.emplace_back( - cbor::make_string(ccf::cose::header::custom::TX_RANGE_BEGIN), - cbor::make_string(from_txid)); - std::string to_txid{}; if (endorsement.endorsement_epoch_end) { to_txid = endorsement.endorsement_epoch_end->to_str(); - ccf_headers.emplace_back( - cbor::make_string(ccf::cose::header::custom::TX_RANGE_END), - cbor::make_string(to_txid)); - } - if (!previous_root.empty()) - { - ccf_headers.emplace_back( - cbor::make_string(ccf::cose::header::custom::EPOCH_LAST_MERKLE_ROOT), - cbor::make_bytes(previous_root)); } const auto time_since_epoch = @@ -648,34 +634,28 @@ namespace ccf std::chrono::system_clock::now().time_since_epoch()) .count(); - std::vector cwt_headers; - cwt_headers.emplace_back( - cbor::make_signed(ccf::cwt::header::iana::IAT), - cbor::make_signed(time_since_epoch)); - - std::vector phdr; - phdr.emplace_back( - cbor::make_signed(ccf::cose::header::iana::CWT_CLAIMS), - cbor::make_map(std::move(cwt_headers))); - phdr.emplace_back( - cbor::make_string(ccf::cose::header::custom::CCF_V1), - cbor::make_map(std::move(ccf_headers))); - - auto phdr_map = cbor::make_map(std::move(phdr)); - try - { - endorsement.endorsement = cose_sign1( - service_key, - phdr_map, - key_to_endorse, - false // detached payload - ); - } - catch (const ccf::crypto::COSESignError& e) + auto key_der = service_key.private_key_der(); + + CoseBuffer cose_buf; + auto rc = cose_sign_endorsement( + key_der.data(), + key_der.size(), + time_since_epoch, + reinterpret_cast(from_txid.data()), + from_txid.size(), + reinterpret_cast(to_txid.data()), + to_txid.size(), + previous_root.data(), + previous_root.size(), + key_to_endorse.data(), + key_to_endorse.size(), + cose_buf); + if (rc != 0 || !cose_buf.ok()) { - LOG_FAIL_FMT("Failed to sign previous service identity: {}", e.what()); + LOG_FAIL_FMT("Failed to sign previous service identity"); return false; } + endorsement.endorsement = cose_buf.to_vector(); previous_identity_endorsement->put(endorsement); return true; From e285b1977b50bda6ad3fa3b278e5b287e38c1f52 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Fri, 20 Mar 2026 12:33:17 +0000 Subject: [PATCH 2/6] Update lib --- 3rdparty/internal/cose-openssl/Cargo.toml | 4 ++-- 3rdparty/internal/cose-openssl/src/cbor.rs | 22 ++++++++++++++++++++++ 3rdparty/internal/cose-openssl/src/cose.rs | 18 +++++++++++------- 3rdparty/internal/cose-openssl/src/sign.rs | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/3rdparty/internal/cose-openssl/Cargo.toml b/3rdparty/internal/cose-openssl/Cargo.toml index 6486a635134a..7ab661ea9da4 100644 --- a/3rdparty/internal/cose-openssl/Cargo.toml +++ b/3rdparty/internal/cose-openssl/Cargo.toml @@ -14,5 +14,5 @@ warnings = "deny" [dependencies] openssl-sys = "0.9" -cborrs = { git = "https://github.com/project-everest/everparse.git", tag = "v2026.02.25" } -cborrs-nondet = { git = "https://github.com/project-everest/everparse.git", tag = "v2026.02.25" } +cborrs = { git = "https://github.com/project-everest/everparse.git", rev = "f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" } # v2026.02.25 +cborrs-nondet = { git = "https://github.com/project-everest/everparse.git", rev = "f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" } # v2026.02.25 diff --git a/3rdparty/internal/cose-openssl/src/cbor.rs b/3rdparty/internal/cose-openssl/src/cbor.rs index 9cc709226e43..ba6c38507591 100644 --- a/3rdparty/internal/cose-openssl/src/cbor.rs +++ b/3rdparty/internal/cose-openssl/src/cbor.rs @@ -287,6 +287,28 @@ fn serialize_det(item: CborDet) -> Result, String> { Ok(buf) } +/// A CBOR item that borrows its data, for zero-copy serialization. +pub enum CborSlice<'a> { + TextStr(&'a str), + ByteStr(&'a [u8]), +} + +/// Serialize a CBOR array of borrowed items without intermediate copies. +pub fn serialize_array(items: &[CborSlice<'_>]) -> Result, String> { + let mut raw: Vec> = items + .iter() + .map(|item| match item { + CborSlice::TextStr(s) => cbor_det_mk_text_string(s) + .ok_or("Failed to make CBOR text string".to_string()), + CborSlice::ByteStr(b) => cbor_det_mk_byte_string(b) + .ok_or("Failed to make CBOR byte string".to_string()), + }) + .collect::>()?; + let array = cbor_det_mk_array(&mut raw) + .ok_or("Failed to build CBOR array".to_string())?; + serialize_det(array) +} + impl std::fmt::Debug for CborValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/3rdparty/internal/cose-openssl/src/cose.rs b/3rdparty/internal/cose-openssl/src/cose.rs index 5741751127b7..5ea1ce314605 100644 --- a/3rdparty/internal/cose-openssl/src/cose.rs +++ b/3rdparty/internal/cose-openssl/src/cose.rs @@ -1,4 +1,4 @@ -use crate::cbor::CborValue; +use crate::cbor::{CborSlice, CborValue, serialize_array}; use crate::ossl_wrappers::{ EvpKey, KeyType, WhichEC, WhichRSA, ecdsa_der_to_fixed, ecdsa_fixed_to_der, rsa_pss_md_for_cose_alg, @@ -56,14 +56,18 @@ fn insert_alg_value( /// To-be-signed (TBS). /// https://www.rfc-editor.org/rfc/rfc9052.html#section-4.4. +/// +/// Uses `serialize_array` with borrowed slices to avoid copying +/// `phdr` and `payload` into intermediate `Vec`s. These can +/// be large (payload especially), so we serialize directly from +/// the caller's buffers. fn sig_structure(phdr: &[u8], payload: &[u8]) -> Result, String> { - CborValue::Array(vec![ - CborValue::TextString(SIG_STRUCTURE1_CONTEXT.to_string()), - CborValue::ByteString(phdr.to_vec()), - CborValue::ByteString(vec![]), - CborValue::ByteString(payload.to_vec()), + serialize_array(&[ + CborSlice::TextStr(SIG_STRUCTURE1_CONTEXT), + CborSlice::ByteStr(phdr), + CborSlice::ByteStr(&[]), + CborSlice::ByteStr(payload), ]) - .to_bytes() } /// Produce a COSE_Sign1 envelope. diff --git a/3rdparty/internal/cose-openssl/src/sign.rs b/3rdparty/internal/cose-openssl/src/sign.rs index 69b7ce9fb45a..32020189ee4e 100644 --- a/3rdparty/internal/cose-openssl/src/sign.rs +++ b/3rdparty/internal/cose-openssl/src/sign.rs @@ -33,7 +33,7 @@ fn sign_with_ctx( msg.len(), ); if res != 1 { - return Err(format!("Failed to signature size, err: {}", res)); + return Err(format!("Failed to get signature size, err: {}", res)); } let mut sig = vec![0u8; sig_size]; From 0fa787c858320232f7e3e83c8e43db67aac98d95 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Fri, 20 Mar 2026 13:02:16 +0000 Subject: [PATCH 3/6] Key cache --- src/cose/cose_rs/Cargo.lock | 4 +- src/cose/cose_rs/src/lib.rs | 119 ++++++++++++++++++--------- src/cose/cose_rs_ffi.h | 89 +++++++++++++++++--- src/cose/test/cose_ffi_test.cpp | 67 ++++++--------- src/node/history.h | 16 +++- src/service/internal_tables_access.h | 4 +- 6 files changed, 196 insertions(+), 103 deletions(-) diff --git a/src/cose/cose_rs/Cargo.lock b/src/cose/cose_rs/Cargo.lock index ca2ca8db930f..61133e099447 100644 --- a/src/cose/cose_rs/Cargo.lock +++ b/src/cose/cose_rs/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "cborrs" version = "0.1.0" -source = "git+https://github.com/project-everest/everparse.git?tag=v2026.02.25#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" +source = "git+https://github.com/project-everest/everparse.git?rev=f4cd5ffa183edd5cc824d66588012bcf8d0bdccd#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" dependencies = [ "static_assertions", ] @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "cborrs-nondet" version = "0.1.0" -source = "git+https://github.com/project-everest/everparse.git?tag=v2026.02.25#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" +source = "git+https://github.com/project-everest/everparse.git?rev=f4cd5ffa183edd5cc824d66588012bcf8d0bdccd#f4cd5ffa183edd5cc824d66588012bcf8d0bdccd" dependencies = [ "static_assertions", ] diff --git a/src/cose/cose_rs/src/lib.rs b/src/cose/cose_rs/src/lib.rs index d7ede67973e8..e6a0d10901d6 100644 --- a/src/cose/cose_rs/src/lib.rs +++ b/src/cose/cose_rs/src/lib.rs @@ -93,44 +93,43 @@ fn build_endorsement_phdr( ]) } -/// Sign a ledger signature. +/// Sign an identity endorsement using a pre-created key handle. /// -/// On success, writes the output pointer and length into `out_ptr`/`out_len` -/// and returns 0. On failure returns non-zero. Caller frees with `cose_free`. +/// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be +/// null/0 if not applicable. /// /// # Safety +/// `key` must be a valid pointer from `cose_key_from_der_private`. /// All pointer+length pairs must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn cose_sign_ledger( - key_der_ptr: *const u8, - key_der_len: usize, - kid_ptr: *const u8, - kid_len: usize, +pub unsafe extern "C" fn cose_sign_endorsement( + key: *const EvpKey, iat: i64, - issuer_ptr: *const u8, - issuer_len: usize, - subject_ptr: *const u8, - subject_len: usize, - txid_ptr: *const u8, - txid_len: usize, + epoch_begin_ptr: *const u8, + epoch_begin_len: usize, + epoch_end_ptr: *const u8, + epoch_end_len: usize, + prev_root_ptr: *const u8, + prev_root_len: usize, payload_ptr: *const u8, payload_len: usize, out_ptr: *mut *mut u8, out_len: *mut usize, ) -> i32 { + if key.is_null() { + return -1; + } let result = std::panic::catch_unwind(|| unsafe { - let key_der = slice_from_raw(key_der_ptr, key_der_len); - let kid = slice_from_raw(kid_ptr, kid_len); - let issuer = str_from_raw(issuer_ptr, issuer_len); - let subject = str_from_raw(subject_ptr, subject_len); - let txid = str_from_raw(txid_ptr, txid_len); + let key = &*key; + let epoch_begin = str_from_raw(epoch_begin_ptr, epoch_begin_len); + let epoch_end = str_from_raw(epoch_end_ptr, epoch_end_len); + let prev_root = slice_from_raw(prev_root_ptr, prev_root_len); let payload = slice_from_raw(payload_ptr, payload_len); - let key = EvpKey::from_der_private(key_der)?; - let phdr = build_ledger_phdr(kid, iat, issuer, subject, txid); + let phdr = build_endorsement_phdr(iat, epoch_begin, epoch_end, prev_root); let uhdr = CborValue::Map(vec![]); - cose_openssl::cose_sign1(&key, phdr, uhdr, payload, true) + cose_openssl::cose_sign1(key, phdr, uhdr, payload, false) }); match result { @@ -145,41 +144,79 @@ pub unsafe extern "C" fn cose_sign_ledger( } } -/// Sign an identity endorsement. -/// -/// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be -/// null/0 if not applicable. +/// Create an opaque signing key from a DER-encoded private key. +/// Returns a pointer to the key, or null on failure. +/// The caller must free the key with `cose_key_free`. /// /// # Safety -/// All pointer+length pairs must be valid. +/// `key_der_ptr` must point to `key_der_len` valid bytes. #[unsafe(no_mangle)] -pub unsafe extern "C" fn cose_sign_endorsement( +pub unsafe extern "C" fn cose_key_from_der_private( key_der_ptr: *const u8, key_der_len: usize, +) -> *mut EvpKey { + let result = std::panic::catch_unwind(|| unsafe { + let key_der = slice_from_raw(key_der_ptr, key_der_len); + EvpKey::from_der_private(key_der) + }); + + match result { + Ok(Ok(key)) => Box::into_raw(Box::new(key)), + _ => std::ptr::null_mut(), + } +} + +/// Free a key previously created by `cose_key_from_der_private`. +/// +/// # Safety +/// `key` must be a pointer returned by `cose_key_from_der_private`, +/// or null (which is a no-op). +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_key_free(key: *mut EvpKey) { + if !key.is_null() { + unsafe { + drop(Box::from_raw(key)); + } + } +} + +/// Sign a ledger signature using a pre-created key handle. +/// +/// # Safety +/// `key` must be a valid pointer from `cose_key_from_der_private`. +/// All pointer+length pairs must be valid. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cose_sign_ledger( + key: *const EvpKey, + kid_ptr: *const u8, + kid_len: usize, iat: i64, - epoch_begin_ptr: *const u8, - epoch_begin_len: usize, - epoch_end_ptr: *const u8, - epoch_end_len: usize, - prev_root_ptr: *const u8, - prev_root_len: usize, + issuer_ptr: *const u8, + issuer_len: usize, + subject_ptr: *const u8, + subject_len: usize, + txid_ptr: *const u8, + txid_len: usize, payload_ptr: *const u8, payload_len: usize, out_ptr: *mut *mut u8, out_len: *mut usize, ) -> i32 { + if key.is_null() { + return -1; + } let result = std::panic::catch_unwind(|| unsafe { - let key_der = slice_from_raw(key_der_ptr, key_der_len); - let epoch_begin = str_from_raw(epoch_begin_ptr, epoch_begin_len); - let epoch_end = str_from_raw(epoch_end_ptr, epoch_end_len); - let prev_root = slice_from_raw(prev_root_ptr, prev_root_len); + let key = &*key; + let kid = slice_from_raw(kid_ptr, kid_len); + let issuer = str_from_raw(issuer_ptr, issuer_len); + let subject = str_from_raw(subject_ptr, subject_len); + let txid = str_from_raw(txid_ptr, txid_len); let payload = slice_from_raw(payload_ptr, payload_len); - let key = EvpKey::from_der_private(key_der)?; - let phdr = build_endorsement_phdr(iat, epoch_begin, epoch_end, prev_root); + let phdr = build_ledger_phdr(kid, iat, issuer, subject, txid); let uhdr = CborValue::Map(vec![]); - cose_openssl::cose_sign1(&key, phdr, uhdr, payload, false) + cose_openssl::cose_sign1(key, phdr, uhdr, payload, true) }); match result { diff --git a/src/cose/cose_rs_ffi.h b/src/cose/cose_rs_ffi.h index 49c766fb4f71..5bfe53b6c8b0 100644 --- a/src/cose/cose_rs_ffi.h +++ b/src/cose/cose_rs_ffi.h @@ -11,11 +11,22 @@ extern "C" { #endif - /// Sign a CCF ledger signature (COSE_Sign1, detached payload). + /// Opaque handle to a Rust-managed signing key. + typedef struct CoseEvpKey CoseEvpKey; + + /// Create a signing key from DER-encoded private key bytes. + /// Returns an opaque pointer, or NULL on failure. + /// The caller must free the key with cose_key_free. + CoseEvpKey* cose_key_from_der_private( + const uint8_t* key_der_ptr, size_t key_der_len); + + /// Free a key created by cose_key_from_der_private. + void cose_key_free(CoseEvpKey* key); + + /// Sign a CCF ledger signature using a pre-created key handle. /// Returns 0 on success, non-zero on failure. int cose_sign_ledger( - const uint8_t* key_der_ptr, - size_t key_der_len, + const CoseEvpKey* key, const uint8_t* kid_ptr, size_t kid_len, int64_t iat, @@ -34,8 +45,7 @@ extern "C" /// epoch_end and prev_root may be NULL/0 if not applicable. /// Returns 0 on success, non-zero on failure. int cose_sign_endorsement( - const uint8_t* key_der_ptr, - size_t key_der_len, + const CoseEvpKey* key, int64_t iat, const uint8_t* epoch_begin_ptr, size_t epoch_begin_len, @@ -141,9 +151,65 @@ class CoseBuffer } }; +/// RAII wrapper for a Rust-managed signing key. +/// Automatically calls cose_key_free on destruction. +class CoseKey +{ + CoseEvpKey* key = nullptr; + +public: + CoseKey() = default; + + CoseKey(const uint8_t* der_ptr, size_t der_len) : + key(cose_key_from_der_private(der_ptr, der_len)) + {} + + CoseKey(const CoseKey&) = delete; + CoseKey& operator=(const CoseKey&) = delete; + + CoseKey(CoseKey&& other) noexcept : key(other.key) + { + other.key = nullptr; + } + + CoseKey& operator=(CoseKey&& other) noexcept + { + if (this != &other) + { + reset(); + key = other.key; + other.key = nullptr; + } + return *this; + } + + ~CoseKey() + { + reset(); + } + + void reset() + { + if (key != nullptr) + { + cose_key_free(key); + key = nullptr; + } + } + + [[nodiscard]] const CoseEvpKey* get() const + { + return key; + } + + [[nodiscard]] bool ok() const + { + return key != nullptr; + } +}; + inline int cose_sign_ledger( - const uint8_t* key_der_ptr, - size_t key_der_len, + const CoseKey& key, const uint8_t* kid_ptr, size_t kid_len, int64_t iat, @@ -158,8 +224,7 @@ inline int cose_sign_ledger( CoseBuffer& out) { return ::cose_sign_ledger( - key_der_ptr, - key_der_len, + key.get(), kid_ptr, kid_len, iat, @@ -176,8 +241,7 @@ inline int cose_sign_ledger( } inline int cose_sign_endorsement( - const uint8_t* key_der_ptr, - size_t key_der_len, + const CoseKey& key, int64_t iat, const uint8_t* epoch_begin_ptr, size_t epoch_begin_len, @@ -190,8 +254,7 @@ inline int cose_sign_endorsement( CoseBuffer& out) { return ::cose_sign_endorsement( - key_der_ptr, - key_der_len, + key.get(), iat, epoch_begin_ptr, epoch_begin_len, diff --git a/src/cose/test/cose_ffi_test.cpp b/src/cose/test/cose_ffi_test.cpp index 0b8994a48bc1..db3fa2873121 100644 --- a/src/cose/test/cose_ffi_test.cpp +++ b/src/cose/test/cose_ffi_test.cpp @@ -84,6 +84,8 @@ namespace TEST_CASE("cose_sign_ledger sign and verify round-trip") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string kid = "test-kid"; const std::string issuer = "test-issuer"; @@ -94,8 +96,7 @@ TEST_CASE("cose_sign_ledger sign and verify round-trip") CoseBuffer buf; auto rc = cose_sign_ledger( - key.priv_der.data(), - key.priv_der.size(), + cose_key, reinterpret_cast(kid.data()), kid.size(), iat, @@ -125,36 +126,15 @@ TEST_CASE("cose_sign_ledger sign and verify round-trip") TEST_CASE("cose_sign_ledger fails with invalid key") { const std::vector bad_key = {0, 1, 2, 3}; - const std::string kid = "k"; - const std::string issuer = "i"; - const std::string subject = "s"; - const std::string txid = "1.1"; - const std::vector payload = {1}; - - CoseBuffer buf; - auto rc = cose_sign_ledger( - bad_key.data(), - bad_key.size(), - reinterpret_cast(kid.data()), - kid.size(), - 0, - reinterpret_cast(issuer.data()), - issuer.size(), - reinterpret_cast(subject.data()), - subject.size(), - reinterpret_cast(txid.data()), - txid.size(), - payload.data(), - payload.size(), - buf); - - CHECK(rc != 0); - CHECK(!buf.ok()); + CoseKey cose_key(bad_key.data(), bad_key.size()); + CHECK(!cose_key.ok()); } TEST_CASE("cose_sign_endorsement sign and verify round-trip") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "2.1"; const std::string epoch_end = "3.10"; @@ -165,8 +145,7 @@ TEST_CASE("cose_sign_endorsement sign and verify round-trip") CoseBuffer buf; auto rc = cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, iat, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -189,6 +168,8 @@ TEST_CASE("cose_sign_endorsement sign and verify round-trip") TEST_CASE("cose_sign_endorsement without optional fields") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "1.1"; const std::vector payload = {42}; @@ -196,8 +177,7 @@ TEST_CASE("cose_sign_endorsement without optional fields") CoseBuffer buf; auto rc = cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, iat, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -220,6 +200,8 @@ TEST_CASE("cose_sign_endorsement without optional fields") TEST_CASE("cose_verify1 fails with wrong key") { TestKey sign_key; + CoseKey sign_cose_key(sign_key.priv_der.data(), sign_key.priv_der.size()); + REQUIRE(sign_cose_key.ok()); TestKey wrong_key; const std::string epoch_begin = "1.1"; @@ -227,8 +209,7 @@ TEST_CASE("cose_verify1 fails with wrong key") CoseBuffer buf; cose_sign_endorsement( - sign_key.priv_der.data(), - sign_key.priv_der.size(), + sign_cose_key, 0, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -249,14 +230,15 @@ TEST_CASE("cose_verify1 fails with wrong key") TEST_CASE("cose_verify1 fails with corrupted signature") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "1.1"; const std::vector payload = {1, 2, 3}; CoseBuffer buf; cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, 0, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -291,14 +273,15 @@ TEST_CASE("cose_verify1 fails with corrupted signature") TEST_CASE("cose_verify1 wrong alg fails") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "1.1"; const std::vector payload = {0xCA, 0xFE}; CoseBuffer buf; cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, 0, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -342,13 +325,14 @@ TEST_CASE("CoseBuffer RAII semantics") SUBCASE("move construction") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "1.1"; const std::vector payload = {1}; CoseBuffer buf; cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, 0, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), @@ -371,13 +355,14 @@ TEST_CASE("CoseBuffer RAII semantics") SUBCASE("reset") { TestKey key; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); + REQUIRE(cose_key.ok()); const std::string epoch_begin = "1.1"; const std::vector payload = {1}; CoseBuffer buf; cose_sign_endorsement( - key.priv_der.data(), - key.priv_der.size(), + cose_key, 0, reinterpret_cast(epoch_begin.data()), epoch_begin.size(), diff --git a/src/node/history.h b/src/node/history.h index 2f740b1cb456..c7ff49bfd63e 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -357,8 +357,7 @@ namespace ccf primary_sig, endorsed_cert); - auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der()); - auto key_der = service_kp.private_key_der(); + static auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der()); const auto tx_id = txid.to_str(); const auto time_since_epoch = @@ -366,10 +365,19 @@ namespace ccf std::chrono::system_clock::now().time_since_epoch()) .count(); + static std::unordered_map key_cache; + auto it = key_cache.find(kid); + if (it == key_cache.end()) + { + auto key_der = service_kp.private_key_der(); + auto [inserted, _] = + key_cache.emplace(kid, CoseKey(key_der.data(), key_der.size())); + it = inserted; + } + CoseBuffer cose_buf; auto rc = cose_sign_ledger( - key_der.data(), - key_der.size(), + it->second, reinterpret_cast(kid.data()), kid.size(), time_since_epoch, diff --git a/src/service/internal_tables_access.h b/src/service/internal_tables_access.h index 0a9998e620a1..981e31dc1321 100644 --- a/src/service/internal_tables_access.h +++ b/src/service/internal_tables_access.h @@ -635,11 +635,11 @@ namespace ccf .count(); auto key_der = service_key.private_key_der(); + CoseKey cose_key(key_der.data(), key_der.size()); CoseBuffer cose_buf; auto rc = cose_sign_endorsement( - key_der.data(), - key_der.size(), + cose_key, time_since_epoch, reinterpret_cast(from_txid.data()), from_txid.size(), From 3879231f3bef6134358dd165f12717a1dd94c7a6 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Fri, 20 Mar 2026 14:27:02 +0000 Subject: [PATCH 4/6] Make cache non-static --- src/node/history.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/node/history.h b/src/node/history.h index c7ff49bfd63e..92d1471205c5 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -310,6 +310,7 @@ namespace ccf ccf::crypto::ECKeyPair_OpenSSL& service_kp; ccf::crypto::Pem& endorsed_cert; const ccf::COSESignaturesConfig& cose_signatures_config; + std::unordered_map& cose_key_cache; public: MerkleTreeHistoryPendingTx( @@ -320,7 +321,8 @@ namespace ccf ccf::crypto::ECKeyPair& node_kp_, ccf::crypto::ECKeyPair_OpenSSL& service_kp_, ccf::crypto::Pem& endorsed_cert_, - const ccf::COSESignaturesConfig& cose_signatures_config_) : + const ccf::COSESignaturesConfig& cose_signatures_config_, + std::unordered_map& cose_key_cache_) : txid(txid_), store(store_), history(history_), @@ -328,7 +330,8 @@ namespace ccf node_kp(node_kp_), service_kp(service_kp_), endorsed_cert(endorsed_cert_), - cose_signatures_config(cose_signatures_config_) + cose_signatures_config(cose_signatures_config_), + cose_key_cache(cose_key_cache_) {} ccf::kv::PendingTxInfo call() override @@ -357,7 +360,7 @@ namespace ccf primary_sig, endorsed_cert); - static auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der()); + auto kid = ccf::crypto::kid_from_key(service_kp.public_key_der()); const auto tx_id = txid.to_str(); const auto time_since_epoch = @@ -365,13 +368,12 @@ namespace ccf std::chrono::system_clock::now().time_since_epoch()) .count(); - static std::unordered_map key_cache; - auto it = key_cache.find(kid); - if (it == key_cache.end()) + auto it = cose_key_cache.find(kid); + if (it == cose_key_cache.end()) { auto key_der = service_kp.private_key_der(); auto [inserted, _] = - key_cache.emplace(kid, CoseKey(key_der.data(), key_der.size())); + cose_key_cache.emplace(kid, CoseKey(key_der.data(), key_der.size())); it = inserted; } @@ -558,6 +560,8 @@ namespace ccf std::optional signing_identity = std::nullopt; + std::unordered_map cose_key_cache; + public: HashedTxHistory( ccf::kv::Store& store_, @@ -891,7 +895,8 @@ namespace ccf node_kp, *signing_identity->service_kp, endorsed_cert.value(), - signing_identity->cose_signatures_config), + signing_identity->cose_signatures_config, + cose_key_cache), true); } From d0f6ee6b778cb9eff3d1b15ed40ca5f2931b4fd7 Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Fri, 20 Mar 2026 18:52:44 +0000 Subject: [PATCH 5/6] Code review, includes, cmake --- cmake/crypto.cmake | 3 --- src/cose/cose_rs_ffi.h | 2 +- src/cose/test/cose_ffi_test.cpp | 2 +- src/crypto/openssl/cose_verifier.cpp | 2 +- src/node/history.h | 2 +- src/service/internal_tables_access.h | 2 +- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/cmake/crypto.cmake b/cmake/crypto.cmake index d04258097497..004c6f13758a 100644 --- a/cmake/crypto.cmake +++ b/cmake/crypto.cmake @@ -45,9 +45,6 @@ target_link_libraries( $ ) add_dependencies(ccfcrypto cargo-build_cose_rs) -target_include_directories( - ccfcrypto PUBLIC $ -) set_property(TARGET ccfcrypto PROPERTY POSITION_INDEPENDENT_CODE ON) install( diff --git a/src/cose/cose_rs_ffi.h b/src/cose/cose_rs_ffi.h index 5bfe53b6c8b0..48d71880fc07 100644 --- a/src/cose/cose_rs_ffi.h +++ b/src/cose/cose_rs_ffi.h @@ -12,7 +12,7 @@ extern "C" #endif /// Opaque handle to a Rust-managed signing key. - typedef struct CoseEvpKey CoseEvpKey; + struct CoseEvpKey; /// Create a signing key from DER-encoded private key bytes. /// Returns an opaque pointer, or NULL on failure. diff --git a/src/cose/test/cose_ffi_test.cpp b/src/cose/test/cose_ffi_test.cpp index db3fa2873121..9c3d12b7c45a 100644 --- a/src/cose/test/cose_ffi_test.cpp +++ b/src/cose/test/cose_ffi_test.cpp @@ -2,7 +2,7 @@ // Licensed under the Apache 2.0 License. #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "cose_rs_ffi.h" +#include "cose/cose_rs_ffi.h" #include "crypto/cbor.h" #include "crypto/cose.h" #include "crypto/openssl/ec_key_pair.h" diff --git a/src/crypto/openssl/cose_verifier.cpp b/src/crypto/openssl/cose_verifier.cpp index 99b35f495e65..33789f814291 100644 --- a/src/crypto/openssl/cose_verifier.cpp +++ b/src/crypto/openssl/cose_verifier.cpp @@ -5,7 +5,7 @@ #include "ccf/crypto/ec_public_key.h" #include "ccf/crypto/openssl/openssl_wrappers.h" -#include "cose_rs_ffi.h" +#include "cose/cose_rs_ffi.h" #include "crypto/openssl/rsa_key_pair.h" #include "ds/internal_logger.h" #include "x509_time.h" diff --git a/src/node/history.h b/src/node/history.h index 92d1471205c5..3b3509764bc8 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -6,7 +6,7 @@ #include "ccf/pal/locking.h" #include "ccf/service/tables/nodes.h" #include "ccf/service/tables/service.h" -#include "cose_rs_ffi.h" +#include "cose/cose_rs_ffi.h" #include "crypto/cose.h" #include "crypto/openssl/ec_key_pair.h" #include "crypto/openssl/hash.h" diff --git a/src/service/internal_tables_access.h b/src/service/internal_tables_access.h index 981e31dc1321..c0891a8fbd64 100644 --- a/src/service/internal_tables_access.h +++ b/src/service/internal_tables_access.h @@ -16,7 +16,7 @@ #include "ccf/service/tables/virtual_measurements.h" #include "ccf/tx.h" #include "consensus/aft/raft_types.h" -#include "cose_rs_ffi.h" +#include "cose/cose_rs_ffi.h" #include "node/ledger_secrets.h" #include "node/uvm_endorsements.h" #include "service/tables/governance_history.h" From a04c68bd25f5bd9aec71f66a3754679900fa147c Mon Sep 17 00:00:00 2001 From: Max Tropets Date: Tue, 24 Mar 2026 21:51:54 +0000 Subject: [PATCH 6/6] Error propagation --- 3rdparty/internal/cose-openssl/src/cose.rs | 101 ++++++++- .../cose-openssl/src/ossl_wrappers.rs | 161 +++++++++++--- 3rdparty/internal/cose-openssl/src/sign.rs | 73 ++++++- 3rdparty/internal/cose-openssl/src/verify.rs | 94 +++++++- src/cose/cose_rs/src/lib.rs | 75 ++++++- src/cose/cose_rs_ffi.h | 89 ++++++-- src/cose/test/cose_ffi_test.cpp | 201 ++++++++++++++---- src/crypto/openssl/cose_verifier.cpp | 27 ++- src/node/history.h | 20 +- src/service/internal_tables_access.h | 18 +- 10 files changed, 742 insertions(+), 117 deletions(-) diff --git a/3rdparty/internal/cose-openssl/src/cose.rs b/3rdparty/internal/cose-openssl/src/cose.rs index 5ea1ce314605..d0bf5250ca67 100644 --- a/3rdparty/internal/cose-openssl/src/cose.rs +++ b/3rdparty/internal/cose-openssl/src/cose.rs @@ -208,7 +208,10 @@ mod tests { let alg = phdr_with_alg.map_at_int(COSE_HEADER_ALG).unwrap(); assert_eq!(alg, &CborValue::Int(cose_alg(&key).unwrap())); - assert!(insert_alg_value(&key, phdr_with_alg).is_err()); + assert_eq!( + insert_alg_value(&key, phdr_with_alg).unwrap_err(), + "Algorithm already set in protected header" + ); } #[test] @@ -263,7 +266,10 @@ mod tests { #[test] fn cose_verify1_wrong_alg() { let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); - assert!(cose_verify1(&key, -35, b"", b"", b"").is_err()); + assert_eq!( + cose_verify1(&key, -35, b"", b"", b"").unwrap_err(), + "Algorithm mismatch between supplied alg and key" + ); } #[test] @@ -463,6 +469,97 @@ mod tests { ); } + // --------------------------------------------------------------- + // Negative tests: error propagation through cose_sign1/cose_verify1 + // --------------------------------------------------------------- + + #[test] + fn cose_sign1_rejects_non_map_phdr() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + assert_eq!( + cose_sign1( + &key, + CborValue::Int(0), + CborValue::Map(vec![]), + b"msg", + false + ) + .unwrap_err(), + "Protected header is not a CBOR map" + ); + } + + #[test] + fn cose_sign1_rejects_duplicate_alg() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let phdr = CborValue::Map(vec![( + CborValue::Int(COSE_HEADER_ALG), + CborValue::Int(-7), + )]); + assert_eq!( + cose_sign1(&key, phdr, CborValue::Map(vec![]), b"msg", false) + .unwrap_err(), + "Algorithm already set in protected header" + ); + } + + #[test] + fn cose_sign1_propagates_ossl_sign_error() { + // Null key triggers EVP_DigestSignInit failure. + let null_key = EvpKey { + key: std::ptr::null_mut(), + typ: KeyType::EC(WhichEC::P256), + }; + let err = cose_sign1( + &null_key, + CborValue::Map(vec![]), + CborValue::Map(vec![]), + b"msg", + false, + ) + .unwrap_err(); + assert!( + err.starts_with("EVP_DigestSignInit returned 0: error:"), + "unexpected error: {err}" + ); + } + + #[test] + fn cose_verify1_wrong_rsa_alg() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + assert_eq!( + cose_verify1(&key, -7, b"", b"", b"").unwrap_err(), + "-7 is not a COSE RSA-PSS algorithm" + ); + } + + #[test] + fn cose_verify1_ec_sig_wrong_length() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + // P-256 expects 64 byte fixed sig, pass 3 bytes. + assert_eq!( + cose_verify1(&pub_key, -7, b"", b"", &[0u8; 3]).unwrap_err(), + "Expected 64 byte ECDSA signature, got 3" + ); + } + + #[test] + fn cose_verify1_propagates_ossl_verify_error() { + // Null key triggers EVP_DigestVerifyInit failure. + let null_key = EvpKey { + key: std::ptr::null_mut(), + typ: KeyType::RSA(WhichRSA::PS256), + }; + let err = + cose_verify1(&null_key, -37, b"", b"", &[0u8; 256]).unwrap_err(); + assert!( + err.starts_with("EVP_DigestVerifyInit returned 0: error:"), + "unexpected error: {err}" + ); + } + #[cfg(feature = "pqc")] mod pqc_tests { use super::*; diff --git a/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs b/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs index 846b51d0b840..fb7f6b2c0cbb 100644 --- a/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs +++ b/3rdparty/internal/cose-openssl/src/ossl_wrappers.rs @@ -16,6 +16,38 @@ unsafe extern "C" { name_sz: usize, gname_len: *mut usize, ) -> std::ffi::c_int; + + fn ERR_error_string_n( + e: std::ffi::c_ulong, + buf: *mut std::ffi::c_char, + len: usize, + ); +} + +/// Drain the OpenSSL error queue and return the last (newest) error. +pub(crate) fn ossl_err_string() -> String { + unsafe { + let mut last_code: std::ffi::c_ulong = 0; + loop { + let code = ossl::ERR_get_error(); + if code == 0 { + break; + } + last_code = code; + } + if last_code == 0 { + return "(no OpenSSL error)".to_string(); + } + let mut buf = [0u8; 256]; + ERR_error_string_n( + last_code, + buf.as_mut_ptr() as *mut std::ffi::c_char, + buf.len(), + ); + std::ffi::CStr::from_ptr(buf.as_ptr() as *const std::ffi::c_char) + .to_string_lossy() + .into_owned() + } } #[cfg(feature = "pqc")] @@ -131,7 +163,10 @@ impl EvpKey { }; if key.is_null() { - return Err("Failed to create signing key".to_string()); + return Err(format!( + "EVP_PKEY_Q_keygen failed: {}", + ossl_err_string() + )); } Ok(EvpKey { key, typ }) @@ -146,7 +181,10 @@ impl EvpKey { let key = ossl::d2i_PUBKEY(ptr::null_mut(), &mut ptr, der.len() as i64); if key.is_null() { - return Err("Failed to parse DER public key".to_string()); + return Err(format!( + "d2i_PUBKEY failed: {}", + ossl_err_string() + )); } key }; @@ -176,7 +214,10 @@ impl EvpKey { der.len() as i64, ); if key.is_null() { - return Err("Failed to parse DER private key".to_string()); + return Err(format!( + "d2i_AutoPrivateKey failed: {}", + ossl_err_string() + )); } key }; @@ -220,7 +261,10 @@ impl EvpKey { &mut len, ) != 1 { - return Err("Failed to get EC group name".to_string()); + return Err(format!( + "EVP_PKEY_get_group_name failed: {}", + ossl_err_string() + )); } let group = std::str::from_utf8(&buf[..len]) .map_err(|_| "EC group name is not UTF-8".to_string())?; @@ -253,8 +297,9 @@ impl EvpKey { if len <= 0 || der_ptr.is_null() { return Err(format!( - "Failed to encode public key to DER (rc={})", - len + "i2d_PUBKEY returned {}: {}", + len, + ossl_err_string() )); } @@ -279,8 +324,9 @@ impl EvpKey { if len <= 0 || der_ptr.is_null() { return Err(format!( - "Failed to encode private key to DER (rc={})", - len + "i2d_PrivateKey returned {}: {}", + len, + ossl_err_string() )); } @@ -305,7 +351,10 @@ impl EvpKey { unsafe { let bits = ossl::EVP_PKEY_bits(self.key); if bits <= 0 { - return Err("EVP_PKEY_bits failed".to_string()); + return Err(format!( + "EVP_PKEY_bits failed: {}", + ossl_err_string() + )); } Ok(((bits + 7) / 8) as usize) } @@ -363,7 +412,7 @@ pub fn ecdsa_der_to_fixed( der.len() as std::ffi::c_long, ); if sig.is_null() { - return Err("Failed to parse DER ECDSA signature".to_string()); + return Err(format!("d2i_ECDSA_SIG failed: {}", ossl_err_string())); } let mut r: *const ossl::BIGNUM = ptr::null(); @@ -386,7 +435,7 @@ pub fn ecdsa_der_to_fixed( if rc_r != field_size as std::ffi::c_int || rc_s != field_size as std::ffi::c_int { - return Err("BN_bn2binpad failed for ECDSA r or s".to_string()); + return Err(format!("BN_bn2binpad failed: {}", ossl_err_string())); } Ok(fixed) @@ -413,7 +462,7 @@ pub fn ecdsa_fixed_to_der( ptr::null_mut(), ); if r.is_null() { - return Err("BN_bin2bn failed for ECDSA r".to_string()); + return Err(format!("BN_bin2bn failed (r): {}", ossl_err_string())); } let s = ossl::BN_bin2bn( @@ -423,21 +472,24 @@ pub fn ecdsa_fixed_to_der( ); if s.is_null() { ossl::BN_free(r); - return Err("BN_bin2bn failed for ECDSA s".to_string()); + return Err(format!("BN_bin2bn failed (s): {}", ossl_err_string())); } let sig = ossl::ECDSA_SIG_new(); if sig.is_null() { ossl::BN_free(r); ossl::BN_free(s); - return Err("ECDSA_SIG_new failed".to_string()); + return Err(format!("ECDSA_SIG_new failed: {}", ossl_err_string())); } if ossl::ECDSA_SIG_set0(sig, r, s) != 1 { ossl::ECDSA_SIG_free(sig); ossl::BN_free(r); ossl::BN_free(s); - return Err("ECDSA_SIG_set0 failed".to_string()); + return Err(format!( + "ECDSA_SIG_set0 failed: {}", + ossl_err_string() + )); } // ECDSA_SIG_set0 takes ownership of r and s on success. @@ -446,7 +498,7 @@ pub fn ecdsa_fixed_to_der( ossl::ECDSA_SIG_free(sig); if len <= 0 || out_ptr.is_null() { - return Err("i2d_ECDSA_SIG failed".to_string()); + return Err(format!("i2d_ECDSA_SIG failed: {}", ossl_err_string())); } let der = std::slice::from_raw_parts(out_ptr, len as usize).to_vec(); @@ -546,17 +598,18 @@ impl EvpMdContext { let ctx = ossl::EVP_MD_CTX_new(); if ctx.is_null() { return Err(format!( - "Failed to create ctx for: {}", - T::purpose() + "EVP_MD_CTX_new failed: {}", + ossl_err_string() )); } let mut pctx: *mut ossl::EVP_PKEY_CTX = ptr::null_mut(); if let Err(err) = T::init(ctx, md, key.key, &mut pctx) { ossl::EVP_MD_CTX_free(ctx); return Err(format!( - "Failed to init context for {} with err {}", + "EVP_Digest{}Init returned {}: {}", T::purpose(), - err + err, + ossl_err_string() )); } // For RSA keys, configure PSS padding. @@ -568,7 +621,10 @@ impl EvpMdContext { ) != 1 { ossl::EVP_MD_CTX_free(ctx); - return Err("Failed to set RSA PSS padding".into()); + return Err(format!( + "EVP_PKEY_CTX_set_rsa_padding failed: {}", + ossl_err_string() + )); } if ossl::EVP_PKEY_CTX_set_rsa_pss_saltlen( pctx, @@ -576,7 +632,10 @@ impl EvpMdContext { ) != 1 { ossl::EVP_MD_CTX_free(ctx); - return Err("Failed to set RSA PSS salt length".into()); + return Err(format!( + "EVP_PKEY_CTX_set_rsa_pss_saltlen failed: {}", + ossl_err_string() + )); } } Ok(EvpMdContext { @@ -698,12 +757,22 @@ mod tests { #[test] fn from_der_rejects_garbage() { - assert!(EvpKey::from_der_public(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + let err = + EvpKey::from_der_public(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err(); + assert!( + err.starts_with("d2i_PUBKEY failed: error:"), + "unexpected error: {err}" + ); } #[test] fn from_der_private_rejects_garbage() { - assert!(EvpKey::from_der_private(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + let err = + EvpKey::from_der_private(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err(); + assert!( + err.starts_with("d2i_AutoPrivateKey failed: error:"), + "unexpected error: {err}" + ); } #[test] @@ -775,4 +844,48 @@ mod tests { let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); std::mem::forget(key); } + + // --------------------------------------------------------------- + // Tests verifying exact OpenSSL errors in Err values + // --------------------------------------------------------------- + + #[test] + fn from_der_public_error_has_ossl_detail() { + let err = + EvpKey::from_der_public(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err(); + assert!( + err.starts_with("d2i_PUBKEY failed: error:"), + "unexpected error: {err}" + ); + } + + #[test] + fn from_der_private_error_has_ossl_detail() { + let err = + EvpKey::from_der_private(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err(); + assert!( + err.starts_with("d2i_AutoPrivateKey failed: error:"), + "unexpected error: {err}" + ); + } + + #[test] + fn ecdsa_der_to_fixed_error() { + assert_eq!( + ecdsa_der_to_fixed(&[0xff, 0xff], 32).unwrap_err(), + "d2i_ECDSA_SIG failed: (no OpenSSL error)", + ); + } + + #[test] + fn sign_with_public_only_key_error_has_ossl_detail() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + let err = crate::sign::sign(&pub_key, b"test message").unwrap_err(); + assert!( + err.starts_with("EVP_DigestSign returned 0: error:"), + "unexpected error: {err}" + ); + } } diff --git a/3rdparty/internal/cose-openssl/src/sign.rs b/3rdparty/internal/cose-openssl/src/sign.rs index 32020189ee4e..556fc426fb5b 100644 --- a/3rdparty/internal/cose-openssl/src/sign.rs +++ b/3rdparty/internal/cose-openssl/src/sign.rs @@ -1,4 +1,4 @@ -use crate::ossl_wrappers::{EvpKey, EvpMdContext, SignOp}; +use crate::ossl_wrappers::{EvpKey, EvpMdContext, SignOp, ossl_err_string}; use openssl_sys as ossl; use std::ptr; @@ -33,7 +33,11 @@ fn sign_with_ctx( msg.len(), ); if res != 1 { - return Err(format!("Failed to get signature size, err: {}", res)); + return Err(format!( + "EVP_DigestSign (get size) returned {}: {}", + res, + ossl_err_string() + )); } let mut sig = vec![0u8; sig_size]; @@ -45,7 +49,11 @@ fn sign_with_ctx( msg.len(), ); if res != 1 { - return Err(format!("Failed to sign, err: {}", res)); + return Err(format!( + "EVP_DigestSign returned {}: {}", + res, + ossl_err_string() + )); } // Not always fixed size, e.g. for EC keys. More on this here: @@ -55,3 +63,62 @@ fn sign_with_ctx( Ok(sig) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ossl_wrappers::{EvpKey, KeyType, WhichEC, WhichRSA}; + + #[test] + fn sign_ec_succeeds() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let sig = sign(&key, b"hello"); + assert!(sig.is_ok()); + assert!(!sig.unwrap().is_empty()); + } + + #[test] + fn sign_rsa_succeeds() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let sig = sign(&key, b"hello"); + assert!(sig.is_ok()); + assert!(!sig.unwrap().is_empty()); + } + + #[test] + fn sign_with_public_only_ec_key_fails_with_ossl_detail() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + let err = sign(&pub_key, b"hello").unwrap_err(); + assert!( + err.starts_with("EVP_DigestSign returned 0: error:"), + "unexpected error: {err}" + ); + } + + #[test] + fn sign_with_public_only_rsa_key_fails_with_ossl_detail() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + let err = sign(&pub_key, b"hello").unwrap_err(); + assert!( + err.starts_with("EVP_DigestSign returned 0: error:"), + "unexpected error: {err}" + ); + } + + #[test] + fn sign_context_init_error_propagates() { + let null_key = EvpKey { + key: std::ptr::null_mut(), + typ: KeyType::EC(WhichEC::P256), + }; + let err = sign(&null_key, b"hello").unwrap_err(); + assert!( + err.starts_with("EVP_DigestSignInit returned 0: error:"), + "unexpected error: {err}" + ); + } +} diff --git a/3rdparty/internal/cose-openssl/src/verify.rs b/3rdparty/internal/cose-openssl/src/verify.rs index 5cdafcdbb68a..5a09e8315e72 100644 --- a/3rdparty/internal/cose-openssl/src/verify.rs +++ b/3rdparty/internal/cose-openssl/src/verify.rs @@ -1,4 +1,4 @@ -use crate::ossl_wrappers::{EvpKey, EvpMdContext, VerifyOp}; +use crate::ossl_wrappers::{EvpKey, EvpMdContext, VerifyOp, ossl_err_string}; use openssl_sys as ossl; @@ -34,7 +34,97 @@ fn verify_with_ctx( match res { 1 => Ok(true), 0 => Ok(false), - err => Err(format!("Failed to verify signature, err: {}", err)), + err => Err(format!( + "EVP_DigestVerify returned {}: {}", + err, + ossl_err_string() + )), } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ossl_wrappers::{EvpKey, KeyType, WhichEC, WhichRSA}; + use crate::sign; + + #[test] + fn verify_ec_valid_signature() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let msg = b"test message"; + let sig = sign::sign(&key, msg).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + assert_eq!(verify(&pub_key, &sig, msg).unwrap(), true); + } + + #[test] + fn verify_ec_wrong_message_returns_false() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let sig = sign::sign(&key, b"correct").unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + assert_eq!(verify(&pub_key, &sig, b"wrong").unwrap(), false); + } + + #[test] + fn verify_rsa_valid_signature() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let msg = b"test message"; + let sig = sign::sign(&key, msg).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + assert_eq!(verify(&pub_key, &sig, msg).unwrap(), true); + } + + #[test] + fn verify_rsa_wrong_message_returns_false() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let sig = sign::sign(&key, b"correct").unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + assert_eq!(verify(&pub_key, &sig, b"wrong").unwrap(), false); + } + + #[test] + fn verify_ec_garbage_signature_returns_false_or_err() { + let key = EvpKey::new(KeyType::EC(WhichEC::P256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + match verify(&pub_key, &[0xde, 0xad], b"msg") { + Ok(valid) => assert!(!valid, "Garbage signature must not verify"), + Err(err) => assert!( + err.starts_with("EVP_DigestVerify returned"), + "unexpected error: {err}" + ), + } + } + + #[test] + fn verify_rsa_garbage_signature_returns_false_or_err() { + let key = EvpKey::new(KeyType::RSA(WhichRSA::PS256)).unwrap(); + let pub_der = key.to_der_public().unwrap(); + let pub_key = EvpKey::from_der_public(&pub_der).unwrap(); + match verify(&pub_key, &[0xde, 0xad], b"msg") { + Ok(valid) => assert!(!valid, "Garbage signature must not verify"), + Err(err) => assert!( + err.starts_with("EVP_DigestVerify returned"), + "unexpected error: {err}" + ), + } + } + + #[test] + fn verify_context_init_error_propagates() { + let null_key = EvpKey { + key: std::ptr::null_mut(), + typ: KeyType::EC(WhichEC::P256), + }; + let err = verify(&null_key, &[0xde], b"hello").unwrap_err(); + assert!( + err.starts_with("EVP_DigestVerifyInit returned 0: error:"), + "unexpected error: {err}" + ); + } +} diff --git a/src/cose/cose_rs/src/lib.rs b/src/cose/cose_rs/src/lib.rs index e6a0d10901d6..4c76a88c8fba 100644 --- a/src/cose/cose_rs/src/lib.rs +++ b/src/cose/cose_rs/src/lib.rs @@ -4,6 +4,23 @@ use cose_openssl::{CborValue, EvpKey}; use std::slice; +/// Write an error message string into caller-provided output pointers. +/// +/// If `err_ptr` and `err_len` are both non-null the message is heap-allocated +/// with `Box<[u8]>` and ownership is transferred to the caller (who must free +/// it with `cose_free`). When either pointer is null the message is silently +/// dropped. +unsafe fn set_error(msg: &str, err_ptr: *mut *mut u8, err_len: *mut usize) { + if err_ptr.is_null() || err_len.is_null() { + return; + } + let bytes = msg.as_bytes().to_vec().into_boxed_slice(); + unsafe { + *err_len = bytes.len(); + *err_ptr = Box::into_raw(bytes) as *mut u8; + } +} + // COSE/CWT header labels (matching CCF's C++ constants). const CWT_CLAIMS: i64 = 15; const KID: i64 = 4; @@ -98,6 +115,9 @@ fn build_endorsement_phdr( /// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be /// null/0 if not applicable. /// +/// On failure the error message is written to `err_ptr`/`err_len` (if +/// non-null). The caller must free it with `cose_free`. +/// /// # Safety /// `key` must be a valid pointer from `cose_key_from_der_private`. /// All pointer+length pairs must be valid. @@ -115,8 +135,11 @@ pub unsafe extern "C" fn cose_sign_endorsement( payload_len: usize, out_ptr: *mut *mut u8, out_len: *mut usize, + err_ptr: *mut *mut u8, + err_len: *mut usize, ) -> i32 { if key.is_null() { + unsafe { set_error("key is null", err_ptr, err_len) }; return -1; } let result = std::panic::catch_unwind(|| unsafe { @@ -140,7 +163,14 @@ pub unsafe extern "C" fn cose_sign_endorsement( std::mem::forget(buf); 0 }, - _ => -1, + Ok(Err(e)) => unsafe { + set_error(&e, err_ptr, err_len); + -1 + }, + Err(_) => unsafe { + set_error("panic during cose_sign_endorsement", err_ptr, err_len); + -1 + }, } } @@ -148,12 +178,17 @@ pub unsafe extern "C" fn cose_sign_endorsement( /// Returns a pointer to the key, or null on failure. /// The caller must free the key with `cose_key_free`. /// +/// On failure the error message is written to `err_ptr`/`err_len` (if +/// non-null). The caller must free it with `cose_free`. +/// /// # Safety /// `key_der_ptr` must point to `key_der_len` valid bytes. #[unsafe(no_mangle)] pub unsafe extern "C" fn cose_key_from_der_private( key_der_ptr: *const u8, key_der_len: usize, + err_ptr: *mut *mut u8, + err_len: *mut usize, ) -> *mut EvpKey { let result = std::panic::catch_unwind(|| unsafe { let key_der = slice_from_raw(key_der_ptr, key_der_len); @@ -162,7 +197,14 @@ pub unsafe extern "C" fn cose_key_from_der_private( match result { Ok(Ok(key)) => Box::into_raw(Box::new(key)), - _ => std::ptr::null_mut(), + Ok(Err(e)) => unsafe { + set_error(&e, err_ptr, err_len); + std::ptr::null_mut() + }, + Err(_) => unsafe { + set_error("panic during cose_key_from_der_private", err_ptr, err_len); + std::ptr::null_mut() + }, } } @@ -182,6 +224,9 @@ pub unsafe extern "C" fn cose_key_free(key: *mut EvpKey) { /// Sign a ledger signature using a pre-created key handle. /// +/// On failure the error message is written to `err_ptr`/`err_len` (if +/// non-null). The caller must free it with `cose_free`. +/// /// # Safety /// `key` must be a valid pointer from `cose_key_from_der_private`. /// All pointer+length pairs must be valid. @@ -201,8 +246,11 @@ pub unsafe extern "C" fn cose_sign_ledger( payload_len: usize, out_ptr: *mut *mut u8, out_len: *mut usize, + err_ptr: *mut *mut u8, + err_len: *mut usize, ) -> i32 { if key.is_null() { + unsafe { set_error("key is null", err_ptr, err_len) }; return -1; } let result = std::panic::catch_unwind(|| unsafe { @@ -227,7 +275,14 @@ pub unsafe extern "C" fn cose_sign_ledger( std::mem::forget(buf); 0 }, - _ => -1, + Ok(Err(e)) => unsafe { + set_error(&e, err_ptr, err_len); + -1 + }, + Err(_) => unsafe { + set_error("panic during cose_sign_ledger", err_ptr, err_len); + -1 + }, } } @@ -253,6 +308,9 @@ pub unsafe extern "C" fn cose_free(ptr: *mut u8, len: usize) { /// /// Returns 0 on successful verification, non-zero on failure. /// +/// On failure the error message is written to `err_ptr`/`err_len` (if +/// non-null). The caller must free it with `cose_free`. +/// /// # Safety /// All pointer+length pairs must be valid. #[unsafe(no_mangle)] @@ -266,6 +324,8 @@ pub unsafe extern "C" fn cose_verify1( payload_len: usize, sig_ptr: *const u8, sig_len: usize, + err_ptr: *mut *mut u8, + err_len: *mut usize, ) -> i32 { let result = std::panic::catch_unwind(|| unsafe { let key_der = slice_from_raw(key_pub_der_ptr, key_pub_der_len); @@ -285,6 +345,13 @@ pub unsafe extern "C" fn cose_verify1( match result { Ok(Ok(rc)) => rc, - _ => -1, + Ok(Err(e)) => unsafe { + set_error(&e, err_ptr, err_len); + -1 + }, + Err(_) => unsafe { + set_error("panic during cose_verify1", err_ptr, err_len); + -1 + }, } } diff --git a/src/cose/cose_rs_ffi.h b/src/cose/cose_rs_ffi.h index 48d71880fc07..3b0f2cd09774 100644 --- a/src/cose/cose_rs_ffi.h +++ b/src/cose/cose_rs_ffi.h @@ -11,20 +11,26 @@ extern "C" { #endif - /// Opaque handle to a Rust-managed signing key. + /// Opaque handle to a signing key (Rust-managed). struct CoseEvpKey; /// Create a signing key from DER-encoded private key bytes. /// Returns an opaque pointer, or NULL on failure. - /// The caller must free the key with cose_key_free. + /// On failure, if err_ptr/err_len are non-null, an error message + /// is written there. CoseEvpKey* cose_key_from_der_private( - const uint8_t* key_der_ptr, size_t key_der_len); + const uint8_t* key_der_ptr, + size_t key_der_len, + uint8_t** err_ptr, + size_t* err_len); /// Free a key created by cose_key_from_der_private. void cose_key_free(CoseEvpKey* key); /// Sign a CCF ledger signature using a pre-created key handle. /// Returns 0 on success, non-zero on failure. + /// On failure, if err_ptr/err_len are non-null, an error message + /// is written there. int cose_sign_ledger( const CoseEvpKey* key, const uint8_t* kid_ptr, @@ -39,11 +45,15 @@ extern "C" const uint8_t* payload_ptr, size_t payload_len, uint8_t** out_ptr, - size_t* out_len); + size_t* out_len, + uint8_t** err_ptr, + size_t* err_len); /// Sign a CCF identity endorsement (COSE_Sign1, embedded payload). /// epoch_end and prev_root may be NULL/0 if not applicable. /// Returns 0 on success, non-zero on failure. + /// On failure, if err_ptr/err_len are non-null, an error message + /// is written there. int cose_sign_endorsement( const CoseEvpKey* key, int64_t iat, @@ -56,14 +66,15 @@ extern "C" const uint8_t* payload_ptr, size_t payload_len, uint8_t** out_ptr, - size_t* out_len); + size_t* out_len, + uint8_t** err_ptr, + size_t* err_len); /// Verify a COSE_Sign1 from pre-parsed components. /// alg: COSE algorithm integer (e.g. -7 for ES256). - /// phdr_cbor_ptr/phdr_cbor_len: serialized CBOR protected header bytes. - /// payload_ptr/payload_len: raw payload bytes (not CBOR-wrapped). - /// sig_ptr/sig_len: the fixed-size signature bytes. /// Returns 0 on successful verification, non-zero on failure. + /// On failure, if err_ptr/err_len are non-null, an error message + /// is written there. int cose_verify1( const uint8_t* key_pub_der_ptr, size_t key_pub_der_len, @@ -73,19 +84,27 @@ extern "C" const uint8_t* payload_ptr, size_t payload_len, const uint8_t* sig_ptr, - size_t sig_len); + size_t sig_len, + uint8_t** err_ptr, + size_t* err_len); - /// Free a buffer returned by cose_sign_*. + /// Free a byte buffer or error string allocated by any cose_* call. void cose_free(uint8_t* ptr, size_t len); #ifdef __cplusplus } # include +# include # include -/// RAII wrapper for buffers allocated by cose_sign_* FFI functions. -/// Automatically calls cose_free on destruction. +/// RAII wrapper for a byte buffer allocated by a COSE FFI call. +/// On destruction any held buffer is freed automatically via cose_free. +/// Pass data()/size() to FFI functions that accept ptr/len output pairs. +/// +/// Used for both output envelopes and error strings: +/// is_set() / to_vector() — for sign output buffers. +/// is_set() / to_string() — for error strings. class CoseBuffer { uint8_t* ptr = nullptr; @@ -140,19 +159,32 @@ class CoseBuffer } } + // -- Buffer accessors -- + [[nodiscard]] std::vector to_vector() const { return {ptr, ptr + len}; } - [[nodiscard]] bool ok() const + [[nodiscard]] std::string to_string() const + { + if (ptr != nullptr && len > 0) + { + return {reinterpret_cast(ptr), len}; + } + return {}; + } + + [[nodiscard]] bool is_set() const { return ptr != nullptr && len > 0; } }; -/// RAII wrapper for a Rust-managed signing key. -/// Automatically calls cose_key_free on destruction. +/// RAII wrapper for a signing key created from DER-encoded private key bytes. +/// On destruction the underlying key is freed automatically. +/// Pass a CoseBuffer& to the constructor; on failure is_set() returns false +/// and the CoseBuffer holds the reason. class CoseKey { CoseEvpKey* key = nullptr; @@ -160,8 +192,8 @@ class CoseKey public: CoseKey() = default; - CoseKey(const uint8_t* der_ptr, size_t der_len) : - key(cose_key_from_der_private(der_ptr, der_len)) + CoseKey(const uint8_t* der_ptr, size_t der_len, CoseBuffer& err) : + key(cose_key_from_der_private(der_ptr, der_len, err.data(), err.size())) {} CoseKey(const CoseKey&) = delete; @@ -202,12 +234,15 @@ class CoseKey return key; } - [[nodiscard]] bool ok() const + [[nodiscard]] bool is_set() const { return key != nullptr; } }; +/// Sign a CCF ledger signature using a pre-created key handle. +/// Returns 0 on success, non-zero on failure. +/// On failure the CoseBuffer holds the error message. inline int cose_sign_ledger( const CoseKey& key, const uint8_t* kid_ptr, @@ -221,7 +256,8 @@ inline int cose_sign_ledger( size_t txid_len, const uint8_t* payload_ptr, size_t payload_len, - CoseBuffer& out) + CoseBuffer& out, + CoseBuffer& err) { return ::cose_sign_ledger( key.get(), @@ -237,9 +273,15 @@ inline int cose_sign_ledger( payload_ptr, payload_len, out.data(), - out.size()); + out.size(), + err.data(), + err.size()); } +/// Sign a CCF identity endorsement (COSE_Sign1, embedded payload). +/// epoch_end and prev_root may be nullptr/0 if not applicable. +/// Returns 0 on success, non-zero on failure. +/// On failure the CoseBuffer holds the error message. inline int cose_sign_endorsement( const CoseKey& key, int64_t iat, @@ -251,7 +293,8 @@ inline int cose_sign_endorsement( size_t prev_root_len, const uint8_t* payload_ptr, size_t payload_len, - CoseBuffer& out) + CoseBuffer& out, + CoseBuffer& err) { return ::cose_sign_endorsement( key.get(), @@ -265,7 +308,9 @@ inline int cose_sign_endorsement( payload_ptr, payload_len, out.data(), - out.size()); + out.size(), + err.data(), + err.size()); } #endif diff --git a/src/cose/test/cose_ffi_test.cpp b/src/cose/test/cose_ffi_test.cpp index 9c3d12b7c45a..3fa1ebe0c249 100644 --- a/src/cose/test/cose_ffi_test.cpp +++ b/src/cose/test/cose_ffi_test.cpp @@ -66,9 +66,11 @@ namespace int verify_decoded( const std::vector& pub_der, const CoseSign1Components& c, - std::span payload) + std::span payload, + CoseBuffer* out_err = nullptr) { - return cose_verify1( + CoseBuffer err; + auto rc = cose_verify1( pub_der.data(), pub_der.size(), c.alg, @@ -77,15 +79,23 @@ namespace payload.data(), payload.size(), c.sig.data(), - c.sig.size()); + c.sig.size(), + err.data(), + err.size()); + if (out_err) + { + *out_err = std::move(err); + } + return rc; } } TEST_CASE("cose_sign_ledger sign and verify round-trip") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string kid = "test-kid"; const std::string issuer = "test-issuer"; @@ -95,6 +105,7 @@ TEST_CASE("cose_sign_ledger sign and verify round-trip") const int64_t iat = 1700000000; CoseBuffer buf; + CoseBuffer sign_err; auto rc = cose_sign_ledger( cose_key, reinterpret_cast(kid.data()), @@ -108,10 +119,11 @@ TEST_CASE("cose_sign_ledger sign and verify round-trip") txid.size(), payload.data(), payload.size(), - buf); + buf, + sign_err); REQUIRE(rc == 0); - REQUIRE(buf.ok()); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); REQUIRE(!envelope.empty()); @@ -120,21 +132,83 @@ TEST_CASE("cose_sign_ledger sign and verify round-trip") CHECK(verify_decoded(key.pub_der, c, payload) == 0); std::vector wrong_payload = {9, 8, 7}; - CHECK(verify_decoded(key.pub_der, c, wrong_payload) != 0); + CoseBuffer wrong_err; + CHECK(verify_decoded(key.pub_der, c, wrong_payload, &wrong_err) != 0); + CHECK(wrong_err.to_string() == "Signature verification failed"); } TEST_CASE("cose_sign_ledger fails with invalid key") { const std::vector bad_key = {0, 1, 2, 3}; - CoseKey cose_key(bad_key.data(), bad_key.size()); - CHECK(!cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(bad_key.data(), bad_key.size(), key_err); + CHECK(!cose_key.is_set()); + CHECK(key_err.is_set()); + CHECK( + key_err.to_string().find("d2i_AutoPrivateKey failed:") != + std::string::npos); +} + +TEST_CASE("CoseKey error propagation") +{ + SUBCASE("null DER pointer") + { + CoseBuffer err; + CoseKey k(nullptr, 0, err); + CHECK(!k.is_set()); + } + + SUBCASE("truncated DER returns OpenSSL error detail") + { + // A plausible but truncated EC private key prefix. + const std::vector truncated = {0x30, 0x81, 0x87, 0x02, 0x01}; + CoseBuffer err; + CoseKey k(truncated.data(), truncated.size(), err); + CHECK(!k.is_set()); + CHECK(err.is_set()); + CHECK( + err.to_string().find("d2i_AutoPrivateKey failed:") != std::string::npos); + } + + SUBCASE("valid key succeeds without error") + { + TestKey tk; + CoseBuffer err; + CoseKey k(tk.priv_der.data(), tk.priv_der.size(), err); + CHECK(k.is_set()); + CHECK(!err.is_set()); + } + + SUBCASE("move preserves key validity") + { + TestKey tk; + CoseBuffer err; + CoseKey k(tk.priv_der.data(), tk.priv_der.size(), err); + REQUIRE(k.is_set()); + + CoseKey moved(std::move(k)); + CHECK(!k.is_set()); + CHECK(moved.is_set()); + } + + SUBCASE("reset releases key") + { + TestKey tk; + CoseBuffer err; + CoseKey k(tk.priv_der.data(), tk.priv_der.size(), err); + REQUIRE(k.is_set()); + + k.reset(); + CHECK(!k.is_set()); + } } TEST_CASE("cose_sign_endorsement sign and verify round-trip") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "2.1"; const std::string epoch_end = "3.10"; @@ -144,6 +218,7 @@ TEST_CASE("cose_sign_endorsement sign and verify round-trip") const int64_t iat = 1700000000; CoseBuffer buf; + CoseBuffer sign_err; auto rc = cose_sign_endorsement( cose_key, iat, @@ -155,10 +230,11 @@ TEST_CASE("cose_sign_endorsement sign and verify round-trip") prev_root.size(), payload.data(), payload.size(), - buf); + buf, + sign_err); REQUIRE(rc == 0); - REQUIRE(buf.ok()); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); auto c = decompose(envelope); @@ -168,14 +244,16 @@ TEST_CASE("cose_sign_endorsement sign and verify round-trip") TEST_CASE("cose_sign_endorsement without optional fields") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "1.1"; const std::vector payload = {42}; const int64_t iat = 1700000000; CoseBuffer buf; + CoseBuffer sign_err; auto rc = cose_sign_endorsement( cose_key, iat, @@ -187,10 +265,11 @@ TEST_CASE("cose_sign_endorsement without optional fields") 0, payload.data(), payload.size(), - buf); + buf, + sign_err); REQUIRE(rc == 0); - REQUIRE(buf.ok()); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); auto c = decompose(envelope); @@ -200,14 +279,17 @@ TEST_CASE("cose_sign_endorsement without optional fields") TEST_CASE("cose_verify1 fails with wrong key") { TestKey sign_key; - CoseKey sign_cose_key(sign_key.priv_der.data(), sign_key.priv_der.size()); - REQUIRE(sign_cose_key.ok()); + CoseBuffer key_err; + CoseKey sign_cose_key( + sign_key.priv_der.data(), sign_key.priv_der.size(), key_err); + REQUIRE(sign_cose_key.is_set()); TestKey wrong_key; const std::string epoch_begin = "1.1"; const std::vector payload = {1, 2, 3}; CoseBuffer buf; + CoseBuffer sign_err; cose_sign_endorsement( sign_cose_key, 0, @@ -219,24 +301,31 @@ TEST_CASE("cose_verify1 fails with wrong key") 0, payload.data(), payload.size(), - buf); - REQUIRE(buf.ok()); + buf, + sign_err); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); auto c = decompose(envelope); - CHECK(verify_decoded(wrong_key.pub_der, c, c.payload.value()) != 0); + CoseBuffer wrong_key_err; + CHECK( + verify_decoded(wrong_key.pub_der, c, c.payload.value(), &wrong_key_err) != + 0); + CHECK(wrong_key_err.to_string() == "Signature verification failed"); } TEST_CASE("cose_verify1 fails with corrupted signature") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "1.1"; const std::vector payload = {1, 2, 3}; CoseBuffer buf; + CoseBuffer sign_err; cose_sign_endorsement( cose_key, 0, @@ -248,8 +337,9 @@ TEST_CASE("cose_verify1 fails with corrupted signature") 0, payload.data(), payload.size(), - buf); - REQUIRE(buf.ok()); + buf, + sign_err); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); auto c = decompose(envelope); @@ -257,6 +347,7 @@ TEST_CASE("cose_verify1 fails with corrupted signature") std::vector bad_sig(c.sig.begin(), c.sig.end()); bad_sig[bad_sig.size() - 1] ^= 0xFF; + CoseBuffer verify_err; auto vrc = cose_verify1( key.pub_der.data(), key.pub_der.size(), @@ -266,20 +357,26 @@ TEST_CASE("cose_verify1 fails with corrupted signature") c.payload.value().data(), c.payload.value().size(), bad_sig.data(), - bad_sig.size()); + bad_sig.size(), + verify_err.data(), + verify_err.size()); CHECK(vrc != 0); + CHECK(verify_err.is_set()); + CHECK(verify_err.to_string() == "Signature verification failed"); } TEST_CASE("cose_verify1 wrong alg fails") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "1.1"; const std::vector payload = {0xCA, 0xFE}; CoseBuffer buf; + CoseBuffer sign_err; cose_sign_endorsement( cose_key, 0, @@ -291,8 +388,9 @@ TEST_CASE("cose_verify1 wrong alg fails") 0, payload.data(), payload.size(), - buf); - REQUIRE(buf.ok()); + buf, + sign_err); + REQUIRE(buf.is_set()); auto envelope = buf.to_vector(); auto c = decompose(envelope); @@ -300,6 +398,7 @@ TEST_CASE("cose_verify1 wrong alg fails") CHECK(verify_decoded(key.pub_der, c, c.payload.value()) == 0); auto payload_span = c.payload.value(); + CoseBuffer verify_err; auto vrc = cose_verify1( key.pub_der.data(), key.pub_der.size(), @@ -309,8 +408,14 @@ TEST_CASE("cose_verify1 wrong alg fails") payload_span.data(), payload_span.size(), c.sig.data(), - c.sig.size()); + c.sig.size(), + verify_err.data(), + verify_err.size()); CHECK(vrc != 0); + CHECK(verify_err.is_set()); + CHECK( + verify_err.to_string() == + "Algorithm mismatch between supplied alg and key"); } TEST_CASE("CoseBuffer RAII semantics") @@ -318,19 +423,21 @@ TEST_CASE("CoseBuffer RAII semantics") SUBCASE("default construction") { CoseBuffer buf; - CHECK(!buf.ok()); + CHECK(!buf.is_set()); CHECK(buf.to_vector().empty()); } SUBCASE("move construction") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "1.1"; const std::vector payload = {1}; CoseBuffer buf; + CoseBuffer sign_err; cose_sign_endorsement( cose_key, 0, @@ -342,25 +449,28 @@ TEST_CASE("CoseBuffer RAII semantics") 0, payload.data(), payload.size(), - buf); - REQUIRE(buf.ok()); + buf, + sign_err); + REQUIRE(buf.is_set()); auto vec_before = buf.to_vector(); CoseBuffer moved(std::move(buf)); - CHECK(!buf.ok()); - CHECK(moved.ok()); + CHECK(!buf.is_set()); + CHECK(moved.is_set()); CHECK(moved.to_vector() == vec_before); } SUBCASE("reset") { TestKey key; - CoseKey cose_key(key.priv_der.data(), key.priv_der.size()); - REQUIRE(cose_key.ok()); + CoseBuffer key_err; + CoseKey cose_key(key.priv_der.data(), key.priv_der.size(), key_err); + REQUIRE(cose_key.is_set()); const std::string epoch_begin = "1.1"; const std::vector payload = {1}; CoseBuffer buf; + CoseBuffer sign_err; cose_sign_endorsement( cose_key, 0, @@ -372,11 +482,12 @@ TEST_CASE("CoseBuffer RAII semantics") 0, payload.data(), payload.size(), - buf); - REQUIRE(buf.ok()); + buf, + sign_err); + REQUIRE(buf.is_set()); buf.reset(); - CHECK(!buf.ok()); + CHECK(!buf.is_set()); } } diff --git a/src/crypto/openssl/cose_verifier.cpp b/src/crypto/openssl/cose_verifier.cpp index 33789f814291..6bded7ade50f 100644 --- a/src/crypto/openssl/cose_verifier.cpp +++ b/src/crypto/openssl/cose_verifier.cpp @@ -124,6 +124,7 @@ namespace ccf::crypto } auto alg = extract_alg(phdr); + CoseBuffer verify_err; auto rc = cose_verify1( key_der.data(), key_der.size(), @@ -133,7 +134,9 @@ namespace ccf::crypto payload->data(), payload->size(), sig.data(), - sig.size()); + sig.size(), + verify_err.data(), + verify_err.size()); if (rc == 0) { authned_content = { @@ -141,7 +144,9 @@ namespace ccf::crypto return true; } - LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); + LOG_DEBUG_FMT( + "COSE Sign1 verification failed: {}", + verify_err.is_set() ? verify_err.to_string() : "unknown error"); } catch (const std::exception& e) { @@ -159,6 +164,7 @@ namespace ccf::crypto auto [phdr, _payload, sig] = decompose_cose_sign1(envelope); auto alg = extract_alg(phdr); + CoseBuffer verify_err; auto rc = cose_verify1( key_der.data(), key_der.size(), @@ -168,13 +174,17 @@ namespace ccf::crypto payload.data(), payload.size(), sig.data(), - sig.size()); + sig.size(), + verify_err.data(), + verify_err.size()); if (rc == 0) { return true; } - LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); + LOG_DEBUG_FMT( + "COSE Sign1 verification failed: {}", + verify_err.is_set() ? verify_err.to_string() : "unknown error"); } catch (const std::exception& e) { @@ -192,6 +202,7 @@ namespace ccf::crypto try { auto key_der = public_key->public_key_der(); + CoseBuffer verify_err; auto rc = cose_verify1( key_der.data(), key_der.size(), @@ -201,13 +212,17 @@ namespace ccf::crypto payload.data(), payload.size(), sig.data(), - sig.size()); + sig.size(), + verify_err.data(), + verify_err.size()); if (rc == 0) { return true; } - LOG_DEBUG_FMT("COSE Sign1 verification failed with rc: {}", rc); + LOG_DEBUG_FMT( + "COSE Sign1 verification failed: {}", + verify_err.is_set() ? verify_err.to_string() : "unknown error"); } catch (const std::exception& e) { diff --git a/src/node/history.h b/src/node/history.h index 3b3509764bc8..9da34f682339 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -372,12 +372,19 @@ namespace ccf if (it == cose_key_cache.end()) { auto key_der = service_kp.private_key_der(); - auto [inserted, _] = - cose_key_cache.emplace(kid, CoseKey(key_der.data(), key_der.size())); + CoseBuffer key_err; + auto [inserted, _] = cose_key_cache.emplace( + kid, CoseKey(key_der.data(), key_der.size(), key_err)); + if (key_err.is_set()) + { + throw std::runtime_error(fmt::format( + "cose_key_from_der_private failed: {}", key_err.to_string())); + } it = inserted; } CoseBuffer cose_buf; + CoseBuffer cose_err; auto rc = cose_sign_ledger( it->second, reinterpret_cast(kid.data()), @@ -391,10 +398,13 @@ namespace ccf tx_id.size(), root_hash.data(), root_hash.size(), - cose_buf); - if (rc != 0 || !cose_buf.ok()) + cose_buf, + cose_err); + if (rc != 0 || !cose_buf.is_set()) { - throw std::runtime_error("cose_sign_ledger failed"); + throw std::runtime_error(fmt::format( + "cose_sign_ledger failed: {}", + cose_err.is_set() ? cose_err.to_string() : "unknown error")); } std::vector cose_sign(cose_buf.to_vector()); diff --git a/src/service/internal_tables_access.h b/src/service/internal_tables_access.h index c0891a8fbd64..ba736bf35c44 100644 --- a/src/service/internal_tables_access.h +++ b/src/service/internal_tables_access.h @@ -635,9 +635,16 @@ namespace ccf .count(); auto key_der = service_key.private_key_der(); - CoseKey cose_key(key_der.data(), key_der.size()); + CoseBuffer key_err; + CoseKey cose_key(key_der.data(), key_der.size(), key_err); + if (key_err.is_set()) + { + LOG_FAIL_FMT("Failed to create signing key: {}", key_err.to_string()); + return false; + } CoseBuffer cose_buf; + CoseBuffer cose_err; auto rc = cose_sign_endorsement( cose_key, time_since_epoch, @@ -649,10 +656,13 @@ namespace ccf previous_root.size(), key_to_endorse.data(), key_to_endorse.size(), - cose_buf); - if (rc != 0 || !cose_buf.ok()) + cose_buf, + cose_err); + if (rc != 0 || !cose_buf.is_set()) { - LOG_FAIL_FMT("Failed to sign previous service identity"); + LOG_FAIL_FMT( + "Failed to sign previous service identity: {}", + cose_err.is_set() ? cose_err.to_string() : "unknown error"); return false; } endorsement.endorsement = cose_buf.to_vector();