diff --git a/port/posix/posix_log_file.c b/port/posix/posix_log_file.c
index 0c086d67..764fede4 100644
--- a/port/posix/posix_log_file.c
+++ b/port/posix/posix_log_file.c
@@ -39,21 +39,6 @@
#ifdef WOLFHSM_CFG_LOGGING
-/* Helper function to convert log level to string */
-static const char* posixLogFile_LevelToString(whLogLevel level)
-{
- switch (level) {
- case WH_LOG_LEVEL_INFO:
- return "INFO";
- case WH_LOG_LEVEL_ERROR:
- return "ERROR";
- case WH_LOG_LEVEL_SECEVENT:
- return "SECEVENT";
- default:
- return "UNKNOWN";
- }
-}
-
/* Helper function to convert string to log level */
static whLogLevel posixLogFile_StringToLevel(const char* str)
{
@@ -146,7 +131,7 @@ int posixLogFile_AddEntry(void* c, const whLogEntry* entry)
/* Format log entry: TIMESTAMP|LEVEL|FILE:LINE|FUNCTION|MESSAGE\n */
len = snprintf(buffer, sizeof(buffer), "%llu|%s|%s:%u|%s|%.*s\n",
(unsigned long long)entry->timestamp,
- posixLogFile_LevelToString(entry->level),
+ wh_Log_LevelToString(entry->level),
entry->file ? entry->file : "", entry->line,
entry->function ? entry->function : "", (int)entry->msg_len,
entry->msg);
diff --git a/src/wh_log.c b/src/wh_log.c
index cb059009..1023df0c 100644
--- a/src/wh_log.c
+++ b/src/wh_log.c
@@ -36,6 +36,20 @@
#ifdef WOLFHSM_CFG_LOGGING
+const char* wh_Log_LevelToString(whLogLevel level)
+{
+ switch (level) {
+ case WH_LOG_LEVEL_INFO:
+ return "INFO";
+ case WH_LOG_LEVEL_ERROR:
+ return "ERROR";
+ case WH_LOG_LEVEL_SECEVENT:
+ return "SECEVENT";
+ default:
+ return "UNKNOWN";
+ }
+}
+
void wh_Log_AddMsg(whLogContext* ctx, whLogLevel level, const char* file,
const char* function, uint32_t line, const char* src,
size_t src_len)
diff --git a/src/wh_log_printf.c b/src/wh_log_printf.c
new file mode 100644
index 00000000..73dc835c
--- /dev/null
+++ b/src/wh_log_printf.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 wolfSSL Inc.
+ *
+ * This file is part of wolfHSM.
+ *
+ * wolfHSM 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.
+ *
+ * wolfHSM 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 wolfHSM. If not, see .
+ */
+/*
+ * src/wh_log_printf.c
+ *
+ * Printf-style logging backend implementation
+ */
+
+#include /* For NULL */
+#include /* For memset, memcpy */
+
+#include "wolfhsm/wh_settings.h"
+
+#include "wolfhsm/wh_log_printf.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_log.h"
+
+#ifdef WOLFHSM_CFG_LOGGING
+
+int whLogPrintf_Init(void* c, const void* cf)
+{
+ whLogPrintfContext* context = (whLogPrintfContext*)c;
+ const whLogPrintfConfig* config = (const whLogPrintfConfig*)cf;
+
+ if (context == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Initialize context */
+ memset(context, 0, sizeof(*context));
+
+ /* Copy config if provided, otherwise use defaults */
+ if (config != NULL) {
+ context->logIfNotDebug = config->logIfNotDebug;
+ }
+ else {
+ context->logIfNotDebug = 0;
+ }
+
+ context->initialized = 1;
+
+ return WH_ERROR_OK;
+}
+
+
+int whLogPrintf_AddEntry(void* c, const whLogEntry* entry)
+{
+ whLogPrintfContext* context = (whLogPrintfContext*)c;
+
+ if ((context == NULL) || (entry == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+
+ if (!context->initialized) {
+ return WH_ERROR_ABORTED;
+ }
+
+ /* Conditional logging:
+ * - If logIfNotDebug is true: always log
+ * - If logIfNotDebug is false: only log if WOLFHSM_CFG_DEBUG is defined
+ */
+#ifndef WOLFHSM_CFG_DEBUG
+ if (!context->logIfNotDebug) {
+ return WH_ERROR_OK;
+ }
+#endif
+
+ /* Format: [TIMESTAMP] [LEVEL] [FILE:LINE FUNC] MESSAGE */
+ (void)WOLFHSM_CFG_PRINTF(
+ "[%llu] [%s] [%s:%u %s] %.*s\n", (unsigned long long)entry->timestamp,
+ wh_Log_LevelToString(entry->level),
+ (entry->file != NULL) ? entry->file : "", entry->line,
+ (entry->function != NULL) ? entry->function : "",
+ (entry->msg_len <= WOLFHSM_CFG_LOG_MSG_MAX)
+ ? (int)(entry->msg_len)
+ : (int)WOLFHSM_CFG_LOG_MSG_MAX,
+ entry->msg);
+
+ return WH_ERROR_OK;
+}
+
+#endif /* WOLFHSM_CFG_LOGGING */
diff --git a/src/wh_server.c b/src/wh_server.c
index cf450db7..83df8acb 100644
--- a/src/wh_server.c
+++ b/src/wh_server.c
@@ -325,6 +325,7 @@ int wh_Server_HandleRequestMessage(whServerContext* server)
uint16_t seq = 0;
uint16_t size = 0;
uint8_t* data = NULL;
+ int handlerRc = 0;
if (server == NULL) {
return WH_ERROR_BADARGS;
@@ -342,7 +343,7 @@ int wh_Server_HandleRequestMessage(whServerContext* server)
int rc = wh_CommServer_RecvRequest(server->comm, &magic, &kind, &seq,
&size, data);
/* Got a packet? */
- if (rc == 0) {
+ if (rc == WH_ERROR_OK) {
group = WH_MESSAGE_GROUP(kind);
action = WH_MESSAGE_ACTION(kind);
switch (group) {
@@ -407,33 +408,56 @@ int wh_Server_HandleRequestMessage(whServerContext* server)
#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER && !WOLFHSM_CFG_NO_CRYPTO */
default:
- /* Unknown group. Return empty packet*/
- /* TODO: Respond with aux error flag */
+ /* Unknown group. Return empty packet */
+ rc = WH_ERROR_NOTIMPL;
+ data = NULL;
size = 0;
}
- /* Send a response */
- /* TODO: Respond with ErrorResponse if handler returns an error */
+ /* Capture handler result for logging. The response packet already
+ * contains the error code for the client in the resp.rc field. */
+ handlerRc = rc;
+
+ /* Handle cancellation by modifying response kind */
#ifdef WOLFHSM_CFG_CANCEL_API
- if (rc == WH_ERROR_CANCEL) {
+ if (handlerRc == WH_ERROR_CANCEL) {
/* notify the client that their request was canceled */
kind = WH_MESSAGE_KIND(WH_MESSAGE_GROUP_CANCEL, 0);
size = 0;
data = NULL;
- /* reset RC so the cancellation response is sent */
- rc = 0;
}
#endif
- if (rc == 0) {
- do {
- rc = wh_CommServer_SendResponse(server->comm, magic, kind, seq,
- size, data);
- } while (rc == WH_ERROR_NOTREADY);
- }
+
+ /* Always send the response to the client, regardless of handler error.
+ * The response packet contains the operational error code for the
+ * client in the resp.rc field. */
+ do {
+ rc = wh_CommServer_SendResponse(server->comm, magic, kind, seq,
+ size, data);
+ } while (rc == WH_ERROR_NOTREADY);
+
+ /* Log error code from request handler, if present */
+ WH_LOG_ON_ERROR_F(&server->log, WH_LOG_LEVEL_ERROR, handlerRc,
+ "Handler (group=%d, action=%d, seq=%d) returned %d",
+ group, action, seq, handlerRc);
+ (void)handlerRc; /* suppress unused var warning */
+
+ /* Log error code from sending response, if present */
+ WH_LOG_ON_ERROR_F(
+ &server->log, WH_LOG_LEVEL_ERROR, rc,
+ "SendResponse failed for (group=%d, action=%d, seq=%d): %d", group,
+ action, seq, rc);
+
+ /* Handler errors are logged above via handlerRc but don't affect
+ * return code. Errors from SendResponse are propagated back to the
+ * caller in rc */
+ }
+ else if (rc != WH_ERROR_NOTREADY) {
+ /* Log error code from processing request, if present */
WH_LOG_ON_ERROR_F(
&server->log, WH_LOG_LEVEL_ERROR, rc,
- "Request Handler for (group=%d, action=%d) Returned Error: %d",
- group, action, rc);
+ "RecvRequest failed for (group=%d, action=%d, seq=%d): %d", group,
+ action, seq, rc);
}
return rc;
diff --git a/src/wh_server_counter.c b/src/wh_server_counter.c
index b2e33ffb..10c672ce 100644
--- a/src/wh_server_counter.c
+++ b/src/wh_server_counter.c
@@ -80,8 +80,6 @@ int wh_Server_HandleCounter(whServerContext* server, uint16_t magic,
resp.counter = *counter;
}
resp.rc = ret;
- /* TODO: are there any fatal server errors? */
- ret = WH_ERROR_OK;
(void)wh_MessageCounter_TranslateInitResponse(
magic, &resp, (whMessageCounter_InitResponse*)resp_packet);
@@ -139,9 +137,6 @@ int wh_Server_HandleCounter(whServerContext* server, uint16_t magic,
magic, &resp, (whMessageCounter_IncrementResponse*)resp_packet);
*out_resp_size = sizeof(resp);
-
- /* TODO: are there any fatal server errors? */
- ret = WH_ERROR_OK;
} break;
case WH_COUNTER_READ: {
@@ -178,9 +173,6 @@ int wh_Server_HandleCounter(whServerContext* server, uint16_t magic,
magic, &resp, (whMessageCounter_ReadResponse*)resp_packet);
*out_resp_size = sizeof(resp);
-
- /* TODO: are there any fatal server errors? */
- ret = WH_ERROR_OK;
} break;
case WH_COUNTER_DESTROY: {
@@ -211,9 +203,6 @@ int wh_Server_HandleCounter(whServerContext* server, uint16_t magic,
magic, &resp, (whMessageCounter_DestroyResponse*)resp_packet);
*out_resp_size = sizeof(resp);
-
- /* TODO: are there any fatal server errors? */
- ret = WH_ERROR_OK;
} break;
default:
diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c
index 0719c79b..deeabcee 100644
--- a/src/wh_server_crypto.c
+++ b/src/wh_server_crypto.c
@@ -4231,16 +4231,6 @@ int wh_Server_HandleCryptoRequest(whServerContext* ctx, uint16_t magic,
WH_DEBUG_SERVER_VERBOSE("End ret:%d\n", ret);
- /* Since crypto error codes are propagated to the client in the response
- * packet, return success to the caller unless a cancellation has occurred
- */
-#ifdef WOLFHSM_CFG_CANCEL_API
- if (ret != WH_ERROR_CANCEL) {
- ret = WH_ERROR_OK;
- }
-#else
- ret = WH_ERROR_OK;
-#endif
return ret;
}
@@ -5724,16 +5714,7 @@ int wh_Server_HandleCryptoDmaRequest(whServerContext* ctx, uint16_t magic,
WH_DEBUG_SERVER_VERBOSE("Crypto DMA request. Action:%u\n", action);
- /* Since crypto error codes are propagated to the client in the response
- * packet, return success to the caller unless a cancellation has occurred
- */
-#ifdef WOLFHSM_CFG_CANCEL_API
- if (ret != WH_ERROR_CANCEL) {
- ret = WH_ERROR_OK;
- }
-#else
- ret = WH_ERROR_OK;
-#endif
+
return ret;
}
#endif /* WOLFHSM_CFG_DMA */
diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c
index d8960cfa..a2a1857c 100644
--- a/src/wh_server_keystore.c
+++ b/src/wh_server_keystore.c
@@ -1360,7 +1360,6 @@ static int _HandleDataUnwrapRequest(whServerContext* server,
whMessageKeystore_DataUnwrapResponse* resp,
uint8_t* respData, uint32_t respDataSz)
{
-
int ret;
uint8_t* wrappedData;
uint8_t* data;
@@ -1380,9 +1379,8 @@ static int _HandleDataUnwrapRequest(whServerContext* server,
wrappedData = reqData;
/* Translate the server key id passed in from the client */
- serverKeyId = wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO,
- server->comm->client_id,
- req->serverKeyId);
+ serverKeyId = wh_KeyId_TranslateFromClient(
+ WH_KEYTYPE_CRYPTO, server->comm->client_id, req->serverKeyId);
/* Ensure the cipher type in the response matches the request */
resp->cipherType = req->cipherType;
@@ -1474,26 +1472,21 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
if (WH_KEYID_ISERASED(meta->id)) {
ret = wh_Server_KeystoreGetUniqueId(server, &meta->id);
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
}
/* write the key */
if (ret == WH_ERROR_OK) {
ret = wh_Server_KeystoreCacheKey(server, meta, in);
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
}
if (ret == WH_ERROR_OK) {
/* Translate server keyId back to client format with flags */
resp.id = wh_KeyId_TranslateToClient(meta->id);
+ }
- (void)wh_MessageKeystore_TranslateCacheResponse(
- magic, &resp,
- (whMessageKeystore_CacheResponse*)resp_packet);
+ (void)wh_MessageKeystore_TranslateCacheResponse(
+ magic, &resp, (whMessageKeystore_CacheResponse*)resp_packet);
- *out_resp_size = sizeof(resp);
- }
+ *out_resp_size = sizeof(resp);
} break;
#ifdef WOLFHSM_CFG_DMA
@@ -1533,8 +1526,6 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
resp.dmaAddrStatus.badAddr.addr = req.key.addr;
resp.dmaAddrStatus.badAddr.sz = req.key.sz;
}
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
}
/* Translate server keyId back to client format with flags */
@@ -1560,13 +1551,12 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
server->comm->client_id, req.id),
req.key.addr, req.key.sz, meta);
resp.rc = ret;
+
/* propagate bad address to client if DMA operation failed */
if (ret != WH_ERROR_OK) {
resp.dmaAddrStatus.badAddr.addr = req.key.addr;
resp.dmaAddrStatus.badAddr.sz = req.key.sz;
}
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
if (ret == WH_ERROR_OK) {
resp.len = req.key.sz;
@@ -1593,17 +1583,11 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO,
server->comm->client_id, req.id));
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
+ resp.ok = 0; /* unused */
- if (ret == WH_ERROR_OK) {
- resp.ok = 0;
-
- (void)wh_MessageKeystore_TranslateEvictResponse(
- magic, &resp,
- (whMessageKeystore_EvictResponse*)resp_packet);
- *out_resp_size = sizeof(resp);
- }
+ (void)wh_MessageKeystore_TranslateEvictResponse(
+ magic, &resp, (whMessageKeystore_EvictResponse*)resp_packet);
+ *out_resp_size = sizeof(resp);
} break;
case WH_KEY_EXPORT: {
@@ -1638,25 +1622,20 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
}
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
+ /* Only provide key output if no error */
if (ret == WH_ERROR_OK) {
- /* Only provide key output if no error */
- if (resp.rc == WH_ERROR_OK) {
- resp.len = keySz;
- }
- else {
- resp.len = 0;
- }
- memcpy(resp.label, meta->label, sizeof(meta->label));
+ resp.len = keySz;
+ }
+ else {
+ resp.len = 0;
+ }
+ memcpy(resp.label, meta->label, sizeof(meta->label));
- (void)wh_MessageKeystore_TranslateExportResponse(
- magic, &resp,
- (whMessageKeystore_ExportResponse*)resp_packet);
+ (void)wh_MessageKeystore_TranslateExportResponse(
+ magic, &resp, (whMessageKeystore_ExportResponse*)resp_packet);
- *out_resp_size = sizeof(resp) + resp.len;
- }
+ *out_resp_size = sizeof(resp) + resp.len;
} break;
case WH_KEY_COMMIT: {
@@ -1672,18 +1651,12 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO,
server->comm->client_id, req.id));
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
+ resp.ok = 0; /* unused */
- if (ret == WH_ERROR_OK) {
- resp.ok = 0;
-
- (void)wh_MessageKeystore_TranslateCommitResponse(
- magic, &resp,
- (whMessageKeystore_CommitResponse*)resp_packet);
+ (void)wh_MessageKeystore_TranslateCommitResponse(
+ magic, &resp, (whMessageKeystore_CommitResponse*)resp_packet);
- *out_resp_size = sizeof(resp);
- }
+ *out_resp_size = sizeof(resp);
} break;
case WH_KEY_ERASE: {
@@ -1699,18 +1672,12 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO,
server->comm->client_id, req.id));
resp.rc = ret;
- /* TODO: Are there any fatal server errors? */
- ret = WH_ERROR_OK;
-
- if (ret == WH_ERROR_OK) {
- resp.ok = 0;
+ resp.ok = 0; /* unused */
- (void)wh_MessageKeystore_TranslateEraseResponse(
- magic, &resp,
- (whMessageKeystore_EraseResponse*)resp_packet);
+ (void)wh_MessageKeystore_TranslateEraseResponse(
+ magic, &resp, (whMessageKeystore_EraseResponse*)resp_packet);
- *out_resp_size = sizeof(resp);
- }
+ *out_resp_size = sizeof(resp);
} break;
#ifdef WOLFHSM_CFG_KEYWRAP
@@ -1740,9 +1707,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
respData = (uint8_t*)resp_packet +
sizeof(whMessageKeystore_KeyWrapResponse);
- wrapResp.rc =
- _HandleKeyWrapRequest(server, &wrapReq, reqData, reqDataSz,
- &wrapResp, respData, respDataSz);
+ ret = _HandleKeyWrapRequest(server, &wrapReq, reqData, reqDataSz,
+ &wrapResp, respData, respDataSz);
+ wrapResp.rc = ret;
(void)wh_MessageKeystore_TranslateKeyWrapResponse(magic, &wrapResp,
resp_packet);
@@ -1776,12 +1743,14 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
respData = (uint8_t*)resp_packet +
sizeof(whMessageKeystore_KeyUnwrapAndExportResponse);
- unwrapResp.rc = _HandleKeyUnwrapAndExportRequest(
- server, &unwrapReq, reqData, reqDataSz, &unwrapResp, respData,
- respDataSz);
+ ret = _HandleKeyUnwrapAndExportRequest(server, &unwrapReq, reqData,
+ reqDataSz, &unwrapResp,
+ respData, respDataSz);
+ unwrapResp.rc = ret;
(void)wh_MessageKeystore_TranslateKeyUnwrapAndExportResponse(
magic, &unwrapResp, resp_packet);
+
*out_resp_size =
sizeof(unwrapResp) + sizeof(whNvmMetadata) + unwrapResp.keySz;
@@ -1812,12 +1781,14 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
respData = (uint8_t*)resp_packet +
sizeof(whMessageKeystore_KeyUnwrapAndCacheResponse);
- cacheResp.rc = _HandleKeyUnwrapAndCacheRequest(
- server, &cacheReq, reqData, reqDataSz, &cacheResp, respData,
- respDataSz);
+ ret = _HandleKeyUnwrapAndCacheRequest(server, &cacheReq, reqData,
+ reqDataSz, &cacheResp,
+ respData, respDataSz);
+ cacheResp.rc = ret;
(void)wh_MessageKeystore_TranslateKeyUnwrapAndCacheResponse(
magic, &cacheResp, resp_packet);
+
*out_resp_size = sizeof(cacheResp);
} break;
@@ -1848,9 +1819,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
respData = (uint8_t*)resp_packet +
sizeof(whMessageKeystore_DataWrapResponse);
- wrapResp.rc =
- _HandleDataWrapRequest(server, &wrapReq, reqData, reqDataSz,
- &wrapResp, respData, respDataSz);
+ ret = _HandleDataWrapRequest(server, &wrapReq, reqData, reqDataSz,
+ &wrapResp, respData, respDataSz);
+ wrapResp.rc = ret;
(void)wh_MessageKeystore_TranslateDataWrapResponse(magic, &wrapResp,
resp_packet);
@@ -1885,9 +1856,10 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
respData = (uint8_t*)resp_packet +
sizeof(whMessageKeystore_DataUnwrapResponse);
- unwrapResp.rc =
+ ret =
_HandleDataUnwrapRequest(server, &unwrapReq, reqData, reqDataSz,
&unwrapResp, respData, respDataSz);
+ unwrapResp.rc = ret;
(void)wh_MessageKeystore_TranslateDataUnwrapResponse(
magic, &unwrapResp, resp_packet);
@@ -1898,7 +1870,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
#endif /* WOLFHSM_CFG_KEYWRAP */
default:
- ret = WH_ERROR_BADARGS;
+ ret = WH_ERROR_NOHANDLER;
break;
}
diff --git a/src/wh_server_she.c b/src/wh_server_she.c
index b1295376..eba75acc 100644
--- a/src/wh_server_she.c
+++ b/src/wh_server_she.c
@@ -1689,10 +1689,7 @@ int wh_Server_HandleSheRequest(whServerContext* server, uint16_t magic,
server->she->cmacKeyFound = 0;
}
- /* Unconditionally return success so response message is sent, propagating
- * the error code to the client */
- /* TODO: Are there any fatal server errors that should be handled here? */
- return 0;
+ return ret;
}
#endif /* WOLFHSM_CFG_SHE_EXTENSION */
diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h
index 9eb1f07c..d918fe61 100644
--- a/wolfhsm/wh_error.h
+++ b/wolfhsm/wh_error.h
@@ -40,7 +40,7 @@ enum WH_ERROR_ENUM {
WH_ERROR_CERT_VERIFY = -2005, /* Certificate verification failed */
WH_ERROR_BUFFER_SIZE = -2006, /* Generic buffer size mismatch. Buffer
* length is not what was expected */
- WH_ERROR_NOHANDLER = -2007, /* No customcb handler registered */
+ WH_ERROR_NOHANDLER = -2007, /* No handler for requested action */
WH_ERROR_NOTIMPL = -2008, /* Functionality not implemented given the
compile-time configuration */
WH_ERROR_USAGE =
diff --git a/wolfhsm/wh_log.h b/wolfhsm/wh_log.h
index 85d61072..2011a3e8 100644
--- a/wolfhsm/wh_log.h
+++ b/wolfhsm/wh_log.h
@@ -82,6 +82,17 @@ typedef struct {
void* config; /* Backend-specific config */
} whLogConfig;
+/* Utility functions */
+
+/**
+ * @brief Convert a log level to its string representation.
+ *
+ * @param level The log level to convert.
+ * @return Pointer to a static string representing the log level:
+ * "INFO", "ERROR", "SECEVENT", or "UNKNOWN".
+ */
+const char* wh_Log_LevelToString(whLogLevel level);
+
/* Frontend API */
/**
diff --git a/wolfhsm/wh_log_printf.h b/wolfhsm/wh_log_printf.h
new file mode 100644
index 00000000..dc5e7ada
--- /dev/null
+++ b/wolfhsm/wh_log_printf.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 wolfSSL Inc.
+ *
+ * This file is part of wolfHSM.
+ *
+ * wolfHSM 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.
+ *
+ * wolfHSM 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 wolfHSM. If not, see .
+ */
+/*
+ * wolfhsm/wh_log_printf.h
+ *
+ * Printf logging backend that simply prints out log entries as they are added,
+ * with no backing store.
+ */
+
+#ifndef WOLFHSM_WH_LOG_PRINTF_H_
+#define WOLFHSM_WH_LOG_PRINTF_H_
+
+#include "wolfhsm/wh_settings.h"
+#include "wolfhsm/wh_log.h"
+
+#include
+
+/* Printf configuration structure */
+typedef struct whLogPrintfConfig_t {
+ int logIfNotDebug; /* When non-zero, log entries are printed even if
+ * WOLFHSM_CFG_DEBUG is not defined. When zero, entries
+ * are only printed if WOLFHSM_CFG_DEBUG is defined. This
+ * flag applies to all log levels */
+} whLogPrintfConfig;
+
+/* Printf context structure */
+typedef struct whLogPrintfContext_t {
+ int initialized; /* Initialization flag */
+ int logIfNotDebug; /* Copied from config */
+} whLogPrintfContext;
+
+/* Callback functions */
+int whLogPrintf_Init(void* context, const void* config);
+int whLogPrintf_AddEntry(void* context, const whLogEntry* entry);
+
+/* Convenience macro for callback table initialization.
+ */
+/* clang-format off */
+#define WH_LOG_PRINTF_CB \
+ { \
+ .Init = whLogPrintf_Init, \
+ .Cleanup = NULL, \
+ .AddEntry = whLogPrintf_AddEntry, \
+ .Export = NULL, \
+ .Iterate = NULL, \
+ .Clear = NULL, \
+ }
+/* clang-format on */
+
+#endif /* !WOLFHSM_WH_LOG_PRINTF_H_ */