kcapi: Enable offloading HS algs to kcapi

Linux Kernel Crypto API

At some point I'd like to make use of kcapi to store keys for persistent
crypto ops.

Signed-off-by: Ben Collins <bcollins@libjwt.io>
This commit is contained in:
Ben Collins 2025-03-07 21:32:39 +00:00
parent e5f00796c7
commit 5f2c45ec2b
2 changed files with 79 additions and 4 deletions

View file

@ -39,6 +39,7 @@ option(WITH_GNUTLS "Whether to use GnuTLS (default is auto detect)" ON)
option(WITH_MBEDTLS "Whether to use mbedTLS (default is OFF)" OFF)
option(WITH_LIBCURL "Whether to include CUrl for retrieving JWKS (default is OFF)" OFF)
option(WITH_TESTS "Whether to build and run the testsuite (default is ON)" ON)
option(WITH_KCAPI_MD "Whether to use the Linux Kernel Crypto API to offload hmac (default OFF)" OFF)
# Optional
if (WITH_GNUTLS)
@ -57,6 +58,10 @@ if (WITH_LIBCURL)
pkg_check_modules(LIBCURL libcurl>=8.0.0 IMPORTED_TARGET REQUIRED)
endif()
if (WITH_KCAPI_MD)
find_library(HAVE_KCAPI kcapi REQUIRED)
endif()
# Required
pkg_check_modules(OPENSSL openssl>=3.0.0 IMPORTED_TARGET
REQUIRED)
@ -67,6 +72,12 @@ set_target_properties(jwt_static PROPERTIES
OUTPUT_NAME jwt
COMPILE_FLAGS -DJWT_STATIC_DEFINE)
if (HAVE_KCAPI)
target_link_libraries(jwt PRIVATE kcapi)
target_link_libraries(jwt_static PRIVATE kcapi)
add_definitions(-DUSE_KCAPI_MD)
endif()
add_custom_command(
OUTPUT jwt-builder.i
COMMAND ${CMAKE_C_COMPILER} -E ${CMAKE_SOURCE_DIR}/libjwt/jwt-common.c -DJWT_BUILDER

View file

@ -12,6 +12,11 @@
#include <jwt.h>
#ifdef USE_KCAPI_MD
#include <kcapi.h>
#define KCAPI_MAX_MD_SIZE 64
#endif
/* https://github.com/zhicheng/base64 */
#include "base64.h"
@ -333,6 +338,67 @@ static int __check_key_bits(jwt_t *jwt)
return 1; // LCOV_EXCL_LINE
}
static int sign_sha_hmac(jwt_t *jwt, char **out, unsigned int *len,
const char *str, unsigned int str_len)
{
#ifdef USE_KCAPI_MD
static int skip_kcapi = 0;
size_t key_len;
void *key;
int ret;
/* If kcapi fails once, we don't try again. */
if (skip_kcapi)
goto fallback_ops; // LCOV_EXCL_LINE
key = jwt->key->oct.key;
key_len = jwt->key->oct.len;
*out = jwt_malloc(KCAPI_MAX_MD_SIZE);
if (*out == NULL)
return 1; // LCOV_EXCL_LINE
switch (jwt->alg) {
/* HMAC */
case JWT_ALG_HS256:
ret = kcapi_md_hmac_sha256(key, key_len, (uint8_t *)str,
str_len, (uint8_t *)*out,
KCAPI_MAX_MD_SIZE);
break;
case JWT_ALG_HS384:
ret = kcapi_md_hmac_sha384(key, key_len, (uint8_t *)str,
str_len, (uint8_t *)*out,
KCAPI_MAX_MD_SIZE);
break;
case JWT_ALG_HS512:
ret = kcapi_md_hmac_sha512(key, key_len, (uint8_t *)str,
str_len, (uint8_t *)*out,
KCAPI_MAX_MD_SIZE);
break;
// LCOV_EXCL_START
default:
/* This isn't a failure in kcapi, so just error out */
jwt_freemem(out);
return 1;
// LCOV_EXCL_STOP
}
if (ret > 0) {
*len = ret;
return 0;
}
/* Fallthrough to normal ops */
// LCOV_EXCL_START
jwt_freemem(*out);
skip_kcapi = 1;
// LCOV_EXCL_STOP
fallback_ops:
#endif
return jwt_ops->sign_sha_hmac(jwt, out, len, str, str_len);
}
int jwt_sign(jwt_t *jwt, char **out, unsigned int *len, const char *str,
unsigned int str_len)
{
@ -343,7 +409,7 @@ int jwt_sign(jwt_t *jwt, char **out, unsigned int *len, const char *str,
case JWT_ALG_HS512:
if (__check_hmac(jwt))
return 1;
if (jwt_ops->sign_sha_hmac(jwt, out, len, str, str_len)) {
if (sign_sha_hmac(jwt, out, len, str, str_len)) {
/* There's not really a way to induce failure here,
* and there's not really much of a chance this can fail
* other than an internal fatal error in the crypto
@ -415,7 +481,7 @@ jwt_t *jwt_verify_sig(jwt_t *jwt, const char *head, unsigned int head_len,
const char *sig_b64)
{
int sig_len;
unsigned char *sig = NULL;
char_auth *sig = NULL;
switch (jwt->alg) {
/* HMAC */
@ -455,8 +521,6 @@ jwt_t *jwt_verify_sig(jwt_t *jwt, const char *head, unsigned int head_len,
if (jwt_ops->verify_sha_pem(jwt, head, head_len, sig, sig_len))
jwt_write_error(jwt, "Token failed verification");
jwt_freemem(sig);
break;
/* You wut, mate? */