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
59 changes: 59 additions & 0 deletions src/wh_client_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,65 @@ int wh_Client_CertVerifyAndCacheLeafPubKey(
inout_keyId, out_rc);
}

#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
int wh_Client_CertVerifyCacheClearRequest(whClientContext* c)
{
if (c == NULL) {
return WH_ERROR_BADARGS;
}
return wh_Client_SendRequest(c, WH_MESSAGE_GROUP_CERT,
WH_MESSAGE_CERT_ACTION_VERIFY_CACHE_CLEAR, 0,
NULL);
}

int wh_Client_CertVerifyCacheClearResponse(whClientContext* c, int32_t* out_rc)
{
int rc;
uint16_t group;
uint16_t action;
uint16_t size;
whMessageCert_SimpleResponse resp;

if (c == NULL) {
return WH_ERROR_BADARGS;
}

rc = wh_Client_RecvResponse(c, &group, &action, &size, &resp);
if (rc == WH_ERROR_OK) {
if ((group != WH_MESSAGE_GROUP_CERT) ||
(action != WH_MESSAGE_CERT_ACTION_VERIFY_CACHE_CLEAR) ||
(size != sizeof(resp))) {
rc = WH_ERROR_ABORTED;
}
else if (out_rc != NULL) {
*out_rc = resp.rc;
}
}
return rc;
}

int wh_Client_CertVerifyCacheClear(whClientContext* c, int32_t* out_rc)
{
int rc = WH_ERROR_OK;

if (c == NULL) {
return WH_ERROR_BADARGS;
}

do {
rc = wh_Client_CertVerifyCacheClearRequest(c);
} while (rc == WH_ERROR_NOTREADY);

if (rc == WH_ERROR_OK) {
do {
rc = wh_Client_CertVerifyCacheClearResponse(c, out_rc);
} while (rc == WH_ERROR_NOTREADY);
}

return rc;
}
#endif /* WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE */

#ifdef WOLFHSM_CFG_DMA

int wh_Client_CertAddTrustedDmaRequest(whClientContext* c, whNvmId id,
Expand Down
8 changes: 8 additions & 0 deletions src/wh_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ int wh_Server_Init(whServerContext* server, whServerConfig* config)
}
#endif /* WOLFHSM_CFG_DMA */

#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) && !defined(WOLFHSM_CFG_NO_CRYPTO)
/* Register the user-supplied verify callback, if any. The cache (if
* compiled in) is already zero-initialized by the memset above. */
if (config->certConfig != NULL) {
server->cert.verifyCb = config->certConfig->verifyCb;
}
#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER && !WOLFHSM_CFG_NO_CRYPTO */

/* Log the server startup */
WH_LOG(&server->log, WH_LOG_LEVEL_INFO, "Server Initialized");

Expand Down
150 changes: 140 additions & 10 deletions src/wh_server_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_server.h"
#include "wolfhsm/wh_server_cert.h"
#include "wolfhsm/wh_server_cert_cache.h"
#include "wolfhsm/wh_server_nvm.h"
#include "wolfhsm/wh_server_keystore.h"
#include "wolfhsm/wh_message.h"
Expand All @@ -41,6 +42,68 @@
#include "wolfssl/wolfcrypt/types.h"
#include "wolfssl/ssl.h"
#include "wolfssl/wolfcrypt/asn.h"
#include "wolfssl/wolfcrypt/sha256.h"


#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
int wh_Server_CertVerifyCache_Lookup(whServerContext* server, whNvmId rootNvmId,
const uint8_t* hash)
{
int i;
if ((server == NULL) || (hash == NULL)) {
return WH_ERROR_BADARGS;
}
for (i = 0; i < WOLFHSM_CFG_CERT_VERIFY_CACHE_COUNT; i++) {
const whCertVerifyCacheSlot* slot = &server->cert.cache.slots[i];
if (slot->committed && (slot->rootNvmId == rootNvmId) &&
(memcmp(slot->hash, hash, WH_CERT_VERIFY_CACHE_HASH_LEN) == 0)) {
return WH_ERROR_OK;
}
}
return WH_ERROR_NOTFOUND;
}

void wh_Server_CertVerifyCache_Insert(whServerContext* server,
whNvmId rootNvmId, const uint8_t* hash)
{
whCertVerifyCacheSlot* slot;
uint16_t idx;

if ((server == NULL) || (hash == NULL)) {
return;
}
/* Skip if already present under this root */
if (wh_Server_CertVerifyCache_Lookup(server, rootNvmId, hash) ==
WH_ERROR_OK) {
return;
}
/* FIFO ring overwrite */
idx = server->cert.cache.writeIdx;
slot = &server->cert.cache.slots[idx];
slot->rootNvmId = rootNvmId;
memcpy(slot->hash, hash, WH_CERT_VERIFY_CACHE_HASH_LEN);
slot->committed = 1;
server->cert.cache.writeIdx =
(uint16_t)((idx + 1) % WOLFHSM_CFG_CERT_VERIFY_CACHE_COUNT);
}

void wh_Server_CertVerifyCache_Clear(whServerContext* server)
{
if (server == NULL) {
return;
}
memset(&server->cert.cache, 0, sizeof(server->cert.cache));
}
#endif /* WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE */

int wh_Server_CertSetVerifyCb(whServerContext* server, VerifyCallback cb)
{
if (server == NULL) {
return WH_ERROR_BADARGS;
}
server->cert.verifyCb = cb;
return WH_ERROR_OK;
Comment thread
bigbrett marked this conversation as resolved.
}


/* Replicates GetSequence, which is WOLFSSL_LOCAL. */
Expand All @@ -61,18 +124,23 @@ static int DerNextSequence(const uint8_t* input, uint32_t maxIdx,
}


static int _verifyChainAgainstCmStore(whServerContext* server,
WOLFSSL_CERT_MANAGER* cm,
const uint8_t* chain, uint32_t chain_len,
whCertFlags flags,
whNvmFlags cachedKeyFlags,
whKeyId* inout_keyId)
static int
_verifyChainAgainstCmStore(whServerContext* server, WOLFSSL_CERT_MANAGER* cm,
const uint8_t* chain, uint32_t chain_len,
whNvmId trustedRootNvmId, whCertFlags flags,
whNvmFlags cachedKeyFlags, whKeyId* inout_keyId)
{
int rc = 0;
const uint8_t* cert_ptr = chain;
uint32_t remaining_len = chain_len;
int cert_len = 0;
word32 idx = 0;
#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
uint8_t certHash[WH_CERT_VERIFY_CACHE_HASH_LEN];
int hashed = 0;
#else
(void)trustedRootNvmId;
#endif

if (cm == NULL || chain == NULL || chain_len == 0) {
return WH_ERROR_BADARGS;
Expand All @@ -82,6 +150,9 @@ static int _verifyChainAgainstCmStore(whServerContext* server,
while (remaining_len > 0) {
/* Reset index for each certificate */
idx = 0;
#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
hashed = 0;
#endif

/* Get the length of the current certificate */
rc = DerNextSequence(cert_ptr, remaining_len, &idx, &cert_len);
Expand All @@ -94,9 +165,28 @@ static int _verifyChainAgainstCmStore(whServerContext* server,
return WH_ERROR_ABORTED;
}

/* Verify the current certificate */
rc = wolfSSL_CertManagerVerifyBuffer(cm, cert_ptr, cert_len + idx,
WOLFSSL_FILETYPE_ASN1);
#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
/* Hash the DER cert and check the verify cache. A hit short-circuits
* the public-key signature check; the cert is otherwise treated as if
* it had verified normally so the rest of the loop (CA decode, store
* load, leaf pubkey extract) continues unchanged. */
rc = wc_Sha256Hash_ex(cert_ptr, (word32)(cert_len + idx), certHash,
NULL, server->devId);
if (rc != 0) {
return rc;
}
hashed = 1;
if (wh_Server_CertVerifyCache_Lookup(server, trustedRootNvmId,
certHash) == WH_ERROR_OK) {
rc = WOLFSSL_SUCCESS;
}
else
#endif
{
/* Verify the current certificate */
rc = wolfSSL_CertManagerVerifyBuffer(cm, cert_ptr, cert_len + idx,
WOLFSSL_FILETYPE_ASN1);
}


Comment thread
bigbrett marked this conversation as resolved.
/* If this is not the leaf certificate and it's trusted, add it to the
Expand Down Expand Up @@ -170,6 +260,15 @@ static int _verifyChainAgainstCmStore(whServerContext* server,
}
}
wc_FreeDecodedCert(&dc);
#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
/* Cert verified (or hit) and post-processed successfully.
* Record the hash bound to this trusted root so subsequent
* verifications under the same root short-circuit. */
if (hashed) {
wh_Server_CertVerifyCache_Insert(server, trustedRootNvmId,
certHash);
}
#endif
}
else {
return rc;
Expand All @@ -190,7 +289,13 @@ int wh_Server_CertInit(whServerContext* server)
#ifdef DEBUG_WOLFSSL
wolfSSL_Debugging_ON();
#endif
#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
if (server != NULL) {
wh_Server_CertVerifyCache_Clear(server);
}
#else
(void)server;
#endif
return WH_ERROR_OK;
}

Expand Down Expand Up @@ -304,6 +409,13 @@ int wh_Server_CertVerify(whServerContext* server, const uint8_t* cert,
return WH_ERROR_ABORTED;
}

/* Apply the user-supplied verify callback, if registered. wolfSSL invokes
* it during wolfSSL_CertManagerVerifyBuffer; cache hits short-circuit that
* path and so deliberately do not invoke the callback. */
if (server->cert.verifyCb != NULL) {
Comment thread
bigbrett marked this conversation as resolved.
wolfSSL_CertManagerSetVerify(cm, server->cert.verifyCb);
}

/* Get the trusted root certificate */
rc = wh_Server_CertReadTrusted(server, trustedRootNvmId, root_cert,
&root_cert_len);
Expand All @@ -313,7 +425,8 @@ int wh_Server_CertVerify(whServerContext* server, const uint8_t* cert,
WOLFSSL_FILETYPE_ASN1);
if (rc == WOLFSSL_SUCCESS) {
/* Verify the certificate */
rc = _verifyChainAgainstCmStore(server, cm, cert, cert_len, flags,
rc = _verifyChainAgainstCmStore(server, cm, cert, cert_len,
trustedRootNvmId, flags,
cachedKeyFlags, inout_keyId);
if (rc != WH_ERROR_OK) {
rc = WH_ERROR_CERT_VERIFY;
Expand Down Expand Up @@ -572,6 +685,23 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic,
*out_resp_size = sizeof(resp);
}; break;

#ifdef WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
case WH_MESSAGE_CERT_ACTION_VERIFY_CACHE_CLEAR: {
Comment thread
bigbrett marked this conversation as resolved.
whMessageCert_SimpleResponse resp = {0};

rc = WH_SERVER_NVM_LOCK(server);
if (rc == WH_ERROR_OK) {
wh_Server_CertVerifyCache_Clear(server);
(void)WH_SERVER_NVM_UNLOCK(server);
}
resp.rc = rc;

wh_MessageCert_TranslateSimpleResponse(
magic, &resp, (whMessageCert_SimpleResponse*)resp_packet);
*out_resp_size = sizeof(resp);
}; break;
#endif /* WOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE */

#ifdef WOLFHSM_CFG_DMA
case WH_MESSAGE_CERT_ACTION_ADDTRUSTED_DMA: {
whMessageCert_AddTrustedDmaRequest req = {0};
Expand Down
5 changes: 5 additions & 0 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ ifeq ($(AUTH),1)
DEF += -DWOLFHSM_CFG_ENABLE_AUTHENTICATION
endif

# Support trusted-cert verify-result cache
ifeq ($(CERT_VERIFY_CACHE),1)
DEF += -DWOLFHSM_CFG_CERTIFICATE_VERIFY_CACHE
endif

## Project defines
# Option to build wolfcrypt tests
ifeq ($(TESTWOLFCRYPT),1)
Expand Down
Loading
Loading