Implement Linux kernel module offline integrity hash calculation:

Add:

* linuxkm/linuxkm-fips-hash.c
* linuxkm/linuxkm-fips-hash-wrapper.sh
* linuxkm/linuxkm_memory.h

Move from linuxkm/module_hooks.c to linuxkm/linuxkm_memory.c:
* reloc_layouts[]
* find_reloc_tab_offset()
* the body of wc_linuxkm_normalize_relocations() as wc_reloc_normalize_text()
* most of updateFipsHash() as wc_fips_generate_hash()

Move from linuxkm/linuxkm_wc_port.h to linuxkm/linuxkm_memory.h:
* struct wc_linuxkm_pie_reloc_tab_ent
* enum wc_reloc_dest_segment
* enum wc_reloc_type

linuxkm/Makefile:
* Update GENERATE_RELOC_TAB recipe to populate new fields in struct wc_reloc_table_ent.
* Add targets:
  * libwolfssl-user-build/src/.libs/libwolfssl.so
  * linuxkm-fips-hash
  * module-with-matching-fips-hash
  * module-with-matching-fips-hash-no-sign
* Add support for alternate target module name, via LIBWOLFSSL_NAME make variable.

linuxkm/linuxkm_wc_port.h and linuxkm/module_hooks.c:
* Fixes to make linuxkm-pie work with CONFIG_KASAN.
* Implement WC_LINUXKM_STACK_DEBUG:
  * wc_linuxkm_stack_bottom()
  * wc_linuxkm_stack_top()
  * wc_linuxkm_stack_current()
  * wc_linuxkm_stack_left()
  * wc_linuxkm_stack_hwm_prepare()
  * wc_linuxkm_stack_hwm_measure_rel()
  * wc_linuxkm_stack_hwm_measure_total()

wolfssl/wolfcrypt/settings.h:
* When WOLFSSL_KERNEL_MODE, make sure WOLFSSL_GENERAL_ALIGNMENT is at least SIZEOF_LONG.
* When WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE, make sure WOLFSSL_BASE16 is defined.

configure.ac and wolfcrypt/benchmark/benchmark.c: Disable scrypt when KERNEL_MODE_DEFAULTS, due to excessive memory requirements.
This commit is contained in:
Daniel Pouzzner
2026-02-18 23:58:11 -06:00
parent 0c19fb17d6
commit f376ae210e
17 changed files with 2080 additions and 787 deletions
+2
View File
@@ -245,6 +245,8 @@ linuxkm/linuxkm/get_thread_size
linuxkm/linuxkm
linuxkm/src
linuxkm/patches/src
linuxkm/libwolfssl-user-build
linuxkm/linuxkm-fips-hash
*.nds
# Generated during FreeBSD kernel module build.
+4 -1
View File
@@ -141,6 +141,8 @@ CONFIG_PTHREAD_IPC
CONFIG_SCHED_INFO
CONFIG_SMP
CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
CONFIG_STACK_GROWSUP
CONFIG_THREAD_INFO_IN_TASK
CONFIG_TIMER_TASK_STACK_DEPTH
CONFIG_TIMER_TASK_STACK_SIZE
CONFIG_TLS_STACK_WOLFSSL
@@ -294,6 +296,7 @@ HAVE_THREADX
HAVE_TM_TYPE
HAVE_VALIDATE_DATE
HAVE_VA_COPY
HAVE_WC_FIPS_OPTEST_CONTESTFAILURE_EXPORT
HAVE_X448
HONOR_MATH_USED_LENGTH
HSM_KEY_TYPE_HMAC_224
@@ -658,7 +661,7 @@ WIFI_101
WIFI_AVAILABLE
WIFI_NINA
WIN_REUSE_CRYPT_HANDLE
WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT
WOLFSENTRY_H
WOLFSENTRY_NO_JSON
WOLFSSL_32BIT_MILLI_TIME
+8 -1
View File
@@ -225,7 +225,8 @@ if BUILD_LINUXKM
CFLAGS_FPU_DISABLE CFLAGS_FPU_ENABLE CFLAGS_SIMD_DISABLE CFLAGS_SIMD_ENABLE \
CFLAGS_AUTO_VECTORIZE_DISABLE CFLAGS_AUTO_VECTORIZE_ENABLE \
ASFLAGS_FPU_DISABLE_SIMD_ENABLE ASFLAGS_FPU_ENABLE_SIMD_DISABLE \
ASFLAGS_FPUSIMD_DISABLE ASFLAGS_FPUSIMD_ENABLE ENABLED_KERNEL_BENCHMARKS
ASFLAGS_FPUSIMD_DISABLE ASFLAGS_FPUSIMD_ENABLE ENABLED_KERNEL_BENCHMARKS \
FIPS_FLAVOR
module:
+$(MAKE) -C linuxkm libwolfssl.ko
@@ -233,6 +234,12 @@ module:
module-update-fips-hash:
+$(MAKE) -C linuxkm module-update-fips-hash
module-with-matching-fips-hash:
+$(MAKE) -C linuxkm module-with-matching-fips-hash
module-with-matching-fips-hash-no-sign:
+$(MAKE) -C linuxkm module-with-matching-fips-hash-no-sign
clean_module:
+$(MAKE) -C linuxkm clean
+7 -5
View File
@@ -415,6 +415,9 @@ AC_ARG_ENABLE([fips],
[ENABLED_FIPS=$enableval],
[ENABLED_FIPS="no"])
FIPS_FLAVOR="$ENABLED_FIPS"
AC_SUBST([FIPS_FLAVOR])
# wolfProvider Options
AC_ARG_ENABLE([wolfprovider],
[AS_HELP_STRING([--enable-wolfprovider],[Enable wolfProvider options (default: disabled)])],
@@ -1463,7 +1466,6 @@ then
test "$enable_pwdbased" = "" && enable_pwdbased=yes
test "$enable_aeskeywrap" = "" && enable_aeskeywrap=yes
test "$enable_x963kdf" = "" && enable_x963kdf=yes
test "$enable_scrypt" = "" && test "$enable_hmac" != "no" && enable_scrypt=yes
test "$enable_indef" = "" && enable_indef=yes
test "$enable_enckeys" = "" && enable_enckeys=yes
test "$enable_hashflags" = "" && enable_hashflags=yes
@@ -1480,11 +1482,11 @@ then
test "$enable_ssh" = "" && test "$enable_hmac" != "no" && enable_ssh=yes
test "$enable_rng_bank" = "" && enable_rng_bank=yes
# the compiler optimizer generates a weird out-of-bounds bss reference for
# find_hole() in the FP_ECC implementation.
if test "$ENABLED_LINUXKM_PIE" != yes
if test "$KERNEL_MODE_DEFAULTS" != "yes"
then
test "$enable_fpecc" = "" && test "$enable_ecc" != "no" && enable_fpecc=yes
# Scrypt is excluded from kernel module builds (unless explicitly
# enabled) because of its excessive memory requirements.
test "$enable_scrypt" = "" && test "$enable_hmac" != "no" && enable_scrypt=yes
fi
if test "x$FIPS_VERSION" != "xv1"
+15 -6
View File
@@ -49,7 +49,11 @@ else ifeq "$(KERNEL_ARCH)" "arm"
WOLFSSL_CFLAGS += -fno-optimize-sibling-calls -Os
endif
obj-m := libwolfssl.o
ifndef LIBWOLFSSL_NAME
LIBWOLFSSL_NAME := libwolfssl
endif
obj-m := $(LIBWOLFSSL_NAME).o
WOLFSSL_OBJ_TARGETS := $(patsubst %, $(obj)/%, $(WOLFSSL_OBJ_FILES))
@@ -88,10 +92,10 @@ ifndef KERNEL_THREAD_STACK_SIZE
endif
MAX_STACK_FRAME_SIZE=$(shell echo $$(( $(KERNEL_THREAD_STACK_SIZE) / 4)))
libwolfssl-y := $(WOLFSSL_OBJ_FILES) linuxkm/module_hooks.o linuxkm/module_exports.o
$(LIBWOLFSSL_NAME)-y := $(WOLFSSL_OBJ_FILES) linuxkm/module_hooks.o linuxkm/module_exports.o
ifeq "$(FIPS_OPTEST)" "1"
libwolfssl-y += linuxkm/optest-140-3/linuxkm_optest_wrapper.o
$(LIBWOLFSSL_NAME)-y += linuxkm/optest-140-3/linuxkm_optest_wrapper.o
endif
WOLFSSL_CFLAGS_NO_VECTOR_INSNS := $(CFLAGS_SIMD_DISABLE) $(CFLAGS_FPU_DISABLE)
@@ -162,7 +166,7 @@ ifdef KERNEL_EXTRA_CFLAGS_REMOVE
ccflags-remove-y += $(KERNEL_EXTRA_CFLAGS_REMOVE)
endif
$(obj)/libwolfssl.mod.o: ccflags-y := $(PIE_SUPPORT_FLAGS)
$(obj)/$(LIBWOLFSSL_NAME).mod.o: ccflags-y := $(PIE_SUPPORT_FLAGS)
$(obj)/wolfcrypt/test/test.o: ccflags-y += -DNO_MAIN_DRIVER -DWOLFSSL_NO_OPTIONS_H
$(obj)/wolfcrypt/src/aes.o: ccflags-y := $(WOLFSSL_CFLAGS) $(WOLFSSL_CFLAGS_YES_VECTOR_INSNS) $(PIE_FLAGS) $(PIE_SUPPORT_FLAGS)
$(obj)/wolfcrypt/benchmark/benchmark.o: ccflags-y := $(WOLFSSL_CFLAGS) $(CFLAGS_FPU_ENABLE) $(CFLAGS_SIMD_ENABLE) $(PIE_SUPPORT_FLAGS) -DNO_MAIN_FUNCTION -DWOLFSSL_NO_OPTIONS_H
@@ -331,15 +335,19 @@ endif
# auto-generate the exported symbol list, leveraging the WOLFSSL_API visibility tags.
# exclude symbols that don't match wc_* or wolf*.
EXPORT_SYMBOL := EXPORT_SYMBOL_NS_GPL
ifndef WOLFSSL_NS
WOLFSSL_NS := WOLFSSL
endif
$(obj)/linuxkm/module_exports.c: $(src)/module_exports.c.template $(WOLFSSL_OBJ_TARGETS) $(obj)/linuxkm/module_hooks.o
@$(RENAME_PIE_TEXT_AND_DATA_SECTIONS)
@cp $< $@ || exit $$?
if [[ "$${VERSION}" -gt 6 || ("$${VERSION}" -eq 6 && "$${PATCHLEVEL}" -ge 13) ]]; then
# use ASCII octal escape to avoid syntax disruption in the awk script.
ns='\042WOLFSSL\042'
ns='\042$(WOLFSSL_NS)\042'
else
ns='WOLFSSL'
ns='$(WOLFSSL_NS)'
fi
ifndef NO_EXPORTS
$(READELF) --symbols --wide $(filter %.o,$^) |
$(AWK) '/^ *[0-9]+: / {
if ($$8 !~ /^(wc_|wolf|WOLF|TLSX_)/){next;}
@@ -348,5 +356,6 @@ $(obj)/linuxkm/module_exports.c: $(src)/module_exports.c.template $(WOLFSSL_OBJ_
}
}' >> $@ || exit $$?
echo -e "#ifndef NO_CRYPT_TEST\n$(EXPORT_SYMBOL)(wolfcrypt_test, $${ns});\n#endif" >> $@
endif
clean-files := linuxkm src wolfcrypt
+75 -11
View File
@@ -21,7 +21,11 @@
.ONESHELL:
SHELL=bash
all: libwolfssl.ko libwolfssl.ko.signed
ifndef LIBWOLFSSL_NAME
LIBWOLFSSL_NAME := libwolfssl
endif
all: $(LIBWOLFSSL_NAME).ko $(LIBWOLFSSL_NAME).ko.signed
ifndef MODULE_TOP
MODULE_TOP=$(CURDIR)
@@ -147,8 +151,9 @@ GENERATE_RELOC_TAB := $(AWK) ' \
n=0; \
bad_relocs=0; \
print "\#include <wolfssl/wolfcrypt/libwolfssl_sources.h>"; \
print "\#include <wolfssl/wolfcrypt/memory.h>"; \
printf("%s\n ", \
"WOLFSSL_LOCAL const struct wc_linuxkm_pie_reloc_tab_ent wc_linuxkm_pie_reloc_tab[] = { "); \
"WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_reloc_tab[] = { "); \
if ("SECTION_MAP" in ENVIRON) { \
while (getline <ENVIRON["SECTION_MAP"] > 0) \
section_map[$$1] = $$2; \
@@ -204,8 +209,10 @@ GENERATE_RELOC_TAB := $(AWK) ' \
print >"/dev/stderr"; \
exit(1); \
} \
printf(" { .offset = 0x%xU, .dest_segment = %s, .reloc_type = WC_%s },\n", \
strtonum("0x" gensub("^0*","",1,$$1)), \
printf(" { .offset = 0x%xU, .dest_offset = 0x%xU, .dest_addend = %+d, .dest_segment = %s, .reloc_type = WC_%s },\n", \
strtonum("0x" $$1), \
strtonum("0x" $$4), \
$$6 strtonum("0x" $$7), \
section_tag, reloc_type); \
} \
} \
@@ -214,8 +221,8 @@ GENERATE_RELOC_TAB := $(AWK) ' \
print "Found " bad_relocs " unresolvable relocations." >"/dev/stderr"; \
exit(1); \
} \
print " { .offset = ~0U, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \
print "WOLFSSL_LOCAL const unsigned long wc_linuxkm_pie_reloc_tab_length = sizeof wc_linuxkm_pie_reloc_tab / sizeof wc_linuxkm_pie_reloc_tab[0];"; \
print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \
print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_reloc_tab / sizeof wc_linuxkm_pie_reloc_tab[0]);"; \
}'
ifeq "$(V)" "1"
@@ -225,8 +232,8 @@ endif
# This rule is .PHONY because it doesn't actually build the module -- Kbuild
# does, and we always need to call Kbuild to enforce rebuild for dependencies
# and config changes.
.PHONY: libwolfssl.ko
libwolfssl.ko:
.PHONY: $(LIBWOLFSSL_NAME).ko
$(LIBWOLFSSL_NAME).ko:
@set -e
@[[ '$(V)' == 1 ]] && { echo 'MODULE_TOP = "$(MODULE_TOP)"';
echo 'SRC_TOP = "$(SRC_TOP)"';
@@ -303,7 +310,7 @@ else
endif
.PHONY: module-update-fips-hash
module-update-fips-hash: libwolfssl.ko
module-update-fips-hash: $(LIBWOLFSSL_NAME).ko
@set -e
@if test -z '$(FIPS_HASH)'; then echo ' $$FIPS_HASH is unset' >&2; exit 1; fi
@if [[ ! '$(FIPS_HASH)' =~ [0-9a-fA-F]{64} ]]; then echo ' $$FIPS_HASH is malformed' >&2; exit 1; fi
@@ -320,9 +327,64 @@ module-update-fips-hash: libwolfssl.ko
if [[ '$(FIPS_HASH)' == "$$current_verifyCore" ]]; then echo ' Supplied FIPS_HASH matches existing verifyCore -- no update needed.'; exit 0; fi; \
echo -n '$(FIPS_HASH)' | dd bs=1 conv=notrunc of="$<" seek=$$verifyCore_offset count=64 status=none && \
echo " FIPS verifyCore updated successfully." && \
if [[ -f libwolfssl.ko.signed ]]; then $(MAKE) -C . libwolfssl.ko.signed; fi
if [[ -f '$(LIBWOLFSSL_NAME).ko.signed' ]]; then $(MAKE) -C . '$(LIBWOLFSSL_NAME).ko.signed'; fi
libwolfssl.ko.signed: libwolfssl.ko
# linuxkm-fips-hash implements offline (no-load) FIPS hash calculation and graft-in.
#
# libwolfssl.so is built from the same sources as the kernel module, with the
# same FIPS setting, then used with linuxkm-fips-hash to calculate and overwrite
# the hash in libwolfssl.ko. Finally, the module is [re]signed.
#
# Note that libwolfssl.so has to be built from a hierarchy of symlinks, to avoid
# depending on changes/config in the source directory. Also, aside from
# FIPS_FLAVOR, inherited configuration settings in the environment are cleansed.
libwolfssl-user-build/src/.libs/libwolfssl.so:
@set -e
@$(RM) -rf '$(MODULE_TOP)/libwolfssl-user-build'
@mkdir '$(MODULE_TOP)/libwolfssl-user-build'
@cd '$(MODULE_TOP)/libwolfssl-user-build'
@pushd '$(SRC_TOP)' >/dev/null
@echo -n 'Populating tree of symlinks...'
@readarray -d '' -t srcfiles < <(find examples src support tests testsuite wolfcrypt wolfssl configure *.in build-aux debian rpm scripts certs doc mcapi cmake linuxkm/*.[ch] \( -name options.h -o -name user_settings\* \) -prune -o \( ! -type d \) \( -name '*.[chsSi]' -o -name configure -o -name '*.in' -o -name \*.sh -o -path support/\* -o -path build-aux/\* -o -path debian/\* -o -path rpm/\* -o -path scripts/\* -o -path certs/\* -o -path doc/\* -o -path mcapi/\* -o -path cmake/\* \) -print0)
@popd >/dev/null
@for file in "$${srcfiles[@]}"; do if [[ ! -e "$$file" ]]; then mkdir -p "$$(dirname "$$file")" && cp --no-dereference --symbolic-link --no-clobber '$(SRC_TOP)'/"$$file" "$$file"; fi; done
@echo ' done.'
@echo '__attribute__ ((visibility("default"))) extern const char coreKey[];' > user_settings.h
@echo > user_settings_asm.h
@echo -n 'Configuring libwolfssl.so...'
@unset WOLFSSL_CFLAGS WOLFCRYPT_PIE_FILES ASFLAGS_FPUSIMD_ENABLE ASFLAGS_FPU_DISABLE_SIMD_ENABLE src_libwolfssl_la_OBJECTS WOLFSSL_ASFLAGS AM_CFLAGS WOLFSSL_OBJ_FILES ENABLED_LINUXKM_LKCAPI_REGISTER EXTRA_LDFLAGS CC LD
@./configure --quiet --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM'
@echo ' done.'
@echo -n 'Compiling and linking libwolfssl.so...'
@$(MAKE) >/dev/null
@echo ' done.'
@echo -n 'Fixing FIPS hash...'
@userhash=$$(wolfcrypt/test/testwolfcrypt 2>&1 | sed -n -E 's/^hash = (.+)$$/\1/p')
@if [[ -z "$$userhash" ]]; then echo ' FIPS hash not found!' >&2; exit 1; fi
@find wolfcrypt/src -name '*fips_test*o' -delete
@$(MAKE) EXTRA_CFLAGS=-DWOLFCRYPT_FIPS_CORE_HASH_VALUE="$$userhash"
@echo ' done.'
linuxkm-fips-hash: libwolfssl-user-build/src/.libs/libwolfssl.so linuxkm-fips-hash.c
@echo -n 'Compiling linuxkm-fips-hash...'
# note direct invocation of cc -- we are compiling for the build host, not the target host.
@cc -I'$(MODULE_TOP)/libwolfssl-user-build' -o linuxkm-fips-hash linuxkm/linuxkm-fips-hash.c -L '$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath-link='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -Wl,-rpath='$(MODULE_TOP)/libwolfssl-user-build/src/.libs' -lwolfssl
@echo ' done.'
.PHONY: module-with-matching-fips-hash
module-with-matching-fips-hash: $(LIBWOLFSSL_NAME).ko linuxkm-fips-hash
@set -e
./linuxkm-fips-hash-wrapper.sh "$<"
$(MAKE) -C . '$(LIBWOLFSSL_NAME).ko.signed'
.PHONY: module-with-matching-fips-hash-no-sign
module-with-matching-fips-hash-no-sign: $(LIBWOLFSSL_NAME).ko linuxkm-fips-hash
@set -e
./linuxkm-fips-hash-wrapper.sh "$<"
$(LIBWOLFSSL_NAME).ko.signed: $(LIBWOLFSSL_NAME).ko
ifdef FORCE_NO_MODULE_SIG
@echo 'Skipping module signature operation because FORCE_NO_MODULE_SIG.'
else
@@ -371,6 +433,8 @@ clean:
$(RM) -rf '$(MODULE_TOP)/linuxkm'
$(RM) -rf '$(MODULE_TOP)/wolfcrypt'
$(RM) -rf '$(MODULE_TOP)/src'
$(RM) -rf '$(MODULE_TOP)/libwolfssl-user-build'
$(RM) -f '$(MODULE_TOP)/linuxkm-fips-hash'
.PHONY: check
check:
+3
View File
@@ -7,10 +7,13 @@ EXTRA_DIST += m4/ax_linuxkm.m4 \
linuxkm/Makefile \
linuxkm/README.md \
linuxkm/get_thread_size.c \
linuxkm/linuxkm-fips-hash.c \
linuxkm/linuxkm-fips-hash-wrapper.sh \
linuxkm/module_hooks.c \
linuxkm/module_exports.c.template \
linuxkm/pie_redirect_table.c \
linuxkm/linuxkm_memory.c \
linuxkm/linuxkm_memory.h \
linuxkm/linuxkm_wc_port.h \
linuxkm/x86_vector_register_glue.c \
linuxkm/lkcapi_glue.c \
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
set -o noclobber -o nounset -o pipefail -o errexit
mod_path=$1
readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | awk '
BEGIN {
fips_fenceposts["wc_linuxkm_pie_reloc_tab"] = "reloc_tab_start";
fips_fenceposts["wc_linuxkm_pie_reloc_tab_length"] = "reloc_tab_len_start";
fips_fenceposts["verifyCore"] = "verifyCore_start";
fips_fenceposts["wolfCrypt_FIPS_first"] = "fips_text_start";
fips_fenceposts["wolfCrypt_FIPS_last"] = "fips_text_end";
fips_fenceposts["wolfCrypt_FIPS_ro_start"] = "fips_rodata_start";
fips_fenceposts["wolfCrypt_FIPS_ro_end"] = "fips_rodata_end";
singleton_ends["wc_linuxkm_pie_reloc_tab"] = "reloc_tab_end";
singleton_ends["wc_linuxkm_pie_reloc_tab_length"] = "reloc_tab_len_end";
singleton_ends["verifyCore"] = "verifyCore_end";
}
/^Section Headers:/ {
in_sections = 1;
in_symbols = 0;
next;
}
/^Symbol table / {
if (! in_sections) {
print "symbol table appeared before section headers." >"/dev/stderr";
exit(1);
}
in_sections = 0;
in_symbols = 1;
next;
}
{
if (in_sections) {
if (match($0,
"^[[:space:]]*\\[([^]]+)\\][[:space:]]+\\.([^[:space:].]+)_wolfcrypt[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+([0-9a-f]+)[[:space:]]+([0-9a-f]+)[[:space:]]",
section_line_a)) {
segnum = strtonum(section_line_a[1]);
segname = section_line_a[2];
segstart = section_line_a[3];
segsize = section_line_a[4];
seg_starts_by_id[segnum] = strtonum("0x" segstart);
printf("--%s_start\n0x%x\n--%s_end\n0x%x\n", segname, strtonum("0x" segstart), segname, strtonum("0x" segstart) + strtonum("0x" segsize));
next;
}
}
if (in_symbols) {
if ($7 !~ "^[0-9]+$")
next;
if (($4 != "NOTYPE") && ($4 != "OBJECT") && ($4 != "FUNC"))
next;
if (! ($8 in fips_fenceposts))
next;
if (! ($7 in seg_starts_by_id)) {
print "segment offset missing for segment " $7 " for symbol " $8 "." >"/dev/stderr";
exit(1);
}
printf("--%s\n0x%x\n", fips_fenceposts[$8], seg_starts_by_id[$7] + strtonum("0x" $2));
if ($8 in singleton_ends)
printf("--%s\n0x%x\n", singleton_ends[$8], seg_starts_by_id[$7] + strtonum("0x" $2) + strtonum($3));
}
}')
./linuxkm-fips-hash "${fenceposts[@]}" --mod-path "$mod_path" --in-place --quiet
+357
View File
@@ -0,0 +1,357 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <getopt.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/memory.h>
/* failsafe definitions for FIPS <5.3 */
#ifndef FIPS_IN_CORE_DIGEST_SIZE
#ifndef NO_SHA256
#define FIPS_IN_CORE_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
#define FIPS_IN_CORE_HASH_TYPE WC_SHA256
#elif defined(WOLFSSL_SHA384)
#define FIPS_IN_CORE_DIGEST_SIZE WC_SHA384_DIGEST_SIZE
#define FIPS_IN_CORE_HASH_TYPE WC_SHA384
#else
#error Unsupported FIPS hash alg.
#endif
#endif
#ifndef FIPS_IN_CORE_KEY_SZ
#define FIPS_IN_CORE_KEY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
#ifndef FIPS_IN_CORE_VERIFY_SZ
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
static const char *user_coreKey;
#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
extern const char coreKey[FIPS_IN_CORE_KEY_SZ*2 + 1];
#endif
static int hmac_setkey_cb(Hmac *hmac, const byte *key, word32 key_len) {
int ret;
ret = wc_HmacSetKey(hmac, FIPS_IN_CORE_HASH_TYPE, key, key_len);
if (ret != 0)
return ret;
return 0;
}
static int hmac_update_cb(Hmac *hmac, const byte *in, word32 in_len) {
return wc_HmacUpdate_fips(hmac, in, in_len);
}
static int hmac_final_cb(Hmac *hmac, byte *out, word32 out_sz) {
int actual_size = wc_HmacSizeByType(hmac->macType);
if (actual_size < 0)
return actual_size;
if ((int)out_sz != actual_size)
return BUFFER_E;
return wc_HmacFinal(hmac, out);
}
int main(int argc, char **argv)
{
Hmac hmac;
int ret;
struct wc_reloc_table_segments seg_map = WC_RELOC_TABLE_SEGMENTS_INITIALIZER;
word32 new_verifyCore_size = FIPS_IN_CORE_DIGEST_SIZE*2 + 1;
char new_verifyCore[new_verifyCore_size];
const char *progname = strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
const char *mod_path = NULL;
int mod_fd;
struct stat st;
byte *mod_map = NULL;
word32 reloc_tab_len;
struct wc_reloc_counts reloc_counts;
int inplace = 0;
int quiet = 0;
int verbose = 0;
static const struct option long_options[] = {
#define FENCEPOST_OPT_FLAG (1U << 30)
#define FENCEPOST_OPT(x) { .name = #x, .has_arg = required_argument, .flag = NULL, .val = FENCEPOST_OPT_FLAG | offsetof(typeof(seg_map), x) }
FENCEPOST_OPT(text_start),
FENCEPOST_OPT(text_end),
FENCEPOST_OPT(reloc_tab_start),
FENCEPOST_OPT(reloc_tab_end),
FENCEPOST_OPT(reloc_tab_len_start),
FENCEPOST_OPT(reloc_tab_len_end),
FENCEPOST_OPT(fips_text_start),
FENCEPOST_OPT(fips_text_end),
FENCEPOST_OPT(rodata_start),
FENCEPOST_OPT(rodata_end),
FENCEPOST_OPT(fips_rodata_start),
FENCEPOST_OPT(fips_rodata_end),
FENCEPOST_OPT(verifyCore_start),
FENCEPOST_OPT(verifyCore_end),
FENCEPOST_OPT(data_start),
FENCEPOST_OPT(data_end),
FENCEPOST_OPT(bss_start),
FENCEPOST_OPT(bss_end),
{ "core-key", required_argument, NULL, 'k' },
{ "mod-path", required_argument, NULL, 'f' },
{ "in-place", no_argument, NULL, 'i' },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
};
ret = wolfCrypt_Init();
if (ret < 0) {
fprintf(stderr, "%s: wolfCrypt_Init() failed: %s.\n", progname, wc_GetErrorString(ret));
exit(1);
}
for (;;) {
int option_index = 0;
int c = getopt_long(argc, argv, "f:ik:qvh", long_options, &option_index);
if (c == -1)
break;
if (c & FENCEPOST_OPT_FLAG) {
char *eptr;
c &= ~FENCEPOST_OPT_FLAG;
*((unsigned long *)((byte *)&seg_map + c)) = strtoul(optarg, &eptr, 0);
if (*eptr != '\0') {
fprintf(stderr, "%s: %s: supplied arg \"%s\" isn't a valid number.\n", progname, long_options[option_index].name, optarg);
exit(1);
}
continue;
}
switch (c) {
case 'f':
mod_path = optarg;
break;
case 'i':
inplace = 1;
break;
case 'k':
user_coreKey = optarg;
break;
case 'q':
quiet = 1;
break;
case 'v':
verbose = 1;
break;
case 'h':
printf("usage: %s \\\n", progname);
for (int i=0; i < (int)(sizeof long_options / sizeof long_options[0]); ++i) {
const struct option *opt = &long_options[i];
if (opt->name == NULL) {
printf("\n");
continue;
}
if (i > 0)
printf(" \\\n");
if (opt->has_arg == no_argument)
printf(" --%s", opt->name);
else if (opt->val & FENCEPOST_OPT_FLAG)
printf(" --%s <offset>", opt->name);
else
printf(" --%s <arg>", opt->name);
}
exit(0);
case ':':
fprintf(stderr, "%s: Missing argument. Try --help.\n", progname);
exit(1);
__builtin_unreachable();
case '?':
fprintf(stderr, "%s: Unrecognized option. Try --help.\n", progname);
exit(1);
__builtin_unreachable();
default:
fprintf(stderr, "%s: Unexpected error. Try --help.\n", progname);
exit(1);
__builtin_unreachable();
}
}
if (optind < argc) {
fprintf(stderr, "%s: unexpected trailing argument(s).\n", progname);
exit(1);
}
if (user_coreKey == NULL) {
#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
user_coreKey = coreKey;
#else
fprintf(stderr, "%s: must supply --core-key.\n", progname);
exit(1);
#endif
}
#ifdef WC_USE_PIE_FENCEPOSTS_FOR_FIPS
if ((seg_map.fips_text_start != ~0UL) ||
(seg_map.fips_text_end != ~0UL) ||
(seg_map.fips_rodata_start != ~0UL) ||
(seg_map.fips_rodata_end != ~0UL))
{
fprintf(stderr, "%s: note, ignoring explicit FIPS fenceposts because WC_USE_PIE_FENCEPOSTS_FOR_FIPS.\n", progname);
}
seg_map.fips_text_start = seg_map.text_start;
seg_map.fips_text_end = seg_map.text_end;
seg_map.fips_rodata_start = seg_map.rodata_start;
seg_map.fips_rodata_end = seg_map.rodata_end;
#endif
if ((seg_map.text_start == ~0UL) ||
(seg_map.text_end == ~0UL) ||
(seg_map.reloc_tab_start == ~0UL) ||
(seg_map.reloc_tab_end == ~0UL) ||
(seg_map.reloc_tab_len_start == ~0UL) ||
(seg_map.reloc_tab_len_end == ~0UL) ||
(seg_map.fips_text_start == ~0UL) ||
(seg_map.fips_text_end == ~0UL) ||
(seg_map.rodata_start == ~0UL) ||
(seg_map.rodata_end == ~0UL) ||
(seg_map.fips_rodata_start == ~0UL) ||
(seg_map.fips_rodata_end == ~0UL) ||
(seg_map.verifyCore_start == ~0UL) ||
(seg_map.verifyCore_end == ~0UL) ||
(seg_map.data_start == ~0UL) ||
(seg_map.data_end == ~0UL) ||
(seg_map.bss_start == ~0UL) ||
(seg_map.bss_end == ~0UL))
{
fprintf(stderr, "%s: segment fencepost(s) missing. Try --help.\n", progname);
exit(1);
}
if (mod_path == NULL) {
fprintf(stderr, "%s: module path missing. Try --help.\n", progname);
exit(1);
}
mod_fd = open(mod_path, inplace ? O_RDWR : O_RDONLY);
if (mod_fd < 0) {
fprintf(stderr, "%s: open %s: %m.\n", progname, mod_path);
exit(1);
}
ret = fstat(mod_fd, &st);
if (ret < 0) {
fprintf(stderr, "%s: fstat %s: %m.\n", progname, mod_path);
exit(1);
}
if ((seg_map.reloc_tab_start >= seg_map.reloc_tab_end) ||
(seg_map.reloc_tab_end >= st.st_size) ||
(seg_map.reloc_tab_len_start >= seg_map.reloc_tab_len_end) ||
(seg_map.reloc_tab_len_end >= st.st_size))
{
fprintf(stderr, "%s: supplied reloc_tab fencepost(s) are out of bounds.\n", progname, mod_path, st.st_size);
exit(1);
}
mod_map = (byte *)mmap(NULL, st.st_size, inplace ? PROT_READ | PROT_WRITE : PROT_READ, MAP_SHARED | MAP_POPULATE, mod_fd, 0);
if (mod_map == MAP_FAILED) {
fprintf(stderr, "%s: mmap() of %s, length %zu: %m.\n", progname, mod_path, st.st_size);
exit(1);
}
seg_map.start = (unsigned long)mod_map;
seg_map.end = (unsigned long)mod_map + st.st_size;
seg_map.reloc_tab_start += (unsigned long)mod_map;
seg_map.reloc_tab_end += (unsigned long)mod_map;
seg_map.reloc_tab_len_start += (unsigned long)mod_map;
seg_map.reloc_tab_len_end += (unsigned long)mod_map;
seg_map.verifyCore_start += (unsigned long)mod_map;
seg_map.verifyCore_end += (unsigned long)mod_map;
seg_map.fips_text_start += (unsigned long)mod_map;
seg_map.fips_text_end += (unsigned long)mod_map;
seg_map.fips_rodata_start += (unsigned long)mod_map;
seg_map.fips_rodata_end += (unsigned long)mod_map;
seg_map.text_start += (unsigned long)mod_map;
seg_map.text_end += (unsigned long)mod_map;
seg_map.rodata_start += (unsigned long)mod_map;
seg_map.rodata_end += (unsigned long)mod_map;
seg_map.data_start += (unsigned long)mod_map;
seg_map.data_end += (unsigned long)mod_map;
seg_map.bss_start += (unsigned long)mod_map;
seg_map.bss_end += (unsigned long)mod_map;
ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID);
if (ret != 0) {
fprintf(stderr, "%s: wc_HmacInit() failed: %s.\n", progname, wc_GetErrorString(ret));
exit(1);
}
if (seg_map.verifyCore_end - seg_map.verifyCore_start != new_verifyCore_size) {
fprintf(stderr, "%s: unexpected verifyCore length %zu.\n", progname, (size_t)(seg_map.verifyCore_end - seg_map.verifyCore_start));
goto out;
}
XMEMSET(&reloc_counts, 0, sizeof(reloc_counts));
ret = wc_fips_generate_hash(
&seg_map,
FIPS_IN_CORE_DIGEST_SIZE,
coreKey,
&hmac,
(wc_fips_verifyCore_hmac_setkey_fn)hmac_setkey_cb,
(wc_fips_verifyCore_hmac_update_fn)hmac_update_cb,
(wc_fips_verifyCore_hmac_final_fn)hmac_final_cb,
new_verifyCore,
&new_verifyCore_size,
&reloc_counts);
if (ret < 0) {
fprintf(stderr, "%s: wc_fips_generate_hash() failed: %s.\n", progname, wc_GetErrorString(ret));
goto out;
}
if (verbose)
fprintf(inplace ? stdout : stderr, "FIPS-bounded relocation normalizations: text=%d, rodata=%d, rwdata=%d, bss=%d, other=%d\n",
reloc_counts.text, reloc_counts.rodata, reloc_counts.rwdata, reloc_counts.bss, reloc_counts.other);
if (new_verifyCore_size < sizeof new_verifyCore) {
fprintf(stderr, "%s: wc_fips_generate_hash() returned unexpected verifyCore length %u.\n", progname, new_verifyCore_size);
goto out;
}
if ((! quiet) && (verbose || !inplace))
printf("%s\n", new_verifyCore);
if (strcmp((char *)seg_map.verifyCore_start, new_verifyCore) == 0) {
fprintf(stderr, "%s: note, verifyCore already matches.\n", progname);
}
else if (inplace) {
XMEMCPY((void *)seg_map.verifyCore_start, new_verifyCore, new_verifyCore_size);
ret = munmap(mod_map, st.st_size);
if (ret < 0) {
fprintf(stderr, "%s: munmap: %m\n", progname);
exit(1);
}
ret = close(mod_fd);
if (ret < 0) {
fprintf(stderr, "%s: close: %m\n", progname);
exit(1);
}
printf("FIPS integrity hash updated successfully.\n");
}
out:
wc_HmacFree(&hmac);
if (ret)
exit(1);
else
exit(0);
}
+762 -1
View File
@@ -21,10 +21,771 @@
/* included by wolfcrypt/src/memory.c */
#if defined(WC_SYM_RELOC_TABLES) && defined(CONFIG_FORTIFY_SOURCE)
#if defined(WOLFSSL_LINUXKM) && defined(WC_SYM_RELOC_TABLES) && defined(CONFIG_FORTIFY_SOURCE)
/* needed because FORTIFY_SOURCE inline implementations call fortify_panic(). */
void __my_fortify_panic(const char *name) {
pr_emerg("__my_fortify_panic in %s\n", name);
BUG();
}
#endif
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
#define RELOC_DEBUG_PRINTF(fmt, ...) WOLFSSL_DEBUG_PRINTF("%s L %d: " fmt, __FILE__, __LINE__, ## __VA_ARGS__)
#else
#define RELOC_DEBUG_PRINTF(...) WC_DO_NOTHING
#endif
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
static const struct reloc_layout_ent {
const char *name;
word64 mask;
word64 width;
word64 is_signed:1;
word64 is_relative:1;
word64 is_pages:1;
word64 is_pair_lo:1;
word64 is_pair_hi:1;
} reloc_layouts[] = {
[WC_R_X86_64_32] = { "R_X86_64_32", ~0UL, 32, .is_signed = 0, .is_relative = 0 },
[WC_R_X86_64_32S] = { "R_X86_64_32S", ~0UL, 32, .is_signed = 1, .is_relative = 0 },
[WC_R_X86_64_64] = { "R_X86_64_64", ~0UL, 64, .is_signed = 0, .is_relative = 0 },
[WC_R_X86_64_PC32] = { "R_X86_64_PC32", ~0UL, 32, .is_signed = 1, .is_relative = 1 },
[WC_R_X86_64_PLT32] = { "R_X86_64_PLT32", ~0UL, 32, .is_signed = 1, .is_relative = 1 },
[WC_R_AARCH64_ABS32] = { "R_AARCH64_ABS32", ~0UL, 32, .is_signed = 1, .is_relative = 0, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_AARCH64_ABS64] = { "R_AARCH64_ABS64", ~0UL, 64, .is_signed = 1, .is_relative = 0, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_AARCH64_ADD_ABS_LO12_NC] = { "R_AARCH64_ADD_ABS_LO12_NC", 0b00000000001111111111110000000000, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 },
[WC_R_AARCH64_ADR_PREL_PG_HI21] = { "R_AARCH64_ADR_PREL_PG_HI21", 0b01100000111111111111111111100000, 32, .is_signed = 1, .is_relative = 1, .is_pages = 1, .is_pair_lo = 0, .is_pair_hi = 1 },
[WC_R_AARCH64_CALL26] = { "R_AARCH64_CALL26", 0b00000011111111111111111111111111, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_AARCH64_JUMP26] = { "R_AARCH64_JUMP26", 0b00000011111111111111111111111111, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_AARCH64_LDST8_ABS_LO12_NC] = { "R_AARCH64_LDST8_ABS_LO12_NC", 0b00000000001111111111110000000000, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 },
[WC_R_AARCH64_LDST16_ABS_LO12_NC] = { "R_AARCH64_LDST16_ABS_LO12_NC", 0b00000000001111111111110000000000, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 },
[WC_R_AARCH64_LDST32_ABS_LO12_NC] = { "R_AARCH64_LDST32_ABS_LO12_NC", 0b00000000001111111111110000000000, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 },
[WC_R_AARCH64_LDST64_ABS_LO12_NC] = { "R_AARCH64_LDST64_ABS_LO12_NC", 0b00000000001111111111110000000000, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 },
[WC_R_AARCH64_PREL32] = { "R_AARCH64_PREL32", ~0UL, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_ABS32] = { "R_ARM_ABS32", ~0UL, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_PREL31] = { "R_ARM_PREL31", 0b01111111111111111111111111111111, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_REL32] = { "R_ARM_REL32", ~0UL, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_THM_CALL] = { "R_ARM_THM_CALL", 0b00000111111111110010111111111111, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_THM_JUMP24] = { "R_ARM_THM_JUMP24", 0b00000111111111110010111111111111, 32, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_THM_JUMP11] = { "R_ARM_THM_JUMP11", 0b00000000000000000000011111111111, 16, .is_signed = 1, .is_relative = 1, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 0 },
[WC_R_ARM_THM_MOVT_ABS] = { "R_ARM_THM_MOVT_ABS", 0b00000100000011110111000011111111, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 0, .is_pair_hi = 1 },
[WC_R_ARM_THM_MOVW_ABS_NC] = { "R_ARM_THM_MOVW_ABS_NC", 0b00000100000011110111000011111111, 32, .is_signed = 0, .is_relative = 0, .is_pages = 0, .is_pair_lo = 1, .is_pair_hi = 0 }
};
static inline long find_reloc_tab_offset(
const struct wc_reloc_table_segments *seg_map,
const struct wc_reloc_table_ent reloc_tab[],
word32 reloc_tab_len,
size_t text_in_offset)
{
long ret;
unsigned long hop;
if (reloc_tab_len <= 1) {
RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__);
return -1;
}
if (text_in_offset >= (size_t)(seg_map->text_end - seg_map->text_start)) {
RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__);
return -1;
}
if (text_in_offset >= (size_t)reloc_tab[reloc_tab_len - 1].offset) {
RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__);
return -1;
}
for (ret = 0,
hop = reloc_tab_len >> 1;
hop;
hop >>= 1)
{
if (text_in_offset == (size_t)reloc_tab[ret].offset)
break;
else if (text_in_offset > (size_t)reloc_tab[ret].offset)
ret += hop;
else if (ret)
ret -= hop;
}
while ((ret < (long)reloc_tab_len - 1) &&
((size_t)reloc_tab[ret].offset < text_in_offset))
++ret;
while ((ret > 0) &&
((size_t)reloc_tab[ret - 1].offset >= text_in_offset))
--ret;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
if (ret < 0)
RELOC_DEBUG_PRINTF("ERROR: %s returning %ld.\n", __FUNCTION__, ret);
#endif
return ret;
}
/* Note we are not currently accommodating endianness conflicts between the
* build and target host, but if we were, these macros would byte swap.
* Currently, we detect and fail early on endianness conflicts.
*/
#define wc_get_unaligned(v) ({ typeof(*(v)) _v_aligned; XMEMCPY((void *)&_v_aligned, (void *)(v), sizeof _v_aligned); _v_aligned; })
#define wc_put_unaligned(v, v_out) do { typeof(v) _v = (v); XMEMCPY((void *)(v_out), (void *)&_v, sizeof(typeof(*(v_out)))); } while (0)
ssize_t wc_reloc_normalize_text(
const byte *text_in,
size_t text_in_len,
byte *text_out,
ssize_t *cur_index_p,
const struct wc_reloc_table_segments *seg_map,
struct wc_reloc_counts *reloc_counts)
{
ssize_t i;
size_t text_in_offset;
const struct wc_reloc_table_ent *last_reloc; /* for error-checking order in reloc_tab[] */
int n_text_r = 0, n_rodata_r = 0, n_rwdata_r = 0, n_bss_r = 0, n_other_r = 0, n_oob_r = 0;
const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->reloc_tab_start;
const word32 reloc_tab_len = *(const word32 *)seg_map->reloc_tab_len_start;
if ((text_in_len == 0) ||
((uintptr_t)text_in < seg_map->text_start) ||
((uintptr_t)(text_in + text_in_len) > seg_map->text_end))
{
RELOC_DEBUG_PRINTF("ERROR: %s returning -1 with span %llx-%llx versus segment %llx-%llx.\n",
__FUNCTION__,
(unsigned long long)(uintptr_t)text_in,
(unsigned long long)(uintptr_t)(text_in + text_in_len),
(unsigned long long)seg_map->text_start,
(unsigned long long)seg_map->text_end);
return -1;
}
text_in_offset = (uintptr_t)text_in - seg_map->text_start;
if (cur_index_p)
i = *cur_index_p;
else
i = -1;
if (i == -1)
i = find_reloc_tab_offset(seg_map, reloc_tab, reloc_tab_len, text_in_offset);
if (i < 0)
return i;
WC_SANITIZE_DISABLE();
memcpy(text_out, text_in, text_in_len);
WC_SANITIZE_ENABLE();
for (last_reloc = &reloc_tab[i > 0 ? i-1 : 0];
(size_t)i < reloc_tab_len - 1;
++i)
{
const struct wc_reloc_table_ent *next_reloc = &reloc_tab[i];
enum wc_reloc_dest_segment dest_seg;
uintptr_t seg_beg;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
uintptr_t seg_end;
const char *seg_name;
#endif
word64 reloc_buf = 0;
const struct reloc_layout_ent *layout;
unsigned int next_reloc_rel;
if (next_reloc->dest_segment == WC_R_SEG_NONE) {
RELOC_DEBUG_PRINTF("BUG: missing dest segment for relocation at reloc_tab[%zd]\n", i);
continue;
}
if (last_reloc->offset > next_reloc->offset) {
RELOC_DEBUG_PRINTF("BUG: out-of-order offset found at reloc_tab[%zd]: %u > %u\n",
i, last_reloc->offset, next_reloc->offset);
return -1;
}
last_reloc = next_reloc;
if (next_reloc->reloc_type >= (sizeof reloc_layouts / sizeof reloc_layouts[0])) {
RELOC_DEBUG_PRINTF("BUG: unknown relocation type %u found at reloc_tab[%zd]\n",
next_reloc->reloc_type, i);
return -1;
}
layout = &reloc_layouts[next_reloc->reloc_type];
switch (layout->width) {
case 32:
case 64:
case 16:
break;
default:
RELOC_DEBUG_PRINTF("BUG: unexpected relocation width %llu found at reloc_tab[%lld], reloc type %u\n",
(unsigned long long)layout->width, (long long)i, next_reloc->reloc_type);
return -1;
}
/* provisionally assign the destination segment from the reloc record --
* it may wind up getting overridden later if things don't go as
* expected.
*/
dest_seg = next_reloc->dest_segment;
/* next_reloc_rel is the offset of the relocation relative to the start
* of the current text chunk (text_in). i.e., text_in + next_reloc_rel
* is the start of the relocation.
*/
next_reloc_rel = next_reloc->offset - text_in_offset;
if (next_reloc_rel >= text_in_len) {
/* no more relocations in this buffer. */
break;
}
if (next_reloc_rel > text_in_len - layout->width) {
/* relocation straddles buffer at end -- caller will try again with
* that relocation at the start.
*/
text_in_len = next_reloc_rel;
break;
}
/* set reloc_buf to the address bits from the live text segment. on
* ARM, this will often also pull in some opcode bits, which we mask out.
*/
if (layout->is_signed) {
/* Note, the intermediate cast to sword64 is necessary to
* sign-extend the value to 64 bits before unsigned
* reinterpretation. Normalization later relies on this.
*/
switch (layout->width) {
case 32:
reloc_buf = (word64)(sword64)(wc_get_unaligned((sword32 *)&text_out[next_reloc_rel]) & (sword32)layout->mask);
break;
case 64:
reloc_buf = (word64)(sword64)(wc_get_unaligned((sword64 *)&text_out[next_reloc_rel]) & (sword64)layout->mask);
break;
case 16:
reloc_buf = (word64)(sword64)(wc_get_unaligned((sword16 *)&text_out[next_reloc_rel]) & (sword16)layout->mask);
break;
}
}
else {
switch (layout->width) {
case 32:
reloc_buf = (word64)(wc_get_unaligned((word32 *)&text_out[next_reloc_rel]) & (word32)layout->mask);
break;
case 64:
reloc_buf = (word64)(wc_get_unaligned((word64 *)&text_out[next_reloc_rel]) & layout->mask);
break;
case 16:
reloc_buf = (word64)(wc_get_unaligned((word16 *)&text_out[next_reloc_rel]) & (word16)layout->mask);
break;
}
}
switch (dest_seg) {
case WC_R_SEG_TEXT:
seg_beg = seg_map->text_start;
++n_text_r;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
seg_end = seg_map->text_end;
seg_name = "text";
#endif
break;
case WC_R_SEG_RODATA:
seg_beg = seg_map->rodata_start;
++n_rodata_r;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
seg_end = seg_map->rodata_end;
seg_name = "rodata";
#endif
break;
case WC_R_SEG_RWDATA:
seg_beg = seg_map->data_start;
++n_rwdata_r;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
seg_end = seg_map->data_end;
seg_name = "data";
#endif
break;
case WC_R_SEG_BSS:
seg_beg = seg_map->bss_start;
++n_bss_r;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
seg_end = seg_map->bss_end;
seg_name = "bss";
#endif
break;
default:
case WC_R_SEG_NONE:
dest_seg = WC_R_SEG_OTHER;
FALL_THROUGH;
case WC_R_SEG_OTHER:
seg_beg = 0;
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
seg_end = 0;
seg_name = "other";
#endif
break;
}
switch (next_reloc->reloc_type) {
case WC_R_X86_64_PC32:
case WC_R_X86_64_PLT32:
case WC_R_X86_64_32:
case WC_R_X86_64_32S:
case WC_R_X86_64_64:
if (dest_seg != WC_R_SEG_OTHER) {
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
word64 raw_dest_addr = reloc_buf;
#endif
if (seg_map->text_is_live) {
/* note these normalize to the base address of the
* destination symbol, S, and removes the addend A, which is
* baked into the reloc_tab for each relocation.
*/
if (layout->is_relative)
reloc_buf = reloc_buf + (uintptr_t)next_reloc->offset - (uintptr_t)next_reloc->dest_addend - (seg_beg - seg_map->text_start);
else
reloc_buf = reloc_buf - seg_beg - (uintptr_t)next_reloc->dest_addend;
}
else {
reloc_buf = (word64)next_reloc->dest_offset;
}
#ifdef DEBUG_LINUXKM_PIE_SUPPORT
if (reloc_buf >= seg_end - seg_beg) {
++n_oob_r;
RELOC_DEBUG_PRINTF("WARNING: normalized value is out of bounds (%s0x%lx) at index %ld, text offset 0x%x, reloc type %s, "
"dest seg .%s_wolfcrypt, offset from text to dest segment %s0x%lx, raw dest addr %s0x%lx, "
"seg span 0x%lx - 0x%lx, seg size 0x%lx, text base 0x%lx\n",
(sword64)reloc_buf < 0 ? "-" : "",
(sword64)reloc_buf < 0 ? -reloc_buf : reloc_buf,
i,
next_reloc->offset,
layout->name,
seg_name,
seg_beg < seg_map->text_start ? "-" : "+",
seg_beg < seg_map->text_start ? (word64)seg_map->text_start - seg_beg : seg_beg - (word64)seg_map->text_start,
(layout->is_signed && ((sword64)raw_dest_addr < 0)) ? "-" : "",
(layout->is_signed && ((sword64)raw_dest_addr < 0)) ? (word64)-(sword64)raw_dest_addr : raw_dest_addr,
(word64)seg_beg,
(word64)seg_end,
(word64)(seg_end - seg_beg),
(word64)seg_map->text_start);
}
#endif
}
break;
case WC_R_ARM_ABS32:
case WC_R_ARM_PREL31:
case WC_R_ARM_REL32:
case WC_R_ARM_THM_CALL:
case WC_R_ARM_THM_JUMP11:
case WC_R_ARM_THM_JUMP24:
case WC_R_ARM_THM_MOVT_ABS:
case WC_R_ARM_THM_MOVW_ABS_NC:
/* Don't attempt to reconstruct ARM destination addresses -- just
* normalize to zero. They can be reconstructed using the
* parameters in reloc_layouts[] and reloc_tab[] but it's very
* fidgety.
*/
reloc_buf = 0;
break;
case WC_R_AARCH64_ABS32:
case WC_R_AARCH64_ABS64:
case WC_R_AARCH64_ADD_ABS_LO12_NC:
case WC_R_AARCH64_ADR_PREL_PG_HI21:
case WC_R_AARCH64_CALL26:
case WC_R_AARCH64_JUMP26:
case WC_R_AARCH64_LDST16_ABS_LO12_NC:
case WC_R_AARCH64_LDST32_ABS_LO12_NC:
case WC_R_AARCH64_LDST64_ABS_LO12_NC:
case WC_R_AARCH64_LDST8_ABS_LO12_NC:
case WC_R_AARCH64_PREL32:
/* Don't attempt to reconstruct ARM destination addresses -- just
* normalize to zero. They can be reconstructed using the
* parameters in reloc_layouts[] and reloc_tab[] but it's very
* fidgety.
*/
reloc_buf = 0;
break;
default:
RELOC_DEBUG_PRINTF("BUG: unrecognized relocation type %u in reloc record %zu, text offset 0x%x\n",
(unsigned)next_reloc->reloc_type, i, reloc_tab[i].offset);
++n_oob_r;
dest_seg = WC_R_SEG_OTHER;
}
if (dest_seg == WC_R_SEG_OTHER) {
/* relocation referring to non-wolfcrypt segment -- these can only
* be stabilized by zeroing them.
*/
reloc_buf = 0;
++n_other_r;
RELOC_DEBUG_PRINTF("found non-wolfcrypt relocation at index %lld, text offset 0x%x.\n",
(long long)i, reloc_tab[i].offset);
}
/* xor in a label identifying the dest segment and reloc type. */
reloc_buf ^= dest_seg << (layout->width - WC_RELOC_DEST_SEGMENT_BITS);
reloc_buf ^= next_reloc->reloc_type << (layout->width - (WC_RELOC_DEST_SEGMENT_BITS + WC_RELOC_TYPE_BITS));
/* write the modified reloc_buf to the destination buffer. */
switch (layout->width) {
case 32:
wc_put_unaligned((word32)reloc_buf, (word32 *)&text_out[next_reloc_rel]);
break;
case 64:
wc_put_unaligned(reloc_buf, (word64 *)&text_out[next_reloc_rel]);
break;
case 16:
wc_put_unaligned((word16)reloc_buf, (word16 *)&text_out[next_reloc_rel]);
break;
}
}
if (reloc_counts) {
reloc_counts->text += n_text_r;
reloc_counts->rodata += n_rodata_r;
reloc_counts->rwdata += n_rwdata_r;
reloc_counts->bss += n_bss_r;
reloc_counts->other += n_other_r;
}
if ((n_other_r > 0) || (n_oob_r > 0))
RELOC_DEBUG_PRINTF("text_in=%llx relocs=%d/%d/%d/%d/%d/%d ret = %llu\n",
(unsigned long long)(uintptr_t)text_in, n_text_r, n_rodata_r,
n_rwdata_r, n_bss_r, n_other_r, n_oob_r,
(unsigned long long)text_in_len);
if (cur_index_p)
*cur_index_p = i;
return (ssize_t)text_in_len;
}
#endif /* WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT */
#ifdef HAVE_FIPS
#ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
#include <wolfssl/wolfcrypt/fips_test.h>
#ifndef MAX_FIPS_DATA_SZ
#define MAX_FIPS_DATA_SZ 10000000
#endif
#ifndef MAX_FIPS_CODE_SZ
#define MAX_FIPS_CODE_SZ 10000000
#endif
#include <wolfssl/wolfcrypt/coding.h>
#ifndef NO_SHA256
#include <wolfssl/wolfcrypt/sha256.h>
#endif
#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
#include <wolfssl/wolfcrypt/sha512.h>
#endif
/* failsafe definitions for FIPS <5.3 */
#ifndef FIPS_IN_CORE_DIGEST_SIZE
#ifndef NO_SHA256
#define FIPS_IN_CORE_DIGEST_SIZE WC_SHA256_DIGEST_SIZE
#define FIPS_IN_CORE_HASH_TYPE WC_SHA256
#elif defined(WOLFSSL_SHA384)
#define FIPS_IN_CORE_DIGEST_SIZE WC_SHA384_DIGEST_SIZE
#define FIPS_IN_CORE_HASH_TYPE WC_SHA384
#elif defined(WOLFSSL_SHA512)
#define FIPS_IN_CORE_DIGEST_SIZE WC_SHA512_DIGEST_SIZE
#define FIPS_IN_CORE_HASH_TYPE WC_SHA512
#else
#error Unsupported FIPS hash alg.
#endif
#endif
#ifndef FIPS_IN_CORE_KEY_SZ
#define FIPS_IN_CORE_KEY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
#ifndef FIPS_IN_CORE_VERIFY_SZ
#define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_DIGEST_SIZE
#endif
int wc_fips_generate_hash(
const struct wc_reloc_table_segments *seg_map,
word32 digest_size,
const char *hmac_key_base16,
void *hmac_ctx,
wc_fips_verifyCore_hmac_setkey_fn hmac_setkey,
wc_fips_verifyCore_hmac_update_fn hmac_update,
wc_fips_verifyCore_hmac_final_fn hmac_final,
char *out,
word32 *out_size,
struct wc_reloc_counts *reloc_counts)
{
word32 binCoreSz = FIPS_IN_CORE_KEY_SZ;
int ret;
byte *hash = NULL;
byte *binCoreKey = NULL;
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
if (seg_map->text_is_live) {
if ((seg_map->reloc_tab_start == 0) ||
(seg_map->reloc_tab_len_start == 0))
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
}
else {
if ((seg_map->reloc_tab_end == 0) ||
(seg_map->reloc_tab_len_end == 0))
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
}
#endif
if (((seg_map->end > 0) && (seg_map->start >= seg_map->end)) ||
(seg_map->fips_text_start >= seg_map->fips_text_end) ||
(seg_map->fips_rodata_start >= seg_map->fips_rodata_end)
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
||
((seg_map->reloc_tab_end != 0) && (seg_map->reloc_tab_start >= seg_map->reloc_tab_end)) ||
((seg_map->reloc_tab_len_end != 0) && (seg_map->reloc_tab_len_start >= seg_map->reloc_tab_len_end)) ||
(seg_map->text_start >= seg_map->text_end) ||
(seg_map->rodata_start >= seg_map->rodata_end) ||
(seg_map->data_start >= seg_map->data_end) ||
(seg_map->bss_start >= seg_map->bss_end)
#endif
)
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
if (seg_map->end > 0) {
if ((seg_map->fips_text_start < seg_map->start) ||
(seg_map->fips_text_end >= seg_map->end) ||
(seg_map->fips_rodata_start < seg_map->start) ||
(seg_map->fips_rodata_end > seg_map->end) ||
(seg_map->verifyCore_start < seg_map->start) ||
(seg_map->verifyCore_end >= seg_map->end)
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
||
((seg_map->reloc_tab_end != 0) &&
((seg_map->reloc_tab_start < seg_map->start) ||
(seg_map->reloc_tab_end >= seg_map->end))) ||
((seg_map->reloc_tab_len_end != 0) &&
((seg_map->reloc_tab_len_start < seg_map->start) ||
(seg_map->reloc_tab_len_end >= seg_map->end))) ||
(seg_map->text_start < seg_map->start) ||
(seg_map->text_end >= seg_map->end) ||
(seg_map->rodata_start < seg_map->start) ||
(seg_map->rodata_end >= seg_map->end) ||
(seg_map->data_start < seg_map->start) ||
(seg_map->data_end >= seg_map->end) ||
(seg_map->bss_start < seg_map->start) ||
(seg_map->bss_end >= seg_map->end)
#endif
)
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BUFFER_E;
}
}
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
if ((seg_map->reloc_tab_len_end != 0) &&
(seg_map->reloc_tab_len_end - seg_map->reloc_tab_len_start != sizeof(word32)))
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
else if (seg_map->reloc_tab_len_start & (sizeof(word32) - 1)) {
/* fprintf(stderr, "%s: seg_map->reloc_tab_len_start isn't properly aligned: 0x%llx.\n", progname, (
unsigned long long)seg_map->reloc_tab_len_start); */
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_ALIGN_E;
}
else {
/* Note we don't currently handle modules that are endian-conflicted
* with the build host -- that'll be caught here, when reloc_tab_len is
* a nonsense byte-swapped value, or the final reloc_tab ent has
* nonsense flags.
*/
word32 reloc_tab_len = *(const word32 *)seg_map->reloc_tab_len_start;
const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->reloc_tab_start;
if (reloc_tab_len == 0) {
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
else if ((seg_map->end != 0) &&
((unsigned long)(reloc_tab + reloc_tab_len) > seg_map->end))
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
else if ((reloc_tab[reloc_tab_len - 1].dest_segment != WC_R_SEG_NONE) ||
(reloc_tab[reloc_tab_len - 1].reloc_type != WC_R_NONE))
{
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
else if ((seg_map->reloc_tab_end != 0) &&
(seg_map->reloc_tab_end - seg_map->reloc_tab_start != sizeof(struct wc_reloc_table_ent) * *(const word32 *)seg_map->reloc_tab_len_start))
{
/*
fprintf(stderr, "%s: wc_linuxkm_pie_reloc_tab_length from module (%u) is inconsistent with actual reloc_tab size %llu.\n",
progname,
*(const word32 *)seg_map->reloc_tab_len_start,
(unsigned long long)(seg_map->reloc_tab_end - seg_map->reloc_tab_start));
*/
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
}
#endif
if (out_size == NULL) {
RELOC_DEBUG_PRINTF("assert failed.\n");
return BAD_FUNC_ARG;
}
if (*out_size < (digest_size * 2) + 1) {
RELOC_DEBUG_PRINTF("assert failed.\n");
return BUFFER_E;
}
hash = XMALLOC(digest_size, 0, DYNAMIC_TYPE_TMP_BUFFER);
if (hash == NULL) {
ret = MEMORY_E;
RELOC_DEBUG_PRINTF("XMALLOC() failed.\n");
goto out;
}
binCoreKey = XMALLOC(binCoreSz, 0, DYNAMIC_TYPE_TMP_BUFFER);
if (binCoreKey == NULL) {
ret = MEMORY_E;
RELOC_DEBUG_PRINTF("XMALLOC() failed.\n");
goto out;
}
{
word32 base16_out_len = binCoreSz;
ret = Base16_Decode((const byte *)hmac_key_base16, strlen(hmac_key_base16), binCoreKey, &base16_out_len);
if (ret != 0) {
RELOC_DEBUG_PRINTF("Base16_Decode() failed.\n");
goto out;
}
if (base16_out_len != binCoreSz) {
ret = BAD_FUNC_ARG;
RELOC_DEBUG_PRINTF("assert failed.\n");
goto out;
}
}
ret = hmac_setkey(hmac_ctx, binCoreKey, binCoreSz);
if (ret) {
RELOC_DEBUG_PRINTF("hmac_setkey() failed.\n");
goto out;
}
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
{
ssize_t cur_reloc_index = -1;
const byte *text_p = (const byte *)seg_map->fips_text_start;
byte *buf = XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (! buf) {
ret = MEMORY_E;
RELOC_DEBUG_PRINTF("XMALLOC() failed.\n");
goto out;
}
while (text_p < (const byte *)seg_map->fips_text_end) {
/* wc_reloc_normalize_text() does its own WC_SANITIZE_DISABLE()s, so
* we defer it here.
*/
ssize_t progress = wc_reloc_normalize_text(
text_p,
min(8192, (word32)((const byte *)seg_map->fips_text_end - text_p)),
buf,
&cur_reloc_index,
seg_map,
reloc_counts);
if (progress <= 0) {
ret = IN_CORE_FIPS_E;
RELOC_DEBUG_PRINTF("wc_reloc_normalize_text() failed.\n");
break;
}
ret = hmac_update(hmac_ctx, buf, (word32)progress);
if (ret) {
RELOC_DEBUG_PRINTF("hmac_update() failed.\n");
break;
}
text_p += progress;
}
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
WC_SANITIZE_DISABLE();
#else
(void)reloc_counts;
WC_SANITIZE_DISABLE();
ret = hmac_update(hmac_ctx, (byte *)(wc_ptr_t)seg_map->fips_text_start, (word32)(seg_map->fips_text_end - seg_map->fips_text_start));
#endif /* !WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE */
if (ret) {
RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret);
ret = BAD_STATE_E;
WC_SANITIZE_ENABLE();
goto out;
}
/* don't hash verifyCore or changing verifyCore will change hash */
if (seg_map->verifyCore_start >= seg_map->fips_rodata_start && seg_map->verifyCore_start < seg_map->fips_rodata_end) {
ret = hmac_update(hmac_ctx, (byte*)seg_map->fips_rodata_start, (word32)(seg_map->verifyCore_start - (unsigned long)seg_map->fips_rodata_start));
if (ret) {
RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret);
ret = BAD_STATE_E;
goto out;
}
ret = hmac_update(hmac_ctx, (const byte *)seg_map->verifyCore_end, (word32)(seg_map->fips_rodata_end - (unsigned long)seg_map->verifyCore_end));
}
else {
ret = hmac_update(hmac_ctx, (byte*)seg_map->fips_rodata_start, (word32)(seg_map->fips_rodata_end - (unsigned long)seg_map->fips_rodata_start));
}
WC_SANITIZE_ENABLE();
if (ret) {
RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret);
ret = BAD_STATE_E;
goto out;
}
ret = hmac_final(hmac_ctx, hash, digest_size);
if (ret) {
RELOC_DEBUG_PRINTF("ERROR: hmac_final failed: err %d\n", ret);
ret = BAD_STATE_E;
goto out;
}
ret = Base16_Encode(hash, digest_size, (byte *)out, out_size);
out:
XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(binCoreKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
#endif /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE */
#endif /* HAVE_FIPS */
+229
View File
@@ -0,0 +1,229 @@
/* linuxkm_memory.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL 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 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* included by wolfssl/wolfcrypt/memory.h */
#ifndef LINUXKM_MEMORY_H
#define LINUXKM_MEMORY_H
enum wc_reloc_dest_segment {
WC_R_SEG_NONE = 1,
WC_R_SEG_TEXT,
WC_R_SEG_RODATA,
WC_R_SEG_RWDATA,
WC_R_SEG_BSS,
WC_R_SEG_OTHER
};
enum wc_reloc_type {
WC_R_NONE = 1,
WC_R_X86_64_32,
WC_R_X86_64_32S,
WC_R_X86_64_64,
WC_R_X86_64_PC32,
WC_R_X86_64_PLT32,
WC_R_AARCH64_ABS32,
WC_R_AARCH64_ABS64,
WC_R_AARCH64_ADD_ABS_LO12_NC,
WC_R_AARCH64_ADR_PREL_PG_HI21,
WC_R_AARCH64_CALL26,
WC_R_AARCH64_JUMP26,
WC_R_AARCH64_LDST8_ABS_LO12_NC,
WC_R_AARCH64_LDST16_ABS_LO12_NC,
WC_R_AARCH64_LDST32_ABS_LO12_NC,
WC_R_AARCH64_LDST64_ABS_LO12_NC,
WC_R_AARCH64_PREL32,
WC_R_ARM_ABS32,
WC_R_ARM_PREL31,
WC_R_ARM_REL32,
WC_R_ARM_THM_CALL,
WC_R_ARM_THM_JUMP11,
WC_R_ARM_THM_JUMP24,
WC_R_ARM_THM_MOVT_ABS,
WC_R_ARM_THM_MOVW_ABS_NC
};
/* This structure is accessed natively by kernel module glue logic, and also
* from outside by linux-fips-hash.c -- pack it, with explicit pad bits, to
* remove all doubt about layout.
*/
struct __attribute__((packed)) wc_reloc_table_ent {
unsigned int offset;
unsigned int dest_offset;
signed int dest_addend;
#define WC_RELOC_DEST_SEGMENT_BITS 3
unsigned int dest_segment:WC_RELOC_DEST_SEGMENT_BITS;
#define WC_RELOC_TYPE_BITS 5
unsigned int reloc_type:WC_RELOC_TYPE_BITS;
unsigned int _pad_bits:(32 - (WC_RELOC_DEST_SEGMENT_BITS + WC_RELOC_TYPE_BITS));
};
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
struct wc_reloc_table_segments {
unsigned long start;
unsigned long end;
unsigned long reloc_tab_start;
unsigned long reloc_tab_end;
unsigned long reloc_tab_len_start;
unsigned long reloc_tab_len_end;
unsigned long text_start;
unsigned long text_end;
#ifdef HAVE_FIPS
unsigned long fips_text_start;
unsigned long fips_text_end;
#endif /* HAVE_FIPS */
unsigned long rodata_start;
unsigned long rodata_end;
#ifdef HAVE_FIPS
unsigned long fips_rodata_start;
unsigned long fips_rodata_end;
unsigned long verifyCore_start;
unsigned long verifyCore_end;
#endif /* HAVE_FIPS */
unsigned long data_start;
unsigned long data_end;
unsigned long bss_start;
unsigned long bss_end;
int text_is_live;
};
#ifdef HAVE_FIPS
#define WC_RELOC_TABLE_SEGMENTS_INITIALIZER { \
.start = ~0UL, \
.end = ~0UL, \
.reloc_tab_start = ~0UL, \
.reloc_tab_end = ~0UL, \
.reloc_tab_len_start = ~0UL, \
.reloc_tab_len_end = ~0UL, \
.text_start = ~0UL, \
.text_end = ~0UL, \
.fips_text_start = ~0UL, \
.fips_text_end = ~0UL, \
.rodata_start = ~0UL, \
.rodata_end = ~0UL, \
.fips_rodata_start = ~0UL, \
.fips_rodata_end = ~0UL, \
.verifyCore_start = ~0UL, \
.verifyCore_end = ~0UL, \
.data_start = ~0UL, \
.data_end = ~0UL, \
.bss_start = ~0UL, \
.bss_end = 0, \
.text_is_live = 0 \
}
#else /* !HAVE_FIPS */
#define WC_RELOC_TABLE_SEGMENTS_INITIALIZER { \
.start = ~0UL, \
.end = ~0UL, \
.reloc_tab_start = ~0UL, \
.reloc_tab_end = ~0UL, \
.reloc_tab_len_start = ~0UL, \
.reloc_tab_len_end = ~0UL, \
.text_start = ~0UL, \
.text_end = ~0UL, \
.rodata_start = ~0UL, \
.rodata_end = ~0UL, \
.data_start = ~0UL, \
.data_end = ~0UL, \
.bss_start = ~0UL, \
.bss_end = 0, \
.text_is_live = 0 \
}
#endif /* !HAVE_FIPS */
struct wc_reloc_counts {
int text;
int rodata;
int rwdata;
int bss;
int other;
};
#elif defined(HAVE_FIPS)
struct wc_reloc_table_segments {
unsigned long start;
unsigned long end;
unsigned long fips_text_start;
unsigned long fips_text_end;
unsigned long fips_rodata_start;
unsigned long fips_rodata_end;
unsigned long verifyCore_start;
unsigned long verifyCore_end;
};
#define WC_RELOC_TABLE_SEGMENTS_INITIALIZER { \
.start = ~0UL, \
.end = ~0UL, \
.fips_text_start = ~0UL, \
.fips_text_end = ~0UL, \
.fips_rodata_start = ~0UL, \
.fips_rodata_end = ~0UL, \
.verifyCore_start = ~0UL, \
.verifyCore_end = ~0UL \
}
struct wc_reloc_counts {
int dummy;
};
#endif /* !WC_SYM_RELOC_TABLES && HAVE_FIPS */
#if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT)
WOLFSSL_API ssize_t wc_reloc_normalize_text(
const byte *text_in,
size_t text_in_len,
byte *text_out,
ssize_t *cur_index_p,
const struct wc_reloc_table_segments *seg_map,
struct wc_reloc_counts *reloc_counts);
#endif /* WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT */
#ifdef HAVE_FIPS
#if defined(WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE) || defined(WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE_SUPPORT)
typedef int (*wc_fips_verifyCore_hmac_setkey_fn)(void *ctx, const byte *key, word32 key_len);
typedef int (*wc_fips_verifyCore_hmac_update_fn)(void *ctx, const byte *in, word32 in_len);
typedef int (*wc_fips_verifyCore_hmac_final_fn)(void *ctx, byte *out, word32 out_sz);
WOLFSSL_API int wc_fips_generate_hash(
const struct wc_reloc_table_segments *seg_map,
word32 digest_size,
const char *hmac_key_base16,
void *hmac_ctx,
wc_fips_verifyCore_hmac_setkey_fn hmac_setkey,
wc_fips_verifyCore_hmac_update_fn hmac_update,
wc_fips_verifyCore_hmac_final_fn hmac_final,
char *out,
word32 *out_size,
struct wc_reloc_counts *reloc_counts);
#endif
#endif /* HAVE_FIPS */
#endif /* LINUXKM_MEMORY_H */
+170 -76
View File
@@ -24,27 +24,6 @@
#ifndef LINUXKM_WC_PORT_H
#define LINUXKM_WC_PORT_H
/*
* CRITICAL: Disable ARM64 LSE atomics for out-of-tree modules.
*
* When CONFIG_ARM64_LSE_ATOMICS is enabled, the kernel uses static keys
* (jump labels) in system_uses_lse_atomics() to choose between LSE and
* LL/SC atomic implementations at runtime. These static keys generate
* asm goto statements that reference .jump_table section symbols which
* cannot be resolved in out-of-tree modules, causing:
* "error: impossible constraint in 'asm'"
*
* By undefining CONFIG_ARM64_LSE_ATOMICS here (before any kernel headers
* that use atomics are included), we force use of the LL/SC fallback path
* which works correctly in out-of-tree modules.
*
* This must appear BEFORE #include <linux/version.h> because that header
* may transitively include headers that use atomics.
*/
#ifdef CONFIG_ARM64_LSE_ATOMICS
#undef CONFIG_ARM64_LSE_ATOMICS
#endif
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
@@ -322,6 +301,22 @@
#define queued_spin_lock_slowpath my__queued_spin_lock_slowpath
#endif
/*
* Disable ARM64 LSE atomics for out-of-tree modules.
*
* When CONFIG_ARM64_LSE_ATOMICS is enabled, the kernel uses static keys
* (jump labels) in system_uses_lse_atomics() to choose between LSE and
* LL/SC atomic implementations at runtime. These static keys generate
* asm goto statements that reference .jump_table section symbols which
* cannot be resolved in out-of-tree modules, causing:
* "error: impossible constraint in 'asm'"
*
* By undefining CONFIG_ARM64_LSE_ATOMICS here (before any kernel headers
* that use atomics are included), we force use of the LL/SC fallback path
* which works correctly in out-of-tree modules.
*/
#undef CONFIG_ARM64_LSE_ATOMICS
#include <linux/kernel.h>
#include <linux/ctype.h>
@@ -511,6 +506,10 @@
#include <linux/slab.h>
#include <linux/sched.h>
#if __has_include(<linux/sched/task_stack.h>)
/* for task_stack_page() */
#include <linux/sched/task_stack.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
/* for signal_pending() */
#include <linux/sched/signal.h>
@@ -816,12 +815,6 @@
#ifdef WC_SYM_RELOC_TABLES
#ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER
#define WOLFSSL_TEXT_SEGMENT_CANONICALIZER(text_in, text_in_len, text_out, cur_index_p) \
wc_linuxkm_normalize_relocations(text_in, text_in_len, text_out, cur_index_p)
#define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192
#endif
extern __attribute__((error("uncallable fencepost"))) int __wc_text_start(void);
extern __attribute__((error("uncallable fencepost"))) int __wc_text_end(void);
#ifdef HAVE_FIPS
@@ -840,59 +833,18 @@
__wc_bss_start[],
__wc_bss_end[];
struct wc_linuxkm_pie_reloc_tab_ent {
unsigned int offset;
#define WC_RELOC_DEST_SEGMENT_BITS 3
unsigned int dest_segment:WC_RELOC_DEST_SEGMENT_BITS;
#define WC_RELOC_TYPE_BITS 5
unsigned int reloc_type:WC_RELOC_TYPE_BITS;
};
enum wc_reloc_dest_segment {
WC_R_SEG_NONE = 0,
WC_R_SEG_TEXT,
WC_R_SEG_RODATA,
WC_R_SEG_RWDATA,
WC_R_SEG_BSS,
WC_R_SEG_OTHER
};
enum wc_reloc_type {
WC_R_NONE = 0,
WC_R_X86_64_32,
WC_R_X86_64_32S,
WC_R_X86_64_64,
WC_R_X86_64_PC32,
WC_R_X86_64_PLT32,
WC_R_AARCH64_ABS32,
WC_R_AARCH64_ABS64,
WC_R_AARCH64_ADD_ABS_LO12_NC,
WC_R_AARCH64_ADR_PREL_PG_HI21,
WC_R_AARCH64_CALL26,
WC_R_AARCH64_JUMP26,
WC_R_AARCH64_LDST8_ABS_LO12_NC,
WC_R_AARCH64_LDST16_ABS_LO12_NC,
WC_R_AARCH64_LDST32_ABS_LO12_NC,
WC_R_AARCH64_LDST64_ABS_LO12_NC,
WC_R_AARCH64_PREL32,
WC_R_ARM_ABS32,
WC_R_ARM_PREL31,
WC_R_ARM_REL32,
WC_R_ARM_THM_CALL,
WC_R_ARM_THM_JUMP11,
WC_R_ARM_THM_JUMP24,
WC_R_ARM_THM_MOVT_ABS,
WC_R_ARM_THM_MOVW_ABS_NC
};
extern const struct wc_linuxkm_pie_reloc_tab_ent wc_linuxkm_pie_reloc_tab[];
extern const unsigned long wc_linuxkm_pie_reloc_tab_length;
extern ssize_t wc_linuxkm_normalize_relocations(
const u8 *text_in,
size_t text_in_len,
u8 *text_out,
ssize_t *cur_index_p);
#ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER
#define WOLFSSL_TEXT_SEGMENT_CANONICALIZER(text_in, text_in_len, text_out, cur_index_p) \
wc_linuxkm_normalize_relocations(text_in, text_in_len, text_out, cur_index_p)
#define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192
#endif
#ifdef CONFIG_MIPS
#undef __ARCH_MEMCMP_NO_REDIRECT
#undef memcmp
@@ -900,7 +852,9 @@
#endif
struct wolfssl_linuxkm_pie_redirect_table {
#ifdef HAVE_FIPS
typeof(wc_linuxkm_normalize_relocations) *wc_linuxkm_normalize_relocations;
#endif
#ifndef __ARCH_MEMCMP_NO_REDIRECT
typeof(memcmp) *memcmp;
@@ -1184,6 +1138,11 @@
typeof(wc_linuxkm_check_for_intr_signals) *wc_linuxkm_check_for_intr_signals;
typeof(wc_linuxkm_relax_long_loop) *wc_linuxkm_relax_long_loop;
#ifdef CONFIG_KASAN
typeof(kasan_disable_current) *kasan_disable_current;
typeof(kasan_enable_current) *kasan_enable_current;
#endif
const void *_last_slot;
};
@@ -1226,8 +1185,10 @@
#ifdef WC_CONTAINERIZE_THIS
#define wc_linuxkm_normalize_relocations \
WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations)
#ifdef HAVE_FIPS
#define wc_linuxkm_normalize_relocations \
WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations)
#endif
#ifndef __ARCH_MEMCMP_NO_REDIRECT
#define memcmp WC_PIE_INDIRECT_SYM(memcmp)
@@ -1469,10 +1430,143 @@
#define wc_linuxkm_check_for_intr_signals WC_PIE_INDIRECT_SYM(wc_linuxkm_check_for_intr_signals)
#define wc_linuxkm_relax_long_loop WC_PIE_INDIRECT_SYM(wc_linuxkm_relax_long_loop)
#ifdef CONFIG_KASAN
#define kasan_disable_current WC_PIE_INDIRECT_SYM(kasan_disable_current)
#define kasan_enable_current WC_PIE_INDIRECT_SYM(kasan_enable_current)
#endif
#endif /* WC_CONTAINERIZE_THIS */
#endif /* WC_SYM_RELOC_TABLES */
#ifdef WC_LINUXKM_STACK_DEBUG
#ifndef CONFIG_THREAD_INFO_IN_TASK
#error WC_LINUXKM_STACK_DEBUG requires CONFIG_THREAD_INFO_IN_TASK
#endif
#ifdef CONFIG_STACK_GROWSUP
#error WC_LINUXKM_STACK_DEBUG requires !CONFIG_STACK_GROWSUP
#endif
static __always_inline unsigned long wc_linuxkm_stack_bottom(void) {
void *ret = task_stack_page(get_current());
return (unsigned long)(uintptr_t)ret;
}
static __always_inline unsigned long wc_linuxkm_stack_top(void) {
return wc_linuxkm_stack_bottom() + THREAD_SIZE;
}
#if defined(CONFIG_X86)
static __always_inline unsigned long wc_linuxkm_stack_current(void) {
unsigned long rsp;
asm volatile("mov %%rsp, %0" : "=r" (rsp));
return wc_linuxkm_stack_top() - rsp;
}
static __always_inline unsigned long wc_linuxkm_stack_left(void) {
unsigned long rsp;
asm volatile("mov %%rsp, %0" : "=r" (rsp));
return rsp - wc_linuxkm_stack_bottom();
}
#define WC_LINUXKM_HAVE_STACK_DEBUG
#elif defined(CONFIG_ARM64)
static __always_inline unsigned long wc_linuxkm_stack_current(void) {
unsigned long sp;
asm volatile("mov %0, sp" : "=r" (sp));
return wc_linuxkm_stack_top() - sp;
}
static __always_inline unsigned long wc_linuxkm_stack_left(void) {
unsigned long sp;
asm volatile("mov %0, sp" : "=r" (sp));
return sp - wc_linuxkm_stack_bottom();
}
#define WC_LINUXKM_HAVE_STACK_DEBUG
#elif defined(CONFIG_ARM)
static __always_inline unsigned long wc_linuxkm_stack_current(void) {
unsigned long sp;
asm volatile("mov %0, sp" : "=r" (sp));
return wc_linuxkm_stack_top() - sp;
}
static __always_inline unsigned long wc_linuxkm_stack_left(void) {
unsigned long sp;
asm volatile("mov %0, sp" : "=r" (sp));
return sp - wc_linuxkm_stack_bottom();
}
#define WC_LINUXKM_HAVE_STACK_DEBUG
#endif /* CONFIG_ARM */
#ifndef WC_LINUXKM_HAVE_STACK_DEBUG
#error WC_LINUXKM_STACK_DEBUG implementation missing for target.
#endif
/* An unsigned long STACK_END_MAGIC is stored at the bottom of the stack.
* Additionally, though the kernel stack doesn't have a red zone, it
* nonetheless uses some bytes below the current stack pointer and mayhem
* ensues immediately if it's overwritten.
*/
#ifndef WC_KERNEL_STACK_MARGIN_BOTTOM
#define WC_KERNEL_STACK_MARGIN_BOTTOM sizeof(unsigned long)
#endif
#ifndef WC_KERNEL_STACK_MARGIN_TOP
#define WC_KERNEL_STACK_MARGIN_TOP 8
#endif
static __always_inline void wc_linuxkm_stack_hwm_prepare(unsigned char sentinel) {
unsigned long s = wc_linuxkm_stack_bottom();
unsigned long z;
unsigned long flags;
if (*(unsigned long *)s != STACK_END_MAGIC)
pr_err("ERROR: bottom of stack is not STACK_END_MAGIC.\n");
local_irq_save(flags);
kasan_disable_current();
z = wc_linuxkm_stack_left();
if (z > WC_KERNEL_STACK_MARGIN_BOTTOM + WC_KERNEL_STACK_MARGIN_TOP)
memset((void *)(s + WC_KERNEL_STACK_MARGIN_BOTTOM), sentinel,
z - (WC_KERNEL_STACK_MARGIN_BOTTOM + WC_KERNEL_STACK_MARGIN_TOP));
kasan_enable_current();
local_irq_restore(flags);
if (z <= WC_KERNEL_STACK_MARGIN_BOTTOM + WC_KERNEL_STACK_MARGIN_TOP)
pr_err("ERROR: wc_linuxkm_stack_hwm_prepare() called with only %lu bytes of stack left, "
"versus margin %zu.\n", z, WC_KERNEL_STACK_MARGIN_BOTTOM + WC_KERNEL_STACK_MARGIN_TOP);
}
static __always_inline unsigned long wc_linuxkm_stack_hwm_measure_rel(unsigned char sentinel) {
unsigned long s = wc_linuxkm_stack_bottom();
unsigned long z = wc_linuxkm_stack_left();
unsigned char *i;
if (z <= WC_KERNEL_STACK_MARGIN_BOTTOM + WC_KERNEL_STACK_MARGIN_TOP)
return (unsigned long)-1;
kasan_disable_current();
for (i = (unsigned char *)s + WC_KERNEL_STACK_MARGIN_BOTTOM;
i < ((unsigned char *)s + z) && (*i == sentinel);
++i);
kasan_enable_current();
return z - ((unsigned long)i - s);
}
static __always_inline unsigned long wc_linuxkm_stack_hwm_measure_total(unsigned char sentinel) {
unsigned long rel = wc_linuxkm_stack_hwm_measure_rel(sentinel);
if (rel == (unsigned long)-1)
return rel;
else
return rel + wc_linuxkm_stack_current();
}
#endif /* WC_LINUXKM_STACK_DEBUG */
/* remove this multifariously conflicting macro, picked up from
* Linux arch/<arch>/include/asm/current.h.
*/
+359 -683
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -2285,7 +2285,7 @@ static const char* bench_result_words2[][6] = {
#warning Large/Unalligned AuthSz could result in errors with /dev/crypto
#endif
/* use kB instead of mB for embedded benchmarking */
/* use kB instead of MB for embedded benchmarking */
#ifdef BENCH_EMBEDDED
#ifndef BENCH_NTIMES
#define BENCH_NTIMES 2
@@ -9089,6 +9089,10 @@ void bench_cmac(int useDeviceID)
#ifdef HAVE_SCRYPT
#ifdef WOLFSSL_KERNEL_MODE
#error wc_scrypt benchmarking with cost 14 is not kernel-compatible (requires 16 MB contiguous allocation)
#endif
void bench_scrypt(void)
{
byte derived[64];
+3 -2
View File
@@ -1827,6 +1827,7 @@ WOLFSSL_LOCAL int SAVE_VECTOR_REGISTERS2_fuzzer(void) {
#endif /* DEBUG_VECTOR_REGISTER_ACCESS_FUZZING */
#ifdef WOLFSSL_LINUXKM
#include "../../linuxkm/linuxkm_memory.c"
#if defined(WOLFSSL_LINUXKM) || defined(WC_SYM_RELOC_TABLES) || \
defined(WC_SYM_RELOC_TABLES_SUPPORT)
#include "linuxkm/linuxkm_memory.c"
#endif
+5
View File
@@ -538,6 +538,11 @@ WOLFSSL_LOCAL int wc_debug_CipherLifecycleFree(void **CipherLifecycleTag,
#endif
#endif
#if defined(WOLFSSL_LINUXKM) || defined(WC_SYM_RELOC_TABLES) || \
defined(WC_SYM_RELOC_TABLES_SUPPORT)
#include "linuxkm/linuxkm_memory.h"
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
+9
View File
@@ -3956,6 +3956,11 @@ extern void uITRON4_free(void *p) ;
#if !defined(WC_NO_VERBOSE_RNG) && !defined(WC_VERBOSE_RNG)
#define WC_VERBOSE_RNG
#endif
#if WOLFSSL_GENERAL_ALIGNMENT < SIZEOF_LONG
#undef WOLFSSL_GENERAL_ALIGNMENT
#define WOLFSSL_GENERAL_ALIGNMENT SIZEOF_LONG
#endif
#endif /* WOLFSSL_KERNEL_MODE */
#if defined(WC_SYM_RELOC_TABLES) && defined(HAVE_FIPS) && \
@@ -4271,6 +4276,10 @@ extern void uITRON4_free(void *p) ;
#define WOLFSSL_BASE64_DECODE
#endif
#if defined(WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE) && !defined(WOLFSSL_BASE16)
#define WOLFSSL_BASE16
#endif
#if defined(FORTRESS) && !defined(HAVE_EX_DATA)
#define HAVE_EX_DATA
#endif