#ifdef WOLFSSL_BSDKM
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#if defined(BSDKM_CRYPTO_REGISTER)
#include <opencrypto/cryptodev.h>
#include <sys/bus.h>
#include "cryptodev_if.h"
#endif
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifdef WOLFCRYPT_ONLY
#include <wolfssl/version.h>
#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
#if !defined(NO_CRYPT_TEST)
#include <wolfcrypt/test/test.h>
#endif
#if defined(WOLFSSL_KERNEL_BENCHMARKS)
#include <wolfcrypt/benchmark/benchmark.h>
#endif
#include <wolfssl/wolfcrypt/random.h>
MALLOC_DEFINE(M_WOLFSSL, "libwolfssl", "wolfSSL kernel memory");
#if defined(BSDKM_CRYPTO_REGISTER)
#include "bsdkm/wolfkmod_aes.c"
#endif
static int wolfkmod_init(void);
static int wolfkmod_cleanup(void);
#if !defined(BSDKM_CRYPTO_REGISTER)
static int wolfkmod_load(void);
static int wolfkmod_unload(void);
#else
static void wolfkdriv_identify(driver_t * driver, device_t parent);
static int wolfkdriv_probe(device_t dev);
static int wolfkdriv_attach(device_t dev);
static int wolfkdriv_detach(device_t dev);
static int wolfkdriv_probesession(device_t dev,
const struct crypto_session_params *csp);
static int wolfkdriv_newsession(device_t dev, crypto_session_t cses,
const struct crypto_session_params *csp);
static void wolfkdriv_freesession(device_t dev, crypto_session_t cses);
static int wolfkdriv_process(device_t dev, struct cryptop *crp, int hint);
#endif
#if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS)
#include "bsdkm/x86_vecreg.c"
#endif
#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
static int wolfkmod_init(void)
{
int error = 0;
#if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS)
error = wolfkmod_vecreg_init();
if (error != 0) {
printf("error: wolfkmod_vecreg_init: %d\n", error);
return (ECANCELED);
}
#endif
#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
#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
#ifdef WOLFCRYPT_ONLY
error = wolfCrypt_Init();
if (error != 0) {
printf("error: wolfCrypt_Init failed: %s\n", wc_GetErrorString(error));
return (ECANCELED);
}
#else
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("info: 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 error = 0;
#ifdef WOLFCRYPT_ONLY
error = wolfCrypt_Cleanup();
if (error != 0) {
printf("error: wolfCrypt_Cleanup failed: %s\n",
wc_GetErrorString(error));
error = ECANCELED;
goto wolfkmod_cleanup_out;
}
#else
error = wolfSSL_Cleanup();
if (error != WOLFSSL_SUCCESS) {
printf("error: wolfSSL_Cleanup failed: %s\n",
wc_GetErrorString(error));
error = ECANCELED;
goto wolfkmod_cleanup_out;
}
#endif
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
printf("info: libwolfssl " LIBWOLFSSL_VERSION_STRING
" cleanup complete.\n");
#endif
error = 0;
wolfkmod_cleanup_out:
#if defined(WOLFSSL_AESNI) || defined(WOLFSSL_KERNEL_BENCHMARKS)
wolfkmod_vecreg_exit();
#endif
return (error);
}
#if !defined(BSDKM_CRYPTO_REGISTER)
static int wolfkmod_load(void)
{
int error = 0;
error = wolfkmod_init();
if (error != 0) {
return (ECANCELED);
}
#ifndef NO_CRYPT_TEST
error = wolfcrypt_test(NULL);
if (error != 0) {
printf("error: wolfcrypt test failed: %d\n", error);
(void)wolfkmod_cleanup();
return (ECANCELED);
}
printf("info: wolfCrypt self-test passed.\n");
#endif
#ifdef WOLFSSL_KERNEL_BENCHMARKS
error = benchmark_test(NULL);
if (error != 0) {
printf("error: wolfcrypt benchmark failed: %d\n", error);
(void)wolfkmod_cleanup();
return (ECANCELED);
}
printf("info: wolfCrypt benchmark passed.\n");
#endif
printf("info: libwolfssl loaded\n");
return (0);
}
static int wolfkmod_unload(void)
{
int error = 0;
#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();
if (error == 0) {
printf("info: libwolfssl unloaded\n");
}
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
static int
wolfkmod_event(struct module * m, int what, void * arg)
{
int error = 0;
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
printf("info: wolfkmod_event: %s\n", wolfkmod_event_to_str(what));
#endif
switch (what) {
case MOD_LOAD:
error = wolfkmod_load();
break;
case MOD_UNLOAD:
error = wolfkmod_unload();
break;
case MOD_SHUTDOWN:
case MOD_QUIESCE:
default:
error = EOPNOTSUPP;
}
(void)m;
(void)arg;
return (error);
}
#endif
#if defined(BSDKM_CRYPTO_REGISTER)
struct wolfkdriv_softc {
int32_t crid;
device_t dev;
};
struct km_aes_ctx {
Aes aes_encrypt;
Aes aes_decrypt;
};
typedef struct km_aes_ctx km_aes_ctx;
struct wolfkdriv_session {
km_aes_ctx aes_ctx;
int32_t crid;
int type;
int ivlen;
int klen;
};
typedef struct wolfkdriv_session wolfkdriv_session_t;
static void km_AesFree(Aes * aes) {
if (aes == NULL) {
return;
}
wc_AesFree(aes);
#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0)
ForceZero(aes, sizeof(*aes));
#endif
}
static void wolfkdriv_aes_ctx_clear(km_aes_ctx * ctx)
{
if (ctx != NULL) {
km_AesFree(&ctx->aes_encrypt);
km_AesFree(&ctx->aes_decrypt);
}
#ifdef WOLFKM_DEBUG_AES
printf("info: exiting km_AesExitCommon\n");
#endif
}
static void wolfkdriv_identify(driver_t * driver, device_t parent)
{
(void)driver;
if (device_find_child(parent, "libwolf", -1) != NULL) {
return;
}
BUS_ADD_CHILD(parent, 10, "libwolf", -1);
}
static int wolfkdriv_probe(device_t dev)
{
device_set_desc(dev, "wolfSSL crypto");
return (BUS_PROBE_DEFAULT);
}
static void wolfkdriv_unregister(struct wolfkdriv_softc * softc)
{
if (softc && softc->crid >= 0) {
crypto_unregister_all(softc->crid);
device_printf(softc->dev, "info: crid unregistered: %d\n", softc->crid);
softc->crid = -1;
}
return;
}
static int wolfkdriv_attach(device_t dev)
{
struct wolfkdriv_softc * softc = NULL;
int flags = CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC |
CRYPTOCAP_F_ACCEL_SOFTWARE | CRYPTOCAP_F_HARDWARE;
int ret = 0;
int crid = 0;
int error = 0;
ret = wolfkmod_init();
if (ret != 0) {
return (ECANCELED);
}
softc = device_get_softc(dev);
softc->dev = dev;
softc->crid = crypto_get_driverid(dev, sizeof(wolfkdriv_session_t), flags);
if (softc->crid < 0) {
device_printf(dev, "error: crypto_get_driverid failed: %d\n",
softc->crid);
return (ENXIO);
}
crid = crypto_find_driver("libwolf");
if (crid != softc->crid) {
device_printf(dev, "error: attach: got crid %d, expected %d\n", crid,
softc->crid);
error = ENXIO;
goto attach_out;
}
error = wolfkdriv_test_aes(dev, crid);
if (error) {
device_printf(dev, "error: attach: test_aes: %d\n", error);
error = ENXIO;
goto attach_out;
}
device_printf(dev, "info: driver loaded: %d\n", crid);
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: exiting attach\n");
#endif
attach_out:
if (error) {
wolfkdriv_unregister(softc);
error = ENXIO;
}
return (error);
}
static int wolfkdriv_detach(device_t dev)
{
struct wolfkdriv_softc * softc = NULL;
int ret = 0;
ret = wolfkmod_cleanup();
if (ret == 0) {
softc = device_get_softc(dev);
wolfkdriv_unregister(softc);
}
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: exiting detach\n");
#endif
return (0);
}
static int wolfkdriv_probesession(device_t dev,
const struct crypto_session_params *csp)
{
struct wolfkdriv_softc * softc = NULL;
int error = CRYPTODEV_PROBE_ACCEL_SOFTWARE;
softc = device_get_softc(dev);
switch (csp->csp_mode) {
case CSP_MODE_CIPHER:
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_CBC:
break;
default:
error = EINVAL;
break;
}
break;
case CSP_MODE_AEAD:
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_NIST_GCM_16:
break;
default:
error = EINVAL;
break;
}
break;
case CSP_MODE_DIGEST:
case CSP_MODE_ETA:
default:
error = EINVAL;
break;
}
(void)softc;
(void)csp;
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: probesession: mode=%d, cipher_alg=%d, error=%d\n",
csp->csp_mode, csp->csp_cipher_alg, error);
#endif
return (error);
}
static int wolfkdriv_newsession_aes(device_t dev,
wolfkdriv_session_t * session,
const struct crypto_session_params *csp)
{
int error = 0;
int klen = csp->csp_cipher_klen;
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_NIST_GCM_16:
session->type = CRYPTO_AES_NIST_GCM_16;
break;
case CRYPTO_AES_CBC:
session->type = CRYPTO_AES_CBC;
break;
default:
return (EOPNOTSUPP);
}
if (klen != 16 && klen != 24 && klen != 32) {
device_printf(dev, "info: newsession_cipher: invalid klen: %d\n", klen);
return (EINVAL);
}
session->klen = klen;
session->ivlen = csp->csp_ivlen;
error = wc_AesInit(&session->aes_ctx.aes_encrypt, NULL, INVALID_DEVID);
if (error) {
device_printf(dev, "error: newsession_cipher: aes init: %d\n", error);
goto newsession_cipher_out;
}
if (session->type == CRYPTO_AES_CBC) {
error = wc_AesInit(&session->aes_ctx.aes_decrypt, NULL, INVALID_DEVID);
if (error) {
device_printf(dev, "error: newsession_cipher: aes init: %d\n",
error);
goto newsession_cipher_out;
}
}
newsession_cipher_out:
if (error != 0) {
wolfkdriv_aes_ctx_clear(&session->aes_ctx);
return (EINVAL);
}
return (error);
}
static int wolfkdriv_newsession(device_t dev, crypto_session_t cses,
const struct crypto_session_params *csp)
{
wolfkdriv_session_t * session = NULL;
int error = 0;
session = crypto_get_driver_session(cses);
switch (csp->csp_mode) {
case CSP_MODE_DIGEST:
case CSP_MODE_ETA:
device_printf(dev, "info: not supported: %d\n", csp->csp_mode);
error = EOPNOTSUPP;
break;
case CSP_MODE_CIPHER:
case CSP_MODE_AEAD:
error = wolfkdriv_newsession_aes(dev, session, csp);
break;
default:
__assert_unreachable();
}
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: newsession: mode=%d, cipher_alg=%d, error=%d\n",
csp->csp_mode, csp->csp_cipher_alg, error);
#endif
return (error);
}
static void
wolfkdriv_freesession(device_t dev, crypto_session_t cses)
{
wolfkdriv_session_t * session = NULL;
(void)dev;
session = crypto_get_driver_session(cses);
wolfkdriv_aes_ctx_clear(&session->aes_ctx);
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: exiting freesession\n");
#endif
return;
}
static int wolfkdriv_cbc_work(device_t dev, wolfkdriv_session_t * session,
struct cryptop * crp,
const struct crypto_session_params * csp)
{
struct crypto_buffer_cursor cc_in;
struct crypto_buffer_cursor cc_out;
const unsigned char * in_block = NULL;
const unsigned char * in_seg = NULL;
unsigned char * out_block = NULL;
unsigned char * out_seg = NULL;
Aes aes;
uint8_t iv[WC_AES_BLOCK_SIZE];
uint8_t block[EALG_MAX_BLOCK_LEN];
size_t data_len = 0;
size_t seg_len = 0;
size_t in_len = 0;
size_t out_len = 0;
int error = 0;
int is_encrypt = 0;
int type = AES_ENCRYPTION;
if (csp->csp_cipher_alg != CRYPTO_AES_CBC) {
error = EINVAL;
goto cbc_work_out;
}
data_len = crp->crp_payload_length;
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
is_encrypt = 1;
type = AES_ENCRYPTION;
memcpy(&aes, &session->aes_ctx.aes_encrypt, sizeof(aes));
}
else {
is_encrypt = 0;
type = AES_DECRYPTION;
memcpy(&aes, &session->aes_ctx.aes_decrypt, sizeof(aes));
}
if (data_len % WC_AES_BLOCK_SIZE) {
error = EINVAL;
goto cbc_work_out;
}
crypto_read_iv(crp, iv);
error = wc_AesSetKey(&aes, csp->csp_cipher_key,
csp->csp_cipher_klen, iv, type);
if (error) {
device_printf(dev, "error: wc_AesSetKey: %d\n", error);
goto cbc_work_out;
}
crypto_cursor_init(&cc_in, &crp->crp_buf);
crypto_cursor_advance(&cc_in, crp->crp_payload_start);
in_seg = crypto_cursor_segment(&cc_in, &in_len);
if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
crypto_cursor_init(&cc_out, &crp->crp_obuf);
crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
}
else {
cc_out = cc_in;
}
out_seg = crypto_cursor_segment(&cc_out, &out_len);
while (data_len) {
if (in_len < WC_AES_BLOCK_SIZE) {
crypto_cursor_copydata(&cc_in, WC_AES_BLOCK_SIZE, block);
in_block = block;
in_len = WC_AES_BLOCK_SIZE;
}
else {
in_block = in_seg;
}
if (out_len < WC_AES_BLOCK_SIZE) {
out_block = block;
out_len = WC_AES_BLOCK_SIZE;
}
else {
out_block = out_seg;
}
seg_len = rounddown(MIN(data_len, MIN(in_len, out_len)),
WC_AES_BLOCK_SIZE);
if (is_encrypt) {
error = wc_AesCbcEncrypt(&aes, out_block, in_block, seg_len);
if (error) {
device_printf(dev, "error: wc_AesCbcEncrypt: %d\n", error);
goto cbc_work_out;
}
}
else {
error = wc_AesCbcDecrypt(&aes, out_block, in_block, seg_len);
if (error) {
device_printf(dev, "error: wc_AesCbcEncrypt: %d\n", error);
goto cbc_work_out;
}
}
if (out_block == block) {
crypto_cursor_copyback(&cc_out, WC_AES_BLOCK_SIZE, block);
out_seg = crypto_cursor_segment(&cc_out, &out_len);
} else {
crypto_cursor_advance(&cc_out, seg_len);
out_seg += seg_len;
out_len -= seg_len;
}
if (in_block == block) {
in_seg = crypto_cursor_segment(&cc_in, &in_len);
} else {
crypto_cursor_advance(&cc_in, seg_len);
in_seg += seg_len;
in_len -= seg_len;
}
data_len -= seg_len;
}
cbc_work_out:
wc_ForceZero(iv, sizeof(iv));
wc_ForceZero(block, sizeof(block));
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: cbc_work: mode=%d, cipher_alg=%d, "
"payload_length=%d, error=%d\n",
csp->csp_mode, csp->csp_cipher_alg, crp->crp_payload_length,
error);
#endif
return (error);
}
static int wolfkdriv_gcm_work(device_t dev, wolfkdriv_session_t * session,
struct cryptop * crp,
const struct crypto_session_params * csp)
{
struct crypto_buffer_cursor cc_in;
struct crypto_buffer_cursor cc_out;
const unsigned char * in_seg = NULL;
unsigned char * out_seg = NULL;
Aes aes;
uint8_t iv[WC_AES_BLOCK_SIZE];
uint8_t auth_tag[WC_AES_BLOCK_SIZE];
size_t data_len = 0;
size_t seg_len = 0;
size_t in_len = 0;
size_t out_len = 0;
int error = 0;
int is_encrypt = 0;
memcpy(&aes, &session->aes_ctx.aes_encrypt, sizeof(aes));
if (csp->csp_cipher_alg != CRYPTO_AES_NIST_GCM_16) {
error = EINVAL;
goto gcm_work_out;
}
data_len = crp->crp_payload_length;
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
is_encrypt = 1;
}
else {
is_encrypt = 0;
}
error = wc_AesGcmSetKey(&aes, csp->csp_cipher_key,
csp->csp_cipher_klen);
if (error) {
device_printf(dev, "error: wc_AesGcmSetKey: %d\n", error);
goto gcm_work_out;
}
crypto_read_iv(crp, iv);
error = wc_AesGcmInit(&aes, NULL , 0 ,
iv, csp->csp_ivlen);
if (error) {
device_printf(dev, "error: wc_AesGcmInit: %d\n", error);
goto gcm_work_out;
}
if (crp->crp_aad != NULL) {
if (is_encrypt) {
error = wc_AesGcmEncryptUpdate(&aes, NULL, NULL, 0,
crp->crp_aad, crp->crp_aad_length);
}
else {
error = wc_AesGcmDecryptUpdate(&aes, NULL, NULL, 0,
crp->crp_aad, crp->crp_aad_length);
}
if (error) {
error = EINVAL;
goto gcm_work_out;
}
}
else {
size_t aad_len = 0;
crypto_cursor_init(&cc_in, &crp->crp_buf);
crypto_cursor_advance(&cc_in, crp->crp_aad_start);
for (aad_len = crp->crp_aad_length; aad_len > 0; aad_len -= seg_len) {
in_seg = crypto_cursor_segment(&cc_in, &in_len);
seg_len = MIN(aad_len, in_len);
if (is_encrypt) {
error = wc_AesGcmEncryptUpdate(&aes, NULL, NULL, 0,
in_seg, seg_len);
}
else {
error = wc_AesGcmDecryptUpdate(&aes, NULL, NULL, 0,
in_seg, seg_len);
}
if (error) {
error = EINVAL;
goto gcm_work_out;
}
crypto_cursor_advance(&cc_in, seg_len);
}
}
crypto_cursor_init(&cc_in, &crp->crp_buf);
crypto_cursor_advance(&cc_in, crp->crp_payload_start);
in_seg = crypto_cursor_segment(&cc_in, &in_len);
if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
crypto_cursor_init(&cc_out, &crp->crp_obuf);
crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
}
else {
cc_out = cc_in;
}
out_seg = crypto_cursor_segment(&cc_out, &out_len);
while (data_len) {
in_seg = crypto_cursor_segment(&cc_in, &in_len);
out_seg = crypto_cursor_segment(&cc_out, &out_len);
seg_len = MIN(data_len, MIN(in_len, out_len));
if (is_encrypt) {
error = wc_AesGcmEncryptUpdate(&aes, out_seg, in_seg, seg_len,
NULL, 0);
if (error) {
device_printf(dev, "error: wc_AesGcmEncrypt: %d\n", error);
goto gcm_work_out;
}
}
else {
error = wc_AesGcmDecryptUpdate(&aes, out_seg, in_seg, seg_len,
NULL, 0);
if (error) {
device_printf(dev, "error: wc_AesGcmDecrypt: %d\n", error);
goto gcm_work_out;
}
}
crypto_cursor_advance(&cc_in, seg_len);
crypto_cursor_advance(&cc_out, seg_len);
data_len -= seg_len;
}
if (is_encrypt) {
error = wc_AesGcmEncryptFinal(&aes, auth_tag, WC_AES_BLOCK_SIZE);
if (error == 0) {
crypto_copyback(crp, crp->crp_digest_start, WC_AES_BLOCK_SIZE,
auth_tag);
}
}
else {
crypto_copydata(crp, crp->crp_digest_start, WC_AES_BLOCK_SIZE,
auth_tag);
error = wc_AesGcmDecryptFinal(&aes, auth_tag, WC_AES_BLOCK_SIZE);
if (error) {
error = EBADMSG;
}
}
gcm_work_out:
wc_ForceZero(iv, sizeof(iv));
wc_ForceZero(auth_tag, sizeof(auth_tag));
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: gcm_work: mode=%d, cipher_alg=%d, "
"payload_length=%d, error=%d\n",
csp->csp_mode, csp->csp_cipher_alg, crp->crp_payload_length,
error);
#endif
return (error);
}
static int wolfkdriv_process(device_t dev, struct cryptop * crp, int hint)
{
const struct crypto_session_params * csp = NULL;
wolfkdriv_session_t * session = NULL;
int error = 0;
(void)hint;
session = crypto_get_driver_session(crp->crp_session);
csp = crypto_get_params(crp->crp_session);
switch (csp->csp_mode) {
case CSP_MODE_CIPHER:
error = wolfkdriv_cbc_work(dev, session, crp, csp);
break;
case CSP_MODE_DIGEST:
case CSP_MODE_ETA:
error = EINVAL;
break;
case CSP_MODE_AEAD:
error = wolfkdriv_gcm_work(dev, session, crp, csp);
break;
default:
__assert_unreachable();
}
crp->crp_etype = error;
crypto_done(crp);
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: process: mode=%d, cipher_alg=%d, error=%d\n",
csp->csp_mode, csp->csp_cipher_alg, error);
#endif
return (error);
}
static device_method_t wolfkdriv_methods[] = {
DEVMETHOD(device_identify, wolfkdriv_identify),
DEVMETHOD(device_probe, wolfkdriv_probe),
DEVMETHOD(device_attach, wolfkdriv_attach),
DEVMETHOD(device_detach, wolfkdriv_detach),
DEVMETHOD(cryptodev_probesession, wolfkdriv_probesession),
DEVMETHOD(cryptodev_newsession, wolfkdriv_newsession),
DEVMETHOD(cryptodev_freesession, wolfkdriv_freesession),
DEVMETHOD(cryptodev_process, wolfkdriv_process),
DEVMETHOD_END
};
static driver_t wolfkdriv_driver = {
.name = "libwolf",
.methods = wolfkdriv_methods,
.size = sizeof(struct wolfkdriv_softc),
};
DRIVER_MODULE(libwolfssl, nexus, wolfkdriv_driver, NULL, NULL);
#endif
#if !defined(BSDKM_CRYPTO_REGISTER)
static moduledata_t libwolfmod = {
#ifdef HAVE_FIPS
"libwolfssl_fips",
#else
"libwolfssl",
#endif
wolfkmod_event,
NULL
};
DECLARE_MODULE(libwolfssl, libwolfmod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
#endif
MODULE_VERSION(libwolfssl, 1);
#endif