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
59 changes: 59 additions & 0 deletions doc/dox_comments/header_files/asn.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,62 @@ word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz);
*/
int wc_DhPublicKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
word32 inSz);

/*!
\ingroup CertManager
\brief Sign a certificate or CSR using a callback function.

This function signs a certificate or Certificate Signing Request (CSR)
using a user-provided signing callback. This allows external signing
implementations (e.g., TPM, HSM) without requiring the crypto callback
infrastructure, making it suitable for FIPS-compliant applications.

The function performs the following:
1. Hashes the certificate/CSR body according to the signature algorithm
2. Encodes the hash (RSA) or prepares it for signing (ECC)
3. Calls the user-provided callback to perform the actual signing
4. Encodes the signature into the certificate/CSR DER structure

\param requestSz Size of the certificate body to sign (from Cert.bodySz).
\param sType Signature algorithm type (e.g., CTC_SHA256wRSA,
CTC_SHA256wECDSA).
\param buf Buffer containing the certificate/CSR DER data to sign.
\param buffSz Total size of the buffer (must be large enough for signature).
\param keyType Type of key used for signing (RSA_TYPE, ECC_TYPE, etc.).
\param signCb User-provided signing callback function.
\param signCtx Context pointer passed to the signing callback.
\param rng Random number generator (may be NULL if not needed).

\return Size of the signed certificate/CSR on success.
\return BAD_FUNC_ARG if signCb is NULL or other parameters are invalid.
\return BUFFER_E if the buffer is too small for the signed certificate.
\return MEMORY_E if memory allocation fails.
\return Negative error code on other failures.

_Example_
\code
Cert cert;
byte derBuf[4096];
int derSz;
MySignCtx myCtx;

wc_InitCert(&cert);

derSz = wc_MakeCert(&cert, derBuf, sizeof(derBuf), NULL, NULL, &rng);

derSz = wc_SignCert_cb(cert.bodySz, cert.sigType, derBuf, sizeof(derBuf),
RSA_TYPE, mySignCallback, &myCtx, &rng);
if (derSz > 0) {
printf("Signed certificate is %d bytes\n", derSz);
}
\endcode

\sa wc_SignCertCb
\sa wc_SignCert
\sa wc_SignCert_ex
\sa wc_MakeCert
\sa wc_MakeCertReq
*/
int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz,
int keyType, wc_SignCertCb signCb, void* signCtx,
WC_RNG* rng);
188 changes: 188 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -19987,6 +19987,191 @@ 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(NO_ASN_TIME)

#ifdef HAVE_ECC
/* Test with ECC key */
{
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);

ret = wc_ecc_free(&key);
ExpectIntEQ(ret, 0);
ret = wc_FreeRng(&rng);
ExpectIntEQ(ret, 0);
}
#endif /* HAVE_ECC */

#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
/* Test with RSA key */
{
Cert cert;
byte der[FOURK_BUF];
int derSize = 0;
WC_RNG rng;
RsaKey key;
MockSignCtx signCtx;
int ret;

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

ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_InitRsaKey(&key, NULL), 0);
ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 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_SHA256wRSA;

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

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

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

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

/* Test error case - NULL callback */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, RSA_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);

ret = wc_FreeRsaKey(&key);
ExpectIntEQ(ret, 0);
ret = wc_FreeRng(&rng);
ExpectIntEQ(ret, 0);
}
#endif /* !NO_RSA && WOLFSSL_KEY_GEN */

#endif /* WOLFSSL_CERT_GEN && !NO_ASN_TIME */
return EXPECT_RESULT();
}
#endif /* WOLFSSL_CERT_SIGN_CB */

static int test_ERR_load_crypto_strings(void)
{
#if defined(OPENSSL_ALL)
Expand Down Expand Up @@ -31467,6 +31652,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
Empty file.
Empty file.
Loading