Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions examples/demo/client/wh_demo_client_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,44 @@ static int wh_DemoClient_AuthUserSetPermissions(whClientContext* clientContext)
}


/**
* Persistence verification: when the server uses NVM-backed auth, users survive
* restarts. Run the full demo once (adds demo user), then restart the server
* and run again. This check will detect the persisted demo user and print a
* verification message.
*/
static int wh_DemoClient_AuthPersistenceCheck(whClientContext* clientContext)
{
int32_t serverRc = 0;
whUserId userId = WH_USER_ID_INVALID;

/* Try to log in as demo user - if successful, user was persisted from a
* previous server run (NVM-backed auth) */
int rc = wh_Client_AuthLogin(clientContext, WH_AUTH_METHOD_PIN, "demo",
"1234", 4, &serverRc, &userId);
if (serverRc == WH_AUTH_NOT_ENABLED) {
return WH_ERROR_OK; /* Auth not enabled, skip */
}
if (rc == 0 && serverRc == 0) {
printf("[AUTH-DEMO] NVM persistence verified: demo user found from "
"previous server run\n");
(void)wh_Client_AuthLogout(clientContext, userId, &serverRc);
}
Comment on lines +395 to +406
return WH_ERROR_OK;
}

int wh_DemoClient_Auth(whClientContext* clientContext)
{
int rc = 0;

printf("[AUTH-DEMO] Starting authentication demo...\n");

/* Check for persisted users from a previous server run (NVM-backed auth) */
rc = wh_DemoClient_AuthPersistenceCheck(clientContext);
if (rc != WH_ERROR_OK) {
return rc;
}

rc = wh_DemoClient_AuthCertificate(clientContext);
if (rc != WH_ERROR_OK) {
return rc;
Expand Down
48 changes: 27 additions & 21 deletions examples/posix/wh_posix_server/wh_posix_server_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,14 +685,14 @@ static whAuthContext auth_ctx = {0};
*/
int wh_PosixServer_ExampleAuthConfig(void* conf)
{
int rc;
whServerConfig* s_conf = (whServerConfig*)conf;
static void* auth_backend_context =
NULL; /* No backend context needed for stubs */
static whAuthConfig auth_config = {0};
whAuthPermissions permissions;
uint16_t out_user_id;
int i;
int rc;
whServerConfig* s_conf = (whServerConfig*)conf;
static void* auth_backend_context = NULL;
static whAuthConfig auth_config = {0};
static whAuthBaseConfig auth_base_config = {0};
whAuthPermissions permissions;
uint16_t out_user_id;
int i;

if (s_conf == NULL) {
return WH_ERROR_BADARGS;
Expand All @@ -701,6 +701,9 @@ int wh_PosixServer_ExampleAuthConfig(void* conf)
/* Set up the auth config with default callbacks */
auth_config.cb = &default_auth_cb;
auth_config.context = auth_backend_context;
/* NVM-backed user database: persist users across server restarts */
auth_base_config.nvm = s_conf->nvm;
auth_config.config = &auth_base_config;

/* Initialize the auth context */
rc = wh_Auth_Init(&auth_ctx, &auth_config);
Expand All @@ -713,19 +716,22 @@ int wh_PosixServer_ExampleAuthConfig(void* conf)
s_conf->auth = &auth_ctx;

WOLFHSM_CFG_PRINTF(
"Default auth context configured (stub implementation)\n");

/* Add an admin user with permissions for everything */
memset(&permissions, 0xFF, sizeof(whAuthPermissions));
permissions.keyIdCount = 0;
for (i = 0; i < WH_AUTH_MAX_KEY_IDS; i++) {
permissions.keyIds[i] = 0;
}
rc = wh_Auth_BaseUserAdd(&auth_ctx, "admin", &out_user_id, permissions,
WH_AUTH_METHOD_PIN, "1234", 4);
if (rc != WH_ERROR_OK) {
WOLFHSM_CFG_PRINTF("Failed to add admin user: %d\n", rc);
return rc;
"Default auth context configured (NVM-backed user database)\n");
Comment on lines 718 to +719

/* Add admin user only if not already present (e.g. from NVM load) */
rc = wh_Auth_BaseUserGet(&auth_ctx, "admin", &out_user_id, &permissions);
if (rc == WH_ERROR_NOTFOUND) {
memset(&permissions, 0xFF, sizeof(whAuthPermissions));
permissions.keyIdCount = 0;
for (i = 0; i < WH_AUTH_MAX_KEY_IDS; i++) {
permissions.keyIds[i] = 0;
}
rc = wh_Auth_BaseUserAdd(&auth_ctx, "admin", &out_user_id, permissions,
WH_AUTH_METHOD_PIN, "1234", 4);
if (rc != WH_ERROR_OK) {
WOLFHSM_CFG_PRINTF("Failed to add admin user: %d\n", rc);
return rc;
}
}

return WH_ERROR_OK;
Expand Down
107 changes: 103 additions & 4 deletions src/wh_auth_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "wolfhsm/wh_message.h"
#include "wolfhsm/wh_message_auth.h"
#include "wolfhsm/wh_auth_base.h"
#include "wolfhsm/wh_nvm.h"

/* hash pin with use as credentials */
#ifndef WOLFHSM_CFG_NO_CRYPTO
Expand All @@ -56,23 +57,116 @@ typedef struct whAuthBase_User {
* wrapper functions in wh_auth.c. */
static whAuthBase_User users[WH_AUTH_BASE_MAX_USERS];

/* NVM persistence: when non-NULL, user database is stored in NVM */
static whNvmContext* s_auth_base_nvm = NULL;

/* Serialization format: magic (4) + version (2) + users array */
#define WH_AUTH_BASE_NVM_MAGIC 0x57484142u /* "WHAB" */
#define WH_AUTH_BASE_NVM_VERSION 1
#define WH_AUTH_BASE_NVM_HEADER_SIZE 6
#define WH_AUTH_BASE_NVM_DATA_SIZE \
(WH_AUTH_BASE_NVM_HEADER_SIZE + sizeof(whAuthBase_User) * WH_AUTH_BASE_MAX_USERS)

#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) && !defined(WOLFHSM_CFG_NO_CRYPTO)
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
#endif

/* Persist users array to NVM. Caller must hold auth lock. */
static int wh_Auth_BasePersistToNvm(void)
{
whNvmMetadata meta = {0};
uint8_t buf[WH_AUTH_BASE_NVM_DATA_SIZE];
int i;

if (s_auth_base_nvm == NULL) {
return WH_ERROR_OK;
}

/* Serialize: magic + version + users (clear is_active before storing) */
((uint32_t*)buf)[0] = WH_AUTH_BASE_NVM_MAGIC;
((uint16_t*)(buf + 4))[0] = WH_AUTH_BASE_NVM_VERSION;
memcpy(buf + WH_AUTH_BASE_NVM_HEADER_SIZE, users, sizeof(users));
Comment thread
JacobBarthelmeh marked this conversation as resolved.
/* Clear is_active in serialized copy - session state is not persisted */
for (i = 0; i < WH_AUTH_BASE_MAX_USERS; i++) {
((whAuthBase_User*)(buf + WH_AUTH_BASE_NVM_HEADER_SIZE))[i].user.is_active = false;
}
Comment on lines +86 to +93

meta.id = WH_NVM_ID_AUTH_USER_DB;
meta.access = WH_NVM_ACCESS_NONE;
meta.flags = WH_NVM_FLAGS_SENSITIVE;
meta.len = WH_AUTH_BASE_NVM_DATA_SIZE;
memset(meta.label, 0, sizeof(meta.label));
memcpy(meta.label, "auth_user_db", 12);

return wh_Nvm_AddObject(s_auth_base_nvm, &meta, WH_AUTH_BASE_NVM_DATA_SIZE, buf);
}
Comment thread
JacobBarthelmeh marked this conversation as resolved.

/* Load users from NVM. Caller must hold auth lock. Returns WH_ERROR_OK on success. */
static int wh_Auth_BaseLoadFromNvm(void)
{
whNvmMetadata meta = {0};
uint8_t buf[WH_AUTH_BASE_NVM_DATA_SIZE];
int rc;

if (s_auth_base_nvm == NULL) {
return WH_ERROR_OK;
}

rc = wh_Nvm_GetMetadata(s_auth_base_nvm, WH_NVM_ID_AUTH_USER_DB, &meta);
if (rc == WH_ERROR_NOTFOUND) {
return WH_ERROR_OK; /* No stored data, keep empty */
}
if (rc != WH_ERROR_OK) {
return rc;
}
if (meta.len != WH_AUTH_BASE_NVM_DATA_SIZE) {
return WH_ERROR_OK; /* Version mismatch, ignore */
}

rc = wh_Nvm_Read(s_auth_base_nvm, WH_NVM_ID_AUTH_USER_DB, 0,
WH_AUTH_BASE_NVM_DATA_SIZE, buf);
if (rc != WH_ERROR_OK) {
return rc;
}
Comment on lines +116 to +131

if (((uint32_t*)buf)[0] != WH_AUTH_BASE_NVM_MAGIC ||
((uint16_t*)(buf + 4))[0] != WH_AUTH_BASE_NVM_VERSION) {
return WH_ERROR_OK; /* Unknown format, start fresh */
}
Comment on lines +133 to +136

memcpy(users, buf + WH_AUTH_BASE_NVM_HEADER_SIZE, sizeof(users));
/* Ensure is_active is false after load (session state is not persisted) */
{
int i;
for (i = 0; i < WH_AUTH_BASE_MAX_USERS; i++) {
users[i].user.is_active = false;
}
}
return WH_ERROR_OK;
}

int wh_Auth_BaseInit(void* context, const void* config)
{
(void)context;
(void)config;

memset(users, 0, sizeof(users));
s_auth_base_nvm = NULL;

if (config != NULL) {
const whAuthBaseConfig* base_config = (const whAuthBaseConfig*)config;
if (base_config->nvm != NULL) {
s_auth_base_nvm = (whNvmContext*)base_config->nvm;
return wh_Auth_BaseLoadFromNvm();
}
Comment on lines +156 to +161
}
return WH_ERROR_OK;
}

int wh_Auth_BaseCleanup(void* context)
{
(void)context;
s_auth_base_nvm = NULL;
wh_Utils_ForceZero(users, sizeof(users));
return WH_ERROR_OK;
}
Expand Down Expand Up @@ -266,6 +360,7 @@ int wh_Auth_BaseUserAdd(void* context, const char* username,
whAuthContext* auth_context = (whAuthContext*)context;
whAuthBase_User* new_user;
int i;
int rc;
int userId = WH_USER_ID_INVALID;

if (username == NULL || out_user_id == NULL) {
Expand Down Expand Up @@ -362,8 +457,9 @@ int wh_Auth_BaseUserAdd(void* context, const char* username,
}
}

rc = wh_Auth_BasePersistToNvm();
(void)auth_context;
return WH_ERROR_OK;
return rc;
Comment on lines +460 to +462
}

int wh_Auth_BaseUserDelete(void* context, uint16_t current_user_id,
Expand Down Expand Up @@ -392,7 +488,7 @@ int wh_Auth_BaseUserDelete(void* context, uint16_t current_user_id,

wh_Utils_ForceZero(user, sizeof(whAuthBase_User));
(void)context;
return WH_ERROR_OK;
return wh_Auth_BasePersistToNvm();
Comment on lines 489 to +491
}

int wh_Auth_BaseUserSetPermissions(void* context, uint16_t current_user_id,
Expand Down Expand Up @@ -433,7 +529,7 @@ int wh_Auth_BaseUserSetPermissions(void* context, uint16_t current_user_id,
}
}
(void)context;
return WH_ERROR_OK;
return wh_Auth_BasePersistToNvm();
Comment on lines 531 to +532
}


Expand Down Expand Up @@ -580,6 +676,9 @@ int wh_Auth_BaseUserSetCredentials(void* context, uint16_t current_user_id,
}
user->method = method;

if (rc == WH_ERROR_OK) {
rc = wh_Auth_BasePersistToNvm();
}
Comment on lines +679 to +681
Comment on lines +679 to +681
(void)auth_context;
return rc;
}
Expand Down
13 changes: 13 additions & 0 deletions wolfhsm/wh_auth_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@
#include "wolfhsm/wh_common.h"
#include "wolfhsm/wh_auth.h"

/** NVM object ID for the auth user database (reserved, do not use for other objects) */
#define WH_NVM_ID_AUTH_USER_DB ((whNvmId)0xFE00)

/**
* @brief Configuration for the auth base implementation.
*
* When nvm is non-NULL and NVM is built in, the user database is persisted to NVM.
* When nvm is NULL, the user database remains in-memory only (lost on restart).
*/
typedef struct {
void* nvm; /**< NVM context (whNvmContext*) for persistent storage; NULL for in-memory only */
} whAuthBaseConfig;

/**
* @brief Initialize the auth base implementation.
*
Expand Down
Loading