diff --git a/.github/docker/wolfsentry-ci/Dockerfile b/.github/docker/wolfsentry-ci/Dockerfile index d864936..aae87db 100644 --- a/.github/docker/wolfsentry-ci/Dockerfile +++ b/.github/docker/wolfsentry-ci/Dockerfile @@ -4,7 +4,9 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends \ bubblewrap \ dbus \ + dwarves \ gcc-arm-none-eabi \ + gcc-multilib \ iproute2 \ iputils-ping \ libnewlib-arm-none-eabi \ diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 5020f7f..5d50319 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -195,7 +195,8 @@ jobs: path: lwip - name: Check out lwIP contrib run: | - git clone --branch STABLE-2_1_0_RELEASE --depth 1 \ + retry() { for attempt in 1 2 3; do "$@" && return 0; [ "$attempt" -lt 3 ] && sleep $((attempt * 15)); done; return 1; } + retry git clone --branch STABLE-2_1_0_RELEASE --depth 1 \ https://git.savannah.nongnu.org/git/lwip/lwip-contrib.git \ lwip/contrib test "$(git -C lwip/contrib rev-parse HEAD)" = \ diff --git a/.github/workflows/options-matrix.yml b/.github/workflows/options-matrix.yml index bfa10e6..aafe4c2 100644 --- a/.github/workflows/options-matrix.yml +++ b/.github/workflows/options-matrix.yml @@ -65,10 +65,211 @@ jobs: target: no-addr-bitmask-matching-test - name: No IPv6 target: no-ipv6-test + - name: C99 + target: c99-test + - name: No alloca + target: no-alloca-test + - name: Static + target: static-build-test + - name: No inline + target: no-inline-test + - name: Fortify source + target: fortify-source-test + - name: Call trace + target: CALL_TRACE-test + - name: Small private data alignment + target: small-PRIVATE_DATA_ALIGNMENT-test + - name: Big private data alignment + target: big-PRIVATE_DATA_ALIGNMENT-test + - name: POSIX vanilla HPI + target: HPI_POSIX_VANILLA-test + - name: No malloc builtins + target: no-malloc-builtins-test + - name: Stripped function sections + target: stripped-function-sections-test + - name: Unoptimized + target: optim-O0-test + - name: Library dependencies single-threaded + target: library-dependency-singlethreaded-build-test + - name: Library dependencies multithreaded + target: library-dependency-multithreaded-build-test + - name: Distribution + target: dist-check + - name: Release archive + target: release-check steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Trust workspace run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Test configuration run: make -j2 ${{ matrix.target }} + + wolfcose-deps: + name: Build COSE dependencies + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + steps: + - name: Build wolfSSL and wolfCOSE + run: | + retry() { for attempt in 1 2 3; do "$@" && return 0; [ "$attempt" -lt 3 ] && sleep $((attempt * 15)); done; return 1; } + WOLFSSL_TAGS=$(retry git ls-remote --tags --refs \ + https://github.com/wolfSSL/wolfssl.git 'v*-stable') + WOLFSSL_REF=$(awk -F/ '{print $NF}' <<<"$WOLFSSL_TAGS" | sort -V | tail -n 1) + test -n "$WOLFSSL_REF" + mkdir -p /opt/wolfsentry-deps + cd /opt/wolfsentry-deps + retry git clone --depth 1 --branch "$WOLFSSL_REF" \ + https://github.com/wolfSSL/wolfssl.git wolfssl + WOLFCOSE_TAGS=$(retry git ls-remote --tags --refs \ + https://github.com/wolfSSL/wolfCOSE.git 'v*') + WOLFCOSE_REF=$(awk -F/ '{print $NF}' <<<"$WOLFCOSE_TAGS" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) + test -n "$WOLFCOSE_REF" + retry git clone --depth 1 --branch "$WOLFCOSE_REF" \ + https://github.com/wolfSSL/wolfCOSE.git wolfCOSE + cd wolfssl + ./autogen.sh + ./configure --enable-ecc --enable-ed25519 --enable-ed448 \ + --enable-curve25519 --enable-curve448 --enable-aesgcm \ + --enable-aesccm --enable-sha384 --enable-sha512 --enable-keygen \ + --enable-hkdf --enable-aeskeywrap --enable-chacha \ + --enable-poly1305 --enable-rsapss \ + --prefix=/opt/wolfsentry-deps/wolfssl-install + make -j"$(nproc)" + make install + cd .. + make -C wolfCOSE -j"$(nproc)" EXTRA_CFLAGS=-fPIC \ + WOLFSSL_CFLAGS="-isystem /opt/wolfsentry-deps/wolfssl-install/include" \ + WOLFSSL_LIBS="-L/opt/wolfsentry-deps/wolfssl-install/lib -lwolfssl" \ + all + tar -C /opt -czf "$GITHUB_WORKSPACE/wolfsentry-deps.tar.gz" \ + wolfsentry-deps/wolfssl-install wolfsentry-deps/wolfCOSE/include \ + wolfsentry-deps/wolfCOSE/libwolfcose.a + - uses: actions/upload-artifact@v4 + with: + name: wolfcose-deps + path: wolfsentry-deps.tar.gz + retention-days: 1 + + wolfcose: + name: COSE ${{ matrix.config }} + needs: wolfcose-deps + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + strategy: + fail-fast: false + matrix: + config: + - default + - no-json + - no-json-dom + - singlethreaded + - c99 + - no-routes + - no-addr-family-names + - no-route-endpoints + - no-events + - no-user-values + - no-eventconfig + - no-transactions + - no-legacy-event-syntax + - no-error-messages + - no-text-numbers + - no-text-addresses + - minimal + - minimal-no-json + - reduced + - total-limit + - nesting-limit + - user-settings + - dynamic + env: + CPATH: /opt/wolfsentry-deps/wolfssl-install/include + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - uses: actions/download-artifact@v4 + with: + name: wolfcose-deps + - name: Install dependencies + run: tar -C /opt -xzf wolfsentry-deps.tar.gz + - name: Test configuration + run: | + make -j2 WOLFCOSE_REQUIRED=1 \ + WOLFCOSE_TEST_TOP=/opt/wolfsentry-deps/wolfCOSE \ + wolfcose-${{ matrix.config }}-test + + toolchain: + name: ${{ matrix.name }} + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: m32 + target: m32-test + - name: m32 C89 + target: m32-c89-test + - name: Route holes + target: route-holes-test + - name: Struct layout + target: pahole-test + - name: FreeRTOS arm32 + target: freertos-arm32-build-test + - name: FreeRTOS arm32 thumb + target: freertos-arm32-thumb-build-test + - name: FreeRTOS arm32 single-threaded + target: freertos-arm32-singlethreaded-build-test + - name: FreeRTOS arm32 C89 + target: freertos-arm32-c89-build-test + - name: Linux lwIP + target: linux-lwip-test + - name: Linux lwIP no IPv6 + target: linux-lwip-test-no-ipv6 + - name: Linux lwIP C89 m32 + target: linux-lwip-c89-m32-test + + steps: + - uses: actions/checkout@v4 + with: + path: wolfsentry + - uses: actions/checkout@v4 + with: + repository: FreeRTOS/FreeRTOS-Kernel + ref: dbf70559b27d39c1fdb68dfb9a32140b6a6777a0 + path: third/FreeRTOS/FreeRTOS/Source + - uses: actions/checkout@v4 + with: + repository: lwip-tcpip/lwip + ref: 3fe8d2fc43a9b69f7ed28c63d44a7744f9c0def9 + path: third/lwip + - name: Apply the lwIP packet filter patch + run: patch --directory third/lwip --strip 1 < wolfsentry/lwip/LWIP_PACKET_FILTER_API.patch + - name: Build the wolfSentry CI image + run: | + docker build \ + --file wolfsentry/.github/docker/wolfsentry-ci/Dockerfile \ + --tag wolfsentry-ci:local wolfsentry + - name: Test configuration + env: + TARGET: ${{ matrix.target }} + run: | + # Ubuntu's arm-none-eabi-gcc links test_lwip slightly above the default limit. + docker run --rm \ + --env TMPDIR=/tmp \ + --env TARGET \ + --volume "$GITHUB_WORKSPACE/wolfsentry:/workspace/wolfsentry:ro" \ + --volume "$GITHUB_WORKSPACE/third:/workspace/third:ro" \ + wolfsentry-ci:local bash -euc ' + cp -R /workspace/wolfsentry /tmp/wolfsentry + cd /tmp/wolfsentry + make -j2 FREERTOS_TOP=/workspace/third/FreeRTOS \ + LWIP_TOP=/workspace/third/lwip \ + FREERTOS_ARM32_MAX_SECTIONS_SIZE=110000 "$TARGET" + ' diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions.yml index 3d9f878..ed46b96 100644 --- a/.github/workflows/wolfssl-versions.yml +++ b/.github/workflows/wolfssl-versions.yml @@ -37,9 +37,10 @@ jobs: - name: Build matrix id: versions run: | - LATEST=$(git ls-remote --tags --refs \ - https://github.com/wolfSSL/wolfssl.git 'v*-stable' \ - | awk -F/ '{print $NF}' | sort -V | tail -n 1) + retry() { for attempt in 1 2 3; do "$@" && return 0; [ "$attempt" -lt 3 ] && sleep $((attempt * 15)); done; return 1; } + TAGS=$(retry git ls-remote --tags --refs \ + https://github.com/wolfSSL/wolfssl.git 'v*-stable') + LATEST=$(awk -F/ '{print $NF}' <<<"$TAGS" | sort -V | tail -n 1) test -n "$LATEST" if [[ ! "$LATEST" =~ ^v[0-9]+(\.[0-9]+)+-stable$ ]]; then echo "Unexpected wolfSSL stable tag: $LATEST" >&2 @@ -83,7 +84,8 @@ jobs: env: WOLFSSL_REF: ${{ matrix.ref }} run: | - git clone --depth 1 --branch "$WOLFSSL_REF" \ + retry() { for attempt in 1 2 3; do "$@" && return 0; [ "$attempt" -lt 3 ] && sleep $((attempt * 15)); done; return 1; } + retry git clone --depth 1 --branch "$WOLFSSL_REF" \ https://github.com/wolfSSL/wolfssl.git "$HOME/wolfssl" cd "$HOME/wolfssl" ./autogen.sh diff --git a/Makefile b/Makefile index 23c98a4..52367e6 100644 --- a/Makefile +++ b/Makefile @@ -148,6 +148,34 @@ ifdef WOLFIP SRCS += wolfip/packet_filter_glue.c endif +ifneq (,$(filter -DWOLFSENTRY_WOLFCOSE%,$(EXTRA_CFLAGS))) + EXTRA_CFLAGS_WOLFCOSE := 1 + WOLFCOSE := 1 +endif + +ifdef USER_SETTINGS_FILE + USER_SETTINGS_WOLFCOSE := $(shell grep -q -E -e '^[[:space:]]*\#[[:space:]]*define[[:space:]]+WOLFSENTRY_WOLFCOSE([[:space:]]|$$)' '$(USER_SETTINGS_FILE)' && echo 1) + ifdef USER_SETTINGS_WOLFCOSE + WOLFCOSE := 1 + endif +endif + +ifdef WOLFCOSE + ifndef WOLFCOSE_TOP + WOLFCOSE_TOP := $(SRC_TOP)/../wolfCOSE + endif + ifndef WOLFCOSE_LIB + WOLFCOSE_LIB := $(WOLFCOSE_TOP)/libwolfcose.a + endif + ifeq (,$(USER_SETTINGS_WOLFCOSE)$(EXTRA_CFLAGS_WOLFCOSE)) + WOLFCOSE_CFLAGS += -DWOLFSENTRY_WOLFCOSE + endif + WOLFCOSE_CFLAGS += -I$(WOLFCOSE_TOP)/include + TEST_LIBS += $(WOLFCOSE_LIB) + DYNLIB_LIBS += $(WOLFCOSE_LIB) + WOLFCOSE_LINK_DEPS += $(WOLFCOSE_LIB) +endif + ifdef NETXDUO ifndef NETXDUO_TOP NETXDUO_TOP=$(THREADX_TOP) @@ -185,7 +213,7 @@ ifndef C_WARNFLAGS endif endif -CFLAGS := -I$(BUILD_TOP) -I$(SRC_TOP) $(OPTIM) $(DEBUG) $(C_WARNFLAGS) $(LWIP_CFLAGS) $(WOLFIP_CFLAGS) $(RUNTIME_CFLAGS) $(EXTRA_CFLAGS) +CFLAGS := -I$(BUILD_TOP) -I$(SRC_TOP) $(OPTIM) $(DEBUG) $(C_WARNFLAGS) $(LWIP_CFLAGS) $(WOLFIP_CFLAGS) $(WOLFCOSE_CFLAGS) $(RUNTIME_CFLAGS) $(EXTRA_CFLAGS) LDFLAGS := $(EXTRA_LDFLAGS) VISIBILITY_CFLAGS := -fvisibility=hidden -DHAVE_VISIBILITY=1 @@ -206,14 +234,20 @@ endif # JSON settings need to be extracted from $(USER_SETTINGS_FILE) to determine if JSON sources should be built. ifdef USER_SETTINGS_FILE - USER_SETTINGS_NO_JSON := $(shell grep -q -x '\#define WOLFSENTRY_NO_JSON' '$(USER_SETTINGS_FILE)' && echo 1) - USER_SETTINGS_NO_JSON_DOM := $(shell grep -q -x '\#define WOLFSENTRY_NO_JSON_DOM' '$(USER_SETTINGS_FILE)' && echo 1) + USER_SETTINGS_NO_JSON := $(shell grep -q -E -e '^[[:space:]]*\#[[:space:]]*define[[:space:]]+WOLFSENTRY_NO_JSON([[:space:]]|$$)' '$(USER_SETTINGS_FILE)' && echo 1) + USER_SETTINGS_NO_JSON_DOM := $(shell grep -q -E -e '^[[:space:]]*\#[[:space:]]*define[[:space:]]+WOLFSENTRY_NO_JSON_DOM([[:space:]]|$$)' '$(USER_SETTINGS_FILE)' && echo 1) endif ifdef NO_JSON CFLAGS += -DWOLFSENTRY_NO_JSON -DWOLFSENTRY_NO_JSON_DOM + ifdef WOLFCOSE + SRCS += json/load_config.c + endif else ifdef USER_SETTINGS_NO_JSON NO_JSON := 1 + ifdef WOLFCOSE + SRCS += json/load_config.c + endif else SRCS += json/centijson_sax.c json/json_util.c json/load_config.c ifdef NO_JSON_DOM @@ -225,6 +259,55 @@ else endif endif +ifdef MINIMAL_CONFIG + CFLAGS += -DWOLFSENTRY_CONFIG_MINIMAL +endif +ifdef NO_CONFIG_ROUTES + CFLAGS += -DWOLFSENTRY_CONFIG_NO_ROUTES +endif +ifdef NO_CONFIG_ADDR_FAMILY_NAMES + CFLAGS += -DWOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES +endif +ifdef NO_CONFIG_ROUTE_ENDPOINTS + CFLAGS += -DWOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS +endif +ifdef NO_CONFIG_EVENTS + CFLAGS += -DWOLFSENTRY_CONFIG_NO_EVENTS +endif +ifdef NO_CONFIG_USER_VALUES + CFLAGS += -DWOLFSENTRY_CONFIG_NO_USER_VALUES +endif +ifdef NO_CONFIG_EVENTCONFIG + CFLAGS += -DWOLFSENTRY_CONFIG_NO_EVENTCONFIG +endif +ifdef NO_CONFIG_TRANSACTIONS + CFLAGS += -DWOLFSENTRY_CONFIG_NO_TRANSACTIONS +endif +ifdef NO_CONFIG_LEGACY_EVENT_SYNTAX + CFLAGS += -DWOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX +endif +ifdef NO_CONFIG_TEXT_NUMBERS + ifndef WOLFCOSE + $(error NO_CONFIG_TEXT_NUMBERS requires WOLFCOSE=1) + endif + ifndef NO_JSON + $(error NO_CONFIG_TEXT_NUMBERS requires NO_JSON=1) + endif + CFLAGS += -DWOLFSENTRY_CONFIG_NO_TEXT_NUMBERS +endif +ifdef NO_CONFIG_TEXT_ADDRESSES + ifndef WOLFCOSE + $(error NO_CONFIG_TEXT_ADDRESSES requires WOLFCOSE=1) + endif + ifndef NO_JSON + $(error NO_CONFIG_TEXT_ADDRESSES requires NO_JSON=1) + endif + CFLAGS += -DWOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES +endif +ifdef NO_CONFIG_ERROR_MESSAGES + CFLAGS += -DWOLFSENTRY_CONFIG_NO_ERROR_MESSAGES +endif + ifdef CALL_TRACE CFLAGS += -DWOLFSENTRY_DEBUG_CALL_TRACE -fno-omit-frame-pointer -Wno-inline endif @@ -266,7 +349,7 @@ LIB_NAME := libwolfsentry.a INSTALL_LIBS := $(BUILD_TOP)/$(LIB_NAME) -INSTALL_HEADERS := wolfsentry/wolfsentry.h wolfsentry/wolfsentry_settings.h wolfsentry/wolfsentry_errcodes.h wolfsentry/wolfsentry_af.h wolfsentry/wolfsentry_util.h wolfsentry/wolfsentry_json.h wolfsentry/centijson_sax.h wolfsentry/centijson_dom.h wolfsentry/centijson_value.h wolfsentry/wolfssl_test.h +INSTALL_HEADERS := wolfsentry/wolfsentry.h wolfsentry/wolfsentry_settings.h wolfsentry/wolfsentry_errcodes.h wolfsentry/wolfsentry_af.h wolfsentry/wolfsentry_util.h wolfsentry/wolfsentry_config.h wolfsentry/wolfsentry_json.h wolfsentry/wolfsentry_cbor.h wolfsentry/wolfsentry_wolfip.h wolfsentry/centijson_sax.h wolfsentry/centijson_dom.h wolfsentry/centijson_value.h wolfsentry/wolfssl_test.h ifdef USER_SETTINGS_FILE OPTIONS_FILE := $(USER_SETTINGS_FILE) @@ -291,7 +374,7 @@ all: $(BUILD_TOP)/$(DYNLIB_NAME) endif #https://stackoverflow.com/questions/3236145/force-gnu-make-to-rebuild-objects-affected-by-compiler-definition/3237349#3237349 -BUILD_PARAMS := (echo 'CC_V:'; echo '$(CC_V)'; echo 'SRC_TOP: $(SRC_TOP)'; echo 'CFLAGS: $(CFLAGS) $(VISIBILITY_CFLAGS)'; echo 'LDFLAGS: $(LDFLAGS)'; echo 'AS_VERSION:'; echo '$(AS_VERSION)'; echo 'LD_VERSION:'; echo '$(LD_VERSION)'; echo 'AR_VERSION:'; echo '$(AR_VERSION)'; echo 'ARFLAGS: $(AR_FLAGS)') +BUILD_PARAMS := (echo 'CC_V:'; echo '$(CC_V)'; echo 'SRC_TOP: $(SRC_TOP)'; echo 'CFLAGS: $(CFLAGS) $(VISIBILITY_CFLAGS)'; echo 'LDFLAGS: $(LDFLAGS)'; echo 'WOLFCOSE_LINK_DEPS: $(WOLFCOSE_LINK_DEPS)'; echo 'AS_VERSION:'; echo '$(AS_VERSION)'; echo 'LD_VERSION:'; echo '$(LD_VERSION)'; echo 'AR_VERSION:'; echo '$(AR_VERSION)'; echo 'ARFLAGS: $(AR_FLAGS)') .PHONY: force $(BUILD_TOP)/.build_params: force @@ -337,11 +420,15 @@ ifndef VERY_QUIET endif $(Q)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) $(DYNAMIC_CFLAGS) $(VISIBILITY_CFLAGS) -MF $(@:.So=.Sd) -c $< -o $@ -$(BUILD_TOP)/$(DYNLIB_NAME): $(addprefix $(BUILD_TOP)/src/,$(SRCS:.c=.So)) - $(Q)$(CC) $(LD_FLAGS) $(DYNAMIC_LDFLAGS) -o $@ $+ +$(BUILD_TOP)/$(DYNLIB_NAME): $(addprefix $(BUILD_TOP)/src/,$(SRCS:.c=.So)) $(WOLFCOSE_LINK_DEPS) + $(Q)$(CC) $(LD_FLAGS) $(DYNAMIC_LDFLAGS) -o $@ $(filter-out $(WOLFCOSE_LINK_DEPS),$+) $(DYNLIB_LIBS) UNITTEST_LIST := test_init test_rwlocks test_static_routes test_dynamic_rules test_user_values test_user_addr_families $(UNITTEST_LIST_EXTRAS) +ifdef WOLFCOSE + UNITTEST_LIST += test_cbor +endif + ifneq "$(NO_JSON)" "1" UNITTEST_LIST += test_json ifndef NO_JSON_DOM @@ -354,23 +441,23 @@ ifneq "$(NO_JSON)" "1" endif $(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST)): UNITTEST_GATE=-D$(shell basename '$@' | tr '[:lower:]' '[:upper:]') -$(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST)): $(SRC_TOP)/tests/unittests.c $(BUILD_TOP)/$(LIB_NAME) $(OPTIONS_FILE) +$(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST)): $(SRC_TOP)/tests/unittests.c $(BUILD_TOP)/$(LIB_NAME) $(OPTIONS_FILE) $(WOLFCOSE_LINK_DEPS) $(Q)[ -d $(dir $@) ] || mkdir -p $(dir $@) ifndef VERY_QUIET $(Q)echo "$(CC) ... -o $@" endif - $(Q)$(CC) $(CFLAGS) $(UNITTEST_GATE) $(LDFLAGS) -o $@ $(filter-out %.h,$^) + $(Q)$(CC) $(CFLAGS) $(UNITTEST_GATE) $(LDFLAGS) -o $@ $(filter-out %.h $(WOLFCOSE_LINK_DEPS),$^) $(TEST_LIBS) UNITTEST_LIST_SHARED=test_all_shared UNITTEST_SHARED_FLAGS := $(addprefix -D,$(shell echo '$(UNITTEST_LIST)' | tr '[:lower:]' '[:upper:]')) $(TEST_JSON_CFLAGS) -$(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST_SHARED)): $(SRC_TOP)/tests/unittests.c $(BUILD_TOP)/$(DYNLIB_NAME) $(OPTIONS_FILE) +$(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST_SHARED)): $(SRC_TOP)/tests/unittests.c $(BUILD_TOP)/$(DYNLIB_NAME) $(OPTIONS_FILE) $(WOLFCOSE_LINK_DEPS) $(Q)[ -d $(dir $@) ] || mkdir -p $(dir $@) ifndef VERY_QUIET $(Q)echo "$(CC) ... -o $@" endif - $(Q)$(CC) $(CFLAGS) $(UNITTEST_SHARED_FLAGS) $(LDFLAGS) -o $@ $< $(BUILD_TOP)/$(DYNLIB_NAME) + $(Q)$(CC) $(CFLAGS) $(UNITTEST_SHARED_FLAGS) $(LDFLAGS) -o $@ $< $(BUILD_TOP)/$(DYNLIB_NAME) $(TEST_LIBS) ifdef BUILD_DYNAMIC $(BUILD_TOP)/.tested: $(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST_SHARED)) @@ -511,7 +598,7 @@ doc-html: doc-html-clean: $(Q)rm -rf '$(BUILD_TOP)/doc/html' -$(BUILD_TOP)/doc/pdf/refman.pdf: $(addprefix $(SRC_TOP)/, $(filter-out %/wolfsentry_options.h,$(INSTALL_HEADERS)) ChangeLog.md README.md doc/freertos-lwip-app.md doc/json_configuration.md) +$(BUILD_TOP)/doc/pdf/refman.pdf: $(addprefix $(SRC_TOP)/, $(filter-out %/wolfsentry_options.h,$(INSTALL_HEADERS)) ChangeLog.md README.md doc/freertos-lwip-app.md doc/json_configuration.md doc/cbor_configuration.md) $(Q)command -v doxygen >/dev/null || doxygen $(Q)command -v pdflatex >/dev/null || pdflatex $(Q)command -v makeindex >/dev/null || makeindex diff --git a/Makefile.analyzers b/Makefile.analyzers index fb91cb1..a798871 100644 --- a/Makefile.analyzers +++ b/Makefile.analyzers @@ -302,6 +302,75 @@ c99-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-c99-builds" clean @echo "passed: std=c99 tests." +WOLFCOSE_TEST_TOP ?= $(SRC_TOP)/../wolfCOSE +WOLFCOSE_TEST_LIB ?= $(WOLFCOSE_TEST_TOP)/libwolfcose.a +WOLFCOSE_TEST_MAKE_ARGS = $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 WOLFCOSE_TOP="$(WOLFCOSE_TEST_TOP)" WOLFCOSE_LIB="$(WOLFCOSE_TEST_LIB)" + +WOLFCOSE_TEST_ARGS_default := EXTRA_CFLAGS='-DWOLFSENTRY_WOLFCOSE' +WOLFCOSE_TEST_ARGS_no-json := WOLFCOSE=1 NO_JSON=1 +WOLFCOSE_TEST_ARGS_no-json-dom := WOLFCOSE=1 NO_JSON_DOM=1 +WOLFCOSE_TEST_ARGS_singlethreaded := WOLFCOSE=1 SINGLETHREADED=1 +WOLFCOSE_TEST_ARGS_c99 := WOLFCOSE=1 NO_JSON=1 SINGLETHREADED=1 EXTRA_CFLAGS+='-std=c99 -pedantic' +WOLFCOSE_TEST_ARGS_no-routes := WOLFCOSE=1 NO_CONFIG_ROUTES=1 +WOLFCOSE_TEST_ARGS_no-addr-family-names := WOLFCOSE=1 NO_CONFIG_ADDR_FAMILY_NAMES=1 +WOLFCOSE_TEST_ARGS_no-route-endpoints := WOLFCOSE=1 NO_CONFIG_ROUTE_ENDPOINTS=1 +WOLFCOSE_TEST_ARGS_no-events := WOLFCOSE=1 NO_CONFIG_EVENTS=1 +WOLFCOSE_TEST_ARGS_no-user-values := WOLFCOSE=1 NO_CONFIG_USER_VALUES=1 +WOLFCOSE_TEST_ARGS_no-eventconfig := WOLFCOSE=1 NO_CONFIG_EVENTCONFIG=1 +WOLFCOSE_TEST_ARGS_no-transactions := WOLFCOSE=1 NO_CONFIG_TRANSACTIONS=1 +WOLFCOSE_TEST_ARGS_no-legacy-event-syntax := WOLFCOSE=1 NO_CONFIG_LEGACY_EVENT_SYNTAX=1 +WOLFCOSE_TEST_ARGS_no-error-messages := WOLFCOSE=1 NO_CONFIG_ERROR_MESSAGES=1 +WOLFCOSE_TEST_ARGS_no-text-numbers := WOLFCOSE=1 NO_JSON=1 NO_CONFIG_TEXT_NUMBERS=1 +WOLFCOSE_TEST_ARGS_no-text-addresses := WOLFCOSE=1 NO_JSON=1 NO_CONFIG_TEXT_ADDRESSES=1 +WOLFCOSE_TEST_ARGS_minimal := WOLFCOSE=1 MINIMAL_CONFIG=1 +WOLFCOSE_TEST_ARGS_minimal-no-json := WOLFCOSE=1 NO_JSON=1 MINIMAL_CONFIG=1 +WOLFCOSE_TEST_ARGS_reduced := WOLFCOSE=1 NO_JSON=1 SINGLETHREADED=1 NO_CONFIG_USER_VALUES=1 NO_CONFIG_ADDR_FAMILY_NAMES=1 NO_CONFIG_TRANSACTIONS=1 NO_CONFIG_LEGACY_EVENT_SYNTAX=1 NO_CONFIG_TEXT_NUMBERS=1 NO_CONFIG_TEXT_ADDRESSES=1 NO_CONFIG_ERROR_MESSAGES=1 +WOLFCOSE_TEST_ARGS_total-limit := WOLFCOSE=1 SINGLETHREADED=1 EXTRA_CFLAGS+='-DWOLFSENTRY_MAX_CBOR_TOTAL_LEN=29 -DWOLFSENTRY_TEST_CBOR_TOTAL_LIMIT' +WOLFCOSE_TEST_ARGS_nesting-limit := WOLFCOSE=1 SINGLETHREADED=1 EXTRA_CFLAGS+='-DWOLFSENTRY_MAX_CBOR_NESTING=4 -DWOLFSENTRY_TEST_CBOR_NESTING_LIMIT' + +WOLFCOSE_TEST_CONFIGS := $(patsubst WOLFCOSE_TEST_ARGS_%,%,$(filter WOLFCOSE_TEST_ARGS_%,$(.VARIABLES))) +WOLFCOSE_TESTS := $(addprefix wolfcose-,$(addsuffix -test,$(WOLFCOSE_TEST_CONFIGS) user-settings dynamic)) + +.PHONY: wolfcose-test wolfcose-lib $(WOLFCOSE_TESTS) +ifneq (,$(wildcard $(WOLFCOSE_TEST_TOP)/Makefile)$(wildcard $(WOLFCOSE_TEST_LIB))) +wolfcose-test: $(WOLFCOSE_TESTS) + @echo "passed: wolfCOSE configuration tests." + +# The dynamic-library test links this archive into a shared object. +wolfcose-lib: + @if [ ! -r "$(WOLFCOSE_TEST_LIB)" ]; then $(MAKE) -C "$(WOLFCOSE_TEST_TOP)" EXTRA_CFLAGS=-fPIC all; fi + +define WOLFCOSE_CONFIG_TEST +wolfcose-$(1)-test: wolfcose-lib + @$$(MAKE) $$(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$$(BUILD_PARENT)/wolfsentry-wolfcose-$(1)-builds" $$(WOLFCOSE_TEST_ARGS_$(1)) clean + @$$(MAKE) $$(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$$(BUILD_PARENT)/wolfsentry-wolfcose-$(1)-builds" $$(WOLFCOSE_TEST_ARGS_$(1)) test + @$$(MAKE) $$(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$$(BUILD_PARENT)/wolfsentry-wolfcose-$(1)-builds" $$(WOLFCOSE_TEST_ARGS_$(1)) clean + @echo "passed: wolfCOSE $(1) test." +endef +$(foreach config,$(WOLFCOSE_TEST_CONFIGS),$(eval $(call WOLFCOSE_CONFIG_TEST,$(config)))) + +wolfcose-user-settings-test: wolfcose-lib + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds" WOLFCOSE=1 clean + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds" WOLFCOSE=1 NO_JSON=1 SINGLETHREADED=1 NO_CONFIG_ERROR_MESSAGES=1 "$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds/wolfsentry/wolfsentry_options.h" + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds" USER_SETTINGS_FILE="$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds/wolfsentry/wolfsentry_options.h" test + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-user-settings-builds" WOLFCOSE=1 clean + @echo "passed: wolfCOSE user-settings test." + +wolfcose-dynamic-test: wolfcose-lib + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds" WOLFCOSE=1 clean + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds" WOLFCOSE=1 "$(addprefix $(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds/tests/,$(UNITTEST_LIST_SHARED))" + @for test in $(UNITTEST_LIST_SHARED); do LD_LIBRARY_PATH="$(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds" $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds/tests/$$test" >/dev/null || exit $$?; done + @$(MAKE) $(WOLFCOSE_TEST_MAKE_ARGS) BUILD_TOP="$(BUILD_PARENT)/wolfsentry-wolfcose-dynamic-builds" WOLFCOSE=1 clean + @echo "passed: wolfCOSE dynamic test." +else ifdef WOLFCOSE_REQUIRED +wolfcose-test wolfcose-lib $(WOLFCOSE_TESTS): + @echo "wolfCOSE sources not found at $(WOLFCOSE_TEST_TOP)." >&2 + @exit 1 +else +wolfcose-test wolfcose-lib $(WOLFCOSE_TESTS): + @echo "wolfCOSE sources not found, skipping $@." +endif + .PHONY: c89-test c89-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-c89-builds" clean @@ -516,6 +585,27 @@ big-PRIVATE_DATA_ALIGNMENT-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/big-PRIVATE_DATA_ALIGNMENT-test" clean @echo "passed: big-PRIVATE_DATA_ALIGNMENT test." +.PHONY: no-malloc-builtins-test +no-malloc-builtins-test: + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/no-malloc-builtins-test" clean + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/no-malloc-builtins-test" EXTRA_CFLAGS='-DWOLFSENTRY_TEST_HPI_POSIX_VANILLA -DWOLFSENTRY_NO_MALLOC_BUILTINS' test + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/no-malloc-builtins-test" clean + @echo "passed: no-malloc-builtins test." + +.PHONY: stripped-function-sections-test +stripped-function-sections-test: + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/stripped-function-sections-test" clean + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/stripped-function-sections-test" STRIPPED=1 FUNCTION_SECTIONS=1 test + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/stripped-function-sections-test" clean + @echo "passed: stripped-function-sections test." + +.PHONY: optim-O0-test +optim-O0-test: + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/optim-O0-test" clean + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/optim-O0-test" OPTIM=-O0 test + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/optim-O0-test" clean + @echo "passed: optim-O0 test." + .PHONY: HPI_POSIX_VANILLA-test HPI_POSIX_VANILLA-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/HPI_POSIX_VANILLA-test" clean @@ -584,6 +674,8 @@ freertos-arm32-thumb-build-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7' UNITTEST_LIST=test_lwip clean @echo "passed: freertos-arm32-thumb-build test." +FREERTOS_ARM32_MAX_SECTIONS_SIZE ?= 100000 + .PHONY: freertos-arm32-build-test freertos-arm32-build-test: @[ -d $(FREERTOS_TOP_FOR_TEST)/FreeRTOS/Source/. ] || ( echo '$@: $(FREERTOS_TOP_FOR_TEST)/FreeRTOS/Source not found.' >&2; exit 1) @@ -597,7 +689,7 @@ freertos-arm32-build-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mcpu=cortex-m3' UNITTEST_LIST=test_lwip clean # now rebuild with FUNCTION_SECTIONS=1, to test expected text size on a parsimonious link. @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mcpu=cortex-m3 -specs=nano.specs -Wno-inline' NO_STDIO_STREAMS=1 '$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds/tests/test_lwip' UNITTEST_LIST=test_lwip OPTIM='-Os' STRIPPED=1 FUNCTION_SECTIONS=1 - @TEST_LWIP_SZ=$$(stat --format='%s' '$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds/tests/test_lwip'); if [[ "$$TEST_LWIP_SZ" -gt 100000 ]]; then echo "$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds/tests/test_lwip is unexpectedly large ($$TEST_LWIP_SZ bytes)."; exit 1; fi + @TEST_LWIP_SZ=$$(stat --format='%s' '$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds/tests/test_lwip'); if [[ "$$TEST_LWIP_SZ" -gt $(FREERTOS_ARM32_MAX_SECTIONS_SIZE) ]]; then echo "$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds/tests/test_lwip is unexpectedly large ($$TEST_LWIP_SZ bytes)."; exit 1; fi @rm -rf '$(BUILD_PARENT)/'wolfsentry-freertos-arm32-test-builds/tests/{freertos,lwip} @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mcpu=cortex-m3' UNITTEST_LIST=test_lwip clean @echo "passed: freertos-arm32-build test." @@ -828,10 +920,10 @@ doc-check: @echo "passed: doc-check." .PHONY: check -check: dynamic-build-test c99-test no-alloca-test singlethreaded-test no-json-test no-json-dom-test no-error-strings-test no-protocol-names-test no-getprotoby-test no-stdio-streams-build-test minimal-build-test minimal-threaded-build-test user-settings-build-test short-enums-test no-addr-bitmask-matching-test no-ipv6-test +check: dynamic-build-test c99-test wolfcose-test no-alloca-test singlethreaded-test no-json-test no-json-dom-test no-error-strings-test no-protocol-names-test no-getprotoby-test no-stdio-streams-build-test minimal-build-test minimal-threaded-build-test user-settings-build-test short-enums-test no-addr-bitmask-matching-test no-ipv6-test .PHONY: check-extra -check-extra: library-dependency-singlethreaded-build-test library-dependency-multithreaded-build-test pahole-test route-holes-test static-build-test c89-test c23-test no-inline-test m32-test m32-c89-test m32-c23-test fortify-source-test CALL_TRACE-test small-PRIVATE_DATA_ALIGNMENT-test big-PRIVATE_DATA_ALIGNMENT-test HPI_POSIX_VANILLA-test freertos-arm32-thumb-build-test freertos-arm32-build-test freertos-arm32-singlethreaded-build-test freertos-arm32-c89-build-test linux-lwip-test linux-lwip-test-no-ipv6 linux-lwip-c89-m32-test dist-check release-check doc-check notification-demo-build-test .WAIT benchmark-test benchmark-singlethreaded-test +check-extra: library-dependency-singlethreaded-build-test library-dependency-multithreaded-build-test pahole-test route-holes-test static-build-test c89-test c23-test no-inline-test m32-test m32-c89-test m32-c23-test fortify-source-test CALL_TRACE-test small-PRIVATE_DATA_ALIGNMENT-test big-PRIVATE_DATA_ALIGNMENT-test HPI_POSIX_VANILLA-test no-malloc-builtins-test stripped-function-sections-test optim-O0-test freertos-arm32-thumb-build-test freertos-arm32-build-test freertos-arm32-singlethreaded-build-test freertos-arm32-c89-build-test linux-lwip-test linux-lwip-test-no-ipv6 linux-lwip-c89-m32-test dist-check release-check doc-check notification-demo-build-test .WAIT benchmark-test benchmark-singlethreaded-test ifdef JSON_TEST_CORPUS_DIR export JSON_TEST_CORPUS_DIR diff --git a/README.md b/README.md index 5fba952..fd9282c 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ wolfSSL library for application-level filtering of inbound and outbound connections. The wolfSentry engine is dynamically configurable programmatically through an -API, or from a textual input file in JSON supplied to the engine, or dynamically -and incrementally with JSON fragments, or any combination of these methods. +API, from JSON, from CBOR using wolfCOSE, or dynamically and incrementally with +JSON fragments, in any combination of these methods. Reconfiguration is protected by transactional semantics, and advanced internal locks on threaded targets assure seamless service availability with atomic policy transition. Callbacks allow for transport-agnostic remote logging, @@ -43,6 +43,9 @@ Basic application integration on FreeRTOS-lwIP is documented, with usable code f JSON configuration is documented in detail by [doc/json_configuration.md](doc/json_configuration.md). +CBOR configuration through wolfCOSE is documented in +[doc/cbor_configuration.md](doc/cbor_configuration.md). + With `doxygen` installed, the HTML version of the full API reference manual can be generated from the top of the wolfSentry source tree with `make doc-html`. This, and the source code itself, are the recommended API references. @@ -131,6 +134,21 @@ topic. | `NO_IPV6` | `WOLFSENTRY_NO_IPV6` | Define to omit support for the IPv6 address family. | | `NO_JSON` | `WOLFSENTRY_NO_JSON` | Define to omit JSON configuration support | | `NO_JSON_DOM` | `WOLFSENTRY_NO_JSON_DOM` | Define to omit JSON DOM API | +| `WOLFCOSE` | `WOLFSENTRY_WOLFCOSE` | Enable CBOR configuration loading through wolfCOSE | +| `WOLFCOSE_TOP` | | Path to the wolfCOSE source tree, defaulting to `../wolfCOSE` | +| `WOLFCOSE_LIB` | | Path to the wolfCOSE library for tests and shared-library builds | +| `MINIMAL_CONFIG` | `WOLFSENTRY_CONFIG_MINIMAL` | Retain the configuration loader but omit routes, events, user values, and event configuration | +| `NO_CONFIG_ROUTES` | `WOLFSENTRY_CONFIG_NO_ROUTES` | Omit route loading, including address and endpoint parsing | +| `NO_CONFIG_ADDR_FAMILY_NAMES` | `WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES` | Require numeric route address-family identifiers | +| `NO_CONFIG_ROUTE_ENDPOINTS` | `WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS` | Omit remote and local endpoint loading while retaining wildcard routes | +| `NO_CONFIG_EVENTS` | `WOLFSENTRY_CONFIG_NO_EVENTS` | Omit event loading | +| `NO_CONFIG_USER_VALUES` | `WOLFSENTRY_CONFIG_NO_USER_VALUES` | Omit user-value loading | +| `NO_CONFIG_EVENTCONFIG` | `WOLFSENTRY_CONFIG_NO_EVENTCONFIG` | Omit global and per-event configuration loading | +| `NO_CONFIG_TRANSACTIONS` | `WOLFSENTRY_CONFIG_NO_TRANSACTIONS` | Omit dry-run and load-then-commit support; configuration loads apply in place | +| `NO_CONFIG_LEGACY_EVENT_SYNTAX` | `WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX` | Omit pre-1.4 event aliases such as `actions` and `insert-event` | +| `NO_CONFIG_TEXT_NUMBERS` | `WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS` | In CBOR-only builds, require native CBOR numbers and omit text-number conversion | +| `NO_CONFIG_TEXT_ADDRESSES` | `WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES` | In CBOR-only builds, require byte strings for route addresses and omit text-address conversion | +| `NO_CONFIG_ERROR_MESSAGES` | `WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES` | Omit detailed configuration parser error-buffer messages | | `CALL_TRACE` | `WOLFSENTRY_DEBUG_CALL_TRACE` | Define to activate runtime call stack logging (profusely verbose) | | `USER_SETTINGS_FILE` | `WOLFSENTRY_USER_SETTINGS_FILE` | A substitute settings file, replacing autogenerated `wolfsentry_settings.h` | | `SINGLETHREADED` | `WOLFSENTRY_SINGLETHREADED` | Define to omit thread safety logic, and replace thread safety functions and macros with no-op macros. | diff --git a/doc/cbor_configuration.md b/doc/cbor_configuration.md new file mode 100644 index 0000000..5ab6631 --- /dev/null +++ b/doc/cbor_configuration.md @@ -0,0 +1,210 @@ +# CBOR configuration with wolfCOSE + +wolfSentry can load its normal configuration schema from CBOR through the +wolfCOSE CBOR decoder. The policy loader is shared with the JSON path, so the +same configuration keys build the same events, routes, default policies, and +user values. + +Build wolfCOSE first, then enable the integration when building wolfSentry: + +```sh +make -C ../wolfCOSE +make WOLFCOSE=1 WOLFCOSE_TOP=../wolfCOSE NO_JSON=1 +``` + +`WOLFCOSE_TOP` defaults to `../wolfCOSE`. `WOLFCOSE_LIB` defaults to +`$(WOLFCOSE_TOP)/libwolfcose.a` and is linked into wolfSentry test and shared +library targets. Set it to a position-independent archive or shared wolfCOSE +library when building `BUILD_DYNAMIC=1`. Applications using the static +libraries should link wolfSentry before wolfCOSE: + +```sh +cc app.o libwolfsentry.a ../wolfCOSE/libwolfcose.a -o app +``` + +Use `wolfsentry_config_cbor_oneshot()` to load a complete CBOR document: + +```c +#include + +ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + cbor, + cbor_len, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + error_buffer, + sizeof error_buffer); +``` + +Load flags have the same behavior as the JSON loader. The default +`WOLFSENTRY_CONFIG_LOAD_FLAG_NONE` flushes the active configuration before +parsing, so a failed load can leave it empty or partially updated. Use +`WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT`, as above, to preserve the +active configuration when parsing fails. + +The CBOR document uses the schema documented in +[`json_configuration.md`](json_configuration.md). Map keys are CBOR text +strings. Maps and arrays must have definite lengths. Text strings, unsigned and +negative integers, booleans, null, and half, single, and double precision +floating point values are accepted. Configuration map order remains +significant because the existing policy schema requires the version and some +referenced objects to appear before their uses. + +The wolfCOSE decoder requires RFC 8949 preferred serialization. Integer and +length arguments must use their shortest encoding. For example, encode version +`1` as `0x01`, not `0x18 0x01`. + +CBOR byte strings are accepted for route `address` and `bitmask` values. They +contain the raw address bytes in network order and must have the full width of +the selected address family, such as 4 bytes for IPv4 or 16 bytes for IPv6. +Tags, indefinite length values, and unregistered simple values are rejected. +Byte-valued user settings continue to use the existing `base64` text field. +Nested `json` user values are available when the JSON DOM is also built; a +`NO_JSON=1` build omits that DOM storage type along with the JSON parser. + +`WOLFSENTRY_MAX_CBOR_NESTING` defaults to 16 and +`WOLFSENTRY_MAX_CBOR_TOTAL_LEN` defaults to 10 MiB. Define either macro in the +application settings to lower the limits for an embedded target. + +The configuration policy sections can be removed independently with +`WOLFSENTRY_CONFIG_NO_ROUTES`, `WOLFSENTRY_CONFIG_NO_EVENTS`, +`WOLFSENTRY_CONFIG_NO_USER_VALUES`, and +`WOLFSENTRY_CONFIG_NO_EVENTCONFIG`. `WOLFSENTRY_CONFIG_MINIMAL` enables all +four. Disabled sections are rejected as invalid keys. The corresponding make +options are `NO_CONFIG_ROUTES`, `NO_CONFIG_EVENTS`, +`NO_CONFIG_USER_VALUES`, `NO_CONFIG_EVENTCONFIG`, and `MINIMAL_CONFIG`. + +`WOLFSENTRY_CONFIG_NO_TRANSACTIONS` removes clone, dry-run, and atomic commit +support. With this option, configuration changes apply directly to the active +context and a failed load can leave a partial update. The loader rejects +`WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN` and +`WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT`. The matching make option is +`NO_CONFIG_TRANSACTIONS`. + +`WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX` removes the pre-1.4 `actions`, +`insert-event`, `match-event`, `update-event`, `delete-event`, and +`decision-event` aliases. Current action-list keys such as `post-actions` and +`match-actions` remain available. The matching make option is +`NO_CONFIG_LEGACY_EVENT_SYNTAX`. + +Routes can be retained while requiring numeric address-family identifiers with +`WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES`, or while omitting remote and local +endpoint objects with `WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS`. The corresponding +make options are `NO_CONFIG_ADDR_FAMILY_NAMES` and +`NO_CONFIG_ROUTE_ENDPOINTS`. + +`WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS` removes text-number conversion from a +CBOR-only build. Numeric fields must use native CBOR integers or floating-point +values. Durations must use integer seconds, so text forms such as `"5m"` are +rejected. Numeric CAN addresses must also use CBOR integers. This option +requires `WOLFSENTRY_WOLFCOSE` and `WOLFSENTRY_NO_JSON`. The matching make +option is `NO_CONFIG_TEXT_NUMBERS`. + +`WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES` removes text-address conversion from a +CBOR-only build. Route `address` and `bitmask` values must use CBOR byte strings +containing the full-width address in network order. This option requires +`WOLFSENTRY_WOLFCOSE` and `WOLFSENTRY_NO_JSON`. The matching make option is +`NO_CONFIG_TEXT_ADDRESSES`. + +`WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES` omits human-readable parser diagnostics. +The loader still returns its normal encoded error value, but does not write to +the supplied error buffer. Combined with native CBOR numbers, this removes the +remaining `snprintf` dependency from the CBOR configuration loader. The +matching make option is `NO_CONFIG_ERROR_MESSAGES`. + +## Measured footprint + +The following linked sizes were measured on x86-64 macOS with Apple Clang +`-Os` and dead section removal. The baseline also used `SINGLETHREADED=1`, +`NO_STDIO_STREAMS=1`, `NO_ADDR_BITMASK_MATCHING=1`, `NO_IPV6=1`, +`WOLFSENTRY_NO_GETPROTOBY`, and `WOLFSENTRY_NO_ERROR_STRINGS`. + +| Make option | Linked bytes | Bytes saved | Removed capability | +| --- | ---: | ---: | --- | +| Full CBOR configuration | 47,822 | 0 | None | +| `NO_CONFIG_TRANSACTIONS=1` | 41,926 | 5,896 | Dry run and atomic commit | +| `NO_CONFIG_ROUTES=1` | 39,020 | 8,802 | Static route loading | +| `NO_CONFIG_ADDR_FAMILY_NAMES=1` | 43,795 | 4,027 | Named route families | +| `NO_CONFIG_ROUTE_ENDPOINTS=1` | 44,676 | 3,146 | Remote and local endpoints | +| `NO_CONFIG_EVENTS=1` | 43,713 | 4,109 | Event loading | +| `NO_CONFIG_USER_VALUES=1` | 42,602 | 5,220 | User-value loading | +| `NO_CONFIG_EVENTCONFIG=1` | 43,611 | 4,211 | Global and per-event settings | +| `MINIMAL_CONFIG=1` | 25,336 | 22,486 | Routes, events, user values, and event settings | + +Each row enables one option against the full baseline. Savings overlap and are +not additive. Results vary with the target, compiler, C library, and enabled +wolfSentry features. + +The recommended profile below keeps routes, endpoints, events, actions, +default policies, and event configuration for an IDPS. Each row adds one +option to the preceding row: + +| Added make option | Linked bytes | Incremental saving | +| --- | ---: | ---: | +| `NO_CONFIG_USER_VALUES=1 NO_CONFIG_ADDR_FAMILY_NAMES=1` | 38,575 | 9,247 | +| `NO_CONFIG_TRANSACTIONS=1` | 32,675 | 5,900 | +| `NO_CONFIG_LEGACY_EVENT_SYNTAX=1` | 32,061 | 614 | +| `NO_CONFIG_TEXT_NUMBERS=1` | 30,459 | 1,602 | +| `NO_CONFIG_ERROR_MESSAGES=1` | 30,017 | 442 | +| `NO_CONFIG_TEXT_ADDRESSES=1` | 29,131 | 886 | + +This profile is 18,691 bytes smaller than the full CBOR configuration build: + +```sh +make WOLFCOSE=1 NO_JSON=1 \ + NO_CONFIG_USER_VALUES=1 \ + NO_CONFIG_ADDR_FAMILY_NAMES=1 \ + NO_CONFIG_TRANSACTIONS=1 \ + NO_CONFIG_LEGACY_EVENT_SYNTAX=1 \ + NO_CONFIG_TEXT_NUMBERS=1 \ + NO_CONFIG_TEXT_ADDRESSES=1 \ + NO_CONFIG_ERROR_MESSAGES=1 +``` + +## Measured loading speed + +A one-route policy was loaded repeatedly into an existing single-threaded +context using the same `-Os` test host. The JSON policy was 261 bytes and the +equivalent CBOR policy was 195 bytes. Results are medians of seven runs with +20,000 complete policy loads per run: + +| Input | Median time per load | Relative throughput | +| --- | ---: | ---: | +| JSON text | 3.07 microseconds | 1.00x | +| Native-number, binary-address CBOR | 1.64 microseconds | 1.88x | + +For this policy, optimized CBOR reduced load time by 47 percent. The result +includes decoding, flushing the old policy, and constructing the new route. +Target-specific results will vary. + +## Using an authenticated COSE payload + +`wolfsentry_config_cbor_oneshot()` consumes plain CBOR and does not verify a +signature or MAC. Verify the COSE envelope first, then pass the authenticated +payload returned by wolfCOSE to wolfSentry. For a `COSE_Sign1` message: + +```c +ret = wc_CoseSign1_Verify( + &key, cose, cose_len, + NULL, 0, NULL, 0, + scratch, sizeof scratch, + &headers, &payload, &payload_len); +if (ret == WOLFCOSE_SUCCESS) { + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + payload, payload_len, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + error_buffer, sizeof error_buffer); +} +``` + +The returned payload points into the COSE input buffer, so keep that buffer +valid until `wolfsentry_config_cbor_oneshot()` returns. + +## Testing build options + +`make wolfcose-test` builds and runs the unit tests once for each supported +wolfCOSE build option, using the wolfCOSE tree at `WOLFCOSE_TEST_TOP` +(default `../wolfCOSE`). Run a single option with its own target, such as +`make wolfcose-no-routes-test` or `make wolfcose-dynamic-test`. The targets +skip when wolfCOSE is absent unless `WOLFCOSE_REQUIRED=1` is set. diff --git a/doc/json_configuration.md b/doc/json_configuration.md index 9aa1bc8..aea5f88 100644 --- a/doc/json_configuration.md +++ b/doc/json_configuration.md @@ -52,6 +52,25 @@ Note that certain element variants may be unavailable due to build settings: * `address_port_name`: available if `!defined(WOLFSENTRY_NO_GETPROTOBY)` * `json_value_clause`: available if `defined(WOLFSENTRY_HAVE_JSON_DOM)` +Entire policy sections can also be omitted from the loader with +`WOLFSENTRY_CONFIG_NO_ROUTES`, `WOLFSENTRY_CONFIG_NO_EVENTS`, +`WOLFSENTRY_CONFIG_NO_USER_VALUES`, and +`WOLFSENTRY_CONFIG_NO_EVENTCONFIG`. `WOLFSENTRY_CONFIG_MINIMAL` enables all +four options. A disabled section is rejected as an invalid configuration key. +The matching make options are documented in the top-level README. + +Route loading can be reduced separately with +`WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES` and +`WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS`. + +`WOLFSENTRY_CONFIG_NO_TRANSACTIONS` omits dry-run and load-then-commit support. +Loads then modify the active context directly, and a failed load can leave a +partial update. The matching make option is `NO_CONFIG_TRANSACTIONS`. + +`WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX` removes the pre-1.4 `actions` and +`*-event` aliases while retaining the current `*-actions` event syntax. The +matching make option is `NO_CONFIG_LEGACY_EVENT_SYNTAX`. + Caller-supplied event and action labels shall not begin with `WOLFSENTRY_BUILTIN_LABEL_PREFIX` (by default `"%"`), as these are reserved for built-ins. diff --git a/src/json/load_config.c b/src/json/load_config.c index 732f17a..8f7901d 100644 --- a/src/json/load_config.c +++ b/src/json/load_config.c @@ -23,6 +23,14 @@ #include "wolfsentry/wolfsentry_json.h" #include "wolfsentry/wolfsentry_util.h" +#ifdef WOLFSENTRY_WOLFCOSE +#include "wolfsentry/wolfsentry_cbor.h" +/* Prevent wolfSSL from redeclaring wolfSentry's byte typedef under C99. */ +#define byte byte +#include +#undef byte +#endif + #define WOLFSENTRY_SOURCE_ID WOLFSENTRY_SOURCE_ID_JSON_LOAD_CONFIG_C #include @@ -56,7 +64,63 @@ * see doc/json_configuration.md */ +enum config_input_format { + CONFIG_INPUT_JSON = 0, + CONFIG_INPUT_CBOR +}; + +#if defined(WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS) && \ + !defined(WOLFSENTRY_WOLFCOSE) + #error WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS requires WOLFSENTRY_WOLFCOSE. +#endif +#if defined(WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS) && \ + !defined(WOLFSENTRY_NO_JSON) + #error WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS requires WOLFSENTRY_NO_JSON. +#endif +#if defined(WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES) && \ + !defined(WOLFSENTRY_WOLFCOSE) + #error WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES requires WOLFSENTRY_WOLFCOSE. +#endif +#if defined(WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES) && \ + !defined(WOLFSENTRY_NO_JSON) + #error WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES requires WOLFSENTRY_NO_JSON. +#endif + +#ifdef WOLFSENTRY_WOLFCOSE + #define CONFIG_VALUE_BYTE_STRING ((JSON_TYPE)(JSON_OBJECT_END + 1)) + #define CONFIG_VALUE_NUMBER ((JSON_TYPE)(JSON_OBJECT_END + 2)) + #define CONFIG_TYPE_IS_NUMBER(type) \ + (((type) == JSON_NUMBER) || ((type) == CONFIG_VALUE_NUMBER)) +#else + #define CONFIG_TYPE_IS_NUMBER(type) ((type) == JSON_NUMBER) +#endif + +#ifdef WOLFSENTRY_WOLFCOSE +enum config_number_type { + CONFIG_NUMBER_NONE = 0, + CONFIG_NUMBER_UINT, + CONFIG_NUMBER_SINT, + CONFIG_NUMBER_FLOAT +}; + +struct config_number { + enum config_number_type type; + union { + uint64_t uint_value; + int64_t sint_value; + double float_value; + } value; +}; +#endif + +#if defined(WOLFSENTRY_HAVE_JSON_DOM) && \ + !defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) + #define WOLFSENTRY_CONFIG_HAVE_JSON_DOM +#endif + struct wolfsentry_json_process_state { + enum config_input_format input_format; + uint32_t config_version; wolfsentry_config_load_flags_t load_flags; @@ -70,40 +134,63 @@ struct wolfsentry_json_process_state { int cur_depth; char cur_keyname[WOLFSENTRY_MAX_LABEL_BYTES]; int cur_keydepth; +#ifndef WOLFSENTRY_NO_JSON JSON_INPUT_POS key_pos; -#if defined(WOLFSENTRY_HAVE_JSON_DOM) && defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) +#if defined(WOLFSENTRY_CONFIG_HAVE_JSON_DOM) && defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) JSON_INPUT_POS json_value_start_pos; #endif wolfsentry_errcode_t fini_ret; +#endif - const struct wolfsentry_host_platform_interface *hpi; - +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG struct wolfsentry_eventconfig default_config; +#endif wolfsentry_action_res_t default_policy; - struct wolfsentry_event *default_event; +#ifndef WOLFSENTRY_NO_JSON JSON_PARSER parser; - struct wolfsentry_context *wolfsentry_actual, *wolfsentry; -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#endif + struct wolfsentry_context *wolfsentry; +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + struct wolfsentry_context *wolfsentry_actual; +#endif +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM unsigned int dom_parser_flags; JSON_DOM_PARSER dom_parser; /* has a duplicate JSON_PARSER in it that is not used, except for its .wolfsentry_context member. */ +#if defined(WOLFSENTRY_WOLFCOSE) && defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) + size_t cbor_offset; + size_t cbor_value_start_offset; + size_t cbor_json_value_start_offset; +#endif #endif #ifdef WOLFSENTRY_THREADSAFE struct wolfsentry_thread_context *thread; +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS int got_reservation; +#endif #define JPS_WOLFSENTRY_CONTEXT_ARGS_OUT jps->wolfsentry, jps->thread #define JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT (*jps)->wolfsentry, (*jps)->thread #define JPSP_P_WOLFSENTRY_CONTEXT_ARGS_OUT &(*jps)->wolfsentry, (*jps)->thread +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS +#define JPSP_WOLFSENTRY_ACTUAL_CONTEXT_ARGS_OUT (*jps)->wolfsentry, (*jps)->thread +#else #define JPSP_WOLFSENTRY_ACTUAL_CONTEXT_ARGS_OUT (*jps)->wolfsentry_actual, (*jps)->thread +#endif #else #define JPS_WOLFSENTRY_CONTEXT_ARGS_OUT jps->wolfsentry #define JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT (*jps)->wolfsentry #define JPSP_P_WOLFSENTRY_CONTEXT_ARGS_OUT &(*jps)->wolfsentry +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS +#define JPSP_WOLFSENTRY_ACTUAL_CONTEXT_ARGS_OUT (*jps)->wolfsentry +#else #define JPSP_WOLFSENTRY_ACTUAL_CONTEXT_ARGS_OUT (*jps)->wolfsentry_actual +#endif #endif union { + unsigned char unused; +#ifndef WOLFSENTRY_CONFIG_NO_ROUTES struct { char event_label[WOLFSENTRY_MAX_LABEL_BYTES]; int event_label_len; @@ -112,27 +199,44 @@ struct wolfsentry_json_process_state { WOLFSENTRY_SOCKADDR(WOLFSENTRY_MAX_ADDR_BITS) local; wolfsentry_route_flags_t flags; } route; +#endif +#ifndef WOLFSENTRY_CONFIG_NO_EVENTS struct { char label[WOLFSENTRY_MAX_LABEL_BYTES]; int label_len; wolfsentry_priority_t priority; +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG struct wolfsentry_eventconfig config; int configed; +#endif int inserted; wolfsentry_action_type_t cur_action_list_under_construction; } event; - struct { - char label[WOLFSENTRY_MAX_LABEL_BYTES]; - int label_len; - wolfsentry_action_flags_t flags; - } action; +#endif +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES struct { char label[WOLFSENTRY_MAX_LABEL_BYTES]; int label_len; } user_value; +#endif } o_u_c; }; +#ifdef WOLFSENTRY_WOLFCOSE +static const struct config_number *get_config_number( + JSON_TYPE type, + const unsigned char *data, + size_t data_size) +{ + if ((type != CONFIG_VALUE_NUMBER) || (data == NULL) || + (data_size != sizeof(struct config_number))) + { + return NULL; + } + return (const struct config_number *)(const void *)data; +} +#endif + static wolfsentry_errcode_t reset_o_u_c(struct wolfsentry_json_process_state *jps) { switch (jps->object_under_construction) { case O_U_C_NONE: @@ -154,7 +258,15 @@ static wolfsentry_errcode_t reset_o_u_c(struct wolfsentry_json_process_state *jp WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_uint64(JSON_TYPE type, const unsigned char *data, size_t data_size, uint64_t *out) { +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES + +static wolfsentry_errcode_t convert_uint64( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + uint64_t *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[24]; char *endptr; #ifdef WOLFSENTRY_HAVE_LONG_LONG @@ -162,7 +274,21 @@ static wolfsentry_errcode_t convert_uint64(JSON_TYPE type, const unsigned char * #else unsigned long conv; #endif +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if ((number == NULL) || (number->type != CONFIG_NUMBER_UINT)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + *out = number->value.uint_value; + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex and octal values. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -188,11 +314,18 @@ static wolfsentry_errcode_t convert_uint64(JSON_TYPE type, const unsigned char * if ((size_t)(endptr - buf) != data_size) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); *out = (uint64_t)conv; +#endif WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_sint64(JSON_TYPE type, const unsigned char *data, size_t data_size, int64_t *out) { +static wolfsentry_errcode_t convert_sint64( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + int64_t *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[24]; char *endptr; #ifdef WOLFSENTRY_HAVE_LONG_LONG @@ -200,7 +333,29 @@ static wolfsentry_errcode_t convert_sint64(JSON_TYPE type, const unsigned char * #else long conv; #endif +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if (number == NULL) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->type == CONFIG_NUMBER_SINT) + *out = number->value.sint_value; + else if ((number->type == CONFIG_NUMBER_UINT) && + (number->value.uint_value <= (uint64_t)INT64_MAX)) + { + *out = (int64_t)number->value.uint_value; + } + else + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex and octal values. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -226,15 +381,40 @@ static wolfsentry_errcode_t convert_sint64(JSON_TYPE type, const unsigned char * if ((size_t)(endptr - buf) != data_size) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); *out = (int64_t)conv; +#endif WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_uint32(JSON_TYPE type, const unsigned char *data, size_t data_size, uint32_t *out) { +#endif /* !WOLFSENTRY_CONFIG_NO_USER_VALUES */ + +static wolfsentry_errcode_t convert_uint32( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + uint32_t *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[16]; char *endptr; unsigned long conv; +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if ((number == NULL) || (number->type != CONFIG_NUMBER_UINT)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->value.uint_value > MAX_UINT_OF(*out)) + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); + *out = (uint32_t)number->value.uint_value; + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex and octal values. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -258,15 +438,41 @@ static wolfsentry_errcode_t convert_uint32(JSON_TYPE type, const unsigned char * if (conv > MAX_UINT_OF(*out)) WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); *out = (uint32_t)conv; +#endif WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_uint16(JSON_TYPE type, const unsigned char *data, size_t data_size, uint16_t *out) { +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) || \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + +static wolfsentry_errcode_t convert_uint16( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + uint16_t *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[8]; char *endptr; unsigned long conv; +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if ((number == NULL) || (number->type != CONFIG_NUMBER_UINT)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->value.uint_value > MAX_UINT_OF(*out)) + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); + *out = (uint16_t)number->value.uint_value; + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex and octal values. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -290,15 +496,42 @@ static wolfsentry_errcode_t convert_uint16(JSON_TYPE type, const unsigned char * if (conv > MAX_UINT_OF(*out)) WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); *out = (uint16_t)conv; +#endif WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_uint8(JSON_TYPE type, const unsigned char *data, size_t data_size, uint8_t *out) { +#endif /* routes or events */ + +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) +static wolfsentry_errcode_t convert_uint8( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + uint8_t *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[4]; char *endptr; unsigned long conv; +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if ((number == NULL) || (number->type != CONFIG_NUMBER_UINT)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->value.uint_value > MAX_UINT_OF(*out)) + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); + *out = (uint8_t)number->value.uint_value; + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex and octal values. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -322,15 +555,45 @@ static wolfsentry_errcode_t convert_uint8(JSON_TYPE type, const unsigned char *d if (conv > MAX_UINT_OF(*out)) WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); *out = (uint8_t)conv; +#endif WOLFSENTRY_RETURN_OK; } +#endif -static wolfsentry_errcode_t convert_double(JSON_TYPE type, const unsigned char *data, size_t data_size, double *out) { - char buf[24]; +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES +static wolfsentry_errcode_t convert_double( + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + double *out) +{ +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + char buf[32]; char *endptr; double conv; +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if (number == NULL) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->type == CONFIG_NUMBER_FLOAT) + *out = number->value.float_value; + else if (number->type == CONFIG_NUMBER_SINT) + *out = (double)number->value.sint_value; + else if (number->type == CONFIG_NUMBER_UINT) + *out = (double)number->value.uint_value; + else + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + WOLFSENTRY_RETURN_OK; + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else /* allow JSON_STRING to accommodate hex, octal, Inf, NaN, etc. */ if ((type != JSON_NUMBER) && (type != JSON_STRING)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -352,10 +615,13 @@ static wolfsentry_errcode_t convert_double(JSON_TYPE type, const unsigned char * if ((size_t)(endptr - buf) != data_size) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); *out = conv; +#endif WOLFSENTRY_RETURN_OK; } +#endif +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG static wolfsentry_errcode_t convert_eventconfig_flag(JSON_TYPE type, wolfsentry_eventconfig_flags_t *flags, wolfsentry_eventconfig_flags_t flag) { if (type == JSON_FALSE) *flags &= ~flag; @@ -366,12 +632,49 @@ static wolfsentry_errcode_t convert_eventconfig_flag(JSON_TYPE type, wolfsentry_ WOLFSENTRY_RETURN_OK; } -static wolfsentry_errcode_t convert_wolfsentry_duration(struct wolfsentry_context *wolfsentry, JSON_TYPE type, const unsigned char *data, size_t data_size, wolfsentry_time_t *out) { +static wolfsentry_errcode_t convert_wolfsentry_duration( + struct wolfsentry_context *wolfsentry, + JSON_TYPE type, + const unsigned char *data, + size_t data_size, + wolfsentry_time_t *out) +{ wolfsentry_errcode_t ret; + long conv; +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS char buf[24]; char *endptr; - long conv; +#endif +#ifdef WOLFSENTRY_WOLFCOSE + const struct config_number *number = + get_config_number(type, data, data_size); + if (type == CONFIG_VALUE_NUMBER) { + if (number == NULL) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->type == CONFIG_NUMBER_SINT) { + if ((number->value.sint_value < (int64_t)LONG_MIN) || + (number->value.sint_value > (int64_t)LONG_MAX)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + conv = (long)number->value.sint_value; + } + else if ((number->type == CONFIG_NUMBER_UINT) && + (number->value.uint_value <= (uint64_t)LONG_MAX)) + { + conv = (long)number->value.uint_value; + } + else + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + WOLFSENTRY_ERROR_RERETURN( + wolfsentry_interval_from_seconds( + wolfsentry, conv, 0 /* howlong_nsecs */, out)); + } +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else if ((type != JSON_STRING) && (type != JSON_NUMBER)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -413,12 +716,16 @@ static wolfsentry_errcode_t convert_wolfsentry_duration(struct wolfsentry_contex } if ((size_t)(endptr - buf) != data_size) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); - if ((ret = wolfsentry_interval_from_seconds(wolfsentry, conv, 0 /* howlong_nsecs */, out)) < 0) +#endif + if ((ret = wolfsentry_interval_from_seconds( + wolfsentry, conv, 0 /* howlong_nsecs */, out)) < 0) WOLFSENTRY_ERROR_RERETURN(ret); else WOLFSENTRY_RETURN_OK; } +#endif /* !WOLFSENTRY_CONFIG_NO_EVENTCONFIG */ + static wolfsentry_errcode_t convert_default_policy(JSON_TYPE type, const unsigned char *data, size_t data_size, wolfsentry_action_res_t *default_policy) { if (type != JSON_STRING) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); @@ -435,6 +742,8 @@ static wolfsentry_errcode_t convert_default_policy(JSON_TYPE type, const unsigne WOLFSENTRY_RETURN_OK; } +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG + static wolfsentry_errcode_t handle_eventconfig_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE type, const unsigned char *data, size_t data_size, struct wolfsentry_eventconfig *eventconfig) { if (jps->cur_depth == 5) { if ((! strcmp(jps->cur_keyname, "route-flags-to-add-on-insert")) || @@ -559,6 +868,8 @@ static wolfsentry_errcode_t handle_eventconfig_clause(struct wolfsentry_json_pro WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); } +#endif /* !WOLFSENTRY_CONFIG_NO_EVENTCONFIG */ + static wolfsentry_errcode_t handle_defaultpolicy_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE type, const unsigned char *data, size_t data_size) { if (jps->table_under_construction != T_U_C_DEFAULTPOLICIES) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); @@ -579,6 +890,8 @@ static wolfsentry_errcode_t handle_defaultpolicy_clause(struct wolfsentry_json_p if (! strcmp(jps->cur_keyname, "default-event")) { struct wolfsentry_route_table *routes; wolfsentry_errcode_t ret; + if (type != JSON_STRING) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); if (WOLFSENTRY_CHECK_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS)) WOLFSENTRY_RETURN_OK; ret = wolfsentry_route_get_main_table(JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, &routes); @@ -588,6 +901,11 @@ static wolfsentry_errcode_t handle_defaultpolicy_clause(struct wolfsentry_json_p WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); } +#ifndef WOLFSENTRY_CONFIG_NO_ROUTES + +#ifndef WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS + +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES static inline int convert_hex_digit(unsigned char digit) { if ((digit >= '0') && (digit <= '9')) return digit - '0'; @@ -622,6 +940,7 @@ static inline int convert_hex_byte(const unsigned char **in, size_t *in_len, byt *out = (byte)((d1 << 4) | d2); return 0; } +#endif static wolfsentry_errcode_t convert_sockaddr_address( struct wolfsentry_json_process_state *jps, @@ -631,6 +950,72 @@ static wolfsentry_errcode_t convert_sockaddr_address( struct wolfsentry_sockaddr *sa, byte *sa_addr) { +#ifdef WOLFSENTRY_WOLFCOSE + if (type == CONFIG_VALUE_BYTE_STRING) { + wolfsentry_addr_bits_t max_addr_bits; + wolfsentry_addr_bits_t max_stored_bits; + wolfsentry_errcode_t ret; + + if (sa->sa_family == WOLFSENTRY_AF_UNSPEC) + WOLFSENTRY_ERROR_RETURN(CONFIG_OUT_OF_SEQUENCE); + + ret = wolfsentry_addr_family_max_addr_bits( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + sa->sa_family, + &max_addr_bits); + WOLFSENTRY_RERETURN_IF_ERROR(ret); + if ((max_addr_bits == 0U) || + (max_addr_bits > WOLFSENTRY_MAX_ADDR_BITS)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + if (data_size != WOLFSENTRY_BITS_TO_BYTES(max_addr_bits)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + + max_stored_bits = max_addr_bits; +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + if ((jps->section_under_construction == S_U_C_REMOTE_ENDPOINT) ? + WOLFSENTRY_CHECK_BITS( + jps->o_u_c.route.flags, + WOLFSENTRY_ROUTE_FLAG_REMOTE_ADDR_BITMASK) : + WOLFSENTRY_CHECK_BITS( + jps->o_u_c.route.flags, + WOLFSENTRY_ROUTE_FLAG_LOCAL_ADDR_BITMASK)) + { + if (max_addr_bits > (WOLFSENTRY_MAX_ADDR_BITS >> 1U)) + WOLFSENTRY_ERROR_RETURN(BUFFER_TOO_SMALL); + max_stored_bits = (wolfsentry_addr_bits_t)(max_addr_bits << 1U); + } +#endif + if (sa->addr_len > max_stored_bits) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + + memcpy(sa_addr, data, data_size); + if (sa->addr_len == 0U) + sa->addr_len = max_addr_bits; + WOLFSENTRY_RETURN_OK; + } + if ((sa->sa_family == WOLFSENTRY_AF_CAN) && + (type == CONFIG_VALUE_NUMBER)) + { + uint32_t addr; + wolfsentry_errcode_t ret; + + ret = convert_uint32(type, data, data_size, &addr); + WOLFSENTRY_RERETURN_IF_ERROR(ret); + sa_addr[0] = (byte)(addr >> 24U); + sa_addr[1] = (byte)(addr >> 16U); + sa_addr[2] = (byte)(addr >> 8U); + sa_addr[3] = (byte)addr; + if (sa->addr_len == 0U) + sa->addr_len = 32U; + WOLFSENTRY_RETURN_OK; + } +#endif + +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#else if ((sa->sa_family == WOLFSENTRY_AF_LINK48) || (sa->sa_family == WOLFSENTRY_AF_LINK64)) { int n; if (type != JSON_STRING) @@ -703,6 +1088,15 @@ static wolfsentry_errcode_t convert_sockaddr_address( #endif else if (sa->sa_family == WOLFSENTRY_AF_CAN) { /* accept CAN addrs as either strings consisting of hex or octal numbers, or as a JSON-native decimal integer. */ +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + uint32_t addr; + wolfsentry_errcode_t ret; + + if (! CONFIG_TYPE_IS_NUMBER(type)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + ret = convert_uint32(type, data, data_size, &addr); + WOLFSENTRY_RERETURN_IF_ERROR(ret); +#else char d_buf[13], *endptr; unsigned long addr; if ((type != JSON_STRING) && (type != JSON_NUMBER)) @@ -725,11 +1119,19 @@ static wolfsentry_errcode_t convert_sockaddr_address( } memcpy(d_buf, data, data_size); d_buf[data_size] = 0; +#ifndef WOLFSENTRY_NO_ERRNO_H + errno = 0; +#endif addr = strtoul(d_buf, &endptr, 0); +#ifndef WOLFSENTRY_NO_ERRNO_H + if (errno != 0) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#endif if ((size_t)(endptr - d_buf) != data_size) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); if (addr > MAX_UINT_OF(uint32_t)) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); +#endif sa_addr[0] = (byte)(addr >> 24U); sa_addr[1] = (byte)(addr >> 16U); sa_addr[2] = (byte)(addr >> 8U); @@ -746,7 +1148,11 @@ static wolfsentry_errcode_t convert_sockaddr_address( wolfsentry_errcode_t ret; wolfsentry_addr_bits_t sa_addr_len; +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + if (type != JSON_STRING) +#else if ((type != JSON_STRING) && (type != JSON_NUMBER)) +#endif WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); if (wolfsentry_addr_family_get_parser(JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, sa->sa_family, &parser) < 0) @@ -761,6 +1167,7 @@ static wolfsentry_errcode_t convert_sockaddr_address( sa->addr_len = sa_addr_len; WOLFSENTRY_ERROR_RERETURN(ret); } +#endif } #ifndef WOLFSENTRY_NO_GETPROTOBY @@ -827,7 +1234,7 @@ static wolfsentry_errcode_t handle_route_endpoint_clause(struct wolfsentry_json_ sa == (struct wolfsentry_sockaddr *)&jps->o_u_c.route.remote ? WOLFSENTRY_ROUTE_FLAG_SA_REMOTE_PORT_WILDCARD : WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD); - if (type == JSON_NUMBER) + if (CONFIG_TYPE_IS_NUMBER(type)) WOLFSENTRY_ERROR_RERETURN(convert_uint16(type, data, data_size, &sa->sa_port)); #ifndef WOLFSENTRY_NO_GETPROTOBY else if (type == JSON_STRING) @@ -910,6 +1317,8 @@ static wolfsentry_errcode_t handle_route_endpoint_clause(struct wolfsentry_json_ WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); } +#endif /* !WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS */ + static wolfsentry_errcode_t handle_route_boolean_clause(JSON_TYPE type, wolfsentry_route_flags_t *flags, wolfsentry_route_flags_t bit) { if (type == JSON_TRUE) { WOLFSENTRY_SET_BITS(*flags, bit); @@ -924,13 +1333,14 @@ static wolfsentry_errcode_t handle_route_boolean_clause(JSON_TYPE type, wolfsent static wolfsentry_errcode_t handle_route_family_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE type, const unsigned char *data, size_t data_size) { WOLFSENTRY_CLEAR_BITS(jps->o_u_c.route.flags, WOLFSENTRY_ROUTE_FLAG_SA_FAMILY_WILDCARD); - if (type == JSON_NUMBER) { + if (CONFIG_TYPE_IS_NUMBER(type)) { wolfsentry_errcode_t ret = convert_uint16(type, data, data_size, &jps->o_u_c.route.remote.sa_family); WOLFSENTRY_RERETURN_IF_ERROR(ret); jps->o_u_c.route.local.sa_family = jps->o_u_c.route.remote.sa_family; WOLFSENTRY_RETURN_OK; } -#ifdef WOLFSENTRY_PROTOCOL_NAMES +#if defined(WOLFSENTRY_PROTOCOL_NAMES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) else if (type == JSON_STRING) { wolfsentry_errcode_t ret; ret = wolfsentry_addr_family_pton(JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, (const char *)data, (int)data_size, &jps->o_u_c.route.local.sa_family); @@ -946,7 +1356,7 @@ static wolfsentry_errcode_t handle_route_family_clause(struct wolfsentry_json_pr static wolfsentry_errcode_t handle_route_protocol_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE type, const unsigned char *data, size_t data_size) { WOLFSENTRY_CLEAR_BITS(jps->o_u_c.route.flags, WOLFSENTRY_ROUTE_FLAG_SA_PROTO_WILDCARD); - if (type == JSON_NUMBER) { + if (CONFIG_TYPE_IS_NUMBER(type)) { wolfsentry_errcode_t ret = convert_uint16(type, data, data_size, &jps->o_u_c.route.remote.sa_proto); WOLFSENTRY_RERETURN_IF_ERROR(ret); jps->o_u_c.route.local.sa_proto = jps->o_u_c.route.remote.sa_proto; @@ -1031,6 +1441,7 @@ static wolfsentry_errcode_t handle_route_clause(struct wolfsentry_json_process_s WOLFSENTRY_ROUTE_FLAG_SA_LOCAL_PORT_WILDCARD); WOLFSENTRY_RETURN_OK; } +#ifndef WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS if (jps->cur_depth == 4) { if (type == JSON_OBJECT_BEG) { if (! strcmp(jps->cur_keyname, "remote")) { @@ -1048,6 +1459,7 @@ static wolfsentry_errcode_t handle_route_clause(struct wolfsentry_json_process_s else WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); /* can't happen. */ } +#endif if ((jps->cur_depth == 3) && (type == JSON_OBJECT_END)) { jps->section_under_construction = S_U_C_NONE; WOLFSENTRY_RETURN_OK; @@ -1057,6 +1469,8 @@ static wolfsentry_errcode_t handle_route_clause(struct wolfsentry_json_process_s WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); if (! strcmp(jps->cur_keyname, "parent-event")) { + if (type != JSON_STRING) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); if (data_size > sizeof jps->o_u_c.route.event_label) WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); jps->o_u_c.route.event_label_len = (int)data_size; @@ -1082,6 +1496,10 @@ static wolfsentry_errcode_t handle_route_clause(struct wolfsentry_json_process_s } } +#endif /* !WOLFSENTRY_CONFIG_NO_ROUTES */ + +#ifndef WOLFSENTRY_CONFIG_NO_EVENTS + static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE type, const unsigned char *data, size_t data_size) { if (jps->table_under_construction != T_U_C_EVENTS) WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); @@ -1107,7 +1525,7 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s WOLFSENTRY_RETURN_OK; } - if ((jps->cur_depth == 3) && (type == JSON_NUMBER)) { + if ((jps->cur_depth == 3) && CONFIG_TYPE_IS_NUMBER(type)) { if (! strcmp(jps->cur_keyname, "priority")) { if (jps->o_u_c.event.inserted) WOLFSENTRY_ERROR_RETURN(CONFIG_OUT_OF_SEQUENCE); @@ -1116,6 +1534,7 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); } +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG if ((jps->cur_depth == 4) && (type == JSON_OBJECT_BEG) && (! strcmp(jps->cur_keyname, "config")) && (jps->section_under_construction == S_U_C_NONE)) { if (jps->o_u_c.event.inserted) WOLFSENTRY_ERROR_RETURN(CONFIG_OUT_OF_SEQUENCE); @@ -1137,6 +1556,7 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s else WOLFSENTRY_RETURN_OK; } +#endif /* !WOLFSENTRY_CONFIG_NO_EVENTCONFIG */ if (! jps->o_u_c.event.inserted) { wolfsentry_ent_id_t id; @@ -1149,7 +1569,11 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s jps->o_u_c.event.label, jps->o_u_c.event.label_len, jps->o_u_c.event.priority, +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG jps->o_u_c.event.configed ? &jps->o_u_c.event.config : NULL, +#else + NULL, +#endif WOLFSENTRY_EVENT_FLAG_NONE, &id); WOLFSENTRY_RERETURN_IF_ERROR(ret); @@ -1160,9 +1584,6 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s WOLFSENTRY_ERROR_RERETURN(reset_o_u_c(jps)); if ((jps->cur_depth == 3) && (type == JSON_STRING)) { - wolfsentry_errcode_t ret; - wolfsentry_action_type_t subevent_type = WOLFSENTRY_ACTION_TYPE_NONE; - if (! strcmp(jps->cur_keyname, "aux-parent-event")) { if (WOLFSENTRY_CHECK_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS)) WOLFSENTRY_RETURN_OK; @@ -1174,71 +1595,81 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s (int)data_size)); } - /* in early versions (pre-1.4.0), there was only one action list in each - * event, and "subevents" held the lists for each type of action. - * emulate that here for backward compatibility. - */ - if (! strcmp(jps->cur_keyname, "insert-event")) - subevent_type = WOLFSENTRY_ACTION_TYPE_INSERT; - else if (! strcmp(jps->cur_keyname, "match-event")) - subevent_type = WOLFSENTRY_ACTION_TYPE_MATCH; - else if (! strcmp(jps->cur_keyname, "update-event")) - subevent_type = WOLFSENTRY_ACTION_TYPE_UPDATE; - else if (! strcmp(jps->cur_keyname, "delete-event")) - subevent_type = WOLFSENTRY_ACTION_TYPE_DELETE; - else if (! strcmp(jps->cur_keyname, "decision-event")) - subevent_type = WOLFSENTRY_ACTION_TYPE_DECISION; - - if (subevent_type != WOLFSENTRY_ACTION_TYPE_NONE) { - struct wolfsentry_action_list_ent *subevent_action_cursor; - const char *action_label; - int action_label_len; - - if (data_size > WOLFSENTRY_MAX_LABEL_BYTES) - WOLFSENTRY_ERROR_RETURN(STRING_ARG_TOO_LONG); - if (WOLFSENTRY_CHECK_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS)) - WOLFSENTRY_RETURN_OK; - - ret = wolfsentry_event_action_list_start( - JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, - (const char *)data, - (int)data_size, - WOLFSENTRY_ACTION_TYPE_POST, - &subevent_action_cursor); - WOLFSENTRY_RERETURN_IF_ERROR(ret); +#ifndef WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX + { + wolfsentry_errcode_t ret; + wolfsentry_action_type_t subevent_type = WOLFSENTRY_ACTION_TYPE_NONE; + + /* In early versions (pre-1.4.0), there was only one action list in + * each event, and "subevents" held the lists for each action type. + */ + if (! strcmp(jps->cur_keyname, "insert-event")) + subevent_type = WOLFSENTRY_ACTION_TYPE_INSERT; + else if (! strcmp(jps->cur_keyname, "match-event")) + subevent_type = WOLFSENTRY_ACTION_TYPE_MATCH; + else if (! strcmp(jps->cur_keyname, "update-event")) + subevent_type = WOLFSENTRY_ACTION_TYPE_UPDATE; + else if (! strcmp(jps->cur_keyname, "delete-event")) + subevent_type = WOLFSENTRY_ACTION_TYPE_DELETE; + else if (! strcmp(jps->cur_keyname, "decision-event")) + subevent_type = WOLFSENTRY_ACTION_TYPE_DECISION; + + if (subevent_type != WOLFSENTRY_ACTION_TYPE_NONE) { + struct wolfsentry_action_list_ent *subevent_action_cursor; + const char *action_label; + int action_label_len; + + if (data_size > WOLFSENTRY_MAX_LABEL_BYTES) + WOLFSENTRY_ERROR_RETURN(STRING_ARG_TOO_LONG); + if (WOLFSENTRY_CHECK_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS)) + WOLFSENTRY_RETURN_OK; - while (wolfsentry_event_action_list_next( - JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, - &subevent_action_cursor, - &action_label, - &action_label_len) >= 0) - { - ret = wolfsentry_event_action_append( + ret = wolfsentry_event_action_list_start( JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, - jps->o_u_c.event.label, - jps->o_u_c.event.label_len, - subevent_type, - action_label, - action_label_len); + (const char *)data, + (int)data_size, + WOLFSENTRY_ACTION_TYPE_POST, + &subevent_action_cursor); WOLFSENTRY_RERETURN_IF_ERROR(ret); - } - ret = wolfsentry_event_action_list_done( - JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, - &subevent_action_cursor); + while (wolfsentry_event_action_list_next( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + &subevent_action_cursor, + &action_label, + &action_label_len) >= 0) + { + ret = wolfsentry_event_action_append( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + jps->o_u_c.event.label, + jps->o_u_c.event.label_len, + subevent_type, + action_label, + action_label_len); + WOLFSENTRY_RERETURN_IF_ERROR(ret); + } - WOLFSENTRY_ERROR_RERETURN(ret); + ret = wolfsentry_event_action_list_done( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + &subevent_action_cursor); + + WOLFSENTRY_ERROR_RERETURN(ret); + } } +#endif WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); } if ((jps->cur_depth == 4) && (type == JSON_ARRAY_BEG) && (jps->section_under_construction == S_U_C_NONE)) { - if ((! strcmp(jps->cur_keyname, "actions")) || - (! strcmp(jps->cur_keyname, "post-actions"))) + if (! strcmp(jps->cur_keyname, "post-actions")) { jps->o_u_c.event.cur_action_list_under_construction = WOLFSENTRY_ACTION_TYPE_POST; - } else if (! strcmp(jps->cur_keyname, "insert-actions")) + } +#ifndef WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX + else if (! strcmp(jps->cur_keyname, "actions")) + jps->o_u_c.event.cur_action_list_under_construction = WOLFSENTRY_ACTION_TYPE_POST; +#endif + else if (! strcmp(jps->cur_keyname, "insert-actions")) jps->o_u_c.event.cur_action_list_under_construction = WOLFSENTRY_ACTION_TYPE_INSERT; else if (! strcmp(jps->cur_keyname, "match-actions")) jps->o_u_c.event.cur_action_list_under_construction = WOLFSENTRY_ACTION_TYPE_MATCH; @@ -1280,6 +1711,10 @@ static wolfsentry_errcode_t handle_event_clause(struct wolfsentry_json_process_s WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); } +#endif /* !WOLFSENTRY_CONFIG_NO_EVENTS */ + +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES + static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_process_state *jps, JSON_TYPE json_type, const unsigned char *data, size_t data_size) { wolfsentry_errcode_t ret; @@ -1302,7 +1737,7 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc } if ((jps->cur_depth == 2) && (jps->cur_keydepth == 2) && (jps->object_under_construction == O_U_C_NONE)) { - switch (json_type) { + switch ((int)json_type) { case JSON_NULL: ret = wolfsentry_user_value_store_null( JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, @@ -1354,6 +1789,43 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc } jps->object_under_construction = O_U_C_NONE; WOLFSENTRY_ERROR_RERETURN(ret); +#ifdef WOLFSENTRY_WOLFCOSE + case CONFIG_VALUE_NUMBER: + { + const struct config_number *number = + get_config_number(json_type, data, data_size); + + if (number == NULL) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (number->type == CONFIG_NUMBER_FLOAT) { + ret = wolfsentry_user_value_store_double( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + jps->cur_keyname, + WOLFSENTRY_LENGTH_NULL_TERMINATED, + number->value.float_value, + 0); + } else { + int64_t value; + + if (number->type == CONFIG_NUMBER_SINT) + value = number->value.sint_value; + else if ((number->type == CONFIG_NUMBER_UINT) && + (number->value.uint_value <= (uint64_t)INT64_MAX)) + { + value = (int64_t)number->value.uint_value; + } else + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + ret = wolfsentry_user_value_store_sint( + JPS_WOLFSENTRY_CONTEXT_ARGS_OUT, + jps->cur_keyname, + WOLFSENTRY_LENGTH_NULL_TERMINATED, + value, + 0); + } + jps->object_under_construction = O_U_C_NONE; + WOLFSENTRY_ERROR_RERETURN(ret); + } +#endif case JSON_STRING: if (data_size >= WOLFSENTRY_KV_MAX_VALUE_BYTES) WOLFSENTRY_ERROR_RETURN(STRING_ARG_TOO_LONG); @@ -1378,11 +1850,23 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc } } -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM if ((jps->object_under_construction == O_U_C_USER_VALUE) && (jps->section_under_construction != S_U_C_USER_VALUE_JSON) && (! strcmp(jps->cur_keyname, "json"))) { #ifdef WOLFSENTRY_JSON_VALUE_MAX_BYTES - jps->json_value_start_pos = jps->parser.pos; -#endif + if (jps->input_format == CONFIG_INPUT_JSON) + jps->json_value_start_pos = jps->parser.pos; +#ifdef WOLFSENTRY_WOLFCOSE + else { + jps->cbor_json_value_start_offset = + jps->cbor_value_start_offset; + if (jps->cbor_offset - jps->cbor_json_value_start_offset > + WOLFSENTRY_JSON_VALUE_MAX_BYTES) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_JSON_VALUE_SIZE); + } + } +#endif +#endif jps->section_under_construction = S_U_C_USER_VALUE_JSON; ret = json_dom_init_1(WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry_get_allocator(jps->wolfsentry), jps->thread), &jps->dom_parser, jps->dom_parser_flags); if (ret < 0) @@ -1392,16 +1876,28 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc if ((jps->cur_depth >= 3) && (jps->object_under_construction == O_U_C_USER_VALUE) && (jps->section_under_construction == S_U_C_USER_VALUE_JSON)) { #ifdef WOLFSENTRY_JSON_VALUE_MAX_BYTES - if (jps->parser.pos.offset - jps->json_value_start_pos.offset > WOLFSENTRY_JSON_VALUE_MAX_BYTES) { + if ((jps->input_format == CONFIG_INPUT_JSON) && + (jps->parser.pos.offset - jps->json_value_start_pos.offset > WOLFSENTRY_JSON_VALUE_MAX_BYTES)) + { memcpy(&jps->parser.err_pos, &jps->parser.pos, sizeof jps->parser.err_pos); WOLFSENTRY_ERROR_RETURN(CONFIG_JSON_VALUE_SIZE); } +#ifdef WOLFSENTRY_WOLFCOSE + if ((jps->input_format == CONFIG_INPUT_CBOR) && + (jps->cbor_offset - jps->cbor_json_value_start_offset > + WOLFSENTRY_JSON_VALUE_MAX_BYTES)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_JSON_VALUE_SIZE); + } +#endif #endif ret = json_dom_process(json_type, data, data_size, (void *)&jps->dom_parser); - if (ret < 0) { + if ((ret < 0) && (jps->input_format == CONFIG_INPUT_JSON)) { memcpy(&jps->parser.err_pos, &jps->parser.value_pos, sizeof jps->parser.err_pos); + } + if (ret < 0) { WOLFSENTRY_ERROR_RERETURN(wolfsentry_centijson_errcode_translate(ret)); } @@ -1431,7 +1927,7 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc } WOLFSENTRY_RETURN_OK; } -#endif /* WOLFSENTRY_HAVE_JSON_DOM */ +#endif /* WOLFSENTRY_CONFIG_HAVE_JSON_DOM */ if ((jps->cur_depth == 3) && (jps->object_under_construction == O_U_C_USER_VALUE)) { wolfsentry_kv_type_t ws_type; @@ -1439,7 +1935,7 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc if (jps->cur_keydepth != 3) WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); - if (! ((json_type == JSON_NUMBER) || + if (! (CONFIG_TYPE_IS_NUMBER(json_type) || (json_type == JSON_STRING))) WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); @@ -1456,6 +1952,13 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc else WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (((ws_type == WOLFSENTRY_KV_STRING) || + (ws_type == WOLFSENTRY_KV_BYTES)) && + (json_type != JSON_STRING)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + switch (ws_type) { case WOLFSENTRY_KV_UINT: { uint64_t i; @@ -1528,6 +2031,8 @@ static wolfsentry_errcode_t handle_user_value_clause(struct wolfsentry_json_proc WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); } +#endif /* !WOLFSENTRY_CONFIG_NO_USER_VALUES */ + #define WOLFSENTRY_ERROR_OUT(x) { ret = WOLFSENTRY_ERROR_ENCODE(x); goto out; } static wolfsentry_errcode_t json_process( @@ -1548,15 +2053,19 @@ static wolfsentry_errcode_t json_process( if (type == JSON_KEY) { -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM if (jps->section_under_construction == S_U_C_USER_VALUE_JSON) { ret = handle_user_value_clause(jps, type, data, data_size); goto out; } #endif - memcpy(&jps->key_pos, &jps->parser.pos, sizeof jps->key_pos); - jps->key_pos.column_number -= (unsigned)(data_size + 2U); /* kludge to move the pointer back to the start of the key */ +#ifndef WOLFSENTRY_NO_JSON + if (jps->input_format == CONFIG_INPUT_JSON) { + memcpy(&jps->key_pos, &jps->parser.pos, sizeof jps->key_pos); + jps->key_pos.column_number -= (unsigned)(data_size + 2U); /* kludge to move the pointer back to the start of the key */ + } +#endif if (data_size >= sizeof jps->cur_keyname) WOLFSENTRY_ERROR_OUT(CONFIG_INVALID_KEY); memcpy(jps->cur_keyname, data, data_size); @@ -1580,10 +2089,13 @@ static wolfsentry_errcode_t json_process( if (jps->table_under_construction == T_U_C_NONE) { if ((jps->cur_keydepth == 1) && (jps->cur_depth <= 2)) { - switch (type) { + switch ((int)type) { case JSON_FALSE: case JSON_TRUE: case JSON_NUMBER: +#ifdef WOLFSENTRY_WOLFCOSE + case CONFIG_VALUE_NUMBER: +#endif case JSON_STRING: if (jps->cur_depth != 1) WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); @@ -1601,36 +2113,44 @@ static wolfsentry_errcode_t json_process( WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); if (jps->cur_depth != 2) WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG if (! strcmp(jps->cur_keyname, "config-update")) { jps->table_under_construction = T_U_C_TOPCONFIG; WOLFSENTRY_RETURN_OK; } +#endif if (! strcmp(jps->cur_keyname, "default-policies")) { jps->table_under_construction = T_U_C_DEFAULTPOLICIES; WOLFSENTRY_RETURN_OK; } +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES if (! strcmp(jps->cur_keyname, "user-values")) { jps->table_under_construction = T_U_C_USER_VALUES; WOLFSENTRY_RETURN_OK; } +#endif WOLFSENTRY_ERROR_OUT(CONFIG_INVALID_KEY); case JSON_ARRAY_BEG: if (jps->config_version == 0) WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); if (jps->cur_depth != 2) WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); +#ifndef WOLFSENTRY_CONFIG_NO_EVENTS if ((! strcmp(jps->cur_keyname, "events-insert")) || (! strcmp(jps->cur_keyname, "events"))) { jps->table_under_construction = T_U_C_EVENTS; WOLFSENTRY_RETURN_OK; } +#endif +#ifndef WOLFSENTRY_CONFIG_NO_ROUTES if ((! strcmp(jps->cur_keyname, "static-routes-insert")) || (! strcmp(jps->cur_keyname, "routes"))) { jps->table_under_construction = T_U_C_STATIC_ROUTES; WOLFSENTRY_RETURN_OK; } +#endif if (! strcmp(jps->cur_keyname, "actions-update")) { WOLFSENTRY_ERROR_RETURN(CONFIG_MISSING_HANDLER); /* @@ -1649,16 +2169,19 @@ static wolfsentry_errcode_t json_process( WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); } +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG if (jps->table_under_construction == T_U_C_TOPCONFIG) { ret = handle_eventconfig_clause(jps, type, data, data_size, &jps->default_config); goto out; } +#endif if (jps->table_under_construction == T_U_C_DEFAULTPOLICIES) { ret = handle_defaultpolicy_clause(jps, type, data, data_size); goto out; } +#ifndef WOLFSENTRY_CONFIG_NO_ROUTES if (jps->table_under_construction == T_U_C_STATIC_ROUTES) { if ((jps->cur_depth == 1) && (type == JSON_ARRAY_END)) { jps->table_under_construction = T_U_C_NONE; @@ -1667,7 +2190,9 @@ static wolfsentry_errcode_t json_process( ret = handle_route_clause(jps, type, data, data_size); goto out; } +#endif +#ifndef WOLFSENTRY_CONFIG_NO_EVENTS if (jps->table_under_construction == T_U_C_EVENTS) { if ((jps->cur_depth == 1) && (type == JSON_ARRAY_END)) { jps->table_under_construction = T_U_C_NONE; @@ -1676,6 +2201,7 @@ static wolfsentry_errcode_t json_process( ret = handle_event_clause(jps, type, data, data_size); goto out; } +#endif #if 0 if (jps->table_under_construction == T_U_C_ACTIONS) { @@ -1688,6 +2214,7 @@ static wolfsentry_errcode_t json_process( } #endif +#ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES if (jps->table_under_construction == T_U_C_USER_VALUES) { if ((jps->cur_depth == 1) && (type == JSON_ARRAY_END)) { jps->table_under_construction = T_U_C_NONE; @@ -1696,6 +2223,7 @@ static wolfsentry_errcode_t json_process( ret = handle_user_value_clause(jps, type, data, data_size); goto out; } +#endif WOLFSENTRY_ERROR_OUT(CONFIG_UNEXPECTED); @@ -1703,95 +2231,89 @@ static wolfsentry_errcode_t json_process( if (ret < 0) { reset_o_u_c(jps); - if (WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_KEY)) - memcpy(&jps->parser.err_pos, &jps->key_pos, sizeof(JSON_INPUT_POS)); - else if (WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)) - memcpy(&jps->parser.err_pos, &jps->parser.value_pos, sizeof(JSON_INPUT_POS)); - else - memcpy(&jps->parser.err_pos, &jps->parser.pos, sizeof(JSON_INPUT_POS)); +#ifndef WOLFSENTRY_NO_JSON + if (jps->input_format == CONFIG_INPUT_JSON) { + if (WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_KEY)) + memcpy(&jps->parser.err_pos, &jps->key_pos, sizeof(JSON_INPUT_POS)); + else if (WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)) + memcpy(&jps->parser.err_pos, &jps->parser.value_pos, sizeof(JSON_INPUT_POS)); + else + memcpy(&jps->parser.err_pos, &jps->parser.pos, sizeof(JSON_INPUT_POS)); + } +#endif WOLFSENTRY_ERROR_RERETURN(ret); } else WOLFSENTRY_RETURN_OK; } -WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( +static wolfsentry_errcode_t config_state_fini( + struct wolfsentry_json_process_state **jps, + wolfsentry_errcode_t ret); + +static wolfsentry_errcode_t config_state_init( WOLFSENTRY_CONTEXT_ARGS_IN, wolfsentry_config_load_flags_t load_flags, - const JSON_CONFIG *json_config, + enum config_input_format input_format, struct wolfsentry_json_process_state **jps) { - wolfsentry_errcode_t ret; + wolfsentry_errcode_t ret = WOLFSENTRY_ERROR_ENCODE(OK); #ifdef WOLFSENTRY_THREADSAFE int locked = 0; #endif - static const JSON_CALLBACKS json_callbacks = { -#ifdef WOLFSENTRY_HAVE_DESIGNATED_INITIALIZERS - .process = -#endif - (int (*)(JSON_TYPE, const unsigned char *, size_t, void *))json_process - }; - - static const JSON_CONFIG default_json_config = { -#ifdef WOLFSENTRY_HAVE_DESIGNATED_INITIALIZERS - .max_total_len = WOLFSENTRY_MAX_JSON_TOTAL_LEN, - .max_total_values = 0, - .max_number_len = 20, - .max_string_len = WOLFSENTRY_KV_MAX_VALUE_BYTES, - .max_key_len = WOLFSENTRY_MAX_LABEL_BYTES, - .max_nesting_level = WOLFSENTRY_MAX_JSON_NESTING, - .flags = JSON_NOSCALARROOT -#else - WOLFSENTRY_MAX_JSON_TOTAL_LEN, - 0, - 20, - WOLFSENTRY_KV_MAX_VALUE_BYTES, - WOLFSENTRY_MAX_LABEL_BYTES, - WOLFSENTRY_MAX_JSON_NESTING, - JSON_NOSCALARROOT -#endif - }; - - if (json_config == NULL) - json_config = &default_json_config; - - /* memory safety currently depends on centijson to reject keys longer than WOLFSENTRY_MAX_LABEL_BYTES. */ - if (json_config->max_key_len > WOLFSENTRY_MAX_LABEL_BYTES) - WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); - if (wolfsentry == NULL) WOLFSENTRY_ERROR_RETURN(INVALID_ARG); if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FINI)) WOLFSENTRY_ERROR_RETURN(INVALID_ARG); +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + if (WOLFSENTRY_MASKIN_BITS( + load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN) && + WOLFSENTRY_MASKIN_BITS( + load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) + { + WOLFSENTRY_ERROR_RETURN(INVALID_ARG); + } +#else + if (WOLFSENTRY_MASKIN_BITS( + load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN | + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) + { + WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); + } +#endif if ((*jps = (struct wolfsentry_json_process_state *)wolfsentry_malloc(WOLFSENTRY_CONTEXT_ARGS_OUT, sizeof **jps)) == NULL) WOLFSENTRY_ERROR_RETURN(SYS_RESOURCE_FAILED); memset(*jps, 0, sizeof **jps); (*jps)->load_flags = load_flags; + (*jps)->input_format = input_format; if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_ABORT)) { -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM (*jps)->dom_parser_flags |= JSON_DOM_DUPKEY_ABORT; #else { ret = WOLFSENTRY_ERROR_ENCODE(IMPLEMENTATION_MISSING); goto out; } #endif } if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USEFIRST)) { -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM (*jps)->dom_parser_flags |= JSON_DOM_DUPKEY_USEFIRST; #else { ret = WOLFSENTRY_ERROR_ENCODE(IMPLEMENTATION_MISSING); goto out; } #endif } if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USELAST)) { -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM (*jps)->dom_parser_flags |= JSON_DOM_DUPKEY_USELAST; #else { ret = WOLFSENTRY_ERROR_ENCODE(IMPLEMENTATION_MISSING); goto out; } #endif } if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_MAINTAINDICTORDER)) { -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM (*jps)->dom_parser_flags |= JSON_DOM_MAINTAINDICTORDER; #else { ret = WOLFSENTRY_ERROR_ENCODE(IMPLEMENTATION_MISSING); goto out; } @@ -1799,6 +2321,10 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( } #ifdef WOLFSENTRY_THREADSAFE +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + if ((ret = WOLFSENTRY_MUTEX_EX(wolfsentry)) < 0) + goto out; +#else if ((! WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN|WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) || (thread == NULL)) { @@ -1815,13 +2341,19 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( if (WOLFSENTRY_SUCCESS_CODE_IS(ret, LOCK_OK_AND_GOT_RESV)) (*jps)->got_reservation = 1; } +#endif locked = 1; #endif +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS (*jps)->wolfsentry_actual = wolfsentry; +#endif #ifdef WOLFSENTRY_THREADSAFE (*jps)->thread = thread; #endif +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + (*jps)->wolfsentry = wolfsentry; +#else if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN|WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) { ret = wolfsentry_context_clone( WOLFSENTRY_CONTEXT_ARGS_OUT, @@ -1839,37 +2371,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( } else { (*jps)->wolfsentry = wolfsentry; } - - ret = json_init(WOLFSENTRY_CONTEXT_ARGS_OUT_EX(wolfsentry_get_allocator((*jps)->wolfsentry)), - &(*jps)->parser, - &json_callbacks, - json_config, - *jps); - if (ret < 0) { - ret = wolfsentry_centijson_errcode_translate(ret); - goto out; - } - - /* initialize with defaults already set in context, particularly to pick up route_private_data* fields. */ - ret = wolfsentry_defaultconfig_get(JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT, &(*jps)->default_config); - if (ret < 0) - goto out; - - if (! WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN|WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH|WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) { - if (WOLFSENTRY_CHECK_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FLUSH_ONLY_ROUTES)) { - struct wolfsentry_route_table *main_table; - wolfsentry_action_res_t action_results; - WOLFSENTRY_CLEAR_ALL_BITS(action_results); - ret = wolfsentry_route_get_main_table(WOLFSENTRY_CONTEXT_ARGS_OUT, &main_table); - if (ret < 0) - goto out; - ret = wolfsentry_route_flush_table(WOLFSENTRY_CONTEXT_ARGS_OUT, main_table, &action_results); - } else { - ret = wolfsentry_context_flush(WOLFSENTRY_CONTEXT_ARGS_OUT); - } - if (ret < 0) - goto out; - } +#endif out: @@ -1877,14 +2379,19 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( #ifdef WOLFSENTRY_THREADSAFE if (locked) { wolfsentry_errcode_t _lock_ret; +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + _lock_ret = wolfsentry_context_unlock(wolfsentry, thread); +#else if ((*jps)->got_reservation) _lock_ret = wolfsentry_context_unlock_and_abandon_reservation(wolfsentry, thread); else _lock_ret = wolfsentry_context_unlock(wolfsentry, thread); +#endif if (_lock_ret < 0) ret = _lock_ret; } #endif +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS if (WOLFSENTRY_MASKIN_BITS(load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN|WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT) && ((*jps)->wolfsentry != NULL)) { @@ -1892,6 +2399,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( if (ret2 < 0) ret = ret2; } +#endif wolfsentry_free(WOLFSENTRY_CONTEXT_ARGS_OUT, *jps); *jps = NULL; WOLFSENTRY_ERROR_RERETURN(ret); @@ -1899,6 +2407,128 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( WOLFSENTRY_RETURN_OK; /* keeping lock! */ } +static wolfsentry_errcode_t config_state_prepare( + struct wolfsentry_json_process_state **jps) +{ + wolfsentry_errcode_t ret; + +#ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG + /* Preserve context-specific defaults such as route private data fields. */ + ret = wolfsentry_defaultconfig_get( + JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT, + &(*jps)->default_config); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); +#endif + +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + if (! WOLFSENTRY_MASKIN_BITS( + (*jps)->load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH)) +#else + if (! WOLFSENTRY_MASKIN_BITS( + (*jps)->load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN | + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT)) +#endif + { + if (WOLFSENTRY_CHECK_BITS( + (*jps)->load_flags, + WOLFSENTRY_CONFIG_LOAD_FLAG_FLUSH_ONLY_ROUTES)) + { + struct wolfsentry_route_table *main_table; + wolfsentry_action_res_t action_results; + + WOLFSENTRY_CLEAR_ALL_BITS(action_results); + ret = wolfsentry_route_get_main_table( + JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT, + &main_table); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + ret = wolfsentry_route_flush_table( + JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT, + main_table, + &action_results); + } else { + ret = wolfsentry_context_flush( + JPSP_WOLFSENTRY_CONTEXT_ARGS_OUT); + } + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + } + + WOLFSENTRY_RETURN_OK; +} + +#ifndef WOLFSENTRY_NO_JSON + +WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init_ex( + WOLFSENTRY_CONTEXT_ARGS_IN, + wolfsentry_config_load_flags_t load_flags, + const JSON_CONFIG *json_config, + struct wolfsentry_json_process_state **jps) +{ + wolfsentry_errcode_t ret; + static const JSON_CALLBACKS json_callbacks = { +#ifdef WOLFSENTRY_HAVE_DESIGNATED_INITIALIZERS + .process = +#endif + (int (*)(JSON_TYPE, const unsigned char *, size_t, void *))json_process + }; + static const JSON_CONFIG default_json_config = { +#ifdef WOLFSENTRY_HAVE_DESIGNATED_INITIALIZERS + .max_total_len = WOLFSENTRY_MAX_JSON_TOTAL_LEN, + .max_total_values = 0, + .max_number_len = 20, + .max_string_len = WOLFSENTRY_KV_MAX_VALUE_BYTES, + .max_key_len = WOLFSENTRY_MAX_LABEL_BYTES, + .max_nesting_level = WOLFSENTRY_MAX_JSON_NESTING, + .flags = JSON_NOSCALARROOT +#else + WOLFSENTRY_MAX_JSON_TOTAL_LEN, + 0, + 20, + WOLFSENTRY_KV_MAX_VALUE_BYTES, + WOLFSENTRY_MAX_LABEL_BYTES, + WOLFSENTRY_MAX_JSON_NESTING, + JSON_NOSCALARROOT +#endif + }; + + if (json_config == NULL) + json_config = &default_json_config; + + /* Key safety depends on CentiJSON enforcing this configured limit. */ + if (json_config->max_key_len > WOLFSENTRY_MAX_LABEL_BYTES) + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); + + ret = config_state_init( + WOLFSENTRY_CONTEXT_ARGS_OUT, + load_flags, + CONFIG_INPUT_JSON, + jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + + ret = json_init( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(wolfsentry_get_allocator((*jps)->wolfsentry)), + &(*jps)->parser, + &json_callbacks, + json_config, + *jps); + if (ret < 0) { + ret = wolfsentry_centijson_errcode_translate(ret); + WOLFSENTRY_ERROR_RERETURN(config_state_fini(jps, ret)); + } + + ret = config_state_prepare(jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(config_state_fini(jps, ret)); + + WOLFSENTRY_RETURN_OK; +} + WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init( WOLFSENTRY_CONTEXT_ARGS_IN, wolfsentry_config_load_flags_t load_flags, @@ -1922,13 +2552,21 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_feed( JSON_INPUT_POS json_pos; int ret; +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + (void)err_buf; + (void)err_buf_size; +#endif + + if (jps == NULL) + WOLFSENTRY_ERROR_RETURN(INVALID_ARG); if (WOLFSENTRY_CHECK_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FINI)) WOLFSENTRY_ERROR_RETURN(INVALID_ARG); ret = json_feed(&jps->parser, json_in, json_in_len); if (ret < 0) { jps->fini_ret = json_fini(&jps->parser, &json_pos); WOLFSENTRY_SET_BITS(jps->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FINI); - if (err_buf) { +#ifndef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + if ((err_buf != NULL) && (err_buf_size > 0U)) { if (WOLFSENTRY_ERROR_DECODE_SOURCE_ID(jps->fini_ret) == WOLFSENTRY_SOURCE_ID_UNSET) ret = snprintf(err_buf, err_buf_size, "json_feed failed at offset %d, line %u, col %u, with centijson code " WOLFSENTRY_ERRCODE_FMT ": %s", (int)json_pos.offset, json_pos.line_number, json_pos.column_number, (int)jps->fini_ret, json_error_str(jps->fini_ret)); else @@ -1936,6 +2574,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_feed( if (ret >= (int)err_buf_size) err_buf[err_buf_size - 1] = 0; } +#endif WOLFSENTRY_ERROR_RERETURN(wolfsentry_centijson_errcode_translate(jps->fini_ret)); } WOLFSENTRY_RETURN_OK; @@ -1952,38 +2591,501 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_centijson_errcode(struct w WOLFSENTRY_RETURN_OK; } -WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_fini( - struct wolfsentry_json_process_state **jps, +#endif /* !WOLFSENTRY_NO_JSON */ + +#ifdef WOLFSENTRY_WOLFCOSE + +struct cbor_container_state { + size_t remaining; + unsigned char major_type; + unsigned char expecting_key; +}; + +static float cbor_half_to_float(uint16_t half) +{ + uint32_t sign = ((uint32_t)half & 0x8000U) << 16U; + uint32_t exponent = ((uint32_t)half >> 10U) & 0x1fU; + uint32_t fraction = (uint32_t)half & 0x3ffU; + uint32_t bits; + float value; + + if (exponent == 0U) { + if (fraction == 0U) { + bits = sign; + } else { + exponent = 113U; + while ((fraction & 0x400U) == 0U) { + fraction <<= 1U; + --exponent; + } + fraction &= 0x3ffU; + bits = sign | (exponent << 23U) | (fraction << 13U); + } + } else if (exponent == 31U) { + bits = sign | 0x7f800000U | (fraction << 13U); + } else { + bits = sign | ((exponent + 112U) << 23U) | (fraction << 13U); + } + + memcpy(&value, &bits, sizeof value); + return value; +} + +static wolfsentry_errcode_t cbor_decode_number( + const WOLFCOSE_CBOR_ITEM *item, + unsigned char additional_info, + struct config_number *number) +{ + if (item->majorType == WOLFCOSE_CBOR_UINT) { + number->type = CONFIG_NUMBER_UINT; + number->value.uint_value = item->val; + } else if (item->majorType == WOLFCOSE_CBOR_NEGINT) { + if (item->val > (uint64_t)INT64_MAX) + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_SMALL); + number->type = CONFIG_NUMBER_SINT; + number->value.sint_value = -1 - (int64_t)item->val; + } else if (additional_info == WOLFCOSE_CBOR_AI_FLOAT16) { + number->type = CONFIG_NUMBER_FLOAT; + number->value.float_value = + (double)cbor_half_to_float((uint16_t)item->val); + } else if (additional_info == WOLFCOSE_CBOR_AI_FLOAT32) { + uint32_t bits = (uint32_t)item->val; + float value; + + memcpy(&value, &bits, sizeof value); + number->type = CONFIG_NUMBER_FLOAT; + number->value.float_value = (double)value; + } else if (additional_info == WOLFCOSE_CBOR_AI_FLOAT64) { + uint64_t bits = item->val; + + number->type = CONFIG_NUMBER_FLOAT; + memcpy(&number->value.float_value, &bits, sizeof bits); + } else { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + + WOLFSENTRY_RETURN_OK; +} + +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS +static int cbor_text_number_is_json(const char *text, size_t text_len) +{ + size_t i = 0U; + + if ((i < text_len) && (text[i] == '-')) + ++i; + if (i >= text_len) + return 0; + if (text[i] == '0') + ++i; + else if ((text[i] >= '1') && (text[i] <= '9')) { + do { + ++i; + } while ((i < text_len) && (text[i] >= '0') && (text[i] <= '9')); + } else + return 0; + if ((i < text_len) && (text[i] == '.')) { + ++i; + if ((i >= text_len) || (text[i] < '0') || (text[i] > '9')) + return 0; + do { + ++i; + } while ((i < text_len) && (text[i] >= '0') && (text[i] <= '9')); + } + if ((i < text_len) && ((text[i] == 'e') || (text[i] == 'E'))) { + ++i; + if ((i < text_len) && ((text[i] == '+') || (text[i] == '-'))) + ++i; + if ((i >= text_len) || (text[i] < '0') || (text[i] > '9')) + return 0; + do { + ++i; + } while ((i < text_len) && (text[i] >= '0') && (text[i] <= '9')); + } + + return i == text_len; +} + +static wolfsentry_errcode_t cbor_emit_text_number( + struct wolfsentry_json_process_state *jps, + const struct config_number *number) +{ + char text[32]; + int number_len; + + if (number->type == CONFIG_NUMBER_UINT) { + number_len = snprintf( + text, + sizeof text, + "%llu", + (unsigned long long)number->value.uint_value); + } else if (number->type == CONFIG_NUMBER_SINT) { + number_len = snprintf( + text, + sizeof text, + "%lld", + (long long)number->value.sint_value); + } else if (number->type == CONFIG_NUMBER_FLOAT) { + char *decimal_point; + + number_len = snprintf( + text, + sizeof text, + "%.17g", + number->value.float_value); + decimal_point = strchr(text, ','); + if (decimal_point != NULL) + *decimal_point = '.'; + if ((number_len > 0) && ((size_t)(number_len + 2) < sizeof text) && + (strspn(text, "-0123456789") == (size_t)number_len)) + { + text[number_len++] = '.'; + text[number_len++] = '0'; + text[number_len] = 0; + } + } else { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + + if ((number_len < 0) || ((size_t)number_len >= sizeof text)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + if (! cbor_text_number_is_json(text, (size_t)number_len)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + + WOLFSENTRY_ERROR_RERETURN(json_process( + JSON_NUMBER, + (const unsigned char *)text, + (size_t)number_len, + jps)); +} +#endif + +static wolfsentry_errcode_t cbor_emit_number( + struct wolfsentry_json_process_state *jps, + const WOLFCOSE_CBOR_ITEM *item, + unsigned char additional_info) +{ + struct config_number number; + + WOLFSENTRY_RERETURN_IF_ERROR( + cbor_decode_number(item, additional_info, &number)); + +#ifndef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + { + int emit_text = 0; + +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + if (((((jps->section_under_construction == S_U_C_REMOTE_ENDPOINT) && + (jps->o_u_c.route.remote.sa_family != WOLFSENTRY_AF_CAN)) || + ((jps->section_under_construction == S_U_C_LOCAL_ENDPOINT) && + (jps->o_u_c.route.local.sa_family != WOLFSENTRY_AF_CAN))) && + ((! strcmp(jps->cur_keyname, "address")) || + (! strcmp(jps->cur_keyname, "bitmask"))))) + { + emit_text = 1; + } +#endif +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM + if ((jps->section_under_construction == S_U_C_USER_VALUE_JSON) || + ((jps->object_under_construction == O_U_C_USER_VALUE) && + (! strcmp(jps->cur_keyname, "json")))) + { + emit_text = 1; + } +#endif + if (emit_text != 0) + return cbor_emit_text_number(jps, &number); + } +#endif + + WOLFSENTRY_ERROR_RERETURN(json_process( + CONFIG_VALUE_NUMBER, + (const unsigned char *)(const void *)&number, + sizeof number, + jps)); +} + +static wolfsentry_errcode_t cbor_emit_scalar( + struct wolfsentry_json_process_state *jps, + const WOLFCOSE_CBOR_ITEM *item, + unsigned char additional_info) +{ + switch (item->majorType) { + case WOLFCOSE_CBOR_UINT: + case WOLFCOSE_CBOR_NEGINT: + WOLFSENTRY_ERROR_RERETURN(cbor_emit_number(jps, item, additional_info)); + + case WOLFCOSE_CBOR_TSTR: + WOLFSENTRY_ERROR_RERETURN(json_process( + JSON_STRING, + item->data, + item->dataLen, + jps)); + + case WOLFCOSE_CBOR_SIMPLE: + switch (additional_info) { + case 20U: + WOLFSENTRY_ERROR_RERETURN(json_process(JSON_FALSE, NULL, 0U, jps)); + case 21U: + WOLFSENTRY_ERROR_RERETURN(json_process(JSON_TRUE, NULL, 0U, jps)); + case 22U: + WOLFSENTRY_ERROR_RERETURN(json_process(JSON_NULL, NULL, 0U, jps)); + case WOLFCOSE_CBOR_AI_FLOAT16: + case WOLFCOSE_CBOR_AI_FLOAT32: + case WOLFCOSE_CBOR_AI_FLOAT64: + WOLFSENTRY_ERROR_RERETURN(cbor_emit_number(jps, item, additional_info)); + default: + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + + case WOLFCOSE_CBOR_BSTR: + if (((jps->section_under_construction != S_U_C_REMOTE_ENDPOINT) && + (jps->section_under_construction != S_U_C_LOCAL_ENDPOINT)) || + ((strcmp(jps->cur_keyname, "address") != 0) && + (strcmp(jps->cur_keyname, "bitmask") != 0))) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + } + WOLFSENTRY_ERROR_RERETURN(json_process( + CONFIG_VALUE_BYTE_STRING, + item->data, + item->dataLen, + jps)); + + case WOLFCOSE_CBOR_TAG: + default: + WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); + } +} + +static wolfsentry_errcode_t cbor_process( + struct wolfsentry_json_process_state *jps, + WOLFCOSE_CBOR_CTX *decoder, + int *decoder_ret) +{ + struct cbor_container_state stack[WOLFSENTRY_MAX_CBOR_NESTING]; + size_t depth = 0U; + int root_seen = 0; + + *decoder_ret = WOLFCOSE_SUCCESS; + + for (;;) { + WOLFCOSE_CBOR_ITEM item; + size_t item_offset; + unsigned char additional_info; + wolfsentry_errcode_t ret; + + if ((depth > 0U) && (stack[depth - 1U].remaining == 0U)) { + JSON_TYPE end_type; + + if ((stack[depth - 1U].major_type == WOLFCOSE_CBOR_MAP) && + (stack[depth - 1U].expecting_key == 0U)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); + } + + end_type = stack[depth - 1U].major_type == WOLFCOSE_CBOR_MAP + ? JSON_OBJECT_END + : JSON_ARRAY_END; +#if defined(WOLFSENTRY_CONFIG_HAVE_JSON_DOM) && \ + defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) + jps->cbor_offset = decoder->idx; +#endif + ret = json_process(end_type, NULL, 0U, jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + --depth; + if (depth == 0U) + break; + continue; + } + + if ((depth > 0U) && + (stack[depth - 1U].major_type == WOLFCOSE_CBOR_MAP) && + (stack[depth - 1U].expecting_key != 0U)) + { + item_offset = decoder->idx; + *decoder_ret = wc_CBOR_DecodeHead(decoder, &item); + if (*decoder_ret < 0) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + --stack[depth - 1U].remaining; + if (item.majorType != WOLFCOSE_CBOR_TSTR) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM + if ((jps->section_under_construction == + S_U_C_USER_VALUE_JSON) && + (item.dataLen > WOLFSENTRY_MAX_LABEL_BYTES)) + { + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_KEY); + } +#endif +#if defined(WOLFSENTRY_CONFIG_HAVE_JSON_DOM) && \ + defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) + jps->cbor_offset = decoder->idx; +#endif + ret = json_process(JSON_KEY, item.data, item.dataLen, jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + stack[depth - 1U].expecting_key = 0U; + continue; + } + + if ((depth == 0U) && (root_seen != 0)) + break; + + item_offset = decoder->idx; + *decoder_ret = wc_CBOR_DecodeHead(decoder, &item); + if (*decoder_ret < 0) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + additional_info = decoder->cbuf[item_offset] & 0x1fU; + + if (depth == 0U) { + root_seen = 1; + if (item.majorType != WOLFCOSE_CBOR_MAP) + WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); + } else { + --stack[depth - 1U].remaining; + if (stack[depth - 1U].major_type == WOLFCOSE_CBOR_MAP) + stack[depth - 1U].expecting_key = 1U; + } + + if ((item.majorType == WOLFCOSE_CBOR_MAP) || + (item.majorType == WOLFCOSE_CBOR_ARRAY)) + { + JSON_TYPE begin_type; + + if (depth >= WOLFSENTRY_MAX_CBOR_NESTING) + WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); + + begin_type = item.majorType == WOLFCOSE_CBOR_MAP + ? JSON_OBJECT_BEG + : JSON_ARRAY_BEG; +#if defined(WOLFSENTRY_CONFIG_HAVE_JSON_DOM) && \ + defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) + jps->cbor_value_start_offset = item_offset; + jps->cbor_offset = decoder->idx; +#endif + ret = json_process(begin_type, NULL, 0U, jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + + stack[depth].major_type = item.majorType; + stack[depth].expecting_key = item.majorType == WOLFCOSE_CBOR_MAP + ? 1U + : 0U; + if (item.val > (uint64_t)SIZE_MAX) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + stack[depth].remaining = (size_t)item.val; + if (item.majorType == WOLFCOSE_CBOR_MAP) { + if (stack[depth].remaining > (SIZE_MAX / 2U)) + WOLFSENTRY_ERROR_RETURN(CONFIG_INVALID_VALUE); + stack[depth].remaining *= 2U; + } + ++depth; + } else { +#if defined(WOLFSENTRY_CONFIG_HAVE_JSON_DOM) && \ + defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) + jps->cbor_value_start_offset = item_offset; + jps->cbor_offset = decoder->idx; +#endif + ret = cbor_emit_scalar(jps, &item, additional_info); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + } + } + + if ((root_seen == 0) || (decoder->idx != decoder->bufSz) || + (jps->config_version != 1U)) + WOLFSENTRY_ERROR_RETURN(CONFIG_UNEXPECTED); + + WOLFSENTRY_RETURN_OK; +} + +WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_IN, + const unsigned char *cbor_in, + size_t cbor_in_len, + wolfsentry_config_load_flags_t load_flags, char *err_buf, size_t err_buf_size) { + struct wolfsentry_json_process_state *jps = NULL; + WOLFCOSE_CBOR_CTX decoder; wolfsentry_errcode_t ret; - JSON_INPUT_POS json_pos; + int decoder_ret; - if ((jps == NULL) || (*jps == NULL)) +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + (void)err_buf; + (void)err_buf_size; +#endif + + if ((cbor_in == NULL) || (cbor_in_len == 0U)) + WOLFSENTRY_ERROR_RETURN(INVALID_ARG); + if ((WOLFSENTRY_MAX_CBOR_TOTAL_LEN > 0U) && + (cbor_in_len > WOLFSENTRY_MAX_CBOR_TOTAL_LEN)) + { + WOLFSENTRY_ERROR_RETURN(NUMERIC_ARG_TOO_BIG); + } + decoder_ret = wc_CBOR_DecoderInit(&decoder, cbor_in, cbor_in_len); + if (decoder_ret < 0) WOLFSENTRY_ERROR_RETURN(INVALID_ARG); - if (WOLFSENTRY_CHECK_BITS((*jps)->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FINI)) { - if ((*jps)->fini_ret < 0) { - ret = wolfsentry_centijson_errcode_translate((*jps)->fini_ret); - goto out; - } - } else { - (*jps)->fini_ret = json_fini(&(*jps)->parser, &json_pos); - if ((*jps)->fini_ret < 0) { - if (err_buf != NULL) { - if (snprintf(err_buf, err_buf_size, "json_fini failed at offset %d, line %u, col %u, with code " WOLFSENTRY_ERRCODE_FMT ": %s.", - (int)json_pos.offset,json_pos.line_number, json_pos.column_number, (int)(*jps)->fini_ret, json_error_str((*jps)->fini_ret)) - >= (int)err_buf_size) - { - err_buf[err_buf_size - 1] = 0; - } - } - ret = wolfsentry_centijson_errcode_translate((*jps)->fini_ret); - goto out; + ret = config_state_init( + WOLFSENTRY_CONTEXT_ARGS_OUT, + load_flags, + CONFIG_INPUT_CBOR, + &jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(ret); + + ret = config_state_prepare(&jps); + if (ret < 0) + WOLFSENTRY_ERROR_RERETURN(config_state_fini(&jps, ret)); + + ret = cbor_process(jps, &decoder, &decoder_ret); +#ifndef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + if ((ret < 0) && (err_buf != NULL) && (err_buf_size > 0U)) { + int print_ret; + + if (decoder_ret < 0) { + print_ret = snprintf( + err_buf, + err_buf_size, + "CBOR decoding failed at offset " SIZET_FMT + ", decoder code %d", + decoder.idx, + decoder_ret); + } else { + print_ret = snprintf( + err_buf, + err_buf_size, + "CBOR configuration failed at offset " SIZET_FMT + ", wolfSentry code " WOLFSENTRY_ERRCODE_FMT, + decoder.idx, + (int)ret); } + if (print_ret >= (int)err_buf_size) + err_buf[err_buf_size - 1U] = 0; } +#endif + WOLFSENTRY_ERROR_RERETURN(config_state_fini(&jps, ret)); +} + +#endif /* WOLFSENTRY_WOLFCOSE */ + +static wolfsentry_errcode_t config_state_fini( + struct wolfsentry_json_process_state **jps, + wolfsentry_errcode_t ret) +{ + if ((jps == NULL) || (*jps == NULL)) + WOLFSENTRY_ERROR_RETURN(INVALID_ARG); + + if (ret < 0) + goto out; + +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS if (WOLFSENTRY_CHECK_BITS((*jps)->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN)) { ret = WOLFSENTRY_ERROR_ENCODE(OK); goto out; @@ -2026,23 +3128,32 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_fini( WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_context_free(JPSP_P_WOLFSENTRY_CONTEXT_ARGS_OUT)); } else ret = WOLFSENTRY_ERROR_ENCODE(OK); +#else + ret = WOLFSENTRY_ERROR_ENCODE(OK); +#endif out: -#ifdef WOLFSENTRY_HAVE_JSON_DOM +#ifdef WOLFSENTRY_CONFIG_HAVE_JSON_DOM (void)json_dom_clean(&(*jps)->dom_parser); #endif +#ifndef WOLFSENTRY_CONFIG_NO_TRANSACTIONS if ((*jps)->wolfsentry && ((*jps)->wolfsentry != (*jps)->wolfsentry_actual)) WOLFSENTRY_WARN_ON_FAILURE(wolfsentry_context_free(JPSP_P_WOLFSENTRY_CONTEXT_ARGS_OUT)); +#endif #ifdef WOLFSENTRY_THREADSAFE { wolfsentry_errcode_t _lock_ret; +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + _lock_ret = wolfsentry_context_unlock((*jps)->wolfsentry, (*jps)->thread); +#else if ((*jps)->got_reservation) _lock_ret = wolfsentry_context_unlock_and_abandon_reservation((*jps)->wolfsentry_actual, (*jps)->thread); else _lock_ret = wolfsentry_context_unlock((*jps)->wolfsentry_actual, (*jps)->thread); +#endif if (_lock_ret < 0) ret = _lock_ret; } @@ -2058,6 +3169,52 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_fini( WOLFSENTRY_RETURN_OK; } +#ifndef WOLFSENTRY_NO_JSON + +WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_fini( + struct wolfsentry_json_process_state **jps, + char *err_buf, + size_t err_buf_size) +{ + wolfsentry_errcode_t ret = WOLFSENTRY_ERROR_ENCODE(OK); + JSON_INPUT_POS json_pos; + +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + (void)err_buf; + (void)err_buf_size; +#endif + + if ((jps == NULL) || (*jps == NULL)) + WOLFSENTRY_ERROR_RETURN(INVALID_ARG); + + if (WOLFSENTRY_CHECK_BITS((*jps)->load_flags, WOLFSENTRY_CONFIG_LOAD_FLAG_FINI)) { + if ((*jps)->fini_ret < 0) + ret = wolfsentry_centijson_errcode_translate((*jps)->fini_ret); + } else { + (*jps)->fini_ret = json_fini(&(*jps)->parser, &json_pos); + if ((*jps)->fini_ret < 0) { +#ifndef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + if ((err_buf != NULL) && (err_buf_size > 0U)) { + int print_ret = snprintf( + err_buf, + err_buf_size, + "json_fini failed at offset %d, line %u, col %u, with code " WOLFSENTRY_ERRCODE_FMT ": %s.", + (int)json_pos.offset, + json_pos.line_number, + json_pos.column_number, + (int)(*jps)->fini_ret, + json_error_str((*jps)->fini_ret)); + if (print_ret >= (int)err_buf_size) + err_buf[err_buf_size - 1U] = 0; + } +#endif + ret = wolfsentry_centijson_errcode_translate((*jps)->fini_ret); + } + } + + WOLFSENTRY_ERROR_RERETURN(config_state_fini(jps, ret)); +} + WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_oneshot_ex( WOLFSENTRY_CONTEXT_ARGS_IN, const unsigned char *json_in, @@ -2096,3 +3253,5 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_oneshot( err_buf, err_buf_size)); } + +#endif /* !WOLFSENTRY_NO_JSON */ diff --git a/tests/unittests.c b/tests/unittests.c index 7a75686..2390409 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -4233,6 +4233,1189 @@ static int test_user_addr_families(void) { #endif /* TEST_USER_ADDR_FAMILIES */ +#ifdef TEST_CBOR + +#include +#ifndef FREERTOS +#include +#endif + +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + #define TEST_CBOR_COMMIT_FLAGS WOLFSENTRY_CONFIG_LOAD_FLAG_NONE +#else + #define TEST_CBOR_COMMIT_FLAGS WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT +#endif + +#if !defined(WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT) && \ + !defined(WOLFSENTRY_TEST_CBOR_NESTING_LIMIT) +static int test_cbor_rejections(WOLFSENTRY_CONTEXT_ARGS_IN) +{ + static const unsigned char empty_map[] = { 0xa0 }; + static const unsigned char trailing_data[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x00 + }; + static const unsigned char non_text_key[] = { 0xa1, 0x01, 0x01 }; + static const unsigned char tagged_root[] = { 0xc0, 0xa0 }; + static const unsigned char indefinite_map[] = { 0xbf, 0xff }; + static const unsigned char simple_root[] = { 0xf7 }; + static const unsigned char truncated_map[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01 + }; + static const unsigned char byte_string_value[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x01 + }; + static const unsigned char nonpreferred_version[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01 + }; + static const unsigned char float_version[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0xf9, 0x3c, 0x00 + }; + static const unsigned char typed_string_number[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, + 0x72, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x61, 0x78, + 0xa1, 0x66, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x01 + }; + static const unsigned char typed_base64_number[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, + 0x72, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x61, 0x78, + 0xa1, 0x66, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x01 + }; + static const unsigned char byte_string_default_event[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x70, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, + 0x65, 0x73, 0xa1, 0x6d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x78 + }; + static const unsigned char byte_string_parent_event[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x81, 0xa1, 0x6c, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x78 + }; + static const struct { + const unsigned char *data; + size_t len; + } invalid[] = { + { empty_map, sizeof empty_map }, + { trailing_data, sizeof trailing_data }, + { non_text_key, sizeof non_text_key }, + { tagged_root, sizeof tagged_root }, + { indefinite_map, sizeof indefinite_map }, + { simple_root, sizeof simple_root }, + { truncated_map, sizeof truncated_map }, + { byte_string_value, sizeof byte_string_value }, + { nonpreferred_version, sizeof nonpreferred_version }, + { float_version, sizeof float_version }, + { typed_string_number, sizeof typed_string_number }, + { typed_base64_number, sizeof typed_base64_number }, + { byte_string_default_event, sizeof byte_string_default_event }, + { byte_string_parent_event, sizeof byte_string_parent_event } + }; + char error[160]; + wolfsentry_errcode_t ret; + size_t i; + + for (i = 0U; i < (sizeof invalid / sizeof invalid[0]); ++i) { + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + invalid[i].data, + invalid[i].len, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); + } + + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + float_version, + sizeof float_version, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#ifndef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + WOLFSENTRY_EXIT_ON_FALSE(strstr(error, "wolfSentry code") != NULL); +#endif + + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + float_version, + sizeof float_version, + WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN | + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + error, + sizeof error); +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, IMPLEMENTATION_MISSING)); +#else + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_ERROR_CODE_IS(ret, INVALID_ARG)); +#endif + + return 0; +} + +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) +static int test_cbor_binary_route(WOLFSENTRY_CONTEXT_ARGS_IN) +{ + static const byte expected_remote[] = { 0xc0, 0x00, 0x02, 0x01 }; + static const byte expected_local[] = { 0xc6, 0x33, 0x64, 0x02 }; +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + static const byte expected_masked_remote[] = { + 0xcb, 0x00, 0x71, 0x00, 0xff, 0xff, 0xff, 0x00 + }; + static const byte expected_masked_local[] = { + 0xc6, 0x33, 0x64, 0x00, 0xff, 0xff, 0xff, 0xf0 + }; +#endif + struct wolfsentry_route_table *main_routes; + struct wolfsentry_cursor *cursor = NULL; + struct wolfsentry_route *route; + struct wolfsentry_route_exports exports; + wolfsentry_errcode_t ret; + int found = 0; +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + int found_masked = 0; +#endif + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_shared( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_get_main_table( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &main_routes)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_iterate_start( + WOLFSENTRY_CONTEXT_ARGS_OUT, + main_routes, + &cursor)); + for (ret = wolfsentry_route_table_iterate_current( + main_routes, cursor, &route); + ret >= 0; + ret = wolfsentry_route_table_iterate_next( + main_routes, cursor, &route)) + { + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_export( + WOLFSENTRY_CONTEXT_ARGS_OUT, + route, + &exports)); + if ((exports.sa_family == WOLFSENTRY_AF_INET) && + (exports.remote.addr_len == 32U) && + (exports.local.addr_len == 32U) && + (memcmp(exports.remote_address, + expected_remote, + sizeof expected_remote) == 0) && + (memcmp(exports.local_address, + expected_local, + sizeof expected_local) == 0)) + { + found = 1; + } +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + if ((exports.sa_family == WOLFSENTRY_AF_INET) && + (exports.remote.addr_len == 64U) && + (exports.local.addr_len == 64U) && + WOLFSENTRY_MASKIN_BITS( + exports.flags, + WOLFSENTRY_ROUTE_FLAG_REMOTE_ADDR_BITMASK | + WOLFSENTRY_ROUTE_FLAG_LOCAL_ADDR_BITMASK) && + (memcmp(exports.remote_address, + expected_masked_remote, + sizeof expected_masked_remote) == 0) && + (memcmp(exports.local_address, + expected_masked_local, + sizeof expected_masked_local) == 0)) + { + found_masked = 1; + } +#endif + } + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_table_iterate_end( + WOLFSENTRY_CONTEXT_ARGS_OUT, + main_routes, + &cursor)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FALSE(found != 0); +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + WOLFSENTRY_EXIT_ON_FALSE(found_masked != 0); +#endif + + return 0; +} +#endif +#endif + +#if defined(WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT) || \ + defined(WOLFSENTRY_TEST_CBOR_NESTING_LIMIT) +static int test_cbor_limits(void) +{ +#ifdef WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT + static const unsigned char at_limit[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01 + }; + static const unsigned char over_limit[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x00 + }; +#else + static const unsigned char at_limit[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, + 0x72, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x61, 0x78, + 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0x80 + }; + static const unsigned char over_limit[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, + 0x72, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x61, 0x78, + 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0x81, 0x80 + }; +#endif + struct wolfsentry_context *wolfsentry = NULL; + struct wolfsentry_eventconfig initial_config; + char error[160]; + wolfsentry_errcode_t ret; + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + memset(&initial_config, 0, sizeof initial_config); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_init( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &initial_config, + &wolfsentry)); +#ifdef WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT + WOLFSENTRY_EXIT_ON_FALSE( + sizeof at_limit == WOLFSENTRY_MAX_CBOR_TOTAL_LEN); +#else + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_MAX_CBOR_NESTING == 4U); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + at_limit, + sizeof at_limit, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + over_limit, + sizeof over_limit, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); +#ifdef WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, NUMERIC_ARG_TOO_BIG)); +#else + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_UNEXPECTED)); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER( + WOLFSENTRY_THREAD_FLAG_NONE)); + + return 0; +} +#endif + +static int test_cbor(void) +{ +#if defined(WOLFSENTRY_TEST_CBOR_TOTAL_LIMIT) || \ + defined(WOLFSENTRY_TEST_CBOR_NESTING_LIMIT) + return test_cbor_limits(); +#else +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + static const unsigned char text_number_cbor[] = { + 0xa1, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x61, 0x31 + }; +#endif +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + static const unsigned char binary_address_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, + 0x81, 0xa4, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x02, + 0x66, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0xa2, 0x67, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x44, 0xc0, 0x00, 0x02, 0x01, 0x6b, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x2d, 0x62, 0x69, 0x74, 0x73, 0x18, 0x20, 0x65, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0xa2, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x44, 0xc6, 0x33, 0x64, 0x02, 0x6b, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x2d, 0x62, 0x69, 0x74, 0x73, 0x18, 0x20 + }; +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + static const unsigned char binary_bitmask_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x81, 0xa4, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x02, 0x66, 0x72, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0xa2, 0x67, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x44, + 0xff, 0xff, 0xff, 0x00, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x44, 0xcb, 0x00, 0x71, 0x01, 0x65, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0xa2, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x44, + 0xc6, 0x33, 0x64, 0x05, 0x67, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x73, + 0x6b, 0x44, 0xff, 0xff, 0xff, 0xf0 + }; +#endif + static const unsigned char can_address_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x81, 0xa3, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x1d, 0x66, 0x72, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0xa1, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x1a, 0xff, 0xff, 0xff, 0xff + }; + static const unsigned char can_address_overflow_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x81, 0xa3, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x1d, 0x66, 0x72, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0xa1, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char can_address_negative_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x81, 0xa3, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x1d, 0x66, 0x72, 0x65, 0x6d, 0x6f, + 0x74, 0x65, 0xa1, 0x67, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x20 + }; +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES + static const unsigned char text_address_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, + 0x81, 0xa3, 0x6c, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2d, 0x69, 0x6e, 0xf5, 0x66, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x02, + 0x66, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0xa1, 0x67, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, + 0x2e, 0x31 + }; +#endif +#endif +#if defined(WOLFSENTRY_CONFIG_NO_ROUTES) || \ + defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) || \ + defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTS) || \ + defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTCONFIG) || \ + defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) + static const unsigned char config_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x70, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0xa1, 0x6e, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x66, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74 + }; +#if defined(WOLFSENTRY_CONFIG_NO_ROUTES) || \ + defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) || \ + defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTS) || \ + defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTCONFIG) + static const unsigned char disabled_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, +#if defined(WOLFSENTRY_CONFIG_NO_ROUTES) + 0x66, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x80 +#elif defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) + 0x66, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x81, 0xa1, 0x66, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x64, 0x69, 0x6e, 0x65, 0x74 +#elif defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + 0x66, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x81, 0xa1, 0x66, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0xa0 +#elif defined(WOLFSENTRY_CONFIG_NO_EVENTS) + 0x66, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x80 +#elif defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) + 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0xa0 +#else + 0x6d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0xa0 +#endif + }; +#endif +#if defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) && \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + static const unsigned char current_event_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x81, 0xa2, 0x65, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x6d, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x2d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x81, 0x6e, 0x25, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2d, 0x70, 0x65, 0x65, + 0x72, 0x2d, 0x76, 0x31 + }; + static const unsigned char legacy_event_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x66, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x81, 0xa2, 0x65, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x6c, 0x6c, 0x65, 0x67, + 0x61, 0x63, 0x79, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x67, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x80 + }; +#endif + struct wolfsentry_context *wolfsentry = NULL; + struct wolfsentry_eventconfig initial_config; + wolfsentry_action_res_t default_policy = WOLFSENTRY_ACTION_RES_NONE; + char error[160]; + wolfsentry_errcode_t ret; + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + memset(&initial_config, 0, sizeof initial_config); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_init( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &initial_config, + &wolfsentry)); +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + text_number_cbor, + sizeof text_number_cbor, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#endif +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + config_cbor, + sizeof config_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, IMPLEMENTATION_MISSING)); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + config_cbor, + sizeof config_cbor, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + WOLFSENTRY_EXIT_ON_FALSE(test_cbor_rejections( + WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); +#if defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) && \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + current_event_cbor, + sizeof current_event_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + legacy_event_cbor, + sizeof legacy_event_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_KEY)); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_shared( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_default_policy_get( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &default_policy)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_MASKIN_BITS( + default_policy, + WOLFSENTRY_ACTION_RES_REJECT)); + +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + binary_address_cbor, + sizeof binary_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + binary_bitmask_cbor, + sizeof binary_bitmask_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); +#endif + WOLFSENTRY_EXIT_ON_FALSE(test_cbor_binary_route( + WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_cbor, + sizeof can_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_overflow_cbor, + sizeof can_address_overflow_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, NUMERIC_ARG_TOO_BIG)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_negative_cbor, + sizeof can_address_negative_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + text_address_cbor, + sizeof text_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#endif +#endif + +#if defined(WOLFSENTRY_CONFIG_NO_ROUTES) || \ + defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) || \ + defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTS) || \ + defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTCONFIG) +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + error[0] = 'x'; +#endif + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + disabled_cbor, + sizeof disabled_cbor, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + WOLFSENTRY_EXIT_ON_FALSE(error[0] == 'x'); +#endif +#endif + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER( + WOLFSENTRY_THREAD_FLAG_NONE)); + return 0; +#else + static const unsigned char config_cbor[] = { + 0xa5, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0xa2, 0x74, 0x6d, 0x61, 0x78, + 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2d, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x05, 0x78, 0x1f, 0x64, 0x65, 0x72, 0x6f, + 0x67, 0x2d, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x2d, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0xf4, 0x70, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0xa1, 0x6e, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x66, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x6d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x2d, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x81, 0xa2, + 0x65, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x6a, 0x63, 0x62, 0x6f, 0x72, 0x2d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x68, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x05, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0xa5, 0x68, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, + 0x67, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x66, 0x61, 0x6e, 0x73, 0x77, + 0x65, 0x72, 0x18, 0x2a, 0x67, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0xf5, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0xf9, 0x3e, 0x00, 0x68, 0x6e, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x21 + }; + static const unsigned char float_types_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa3, 0x63, 0x6f, 0x6e, 0x65, 0xf9, 0x3c, + 0x00, 0x6d, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2d, 0x7a, + 0x65, 0x72, 0x6f, 0xfb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x68, 0x75, 0x67, 0x65, 0xfb, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + }; + static const unsigned char implicit_int64_overflow_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x67, 0x74, 0x6f, 0x6f, 0x2d, 0x62, + 0x69, 0x67, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char implicit_uint64_max_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x6b, 0x77, 0x61, 0x79, 0x2d, 0x74, + 0x6f, 0x6f, 0x2d, 0x62, 0x69, 0x67, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff + }; +#ifdef WOLFSENTRY_HAVE_JSON_DOM + static const unsigned char nested_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x66, 0x6e, 0x65, 0x73, 0x74, 0x65, + 0x64, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0xa2, 0x61, 0x61, 0x83, 0x01, + 0xf5, 0xf6, 0x61, 0x73, 0x61, 0x78 + }; + static const unsigned char json_integer_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x6c, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0xa1, 0x64, 0x6a, 0x73, 0x6f, + 0x6e, 0x01 + }; + static const unsigned char json_float_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x6a, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0xfb, + 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char json_nan_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x68, 0x6a, 0x73, 0x6f, 0x6e, 0x2d, + 0x6e, 0x61, 0x6e, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0x81, 0xfb, 0x7f, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; +#ifndef WOLFSENTRY_JSON_VALUE_MAX_BYTES + static const unsigned char json_key_at_limit_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x69, 0x6b, 0x65, 0x79, 0x2d, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0xa1, 0x78, + 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xf6 + }; + static const unsigned char json_key_over_limit_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x68, 0x6b, 0x65, 0x79, 0x2d, 0x6f, + 0x76, 0x65, 0x72, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0xa1, 0x78, 0x21, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xf6 + }; +#endif +#if defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) && \ + (WOLFSENTRY_JSON_VALUE_MAX_BYTES == 10) + static const unsigned char json_string_size_10_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x67, 0x73, 0x69, 0x7a, 0x65, 0x2d, + 0x31, 0x30, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0x69, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61 + }; + static const unsigned char json_string_size_11_cbor[] = { + 0xa2, 0x78, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x01, 0x6b, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0xa1, 0x67, 0x73, 0x69, 0x7a, 0x65, 0x2d, + 0x31, 0x31, 0xa1, 0x64, 0x6a, 0x73, 0x6f, 0x6e, 0x6a, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61 + }; +#endif +#endif + struct wolfsentry_context *wolfsentry = NULL; + struct wolfsentry_eventconfig initial_config; + struct wolfsentry_eventconfig loaded_config; + struct wolfsentry_kv_pair_internal *reference = NULL; + const char *string_value = NULL; + int string_len = 0; + int64_t answer = 0; + int64_t negative = 0; + wolfsentry_kv_type_t enabled = WOLFSENTRY_KV_FALSE; + double ratio = 0.0; + double float_value = 0.0; + uint64_t float_bits = 0U; + wolfsentry_action_res_t default_policy = WOLFSENTRY_ACTION_RES_NONE; +#ifdef WOLFSENTRY_HAVE_JSON_DOM + JSON_VALUE *json_value = NULL; +#ifndef FREERTOS + const char *old_numeric_locale; + char saved_numeric_locale[64]; + int changed_numeric_locale = 0; +#endif +#endif + char error[160]; + wolfsentry_errcode_t ret; + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + memset(&initial_config, 0, sizeof initial_config); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_init( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &initial_config, + &wolfsentry)); + +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + text_number_cbor, + sizeof text_number_cbor, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#endif + +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + config_cbor, + sizeof config_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, IMPLEMENTATION_MISSING)); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + config_cbor, + sizeof config_cbor, + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + WOLFSENTRY_EXIT_ON_FALSE(test_cbor_rejections( + WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_defaultconfig_get( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &loaded_config)); + WOLFSENTRY_EXIT_ON_FALSE(loaded_config.max_connection_count == 5U); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_lock_shared( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_route_default_policy_get( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &default_policy)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_context_unlock( + WOLFSENTRY_CONTEXT_ARGS_OUT)); + WOLFSENTRY_EXIT_ON_FALSE(WOLFSENTRY_MASKIN_BITS( + default_policy, + WOLFSENTRY_ACTION_RES_REJECT)); + +#if !defined(WOLFSENTRY_CONFIG_NO_ROUTES) && \ + !defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + binary_address_cbor, + sizeof binary_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); +#ifdef WOLFSENTRY_ADDR_BITMASK_MATCHING + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + binary_bitmask_cbor, + sizeof binary_bitmask_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); +#endif + WOLFSENTRY_EXIT_ON_FALSE(test_cbor_binary_route( + WOLFSENTRY_CONTEXT_ARGS_OUT) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_cbor, + sizeof can_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_overflow_cbor, + sizeof can_address_overflow_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, NUMERIC_ARG_TOO_BIG)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + can_address_negative_cbor, + sizeof can_address_negative_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#ifdef WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + text_address_cbor, + sizeof text_address_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); +#endif +#endif + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_event_get_config( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "cbor-event", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &loaded_config)); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_string( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "greeting", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &string_value, + &string_len, + &reference)); + WOLFSENTRY_EXIT_ON_FALSE(string_len == 5); + WOLFSENTRY_EXIT_ON_FALSE(memcmp(string_value, "hello", 5U) == 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_release_record( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &reference)); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_sint( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "answer", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &answer)); + WOLFSENTRY_EXIT_ON_FALSE(answer == 42); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_sint( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "negative", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &negative)); + WOLFSENTRY_EXIT_ON_FALSE(negative == -2); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_bool( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "enabled", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &enabled)); + WOLFSENTRY_EXIT_ON_FALSE(enabled == WOLFSENTRY_KV_TRUE); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_float( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "ratio", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &ratio)); + WOLFSENTRY_EXIT_ON_FALSE(ratio == 1.5); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + float_types_cbor, + sizeof float_types_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_float( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "one", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &float_value)); + WOLFSENTRY_EXIT_ON_FALSE(float_value == 1.0); + ret = wolfsentry_user_value_get_sint( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "one", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &answer); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_float( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "negative-zero", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &float_value)); + memcpy(&float_bits, &float_value, sizeof float_bits); + WOLFSENTRY_EXIT_ON_FALSE(float_bits == UINT64_C(0x8000000000000000)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_float( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "huge", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &float_value)); + WOLFSENTRY_EXIT_ON_FALSE(float_value < -1.0e300); + + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + implicit_int64_overflow_cbor, + sizeof implicit_int64_overflow_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + implicit_uint64_max_cbor, + sizeof implicit_uint64_max_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_VALUE)); + +#ifdef WOLFSENTRY_HAVE_JSON_DOM + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_integer_cbor, + sizeof json_integer_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_json( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "json-integer", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &json_value, + &reference)); + WOLFSENTRY_EXIT_ON_FALSE(json_value != NULL); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_release_record( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &reference)); + +#if defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) && \ + (WOLFSENTRY_JSON_VALUE_MAX_BYTES < 9) + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_float_cbor, + sizeof json_float_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_JSON_VALUE_SIZE)); +#else +#ifndef FREERTOS + old_numeric_locale = setlocale(LC_NUMERIC, NULL); + if ((old_numeric_locale != NULL) && + (strlen(old_numeric_locale) < sizeof saved_numeric_locale)) + { + memcpy(saved_numeric_locale, + old_numeric_locale, + strlen(old_numeric_locale) + 1U); + if (setlocale(LC_NUMERIC, "de_DE.UTF-8") != NULL) + changed_numeric_locale = 1; + } +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_float_cbor, + sizeof json_float_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); +#ifndef FREERTOS + if (changed_numeric_locale != 0) + WOLFSENTRY_EXIT_ON_FALSE(setlocale( + LC_NUMERIC, + saved_numeric_locale) != NULL); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_json( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "json-float", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &json_value, + &reference)); + WOLFSENTRY_EXIT_ON_FALSE(json_value != NULL); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_release_record( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &reference)); +#endif + + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_nan_cbor, + sizeof json_nan_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); + +#ifndef WOLFSENTRY_JSON_VALUE_MAX_BYTES + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_key_at_limit_cbor, + sizeof json_key_at_limit_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_key_over_limit_cbor, + sizeof json_key_over_limit_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_KEY)); +#endif + +#if defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) && \ + (WOLFSENTRY_JSON_VALUE_MAX_BYTES == 10) + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_string_size_10_cbor, + sizeof json_string_size_10_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + json_string_size_11_cbor, + sizeof json_string_size_11_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_JSON_VALUE_SIZE)); +#endif + +#if defined(WOLFSENTRY_JSON_VALUE_MAX_BYTES) && \ + (WOLFSENTRY_JSON_VALUE_MAX_BYTES < 11) + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + nested_cbor, + sizeof nested_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_JSON_VALUE_SIZE)); +#else + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + nested_cbor, + sizeof nested_cbor, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_json( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "nested", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &json_value, + &reference)); + WOLFSENTRY_EXIT_ON_FALSE(json_value != NULL); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_release_record( + WOLFSENTRY_CONTEXT_ARGS_OUT, + &reference)); +#endif +#endif + +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + error[0] = 'x'; +#endif + ret = wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + config_cbor, + sizeof config_cbor - 1U, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | + TEST_CBOR_COMMIT_FLAGS, + error, + sizeof error); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); +#ifdef WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES + WOLFSENTRY_EXIT_ON_FALSE(error[0] == 'x'); +#endif + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_user_value_get_sint( + WOLFSENTRY_CONTEXT_ARGS_OUT, + "answer", + WOLFSENTRY_LENGTH_NULL_TERMINATED, + &answer)); + WOLFSENTRY_EXIT_ON_FALSE(answer == 42); + + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER( + WOLFSENTRY_THREAD_FLAG_NONE)); + + return 0; +#endif +#endif +} + +#undef TEST_CBOR_COMMIT_FLAGS + +#endif /* TEST_CBOR */ + #ifdef TEST_JSON #include "wolfsentry/wolfsentry_json.h" @@ -4241,6 +5424,138 @@ static int test_user_addr_families(void) { #endif static int test_json(const char *fname, const char *extra_fname) { +#if defined(WOLFSENTRY_CONFIG_NO_TRANSACTIONS) || \ + defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) +#if defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) && \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + static const unsigned char valid_config[] = + "{\"wolfsentry-config-version\":1,\"events\":[{\"label\":" + "\"current-event\",\"match-actions\":[\"%track-peer-v1\"]}]}"; + static const unsigned char legacy_config[] = + "{\"wolfsentry-config-version\":1,\"events\":[{\"label\":" + "\"legacy-event\",\"actions\":[]}]}"; +#else + static const unsigned char valid_config[] = + "{\"wolfsentry-config-version\":1,\"default-policies\":" + "{\"default-policy\":\"reject\"}}"; +#endif + struct wolfsentry_context *wolfsentry = NULL; + struct wolfsentry_eventconfig config; + wolfsentry_config_load_flags_t test_load_flags; +#if defined(WOLFSENTRY_CONFIG_NO_TRANSACTIONS) || \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + wolfsentry_errcode_t ret; +#endif + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + (void)fname; + (void)extra_fname; + memset(&config, 0, sizeof config); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_init( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &config, + &wolfsentry)); +#ifdef WOLFSENTRY_CONFIG_NO_TRANSACTIONS + ret = wolfsentry_config_json_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + valid_config, + sizeof valid_config - 1U, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + NULL, + 0U); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, IMPLEMENTATION_MISSING)); + test_load_flags = WOLFSENTRY_CONFIG_LOAD_FLAG_NONE; +#else + test_load_flags = WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT; +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_json_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + valid_config, + sizeof valid_config - 1U, + test_load_flags, + NULL, + 0U)); +#if defined(WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX) && \ + !defined(WOLFSENTRY_CONFIG_NO_EVENTS) + ret = wolfsentry_config_json_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + legacy_config, + sizeof legacy_config - 1U, + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH | test_load_flags, + NULL, + 0U); + WOLFSENTRY_EXIT_ON_FALSE( + WOLFSENTRY_ERROR_CODE_IS(ret, CONFIG_INVALID_KEY)); +#endif + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER( + WOLFSENTRY_THREAD_FLAG_NONE)); + WOLFSENTRY_RETURN_OK; +#elif defined(WOLFSENTRY_CONFIG_NO_ROUTES) || \ + defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) || \ + defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTS) || \ + defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) || \ + defined(WOLFSENTRY_CONFIG_NO_EVENTCONFIG) + static const unsigned char valid_config[] = + "{\"wolfsentry-config-version\":1,\"default-policies\":" + "{\"default-policy\":\"reject\"}}"; +#if defined(WOLFSENTRY_CONFIG_NO_ROUTES) + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"routes\":[]}"; +#elif defined(WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES) + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"routes\":[{\"family\":\"inet\"}]}"; +#elif defined(WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS) + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"routes\":[{\"remote\":{}}]}"; +#elif defined(WOLFSENTRY_CONFIG_NO_EVENTS) + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"events\":[]}"; +#elif defined(WOLFSENTRY_CONFIG_NO_USER_VALUES) + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"user-values\":{}}"; +#else + static const unsigned char disabled_config[] = + "{\"wolfsentry-config-version\":1,\"config-update\":{}}"; +#endif + struct wolfsentry_context *wolfsentry = NULL; + struct wolfsentry_eventconfig config; + wolfsentry_errcode_t ret; + WOLFSENTRY_THREAD_HEADER_CHECKED(WOLFSENTRY_THREAD_FLAG_NONE); + + (void)fname; + (void)extra_fname; + memset(&config, 0, sizeof config); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_init( + wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(WOLFSENTRY_TEST_HPI), + &config, + &wolfsentry)); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_config_json_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + valid_config, + sizeof valid_config - 1U, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + NULL, + 0U)); + ret = wolfsentry_config_json_oneshot( + WOLFSENTRY_CONTEXT_ARGS_OUT, + disabled_config, + sizeof disabled_config - 1U, + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT, + NULL, + 0U); + WOLFSENTRY_EXIT_ON_FALSE(ret < 0); + WOLFSENTRY_EXIT_ON_FAILURE(wolfsentry_shutdown( + WOLFSENTRY_CONTEXT_ARGS_OUT_EX(&wolfsentry))); + WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER( + WOLFSENTRY_THREAD_FLAG_NONE)); + WOLFSENTRY_RETURN_OK; +#else wolfsentry_errcode_t ret; struct wolfsentry_context *wolfsentry; wolfsentry_ent_id_t id; @@ -5464,6 +6779,7 @@ static int test_json(const char *fname, const char *extra_fname) { WOLFSENTRY_EXIT_ON_FAILURE(WOLFSENTRY_THREAD_TAILER(WOLFSENTRY_THREAD_FLAG_NONE)); WOLFSENTRY_RETURN_OK; +#endif } #endif /* TEST_JSON */ @@ -5767,6 +7083,14 @@ int main(int argc, char* argv[]) { } #endif +#ifdef TEST_CBOR + ret = test_cbor(); + if (! WOLFSENTRY_ERROR_CODE_IS(ret, OK)) { + (void)fprintf(stderr, "test_cbor failed\n"); + err = 1; + } +#endif + #ifdef TEST_JSON #if defined(WOLFSENTRY_PROTOCOL_NAMES) && !defined(WOLFSENTRY_NO_GETPROTOBY) #ifdef EXTRA_TEST_JSON_CONFIG_PATH diff --git a/wolfsentry/wolfsentry.h b/wolfsentry/wolfsentry.h index 225980b..63e5b6d 100644 --- a/wolfsentry/wolfsentry.h +++ b/wolfsentry/wolfsentry.h @@ -3368,6 +3368,10 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_base64_decode( #include "wolfsentry/wolfsentry_wolfip.h" #endif +#ifdef WOLFSENTRY_WOLFCOSE + #include "wolfsentry/wolfsentry_cbor.h" +#endif + #ifdef WOLFSENTRY_NETXDUO #include "wolfsentry/wolfsentry_netxduo.h" #endif diff --git a/wolfsentry/wolfsentry_cbor.h b/wolfsentry/wolfsentry_cbor.h new file mode 100644 index 0000000..17e0070 --- /dev/null +++ b/wolfsentry/wolfsentry_cbor.h @@ -0,0 +1,44 @@ +/* + * wolfsentry_cbor.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfSentry. + * + * wolfSentry is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/*! @file wolfsentry_cbor.h + \brief Loading wolfSentry configuration from CBOR using wolfCOSE. + */ + +#ifndef WOLFSENTRY_CBOR_H +#define WOLFSENTRY_CBOR_H + +#include "wolfsentry.h" +#include "wolfsentry_config.h" + +#ifndef WOLFSENTRY_MAX_CBOR_NESTING +#define WOLFSENTRY_MAX_CBOR_NESTING 16U +#endif +#if WOLFSENTRY_MAX_CBOR_NESTING < 1U +#error WOLFSENTRY_MAX_CBOR_NESTING must be at least 1. +#endif + +#ifndef WOLFSENTRY_MAX_CBOR_TOTAL_LEN +#define WOLFSENTRY_MAX_CBOR_TOTAL_LEN (10U * 1024U * 1024U) +#endif + +WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_cbor_oneshot( + WOLFSENTRY_CONTEXT_ARGS_IN, + const unsigned char *cbor_in, + size_t cbor_in_len, + wolfsentry_config_load_flags_t load_flags, + char *err_buf, + size_t err_buf_size); + /*!< \brief Load a complete CBOR configuration from an in-memory buffer. */ + +#endif /* WOLFSENTRY_CBOR_H */ diff --git a/wolfsentry/wolfsentry_config.h b/wolfsentry/wolfsentry_config.h new file mode 100644 index 0000000..7dca07f --- /dev/null +++ b/wolfsentry/wolfsentry_config.h @@ -0,0 +1,86 @@ +/* + * wolfsentry_config.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfSentry. + * + * wolfSentry is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/*! @file wolfsentry_config.h + \brief Format-independent configuration loader options. + */ + +#ifndef WOLFSENTRY_CONFIG_H +#define WOLFSENTRY_CONFIG_H + +#ifndef WOLFSENTRY_NO_STDINT_H +#include +#endif + +/* + * Optional configuration loader profiles. Each disabled section is rejected + * as an invalid configuration key rather than being silently ignored. + * + * WOLFSENTRY_CONFIG_NO_ROUTES omits static route loading. + * WOLFSENTRY_CONFIG_NO_ADDR_FAMILY_NAMES requires numeric route families. + * WOLFSENTRY_CONFIG_NO_ROUTE_ENDPOINTS omits remote and local route endpoints. + * WOLFSENTRY_CONFIG_NO_EVENTS omits event loading. + * WOLFSENTRY_CONFIG_NO_USER_VALUES omits user-value loading. + * WOLFSENTRY_CONFIG_NO_EVENTCONFIG omits global and per-event configuration. + * WOLFSENTRY_CONFIG_NO_TRANSACTIONS omits clone, dry-run, and commit support. + * WOLFSENTRY_CONFIG_NO_LEGACY_EVENT_SYNTAX omits pre-1.4 event aliases. + * WOLFSENTRY_CONFIG_NO_TEXT_NUMBERS requires native CBOR numeric values. + * WOLFSENTRY_CONFIG_NO_TEXT_ADDRESSES requires native CBOR byte-string addresses. + * WOLFSENTRY_CONFIG_NO_ERROR_MESSAGES omits detailed parser error messages. + * WOLFSENTRY_CONFIG_MINIMAL enables the four section-omission options. + */ +#ifdef WOLFSENTRY_CONFIG_MINIMAL + #ifndef WOLFSENTRY_CONFIG_NO_ROUTES + #define WOLFSENTRY_CONFIG_NO_ROUTES + #endif + #ifndef WOLFSENTRY_CONFIG_NO_EVENTS + #define WOLFSENTRY_CONFIG_NO_EVENTS + #endif + #ifndef WOLFSENTRY_CONFIG_NO_USER_VALUES + #define WOLFSENTRY_CONFIG_NO_USER_VALUES + #endif + #ifndef WOLFSENTRY_CONFIG_NO_EVENTCONFIG + #define WOLFSENTRY_CONFIG_NO_EVENTCONFIG + #endif +#endif + +typedef uint32_t wolfsentry_config_load_flags_t; + /*!< \brief Type for holding flag bits from #wolfsentry_config_load_flags. */ + +/*! \brief Flags to be `OR`d together to control configuration loading. */ +enum wolfsentry_config_load_flags { + WOLFSENTRY_CONFIG_LOAD_FLAG_NONE = 0U, + /*!< \brief Use the default behavior. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH = 1U << 0U, + /*!< \brief Add to the current configuration instead of replacing it. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN = 1U << 1U, + /*!< \brief Test the load without updating the current configuration. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT = 1U << 2U, + /*!< \brief Load into a clone before replacing the current configuration. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS = 1U << 3U, + /*!< \brief Skip routes and events in the supplied configuration. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_ABORT = 1U << 4U, + /*!< \brief Reject duplicate keys in structured user values. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USEFIRST = 1U << 5U, + /*!< \brief Keep the first duplicate key in structured user values. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USELAST = 1U << 6U, + /*!< \brief Keep the last duplicate key in structured user values. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_MAINTAINDICTORDER = 1U << 7U, + /*!< \brief Retain dictionary insertion order in structured user values. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_FLUSH_ONLY_ROUTES = 1U << 8U, + /*!< \brief Flush routes while retaining events and user values. @hideinitializer */ + WOLFSENTRY_CONFIG_LOAD_FLAG_FINI = 1U << 30U + /*!< \brief Reserved for internal use. @hideinitializer */ +}; + +#endif /* WOLFSENTRY_CONFIG_H */ diff --git a/wolfsentry/wolfsentry_json.h b/wolfsentry/wolfsentry_json.h index ce8cfda..bc2bba6 100644 --- a/wolfsentry/wolfsentry_json.h +++ b/wolfsentry/wolfsentry_json.h @@ -30,6 +30,7 @@ #define WOLFSENTRY_JSON_H #include "wolfsentry.h" +#include "wolfsentry_config.h" #ifndef WOLFSENTRY #define WOLFSENTRY @@ -57,35 +58,6 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_centijson_errcode_translate(wolfs */ #endif -typedef uint32_t wolfsentry_config_load_flags_t; - /*!< \brief Type for holding flag bits from #wolfsentry_config_load_flags */ - -/*! \brief Flags to be `OR`d together to communicate options to wolfsentry_config_json_init() */ -enum wolfsentry_config_load_flags { - WOLFSENTRY_CONFIG_LOAD_FLAG_NONE = 0U, - /*!< \brief Default behavior @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH = 1U << 0U, - /*!< \brief Add to current configuration, rather than replacing it. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_DRY_RUN = 1U << 1U, - /*!< \brief Test the load operation, as modified by other flags, without updating current configuration. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_LOAD_THEN_COMMIT = 1U << 2U, - /*!< \brief Test the load operation before replacing the current configuration. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_NO_ROUTES_OR_EVENTS = 1U << 3U, - /*!< \brief Skip routes and events in the supplied configuration. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_ABORT = 1U << 4U, - /*!< \brief When loading JSON user values, treat as an error when duplicate keys are found. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USEFIRST = 1U << 5U, - /*!< \brief When loading JSON user values, when duplicate keys are found, keep the first one. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_DUPKEY_USELAST = 1U << 6U, - /*!< \brief When loading JSON user values, when duplicate keys are found, keep the last one. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_JSON_DOM_MAINTAINDICTORDER = 1U << 7U, - /*!< \brief When loading JSON user values, store extra sequence information so that dictionaries are rendered in same sequence by `json_dom_dump()` and `wolfsentry_kv_render_value()`. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_FLUSH_ONLY_ROUTES = 1U << 8U, - /*!< \brief Don't flush the events or user values, just flush the routes, before loading incremental configuration JSON. @hideinitializer */ - WOLFSENTRY_CONFIG_LOAD_FLAG_FINI = 1U << 30U - /*!< \brief Internal use. @hideinitializer */ -}; - struct wolfsentry_json_process_state; WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_config_json_init(