bsdkm: fips support.

This commit is contained in:
jordan
2025-12-28 10:16:53 -06:00
parent e70e7cb144
commit e4996c317e
8 changed files with 332 additions and 48 deletions

View File

@@ -5,8 +5,14 @@ WOLFSSL_DIR=../
CFLAGS+=-I${WOLFSSL_DIR}
CFLAGS+=-DWOLFSSL_IGNORE_FILE_WARN -DHAVE_CONFIG_H -DNO_MAIN_DRIVER
# debug printing
# CFLAGS+=-DWOLFSSL_BSDKM_VERBOSE_DEBUG
#
# debug options
# verbose printing:
# CFLAGS+=-DWOLFSSL_BSDKM_VERBOSE_DEBUG
#
# print memory mallocs / frees:
# CFLAGS+=-DWOLFSSL_BSDKM_MEMORY_DEBUG
#
CFLAGS+=$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
# FreeBSD make does not support GNU make's patsubst and related. Filter

98
bsdkm/README.md Normal file
View File

@@ -0,0 +1,98 @@
# wolfSSL bsdkm (bsd kernel module)
libwolfssl supports building as a FreeBSD kernel module (`libwolfssl.ko`).
When loaded, wolfCrypt is made available to the rest of the kernel, allowing
other loadable modules to link to wolfCrypt.
Supported features:
- wolfCrypt in kernel.
- FIPS-wolfcrypt.
Planned features:
- crypto acceleration: AES-NI, AVX, etc.
- kernel opencrypto driver registration.
- full wolfSSL in kernel (kernel TLS).
## Building and Installing
Build bsdkm with:
```sh
./configure --enable-freebsdkm --enable-cryptonly && make
```
The default freebsdkm build assumes kernel source tree root at `/usr/src/sys/`.
Use `--with-kernel-source=PATH` to configure a different path.
Assuming you are targeting your native system, install with:
```sh
sudo kldload bsdkm/libwolfssl.ko
```
You should see it now:
```sh
kldstat -m libwolfssl
Id Refs Name
509 1 libwolfssl
```
Unload with:
```sh
sudo kldunload libwolfssl
```
### options
| freebsdkm option | description |
| :------------------------------- | :--------------------------------------- |
| --with-bsd-export-syms=LIST | Export list of symbols as global. <br>. Options are 'all', 'none', or <br> comma separated list of symbols. |
| --with-kernel-source=PATH | Path to kernel tree root (default `/usr/src/sys`) |
### FIPS
Building with FIPS is largely the same, with the additional step of
configuring a fips hash.
1. Build bsdkm (the `fips_hash` here is a placeholder):
```sh
fips_hash=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
./configure --enable-freebsdkm --enable-cryptonly --enable-fips=v6 \
CFLAGS="-DWOLFCRYPT_FIPS_CORE_HASH_VALUE=$fips_hash" && make
```
2. Attempt first install. This is expected to fail, because the hash was a
placeholder.
```sh
$ sudo kldload bsdkm/libwolfssl.ko
Password:
kldload: an error occurred while loading module bsdkm/libwolfssl.ko. Please check dmesg(8) for more details.
```
3. Check dmesg output for the updated hash value (yours will be different).
```sh
$ dmesg | tail -n5
In-core integrity hash check failure.
Rebuild with "WOLFCRYPT_FIPS_CORE_HASH_VALUE=3B144A08F291DBA536324646BBD127447B8F222D29A135780E330351E0DF9F0F".
error: wc_RunAllCast_fips failed at shutdown with return value 19
info: libwolfssl unloaded
module_register_init: MOD_LOAD (libwolfssl_fips, 0xffffffff842c28d0, 0) error 85
```
4. Repeat steps 1-2 with the new hash value. The load should succeed now.
```
$ kldstat -m libwolfssl_fips
Id Refs Name
523 1 libwolfssl_fips
```
On unload, the FIPS self-test will run a final time and print its status
to system message buffer:
```
info: wolfCrypt FIPS re-self-test succeeded at unload: all algorithms re-verified.
info: libwolfssl unloaded
```

View File

@@ -37,11 +37,15 @@
#include <sys/limits.h>
#endif /* !CHAR_BIT*/
#define NO_THREAD_LS
#define NO_ATTRIBUTE_CONSTRUCTOR
/* needed to prevent wolfcrypt/src/asn.c version shadowing
* extern global version from /usr/src/sys/sys/systm.h */
#define version wc_version
#define wc_km_printf printf
#define wc_km_printf printf
#define wc_km_print_err printf
/* str and char utility functions */
#define XATOI(s) ({ \
@@ -51,7 +55,7 @@
_xatoi_ret = 0; \
} \
(int)_xatoi_ret; \
})
})
#if !defined(XMALLOC_OVERRIDE)
#error bsdkm requires XMALLOC_OVERRIDE
@@ -60,21 +64,45 @@
/* use malloc and free from /usr/include/sys/malloc.h */
extern struct malloc_type M_WOLFSSL[1];
#define XMALLOC(s, h, t) \
({(void)(h); (void)(t); malloc(s, M_WOLFSSL, M_WAITOK | M_ZERO);})
#if defined(WOLFSSL_BSDKM_MEMORY_DEBUG)
#define XMALLOC(s, h, t) ({ \
(void)(h); (void)(t); \
void * _ptr = malloc(s, M_WOLFSSL, M_WAITOK | M_ZERO); \
printf("info: malloc: %p, M_WOLFSSL, %zu\n", _ptr, (size_t) s); \
(void *)_ptr; \
})
#ifdef WOLFSSL_XFREE_NO_NULLNESS_CHECK
#define XFREE(p, h, t) \
({(void)(h); (void)(t); free(p, M_WOLFSSL);})
#define XFREE(p, h, t) ({ \
void* _xp; (void)(h); (void)(t); _xp = (p); \
printf("info: free: %p, M_WOLFSSL\n", p); \
if(_xp) free(_xp, M_WOLFSSL); \
})
#else
#define XFREE(p, h, t) \
({void* _xp; (void)(h); (void)(t); _xp = (p); \
if(_xp) free(_xp, M_WOLFSSL);})
#endif
#define XMALLOC(s, h, t) ({ \
(void)(h); (void)(t); \
void * _ptr = malloc(s, M_WOLFSSL, M_WAITOK | M_ZERO); \
(void *)_ptr; \
})
#define XFREE(p, h, t) ({ \
void* _xp; (void)(h); (void)(t); _xp = (p); \
if(_xp) free(_xp, M_WOLFSSL); \
})
#endif /* WOLFSSL_BSDKM_DEBUG_MEMORY */
#if !defined(SINGLE_THREADED)
#define WC_MUTEX_OPS_INLINE
/* Copied from wc_port.h */
#if defined(HAVE_FIPS) && !defined(WOLFSSL_API_PREFIX_MAP)
/* For FIPS keep the function names the same */
#define wc_InitMutex InitMutex
#define wc_FreeMutex FreeMutex
#define wc_LockMutex LockMutex
#define wc_UnLockMutex UnLockMutex
#define NO_THREAD_LS
#endif /* HAVE_FIPS */
typedef struct wolfSSL_Mutex {
struct mtx lock;
} wolfSSL_Mutex;
@@ -106,12 +134,18 @@ extern struct malloc_type M_WOLFSSL[1];
#if defined(WOLFSSL_HAVE_ATOMIC_H) && !defined(WOLFSSL_NO_ATOMICS)
#include <machine/atomic.h>
typedef volatile int wolfSSL_Atomic_Int;
typedef volatile int wolfSSL_Atomic_Int;
typedef volatile unsigned int wolfSSL_Atomic_Uint;
#define WOLFSSL_ATOMIC_INITIALIZER(x) (x)
#define WOLFSSL_ATOMIC_LOAD(x) (int)atomic_load_acq_int(&(x))
#define WOLFSSL_ATOMIC_STORE(x, v) atomic_store_rel_int(&(x), (v))
#define WOLFSSL_ATOMIC_OPS
#if defined(HAVE_FIPS)
/* There is no corresponding ATOMIC_INIT macro in FreeBSD.
* The FreeBSD equivalent is just an integer initialization. */
#define ATOMIC_INIT(x) (x)
#endif
#endif /* WOLFSSL_HAVE_ATOMIC_H && !WOLFSSL_NO_ATOMICS */
#endif /* WOLFSSL_BSDKM */

View File

@@ -4,5 +4,6 @@
EXTRA_DIST += m4/ax_bsdkm.m4 \
bsdkm/Makefile \
bsdkm/README.md \
bsdkm/wolfkmod.c \
bsdkm/bsdkm_wc_port.h

View File

@@ -33,10 +33,20 @@
#else
#include <wolfssl/ssl.h>
#endif
#ifdef HAVE_FIPS
#ifdef USE_CONTESTMUTEX
#error USE_CONTESTMUTEX is incompatible with WOLFSSL_BSDKM
#endif
#include <wolfssl/wolfcrypt/fips_test.h>
#endif /* HAVE_FIPS */
#if !defined(NO_CRYPT_TEST)
#include <wolfcrypt/test/test.h>
#endif
#include <wolfssl/wolfcrypt/random.h>
MALLOC_DEFINE(M_WOLFSSL, "libwolfssl", "wolfSSL kernel memory");
static int wolfkmod_init(void);
@@ -44,47 +54,140 @@ static int wolfkmod_cleanup(void);
static int wolfkmod_load(void);
static int wolfkmod_unload(void);
#ifdef HAVE_FIPS
#define WOLFKMOD_FIPS_ERR_MSG(hash) ({ \
printf("In-core integrity hash check failure.\n"); \
if ((hash)) \
printf("Rebuild with \"WOLFCRYPT_FIPS_CORE_HASH_VALUE=%s\".\n", \
hash); \
else \
printf("error: could not compute new hash. " \
"Contact customer support.\n"); \
})
static void wolfkmod_fips_cb(int ok, int err, const char * hash)
{
if ((!ok) || (err != 0)) {
printf("error: libwolfssl FIPS error: %s\n",
wc_GetErrorString(err));
}
if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) {
WOLFKMOD_FIPS_ERR_MSG(hash);
}
}
#endif /* HAVE_FIPS */
static int wolfkmod_init(void)
{
int ret = 0;
int error = 0;
#ifdef HAVE_FIPS
error = wolfCrypt_SetCb_fips(wolfkmod_fips_cb);
if (error != 0) {
printf("error: wolfCrypt_SetCb_fips failed: %s\n",
wc_GetErrorString(error));
return (ECANCELED);
}
fipsEntry();
error = wolfCrypt_GetStatus_fips();
if (error != 0) {
printf("error: wolfCrypt_GetStatus_fips failed: %d: %s\n",
error, wc_GetErrorString(error));
if (error == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) {
const char *newhash = wolfCrypt_GetCoreHash_fips();
WOLFKMOD_FIPS_ERR_MSG(newhash);
}
return (ECANCELED);
}
#endif /* HAVE_FIPS */
#ifdef WC_RNG_SEED_CB
error = wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT);
if (error < 0) {
printf("error: wc_SetSeed_Cb failed: %d\n", error);
return (ECANCELED);
}
#endif /* WC_RNG_SEED_CB */
#ifdef WOLFCRYPT_ONLY
ret = wolfCrypt_Init();
if (ret != 0) {
printf("error: wolfCrypt_Init failed: %s\n", wc_GetErrorString(ret));
error = wolfCrypt_Init();
if (error != 0) {
printf("error: wolfCrypt_Init failed: %s\n", wc_GetErrorString(error));
return (ECANCELED);
}
#else
ret = wolfSSL_Init();
if (ret != WOLFSSL_SUCCESS) {
printf("error: wolfSSL_Init failed: %s\n", wc_GetErrorString(ret));
error = wolfSSL_Init();
if (error != WOLFSSL_SUCCESS) {
printf("error: wolfSSL_Init failed: %s\n", wc_GetErrorString(error));
return (ECANCELED);
}
#endif
#ifdef HAVE_FIPS
error = wc_RunAllCast_fips();
if (error != 0) {
printf("error: wc_RunAllCast_fips failed with "
"return value %d\n", error);
return (ECANCELED);
}
else {
printf("FIPS 140-3 wolfCrypt-fips v%d.%d.%d%s%s startup "
"self-test succeeded.\n",
#ifdef HAVE_FIPS_VERSION_MAJOR
HAVE_FIPS_VERSION_MAJOR,
#else
HAVE_FIPS_VERSION,
#endif
#ifdef HAVE_FIPS_VERSION_MINOR
HAVE_FIPS_VERSION_MINOR,
#else
0,
#endif
#ifdef HAVE_FIPS_VERSION_PATCH
HAVE_FIPS_VERSION_PATCH,
#else
0,
#endif
#ifdef HAVE_FIPS_VERSION_PORT
"-",
HAVE_FIPS_VERSION_PORT
#else
"",
""
#endif
);
}
#endif
return (0);
}
static int wolfkmod_cleanup(void)
{
int ret = 0;
int error = 0;
#ifdef WOLFCRYPT_ONLY
ret = wolfCrypt_Cleanup();
if (ret != 0) {
printf("error: wolfCrypt_Cleanup failed: %s\n", wc_GetErrorString(ret));
error = wolfCrypt_Cleanup();
if (error != 0) {
printf("error: wolfCrypt_Cleanup failed: %s\n",
wc_GetErrorString(error));
return (ECANCELED);
}
#else
ret = wolfSSL_Cleanup();
if (ret != WOLFSSL_SUCCESS) {
printf("error: wolfSSL_Cleanup failed: %s\n", wc_GetErrorString(ret));
error = wolfSSL_Cleanup();
if (error != WOLFSSL_SUCCESS) {
printf("error: wolfSSL_Cleanup failed: %s\n",
wc_GetErrorString(error));
return (ECANCELED);
}
#endif /* WOLFCRYPT_ONLY */
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
printf("info: libwolfssl " LIBWOLFSSL_VERSION_STRING " cleanup complete.\n");
printf("info: libwolfssl " LIBWOLFSSL_VERSION_STRING
" cleanup complete.\n");
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
return (0);
@@ -92,17 +195,17 @@ static int wolfkmod_cleanup(void)
static int wolfkmod_load(void)
{
int ret = 0;
int error = 0;
ret = wolfkmod_init();
if (ret != 0) {
error = wolfkmod_init();
if (error != 0) {
return (ECANCELED);
}
#ifndef NO_CRYPT_TEST
ret = wolfcrypt_test(NULL);
if (ret != 0) {
printf("error: wolfcrypt test failed with return code: %d\n", ret);
error = wolfcrypt_test(NULL);
if (error != 0) {
printf("error: wolfcrypt test failed: %d\n", error);
(void)wolfkmod_cleanup();
return (ECANCELED);
}
@@ -123,52 +226,83 @@ static int wolfkmod_load(void)
static int wolfkmod_unload(void)
{
int ret = 0;
int error = 0;
ret = wolfkmod_cleanup();
#ifdef HAVE_FIPS
error = wc_RunAllCast_fips();
if (error != 0) {
printf("error: wc_RunAllCast_fips failed at shutdown with "
"return value %d\n", error);
}
else
printf("info: wolfCrypt FIPS re-self-test succeeded at unload: "
"all algorithms re-verified.\n");
#endif
error = wolfkmod_cleanup();
/**
* todo: unregister wolfcrypt algs here with crypto_unregister_all
* and related.
* */
if (ret == 0) {
if (error == 0) {
printf("info: libwolfssl unloaded\n");
}
return (ret);
return (error);
}
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
static const char * wolfkmod_event_to_str(modeventtype_t what)
{
switch (what) {
case MOD_LOAD:
return "MOD_LOAD";
case MOD_UNLOAD:
return "MOD_UNLOAD";
case MOD_SHUTDOWN:
return "MOD_SHUTDOWN";
case MOD_QUIESCE:
return "MOD_QUIESCE";
}
}
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
/* see /usr/include/sys/module.h for more info. */
static int
wolfkmod_event(struct module * m, int what, void * arg)
{
int ret = 0;
int error = 0;
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
printf("info: wolfkmod_event: %s\n", wolfkmod_event_to_str(what));
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
switch (what) {
case MOD_LOAD:
ret = wolfkmod_load();
error = wolfkmod_load();
break;
case MOD_UNLOAD:
ret = wolfkmod_unload();
error = wolfkmod_unload();
break;
case MOD_SHUTDOWN:
case MOD_QUIESCE:
default:
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
printf("info: not implemented: %d\n", what);
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
ret = EOPNOTSUPP;
error = EOPNOTSUPP;
}
(void)m;
(void)arg;
return (ret);
return (error);
}
static moduledata_t libwolfmod = {
#ifdef HAVE_FIPS
"libwolfssl_fips", /* module name */
#else
"libwolfssl", /* module name */
#endif /* HAVE_FIPS */
wolfkmod_event, /* module event handler */
NULL /* extra data, unused */
};

View File

@@ -830,6 +830,11 @@ then
AM_CFLAGS="$AM_CFLAGS -DXMALLOC_OVERRIDE -DWOLFCRYPT_ONLY"
AM_CFLAGS="$AM_CFLAGS -DNO_ASN_TIME"
if test "$ax_enable_debug" = "yes"; then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_BSDKM_VERBOSE_DEBUG"
AM_CFLAGS="$AM_CFLAGS -DNO_WOLFSSL_DEBUG_CERTS"
fi
if test "$KERNEL_ROOT" = ""; then
AC_PATH_DEFAULT_BSDKM_SOURCE
KERNEL_ROOT="$DEFAULT_BSDKM_ROOT"

View File

@@ -1430,6 +1430,8 @@
#endif
#define printf(...) wc_km_printf(__VA_ARGS__)
#define wc_km_print_err pr_err
#ifdef HAVE_FIPS
extern void fipsEntry(void);
#endif

View File

@@ -430,7 +430,11 @@ static void wolfssl_log(const int logLevel, const char* const file_name,
#endif /* (!WOLFSSL_DEBUG_CERTS && !DEBUG_WOLFSSL) || NO_WOLFSSL_DEBUG_CERTS */
#if defined(XVSNPRINTF) && !defined(NO_WOLFSSL_MSG_EX)
#include <stdarg.h> /* for var args */
#if defined(WOLFSSL_BSDKM)
#include <machine/stdarg.h> /* for var args */
#else
#include <stdarg.h> /* for var args */
#endif /* WOLFSSL_BSDKM */
#ifndef WOLFSSL_MSG_EX_BUF_SZ
#define WOLFSSL_MSG_EX_BUF_SZ 100