From 4aa26c13fff908594020a19549a92e263662077e Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:20:00 -0700 Subject: [PATCH 1/9] Add wc_SignCert_cb API for external signing callbacks --- tests/api.c | 106 +++++++++++++++++++++ wolfcrypt/src/asn.c | 162 +++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/asn_public.h | 103 +++++++++++++++++++++ 3 files changed, 371 insertions(+) diff --git a/tests/api.c b/tests/api.c index 1a3162b2456..e1fa2678142 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26920,6 +26920,112 @@ static int test_MakeCertWithCaFalse(void) return EXPECT_RESULT(); } +/* Mock callback for testing wc_SignCert_cb */ +#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) +static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, + int sigAlgo, int keyType, void* ctx) +{ + int ret = 0; + void* key = ctx; + + if (key == NULL || in == NULL || out == NULL || outLen == NULL) { + return BAD_FUNC_ARG; + } + + (void)sigAlgo; + +#ifndef NO_RSA + if (keyType == RSA_TYPE) { + RsaKey* rsaKey = (RsaKey*)key; + word32 idx = 0; + word32 outSz = *outLen; + + /* For RSA, input is pre-encoded digest, just sign it */ + ret = wc_RsaSSL_Sign(in, inLen, out, outSz, rsaKey, NULL); + if (ret > 0) { + *outLen = (word32)ret; + ret = 0; + } + } + else +#endif +#ifdef HAVE_ECC + if (keyType == ECC_TYPE) { + ecc_key* eccKey = (ecc_key*)key; + word32 outSz = *outLen; + + /* For ECC, input is raw hash, sign it */ + ret = wc_ecc_sign_hash(in, inLen, out, &outSz, NULL, eccKey); + if (ret == 0) { + *outLen = outSz; + } + } + else +#endif + { + ret = BAD_FUNC_ARG; + } + + return ret; +} +#endif + +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; + int ret; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&key, 0, sizeof(ecc_key)); + XMEMSET(&cert, 0, sizeof(Cert)); + + 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); + + /* Sign using callback API */ + ExpectIntGT(derSize = wc_SignCert_cb(cert.bodySz, cert.sigType, der, + FOURK_BUF, ECC_TYPE, mockSignCb, &key, &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, &key, &rng), BAD_FUNC_ARG); + + ret = wc_ecc_free(&key); + ExpectIntEQ(ret, 0); + ret = wc_FreeRng(&rng); + ExpectIntEQ(ret, 0); +#endif + return EXPECT_RESULT(); +} + + static int test_wolfSSL_EVP_PKEY_encrypt(void) { EXPECT_DECLS; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8452f99c28c..70d51c7ff0e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33805,6 +33805,103 @@ int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, #endif /* WOLFSSL_CERT_REQ */ + +#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) +/* Internal function to create signature using callback + * This allows external signing implementations (e.g., TPM, HSM) without + * requiring the crypto callback infrastructure. + */ +static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, + word32 sz, byte* sig, word32 sigSz, int sigAlgoType, int keyType, + wc_SignCertCb signCb, void* signCtx, WC_RNG* rng, void* heap) +{ + int digestSz = 0, typeH = 0, ret = 0; + word32 outLen; + + (void)rng; + (void)heap; + + switch (certSignCtx->state) { + case CERTSIGN_STATE_BEGIN: + case CERTSIGN_STATE_DIGEST: + certSignCtx->state = CERTSIGN_STATE_DIGEST; +#ifndef WOLFSSL_NO_MALLOC + certSignCtx->digest = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certSignCtx->digest == NULL) { + ret = MEMORY_E; + goto exit_ms; + } +#endif + ret = HashForSignature(buf, sz, sigAlgoType, certSignCtx->digest, + &typeH, &digestSz, 0, NULL, INVALID_DEVID); + certSignCtx->state = CERTSIGN_STATE_ENCODE; + if (ret != 0) { + goto exit_ms; + } + FALL_THROUGH; + + case CERTSIGN_STATE_ENCODE: + /* For RSA, encode the digest with algorithm identifier */ + if (keyType == RSA_TYPE) { +#ifndef WOLFSSL_NO_MALLOC + certSignCtx->encSig = (byte*)XMALLOC(MAX_DER_DIGEST_SZ, heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certSignCtx->encSig == NULL) { + ret = MEMORY_E; + goto exit_ms; + } +#endif + certSignCtx->encSigSz = (int)wc_EncodeSignature(certSignCtx->encSig, + certSignCtx->digest, (word32)digestSz, typeH); + } + FALL_THROUGH; + + case CERTSIGN_STATE_DO: + certSignCtx->state = CERTSIGN_STATE_DO; + outLen = sigSz; + + /* Call the user-provided signing callback */ + if (keyType == RSA_TYPE) { + /* RSA: pass encoded digest */ + ret = signCb(certSignCtx->encSig, (word32)certSignCtx->encSigSz, + sig, &outLen, sigAlgoType, keyType, signCtx); + } + else { + /* ECC/EdDSA: pass raw hash or message */ + ret = signCb(certSignCtx->digest, (word32)digestSz, + sig, &outLen, sigAlgoType, keyType, signCtx); + } + + if (ret == 0) { + ret = (int)outLen; + } + break; + } + +exit_ms: +#ifndef WOLFSSL_NO_MALLOC + if (keyType == RSA_TYPE) { + XFREE(certSignCtx->encSig, heap, DYNAMIC_TYPE_TMP_BUFFER); + certSignCtx->encSig = NULL; + } + XFREE(certSignCtx->digest, heap, DYNAMIC_TYPE_TMP_BUFFER); + certSignCtx->digest = NULL; +#endif + + /* reset state */ + certSignCtx->state = CERTSIGN_STATE_BEGIN; + + if (ret < 0) { + WOLFSSL_ERROR_VERBOSE(ret); + } + + return ret; +} +#endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ */ + + + static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, @@ -34103,6 +34200,71 @@ int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, NULL, NULL, NULL, rng); } +/* Sign certificate/CSR using a callback function + * This allows external signing implementations (e.g., TPM, HSM) + * without requiring the crypto callback infrastructure. + * + * @param [in] requestSz Size of certificate body to sign. + * @param [in] sType The signature type. + * @param [in,out] buf Der buffer to sign. + * @param [in] buffSz Der buffer size. + * @param [in] keyType The type of key. + * @param [in] signCb User signing callback. + * @param [in] signCtx Context passed to callback. + * @param [in] rng Random number generator (may be NULL). + * + * @return Size of signature on success. + * @return < 0 on error + */ +int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, + int keyType, wc_SignCertCb signCb, void* signCtx, + WC_RNG* rng) +{ + int sigSz = 0; + CertSignCtx certSignCtx_lcl; + CertSignCtx* certSignCtx = &certSignCtx_lcl; + + if (signCb == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); + + if (requestSz < 0) { + return requestSz; + } + +#ifndef WOLFSSL_NO_MALLOC + certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (certSignCtx->sig == NULL) { + return MEMORY_E; + } +#endif + + sigSz = MakeSignatureCb(certSignCtx, buf, (word32)requestSz, + certSignCtx->sig, MAX_ENCODED_SIG_SZ, sType, keyType, + signCb, signCtx, rng, NULL); + + if (sigSz >= 0) { + if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) { + sigSz = BUFFER_E; + } + else { + sigSz = AddSignature(buf, requestSz, certSignCtx->sig, sigSz, sType); + } + } + +#ifndef WOLFSSL_NO_MALLOC + XFREE(certSignCtx->sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + certSignCtx->sig = NULL; +#endif + + return sigSz; +} + + + WOLFSSL_ABI int wc_MakeSelfCert(Cert* cert, byte* buf, word32 buffSz, diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 685f8069961..e43f9576c27 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -233,6 +233,46 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); #define pem_password_cb wc_pem_password_cb #endif +/*! + \ingroup CertManager + \brief Callback function type for certificate/CSR signing. + + This callback allows external signing implementations (e.g., TPM, HSM) + to sign certificates and CSRs without requiring the crypto callback + infrastructure. This is particularly useful for FIPS compliance where + offloading wolfCrypt operations is not acceptable. + + \param in Data to sign. For RSA, this is the PKCS#1 v1.5 padded digest. + For ECC, this is the raw hash to sign. + \param inLen Length of data to sign in bytes. + \param out Output buffer for the signature. + \param outLen Input: size of output buffer. Output: actual signature size. + \param sigAlgo Signature algorithm identifier (e.g., CTC_SHA256wRSA, + CTC_SHA256wECDSA). + \param keyType Key type (RSA_TYPE, ECC_TYPE, etc.). + \param ctx User-provided context pointer for callback state. + + \return 0 on success. + \return Negative error code on failure (BAD_FUNC_ARG, MEMORY_E, etc.). + + \sa wc_SignCert_cb + \sa wc_SignCert_ex + + _Example_ + \code + int mySignCallback(const byte* in, word32 inLen, byte* out, + word32* outLen, int sigAlgo, int keyType, void* ctx) + { + MySignCtx* myCtx = (MySignCtx*)ctx; + // Perform signing using external device/HSM + return myDevice_Sign(myCtx->device, in, inLen, out, outLen); + } + \endcode +*/ +typedef int (*wc_SignCertCb)(const byte* in, word32 inLen, + byte* out, word32* outLen, + int sigAlgo, int keyType, void* ctx); + typedef struct EncryptedInfo { long consumed; /* tracks PEM bytes consumed */ @@ -511,6 +551,69 @@ WOLFSSL_API int wc_SignCert_ex(int requestSz, int sType, byte* buf, WC_RNG* rng); WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng); +/*! + \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. + + \sa wc_SignCertCb + \sa wc_SignCert + \sa wc_SignCert_ex + \sa wc_MakeCert + \sa wc_MakeCertReq + + _Example_ + \code + Cert cert; + byte derBuf[4096]; + int derSz; + MySignCtx myCtx; + + // Initialize cert and set subject, etc. + wc_InitCert(&cert); + // ... set cert fields ... + + // Make certificate body + derSz = wc_MakeCert(&cert, derBuf, sizeof(derBuf), NULL, NULL, &rng); + + // Sign using callback + 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 +*/ +WOLFSSL_API int wc_SignCert_cb(int requestSz, int sType, byte* buf, + word32 buffSz, int keyType, + wc_SignCertCb signCb, void* signCtx, + WC_RNG* rng); #ifdef WOLFSSL_DUAL_ALG_CERTS WOLFSSL_API int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, word32 bufSz, int keyType, void* key, From 2e3fa9b22b020ad7ff50e5a61d6f8ad0984baa04 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:57:42 -0700 Subject: [PATCH 2/9] removed idx, added to test matrix --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index e1fa2678142..541e4b4fc90 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26937,7 +26937,6 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, #ifndef NO_RSA if (keyType == RSA_TYPE) { RsaKey* rsaKey = (RsaKey*)key; - word32 idx = 0; word32 outSz = *outLen; /* For RSA, input is pre-encoded digest, just sign it */ @@ -41641,6 +41640,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_MakeCertWithPathLen), TEST_DECL(test_MakeCertWith0Ser), TEST_DECL(test_MakeCertWithCaFalse), + TEST_DECL(test_wc_SignCert_cb), TEST_DECL(test_wc_SetKeyUsage), TEST_DECL(test_wc_SetAuthKeyIdFromPublicKey_ex), TEST_DECL(test_wc_SetSubjectBuffer), From 7dbbf7441378bad46132b8aef905184f282747f0 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Fri, 9 Jan 2026 10:21:39 -0700 Subject: [PATCH 3/9] Fix test_wc_SignCert_cb: pass RNG for ECC signing --- tests/api.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/api.c b/tests/api.c index 541e4b4fc90..e171e7955d5 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26922,13 +26922,20 @@ static int test_MakeCertWithCaFalse(void) /* Mock callback for testing wc_SignCert_cb */ #if 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; - void* key = ctx; + MockSignCtx* signCtx = (MockSignCtx*)ctx; - if (key == NULL || in == NULL || out == NULL || outLen == NULL) { + if (signCtx == NULL || signCtx->key == NULL || in == NULL || + out == NULL || outLen == NULL) { return BAD_FUNC_ARG; } @@ -26936,7 +26943,7 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, #ifndef NO_RSA if (keyType == RSA_TYPE) { - RsaKey* rsaKey = (RsaKey*)key; + RsaKey* rsaKey = (RsaKey*)signCtx->key; word32 outSz = *outLen; /* For RSA, input is pre-encoded digest, just sign it */ @@ -26950,11 +26957,11 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, #endif #ifdef HAVE_ECC if (keyType == ECC_TYPE) { - ecc_key* eccKey = (ecc_key*)key; + ecc_key* eccKey = (ecc_key*)signCtx->key; word32 outSz = *outLen; - /* For ECC, input is raw hash, sign it */ - ret = wc_ecc_sign_hash(in, inLen, out, &outSz, NULL, eccKey); + /* 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; } @@ -26978,11 +26985,13 @@ static int test_wc_SignCert_cb(void) 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); @@ -27005,16 +27014,20 @@ static int test_wc_SignCert_cb(void) /* 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, &key, &rng), 0); + 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, &key, &rng), BAD_FUNC_ARG); + FOURK_BUF, ECC_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG); ret = wc_ecc_free(&key); ExpectIntEQ(ret, 0); From 8616922598d7da53ffb992381b207f5d86e508bd Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Fri, 9 Jan 2026 11:08:34 -0700 Subject: [PATCH 4/9] FIX: (word32) cast --- wolfcrypt/src/asn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 70d51c7ff0e..9bf7fce0652 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33833,7 +33833,7 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, goto exit_ms; } #endif - ret = HashForSignature(buf, sz, sigAlgoType, certSignCtx->digest, + ret = HashForSignature(buf, sz, (word32)sigAlgoType, certSignCtx->digest, &typeH, &digestSz, 0, NULL, INVALID_DEVID); certSignCtx->state = CERTSIGN_STATE_ENCODE; if (ret != 0) { From 2d36f0d4536d9f84bfe93047101ebb2d1ff1bf91 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 14:43:38 -0700 Subject: [PATCH 5/9] Add --enable-certsigncb build option and eliminate cert signing duplication --- configure.ac | 13 ++ wolfcrypt/src/asn.c | 335 +++++++++++++++++++-------------- wolfssl/wolfcrypt/asn_public.h | 4 + 3 files changed, 210 insertions(+), 142 deletions(-) diff --git a/configure.ac b/configure.ac index d6c44305d65..45b2b985224 100644 --- a/configure.ac +++ b/configure.ac @@ -4534,6 +4534,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)])], diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 9bf7fce0652..ecee79766e2 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -31920,23 +31920,128 @@ static int WriteCertBody(DerCert* der, byte* buf) #endif /* !WOLFSSL_ASN_TEMPLATE */ -/* Make signature from buffer (sz), write to sig (sigSz) */ +#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) +/* Internal typedef for callback signature if not already defined in header */ +#ifndef WOLFSSL_CERT_SIGN_CB +typedef int (*wc_SignCertCb)(const byte* in, word32 inLen, + byte* out, word32* outLen, + int sigAlgo, int keyType, void* ctx); +#endif + +/* Forward declaration for internal use */ +static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, + word32 sz, byte* sig, word32 sigSz, int sigAlgoType, int keyType, + wc_SignCertCb signCb, void* signCtx, WC_RNG* rng, void* heap); + +/* Internal context for default signing operations (when no callback provided) */ +typedef struct { + RsaKey* rsaKey; + ecc_key* eccKey; + ed25519_key* ed25519Key; + ed448_key* ed448Key; + falcon_key* falconKey; + dilithium_key* dilithiumKey; + sphincs_key* sphincsKey; + WC_RNG* rng; +} InternalSignCtx; + +/* Internal signing callback that uses wolfCrypt APIs + * This is used by MakeSignature to delegate to MakeSignatureCb internally */ +static int InternalSignCb(const byte* in, word32 inLen, + byte* out, word32* outLen, int sigAlgo, int keyType, void* ctx) +{ + InternalSignCtx* signCtx = (InternalSignCtx*)ctx; + int ret = ALGO_ID_E; + + (void)sigAlgo; /* Algorithm determined by key type */ + +#if !defined(NO_RSA) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && !defined(WOLFSSL_RSA_VERIFY_ONLY) + if (keyType == RSA_TYPE && signCtx->rsaKey) { + /* For RSA, input is already encoded digest */ + ret = wc_RsaSSL_Sign(in, inLen, out, *outLen, + signCtx->rsaKey, signCtx->rng); + if (ret > 0) { + *outLen = (word32)ret; + ret = 0; + } + } +#endif /* !NO_RSA && !WOLFSSL_RSA_PUBLIC_ONLY && !WOLFSSL_RSA_VERIFY_ONLY */ + +#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN) + if (keyType == ECC_TYPE && signCtx->eccKey) { + /* For ECC, input is the raw hash */ + ret = wc_ecc_sign_hash(in, inLen, out, outLen, + signCtx->rng, signCtx->eccKey); + } +#endif /* HAVE_ECC && HAVE_ECC_SIGN */ + +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN) + if (keyType == ED25519_TYPE && signCtx->ed25519Key) { + /* Ed25519 needs the original message, not hash */ + /* Note: For Ed25519, 'in' should be the original message buffer */ + /* This is a limitation of the refactoring - Ed25519 signs messages, not hashes */ + ret = NOT_COMPILED_IN; /* Cannot support Ed25519 through callback path */ + } +#endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */ + +#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) + if (keyType == ED448_TYPE && signCtx->ed448Key) { + /* Ed448 needs the original message, not hash */ + ret = NOT_COMPILED_IN; /* Cannot support Ed448 through callback path */ + } +#endif /* HAVE_ED448 && HAVE_ED448_SIGN */ + +#if defined(HAVE_FALCON) + if (keyType == FALCON_LEVEL1_TYPE || keyType == FALCON_LEVEL5_TYPE) { + if (signCtx->falconKey) { + /* Falcon needs the original message */ + ret = NOT_COMPILED_IN; /* Cannot support Falcon through callback path */ + } + } +#endif /* HAVE_FALCON */ + +#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) + if (keyType == DILITHIUM_LEVEL2_TYPE || keyType == DILITHIUM_LEVEL3_TYPE || + keyType == DILITHIUM_LEVEL5_TYPE) { + if (signCtx->dilithiumKey) { + /* Dilithium needs the original message */ + ret = NOT_COMPILED_IN; /* Cannot support Dilithium through callback path */ + } + } +#endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ + +#if defined(HAVE_SPHINCS) + if (keyType == SPHINCS_FAST_LEVEL1_TYPE || keyType == SPHINCS_FAST_LEVEL3_TYPE || + keyType == SPHINCS_FAST_LEVEL5_TYPE || keyType == SPHINCS_SMALL_LEVEL1_TYPE || + keyType == SPHINCS_SMALL_LEVEL3_TYPE || keyType == SPHINCS_SMALL_LEVEL5_TYPE) { + if (signCtx->sphincsKey) { + /* Sphincs needs the original message */ + ret = NOT_COMPILED_IN; /* Cannot support Sphincs through callback path */ + } + } +#endif /* HAVE_SPHINCS */ + + return ret; +} +#endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ */ + + +/* Make signature from buffer (sz), write to sig (sigSz) + * This function now uses MakeSignatureCb internally for RSA and ECC, + * eliminating code duplication. Ed25519, Ed448, and post-quantum algorithms + * still use direct signing since they sign messages, not hashes. */ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, byte* sig, word32 sigSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, sphincs_key* sphincsKey, WC_RNG* rng, word32 sigAlgoType, void* heap) { - int digestSz = 0, typeH = 0, ret = 0; - - (void)digestSz; - (void)typeH; + int ret = 0; + (void)buf; (void)sz; (void)sig; (void)sigSz; - (void)rsaKey; - (void)eccKey; (void)ed25519Key; (void)ed448Key; (void)falconKey; @@ -31945,161 +32050,105 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, (void)rng; (void)heap; - switch (certSignCtx->state) { - case CERTSIGN_STATE_BEGIN: - case CERTSIGN_STATE_DIGEST: - - certSignCtx->state = CERTSIGN_STATE_DIGEST; - #ifndef WOLFSSL_NO_MALLOC - certSignCtx->digest = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (certSignCtx->digest == NULL) { - ret = MEMORY_E; goto exit_ms; - } - #endif - - ret = HashForSignature(buf, sz, sigAlgoType, certSignCtx->digest, - &typeH, &digestSz, 0, NULL, - INVALID_DEVID); - /* set next state, since WC_PENDING_E rentry for these are not "call again" */ - certSignCtx->state = CERTSIGN_STATE_ENCODE; - if (ret != 0) { - goto exit_ms; - } - FALL_THROUGH; - - case CERTSIGN_STATE_ENCODE: - #ifndef NO_RSA + /* For RSA and ECC, use the callback path to eliminate duplication */ +#if (!defined(NO_RSA) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) || \ + (defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)) + if (rsaKey || eccKey) { + InternalSignCtx signCtx; + int keyType; + + /* Setup internal signing context */ + XMEMSET(&signCtx, 0, sizeof(signCtx)); + signCtx.rsaKey = rsaKey; + signCtx.eccKey = eccKey; + signCtx.rng = rng; + + /* Determine key type */ if (rsaKey) { - #ifndef WOLFSSL_NO_MALLOC - certSignCtx->encSig = (byte*)XMALLOC(MAX_DER_DIGEST_SZ, heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (certSignCtx->encSig == NULL) { - ret = MEMORY_E; goto exit_ms; - } - #endif - - /* signature */ - certSignCtx->encSigSz = (int)wc_EncodeSignature(certSignCtx->encSig, - certSignCtx->digest, (word32)digestSz, typeH); + keyType = RSA_TYPE; } - #endif /* !NO_RSA */ - FALL_THROUGH; - - case CERTSIGN_STATE_DO: - certSignCtx->state = CERTSIGN_STATE_DO; - ret = -1; /* default to error, reassigned to ALGO_ID_E below. */ - - #if !defined(NO_RSA) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && !defined(WOLFSSL_RSA_VERIFY_ONLY) - if (rsaKey) { - /* signature */ - ret = wc_RsaSSL_Sign(certSignCtx->encSig, - (word32)certSignCtx->encSigSz, - sig, sigSz, rsaKey, rng); + else if (eccKey) { + keyType = ECC_TYPE; } - #endif /* !NO_RSA */ - - #if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN) - if (!rsaKey && eccKey) { - word32 outSz = sigSz; - - ret = wc_ecc_sign_hash(certSignCtx->digest, (word32)digestSz, - sig, &outSz, rng, eccKey); - if (ret == 0) - ret = (int)outSz; + else { + ret = BAD_FUNC_ARG; + goto exit_ms; } - #endif /* HAVE_ECC && HAVE_ECC_SIGN */ + + /* Use unified callback path */ + ret = MakeSignatureCb(certSignCtx, buf, sz, sig, sigSz, + (int)sigAlgoType, keyType, + InternalSignCb, &signCtx, rng, heap); + goto exit_ms; + } +#endif - #if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN) - if (!rsaKey && !eccKey && ed25519Key) { - word32 outSz = sigSz; + /* Ed25519, Ed448, and post-quantum algorithms sign messages (not hashes), + * so they cannot use the callback path. Keep original implementation. */ + ret = -1; /* default to error, reassigned to ALGO_ID_E below. */ - ret = wc_ed25519_sign_msg(buf, sz, sig, &outSz, ed25519Key); - if (ret == 0) - ret = (int)outSz; - } - #endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */ +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN) + if (ed25519Key) { + word32 outSz = sigSz; + ret = wc_ed25519_sign_msg(buf, sz, sig, &outSz, ed25519Key); + if (ret == 0) + ret = (int)outSz; + } +#endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */ - #if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) - if (!rsaKey && !eccKey && !ed25519Key && ed448Key) { - word32 outSz = sigSz; +#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) + if (ed448Key) { + word32 outSz = sigSz; + ret = wc_ed448_sign_msg(buf, sz, sig, &outSz, ed448Key, NULL, 0); + if (ret == 0) + ret = (int)outSz; + } +#endif /* HAVE_ED448 && HAVE_ED448_SIGN */ - ret = wc_ed448_sign_msg(buf, sz, sig, &outSz, ed448Key, NULL, 0); - if (ret == 0) - ret = (int)outSz; - } - #endif /* HAVE_ED448 && HAVE_ED448_SIGN */ +#if defined(HAVE_FALCON) + if (falconKey) { + word32 outSz = sigSz; + ret = wc_falcon_sign_msg(buf, sz, sig, &outSz, falconKey, rng); + if (ret == 0) + ret = outSz; + } +#endif /* HAVE_FALCON */ - #if defined(HAVE_FALCON) - if (!rsaKey && !eccKey && !ed25519Key && !ed448Key && falconKey) { - word32 outSz = sigSz; - ret = wc_falcon_sign_msg(buf, sz, sig, &outSz, falconKey, rng); +#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) + if (dilithiumKey) { + word32 outSz = sigSz; + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + if ((dilithiumKey->params->level == WC_ML_DSA_44_DRAFT) || + (dilithiumKey->params->level == WC_ML_DSA_65_DRAFT) || + (dilithiumKey->params->level == WC_ML_DSA_87_DRAFT)) { + ret = wc_dilithium_sign_msg(buf, sz, sig, &outSz, dilithiumKey, rng); if (ret == 0) ret = outSz; } - #endif /* HAVE_FALCON */ - #if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) - if (!rsaKey && !eccKey && !ed25519Key && !ed448Key && !falconKey && - dilithiumKey) { - word32 outSz = sigSz; - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - if ((dilithiumKey->params->level == WC_ML_DSA_44_DRAFT) || - (dilithiumKey->params->level == WC_ML_DSA_65_DRAFT) || - (dilithiumKey->params->level == WC_ML_DSA_87_DRAFT)) { - ret = wc_dilithium_sign_msg(buf, sz, sig, &outSz, dilithiumKey, - rng); - if (ret == 0) - ret = outSz; - } - else - #endif - { - ret = wc_dilithium_sign_ctx_msg(NULL, 0, buf, sz, sig, - &outSz, dilithiumKey, rng); - if (ret == 0) - ret = outSz; - } - } - #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ - #if defined(HAVE_SPHINCS) - if (!rsaKey && !eccKey && !ed25519Key && !ed448Key && !falconKey && - !dilithiumKey && sphincsKey) { - word32 outSz = sigSz; - ret = wc_sphincs_sign_msg(buf, sz, sig, &outSz, sphincsKey, rng); + else + #endif + { + ret = wc_dilithium_sign_ctx_msg(NULL, 0, buf, sz, sig, + &outSz, dilithiumKey, rng); if (ret == 0) ret = outSz; } - #endif /* HAVE_SPHINCS */ - - if (ret == -1) - ret = ALGO_ID_E; - - break; } +#endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ -exit_ms: - -#ifdef WOLFSSL_ASYNC_CRYPT - if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { - return ret; - } -#endif - -#ifndef WOLFSSL_NO_MALLOC -#ifndef NO_RSA - if (rsaKey) { - XFREE(certSignCtx->encSig, heap, DYNAMIC_TYPE_TMP_BUFFER); - certSignCtx->encSig = NULL; +#if defined(HAVE_SPHINCS) + if (sphincsKey) { + word32 outSz = sigSz; + ret = wc_sphincs_sign_msg(buf, sz, sig, &outSz, sphincsKey, rng); + if (ret == 0) + ret = outSz; } -#endif /* !NO_RSA */ - - XFREE(certSignCtx->digest, heap, DYNAMIC_TYPE_TMP_BUFFER); - certSignCtx->digest = NULL; -#endif /* !WOLFSSL_NO_MALLOC */ +#endif /* HAVE_SPHINCS */ - /* reset state */ - certSignCtx->state = CERTSIGN_STATE_BEGIN; + if (ret == -1) + ret = ALGO_ID_E; +exit_ms: if (ret < 0) { WOLFSSL_ERROR_VERBOSE(ret); } @@ -34216,6 +34265,7 @@ int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, * @return Size of signature on success. * @return < 0 on error */ +#ifdef WOLFSSL_CERT_SIGN_CB int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, int keyType, wc_SignCertCb signCb, void* signCtx, WC_RNG* rng) @@ -34262,6 +34312,7 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, return sigSz; } +#endif /* WOLFSSL_CERT_SIGN_CB */ diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index e43f9576c27..6e1a36bed26 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -233,6 +233,7 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); #define pem_password_cb wc_pem_password_cb #endif +#ifdef WOLFSSL_CERT_SIGN_CB /*! \ingroup CertManager \brief Callback function type for certificate/CSR signing. @@ -272,6 +273,7 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); typedef int (*wc_SignCertCb)(const byte* in, word32 inLen, byte* out, word32* outLen, int sigAlgo, int keyType, void* ctx); +#endif /* WOLFSSL_CERT_SIGN_CB */ typedef struct EncryptedInfo { long consumed; /* tracks PEM bytes consumed */ @@ -610,10 +612,12 @@ WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, } \endcode */ +#ifdef WOLFSSL_CERT_SIGN_CB WOLFSSL_API int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, int keyType, wc_SignCertCb signCb, void* signCtx, WC_RNG* rng); +#endif /* WOLFSSL_CERT_SIGN_CB */ #ifdef WOLFSSL_DUAL_ALG_CERTS WOLFSSL_API int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, word32 bufSz, int keyType, void* key, From c6dd3f1fab75a38d62e7dd6bcbd03cfd73b21875 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 15:16:24 -0700 Subject: [PATCH 6/9] Guard wc_SignCert_cb test with WOLFSSL_CERT_SIGN_CB to fix CI failures --- tests/api.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index e171e7955d5..2dfc468d658 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26921,7 +26921,7 @@ static int test_MakeCertWithCaFalse(void) } /* Mock callback for testing wc_SignCert_cb */ -#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) +#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 */ @@ -26976,6 +26976,7 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, } #endif +#ifdef WOLFSSL_CERT_SIGN_CB static int test_wc_SignCert_cb(void) { EXPECT_DECLS; @@ -27036,6 +27037,7 @@ static int test_wc_SignCert_cb(void) #endif return EXPECT_RESULT(); } +#endif /* WOLFSSL_CERT_SIGN_CB */ static int test_wolfSSL_EVP_PKEY_encrypt(void) @@ -41653,7 +41655,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), From d84e1d17dbab9c0d388c21d98cbbd2c39288d248 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 16:16:35 -0700 Subject: [PATCH 7/9] Fix for when RSA is enabled --- wolfcrypt/src/asn.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index ecee79766e2..6f50dbad0b5 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33892,6 +33892,7 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, case CERTSIGN_STATE_ENCODE: /* For RSA, encode the digest with algorithm identifier */ +#ifndef NO_RSA if (keyType == RSA_TYPE) { #ifndef WOLFSSL_NO_MALLOC certSignCtx->encSig = (byte*)XMALLOC(MAX_DER_DIGEST_SZ, heap, @@ -33904,6 +33905,7 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, certSignCtx->encSigSz = (int)wc_EncodeSignature(certSignCtx->encSig, certSignCtx->digest, (word32)digestSz, typeH); } +#endif /* !NO_RSA */ FALL_THROUGH; case CERTSIGN_STATE_DO: @@ -33911,12 +33913,15 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, outLen = sigSz; /* Call the user-provided signing callback */ +#ifndef NO_RSA if (keyType == RSA_TYPE) { /* RSA: pass encoded digest */ ret = signCb(certSignCtx->encSig, (word32)certSignCtx->encSigSz, sig, &outLen, sigAlgoType, keyType, signCtx); } - else { + else +#endif /* !NO_RSA */ + { /* ECC/EdDSA: pass raw hash or message */ ret = signCb(certSignCtx->digest, (word32)digestSz, sig, &outLen, sigAlgoType, keyType, signCtx); @@ -33930,10 +33935,12 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, exit_ms: #ifndef WOLFSSL_NO_MALLOC +#ifndef NO_RSA if (keyType == RSA_TYPE) { XFREE(certSignCtx->encSig, heap, DYNAMIC_TYPE_TMP_BUFFER); certSignCtx->encSig = NULL; } +#endif /* !NO_RSA */ XFREE(certSignCtx->digest, heap, DYNAMIC_TYPE_TMP_BUFFER); certSignCtx->digest = NULL; #endif From 81df4a3026247f1f9fcd2965574f648e9311daac Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 15 Jan 2026 12:27:20 -0700 Subject: [PATCH 8/9] Fix cert sign callback issues: heap usage, documentation, and test RNG --- tests/api.c | 4 ++-- wolfcrypt/src/asn.c | 4 +++- wolfssl/wolfcrypt/asn_public.h | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/api.c b/tests/api.c index 2dfc468d658..fd54aeadb76 100644 --- a/tests/api.c +++ b/tests/api.c @@ -26946,8 +26946,8 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, RsaKey* rsaKey = (RsaKey*)signCtx->key; word32 outSz = *outLen; - /* For RSA, input is pre-encoded digest, just sign it */ - ret = wc_RsaSSL_Sign(in, inLen, out, outSz, rsaKey, NULL); + /* 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; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 6f50dbad0b5..6341f5e8427 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33868,7 +33868,9 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, word32 outLen; (void)rng; +#ifdef WOLFSSL_NO_MALLOC (void)heap; +#endif switch (certSignCtx->state) { case CERTSIGN_STATE_BEGIN: @@ -33922,7 +33924,7 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf, else #endif /* !NO_RSA */ { - /* ECC/EdDSA: pass raw hash or message */ + /* ECC: pass raw hash */ ret = signCb(certSignCtx->digest, (word32)digestSz, sig, &outLen, sigAlgoType, keyType, signCtx); } diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 6e1a36bed26..bf58c787140 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -243,8 +243,9 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); infrastructure. This is particularly useful for FIPS compliance where offloading wolfCrypt operations is not acceptable. - \param in Data to sign. For RSA, this is the PKCS#1 v1.5 padded digest. - For ECC, this is the raw hash to sign. + \param in Data to sign. For RSA, this is the DER-encoded digest + (DigestInfo structure with algorithm identifier). For ECC, + this is the raw hash to sign. \param inLen Length of data to sign in bytes. \param out Output buffer for the signature. \param outLen Input: size of output buffer. Output: actual signature size. From 90ce2375302d23b9bb5acbe29cc604ea239ac936 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 15 Jan 2026 16:47:57 -0700 Subject: [PATCH 9/9] Address Copilot feedback: clarify typedef and fix error codes for unsupported algos --- wolfcrypt/src/asn.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 6341f5e8427..d7edf1042fc 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -31921,7 +31921,9 @@ static int WriteCertBody(DerCert* der, byte* buf) #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) -/* Internal typedef for callback signature if not already defined in header */ +/* Internal typedef for callback signature - must match wc_SignCertCb in asn_public.h + * This fallback is needed when WOLFSSL_CERT_SIGN_CB is not defined but + * MakeSignatureCb is still used internally by the refactored MakeSignature. */ #ifndef WOLFSSL_CERT_SIGN_CB typedef int (*wc_SignCertCb)(const byte* in, word32 inLen, byte* out, word32* outLen, @@ -31977,25 +31979,23 @@ static int InternalSignCb(const byte* in, word32 inLen, #if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN) if (keyType == ED25519_TYPE && signCtx->ed25519Key) { - /* Ed25519 needs the original message, not hash */ - /* Note: For Ed25519, 'in' should be the original message buffer */ - /* This is a limitation of the refactoring - Ed25519 signs messages, not hashes */ - ret = NOT_COMPILED_IN; /* Cannot support Ed25519 through callback path */ + /* Ed25519 signs messages, not hashes - cannot use callback path */ + ret = SIG_TYPE_E; } #endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */ #if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) if (keyType == ED448_TYPE && signCtx->ed448Key) { - /* Ed448 needs the original message, not hash */ - ret = NOT_COMPILED_IN; /* Cannot support Ed448 through callback path */ + /* Ed448 signs messages, not hashes - cannot use callback path */ + ret = SIG_TYPE_E; } #endif /* HAVE_ED448 && HAVE_ED448_SIGN */ #if defined(HAVE_FALCON) if (keyType == FALCON_LEVEL1_TYPE || keyType == FALCON_LEVEL5_TYPE) { if (signCtx->falconKey) { - /* Falcon needs the original message */ - ret = NOT_COMPILED_IN; /* Cannot support Falcon through callback path */ + /* Falcon signs messages, not hashes - cannot use callback path */ + ret = SIG_TYPE_E; } } #endif /* HAVE_FALCON */ @@ -32004,8 +32004,8 @@ static int InternalSignCb(const byte* in, word32 inLen, if (keyType == DILITHIUM_LEVEL2_TYPE || keyType == DILITHIUM_LEVEL3_TYPE || keyType == DILITHIUM_LEVEL5_TYPE) { if (signCtx->dilithiumKey) { - /* Dilithium needs the original message */ - ret = NOT_COMPILED_IN; /* Cannot support Dilithium through callback path */ + /* Dilithium signs messages, not hashes - cannot use callback path */ + ret = SIG_TYPE_E; } } #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ @@ -32015,8 +32015,8 @@ static int InternalSignCb(const byte* in, word32 inLen, keyType == SPHINCS_FAST_LEVEL5_TYPE || keyType == SPHINCS_SMALL_LEVEL1_TYPE || keyType == SPHINCS_SMALL_LEVEL3_TYPE || keyType == SPHINCS_SMALL_LEVEL5_TYPE) { if (signCtx->sphincsKey) { - /* Sphincs needs the original message */ - ret = NOT_COMPILED_IN; /* Cannot support Sphincs through callback path */ + /* Sphincs signs messages, not hashes - cannot use callback path */ + ret = SIG_TYPE_E; } } #endif /* HAVE_SPHINCS */