Skip to content
Open
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
13 changes: 13 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4591,6 +4591,19 @@ then
fi


# CERT SIGN CALLBACK
AC_ARG_ENABLE([certsigncb],
[AS_HELP_STRING([--enable-certsigncb],[Enable cert signing callback API for TPM/HSM (default: disabled)])],
[ ENABLED_CERTSIGNCB=$enableval ],
[ ENABLED_CERTSIGNCB=no ]
)

if test "$ENABLED_CERTSIGNCB" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_SIGN_CB"
fi


# SEP
AC_ARG_ENABLE([sep],
[AS_HELP_STRING([--enable-sep],[Enable sep extensions (default: disabled)])],
Expand Down
122 changes: 122 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -19987,6 +19987,125 @@ static int test_MakeCertWithCaFalse(void)
return EXPECT_RESULT();
}

/* Mock callback for testing wc_SignCert_cb */
#if defined(WOLFSSL_CERT_SIGN_CB) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ))
/* Context structure for mock signing callback */
typedef struct {
void* key; /* Pointer to RSA or ECC key */
WC_RNG* rng; /* Random number generator (required for ECC) */
} MockSignCtx;

static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen,
int sigAlgo, int keyType, void* ctx)
{
int ret = 0;
MockSignCtx* signCtx = (MockSignCtx*)ctx;

if (signCtx == NULL || signCtx->key == NULL || in == NULL ||
out == NULL || outLen == NULL) {
return BAD_FUNC_ARG;
}

(void)sigAlgo;

#ifndef NO_RSA
if (keyType == RSA_TYPE) {
RsaKey* rsaKey = (RsaKey*)signCtx->key;
word32 outSz = *outLen;

/* For RSA, input is DER-encoded digest (DigestInfo structure) */
ret = wc_RsaSSL_Sign(in, inLen, out, outSz, rsaKey, signCtx->rng);
if (ret > 0) {
*outLen = (word32)ret;
ret = 0;
}
}
else
#endif
#ifdef HAVE_ECC
if (keyType == ECC_TYPE) {
ecc_key* eccKey = (ecc_key*)signCtx->key;
word32 outSz = *outLen;

/* For ECC, input is raw hash, sign it (RNG required for ECDSA k value) */
ret = wc_ecc_sign_hash(in, inLen, out, &outSz, signCtx->rng, eccKey);
if (ret == 0) {
*outLen = outSz;
}
}
else
#endif
{
ret = BAD_FUNC_ARG;
}

return ret;
}
#endif

#ifdef WOLFSSL_CERT_SIGN_CB
static int test_wc_SignCert_cb(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && !defined(NO_ASN_TIME)
Cert cert;
byte der[FOURK_BUF];
int derSize = 0;
WC_RNG rng;
ecc_key key;
MockSignCtx signCtx;
int ret;

XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&key, 0, sizeof(ecc_key));
XMEMSET(&cert, 0, sizeof(Cert));
XMEMSET(&signCtx, 0, sizeof(MockSignCtx));

ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ecc_init(&key), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &key), 0);
ExpectIntEQ(wc_InitCert(&cert), 0);

(void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.state, "state", CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.locality, "locality", CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.org, "org", CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.unit, "unit", CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.commonName, "www.example.com",
CTC_NAME_SIZE);
(void)XSTRNCPY(cert.subject.email, "test@example.com", CTC_NAME_SIZE);

cert.selfSigned = 1;
cert.isCA = 0;
cert.sigType = CTC_SHA256wECDSA;

/* Make cert body */
ExpectIntGT(wc_MakeCert(&cert, der, FOURK_BUF, NULL, &key, &rng), 0);

/* Setup signing context with key and RNG */
signCtx.key = &key;
signCtx.rng = &rng;

/* Sign using callback API */
ExpectIntGT(derSize = wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), 0);

/* Verify the certificate was created properly */
ExpectIntGT(derSize, 0);

/* Test error cases */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ECC_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);
Comment on lines +20096 to +20098
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test only checks one error case (NULL callback). Additional error cases should be tested to ensure robust error handling:

  1. NULL buf parameter (should return BAD_FUNC_ARG per line 34426)
  2. requestSz < 0 (should return requestSz per line 34432-34434)
  3. Invalid keyType (to ensure proper error handling)
  4. Buffer too small (buffSz too small for signature)

These additional test cases would improve confidence in the error handling paths of the new API.

Copilot uses AI. Check for mistakes.

ret = wc_ecc_free(&key);
ExpectIntEQ(ret, 0);
ret = wc_FreeRng(&rng);
ExpectIntEQ(ret, 0);
#endif
return EXPECT_RESULT();
}
#endif /* WOLFSSL_CERT_SIGN_CB */
Comment on lines +20047 to +20107
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test function test_wc_SignCert_cb only tests with ECC keys (CTC_SHA256wECDSA). Since the new API explicitly supports both RSA and ECC key types, and the mockSignCb callback implementation includes RSA support (lines 20011-20023), there should be test coverage for RSA as well to ensure the RSA code path works correctly. Consider adding an RSA test case to verify that RSA signing through the callback works properly.

Copilot uses AI. Check for mistakes.

static int test_ERR_load_crypto_strings(void)
{
#if defined(OPENSSL_ALL)
Expand Down Expand Up @@ -31467,6 +31586,9 @@ TEST_CASE testCases[] = {
TEST_DECL(test_MakeCertWithPathLen),
TEST_DECL(test_MakeCertWith0Ser),
TEST_DECL(test_MakeCertWithCaFalse),
#ifdef WOLFSSL_CERT_SIGN_CB
TEST_DECL(test_wc_SignCert_cb),
#endif
TEST_DECL(test_wc_SetKeyUsage),
TEST_DECL(test_wc_SetAuthKeyIdFromPublicKey_ex),
TEST_DECL(test_wc_SetSubjectBuffer),
Expand Down
Loading