Address copilot feedback

This commit is contained in:
jackctj117
2026-02-05 11:57:33 -07:00
parent cb2b7adfcc
commit d774825ab8
5 changed files with 180 additions and 19 deletions
+13 -2
View File
@@ -253,18 +253,29 @@ int wc_DhPublicKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
3. Calls the user-provided callback to perform the actual signing
4. Encodes the signature into the certificate/CSR DER structure
NOTE: Only RSA and ECC key types are supported. Ed25519, Ed448, and
post-quantum algorithms (Falcon, Dilithium, SPHINCS+) sign messages
directly rather than hashes, so they cannot use this callback-based API.
Use wc_SignCert_ex for those algorithms.
NOTE: This function does NOT support async crypto (WOLFSSL_ASYNC_CRYPT).
The internal context is local to this function and cannot persist across
async re-entry.
\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 keyType Type of key used for signing. Only RSA_TYPE and ECC_TYPE
are supported.
\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 BAD_FUNC_ARG if signCb or buf is NULL, buffSz is 0, or keyType
is not RSA_TYPE or ECC_TYPE.
\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.
+72 -1
View File
@@ -20041,6 +20041,20 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen,
return ret;
}
/* Mock callback that always returns an error for testing */
static int mockSignCbError(const byte* in, word32 inLen, byte* out,
word32* outLen, int sigAlgo, int keyType, void* ctx)
{
(void)in;
(void)inLen;
(void)out;
(void)outLen;
(void)sigAlgo;
(void)keyType;
(void)ctx;
return BAD_STATE_E; /* Return an error */
}
#endif
#ifdef WOLFSSL_CERT_SIGN_CB
@@ -20058,12 +20072,14 @@ static int test_wc_SignCert_cb(void)
WC_RNG rng;
ecc_key key;
MockSignCtx signCtx;
DecodedCert decodedCert;
int ret;
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&key, 0, sizeof(ecc_key));
XMEMSET(&cert, 0, sizeof(Cert));
XMEMSET(&signCtx, 0, sizeof(MockSignCtx));
XMEMSET(&decodedCert, 0, sizeof(DecodedCert));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ecc_init(&key), 0);
@@ -20097,9 +20113,37 @@ static int test_wc_SignCert_cb(void)
/* Verify the certificate was created properly */
ExpectIntGT(derSize, 0);
/* Parse the certificate and verify it's well-formed */
if (EXPECT_SUCCESS()) {
wc_InitDecodedCert(&decodedCert, der, (word32)derSize, NULL);
ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL),
0);
/* Verify signature algorithm matches what we set */
ExpectIntEQ(decodedCert.signatureOID, CTC_SHA256wECDSA);
wc_FreeDecodedCert(&decodedCert);
}
/* Test error cases */
/* NULL callback */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ECC_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);
/* NULL buffer */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, NULL,
FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* Zero buffer size */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
0, ECC_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* Negative requestSz - should return the negative value */
ExpectIntLT(wc_SignCert_cb(-1, cert.sigType, der,
FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), 0);
/* Callback returning error */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ECC_TYPE, mockSignCbError, &signCtx, &rng), BAD_STATE_E);
#ifndef NO_RSA
/* Invalid keyType for ECC signature */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED25519_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
#endif
ret = wc_ecc_free(&key);
ExpectIntEQ(ret, 0);
@@ -20117,12 +20161,14 @@ static int test_wc_SignCert_cb(void)
WC_RNG rng;
RsaKey key;
MockSignCtx signCtx;
DecodedCert decodedCert;
int ret;
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&key, 0, sizeof(RsaKey));
XMEMSET(&cert, 0, sizeof(Cert));
XMEMSET(&signCtx, 0, sizeof(MockSignCtx));
XMEMSET(&decodedCert, 0, sizeof(DecodedCert));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_InitRsaKey(&key, NULL), 0);
@@ -20156,9 +20202,34 @@ static int test_wc_SignCert_cb(void)
/* Verify the certificate was created properly */
ExpectIntGT(derSize, 0);
/* Test error case - NULL callback */
/* Parse the certificate and verify it's well-formed */
if (EXPECT_SUCCESS()) {
wc_InitDecodedCert(&decodedCert, der, (word32)derSize, NULL);
ExpectIntEQ(wc_ParseCert(&decodedCert, CERT_TYPE, NO_VERIFY, NULL),
0);
/* Verify signature algorithm matches what we set */
ExpectIntEQ(decodedCert.signatureOID, CTC_SHA256wRSA);
wc_FreeDecodedCert(&decodedCert);
}
/* Test error cases */
/* NULL callback */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, RSA_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG);
/* NULL buffer */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, NULL,
FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* Zero buffer size */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
0, RSA_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* Callback returning error */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, RSA_TYPE, mockSignCbError, &signCtx, &rng), BAD_STATE_E);
#ifdef HAVE_ECC
/* Invalid keyType */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED448_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
#endif
ret = wc_FreeRsaKey(&key);
ExpectIntEQ(ret, 0);
+92 -15
View File
@@ -32112,46 +32112,46 @@ static int InternalSignCb(const byte* in, word32 inLen,
ret = 0;
}
}
else
#endif /* !NO_RSA && !WOLFSSL_RSA_PUBLIC_ONLY && !WOLFSSL_RSA_VERIFY_ONLY */
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
if (keyType == ECC_TYPE && signCtx->key) {
/* For ECC, input is the raw hash */
ret = wc_ecc_sign_hash(in, inLen, out, outLen,
signCtx->rng, (ecc_key*)signCtx->key);
}
else
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN)
if (keyType == ED25519_TYPE && signCtx->key) {
/* Ed25519 signs messages, not hashes - cannot use callback path */
ret = SIG_TYPE_E;
}
else
#endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */
#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN)
if (keyType == ED448_TYPE && signCtx->key) {
/* Ed448 signs messages, not hashes - cannot use callback path */
ret = SIG_TYPE_E;
}
else
#endif /* HAVE_ED448 && HAVE_ED448_SIGN */
#if defined(HAVE_FALCON)
if ((keyType == FALCON_LEVEL1_TYPE || keyType == FALCON_LEVEL5_TYPE) &&
signCtx->key) {
/* Falcon signs messages, not hashes - cannot use callback path */
ret = SIG_TYPE_E;
}
else
#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) && signCtx->key) {
/* Dilithium signs messages, not hashes - cannot use callback path */
ret = SIG_TYPE_E;
}
else
#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 ||
@@ -32160,7 +32160,17 @@ static int InternalSignCb(const byte* in, word32 inLen,
/* Sphincs signs messages, not hashes - cannot use callback path */
ret = SIG_TYPE_E;
}
else
#endif /* HAVE_SPHINCS */
{
/* Unhandled key type */
(void)in;
(void)inLen;
(void)out;
(void)outLen;
(void)keyType;
(void)signCtx;
}
return ret;
}
@@ -34004,7 +34014,7 @@ 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;
int ret = 0;
word32 outLen;
(void)rng;
@@ -34012,6 +34022,26 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf,
(void)heap;
#endif
/* Validate keyType - only RSA and ECC are supported for callback signing.
* Ed25519, Ed448, and post-quantum algorithms sign messages directly,
* not hashes, so they cannot use the callback path. */
#if !defined(NO_RSA) && defined(HAVE_ECC)
if (keyType != RSA_TYPE && keyType != ECC_TYPE) {
return BAD_FUNC_ARG;
}
#elif !defined(NO_RSA)
if (keyType != RSA_TYPE) {
return BAD_FUNC_ARG;
}
#elif defined(HAVE_ECC)
if (keyType != ECC_TYPE) {
return BAD_FUNC_ARG;
}
#else
(void)keyType;
return NOT_COMPILED_IN;
#endif
switch (certSignCtx->state) {
case CERTSIGN_STATE_BEGIN:
case CERTSIGN_STATE_DIGEST:
@@ -34025,7 +34055,8 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf,
}
#endif
ret = HashForSignature(buf, sz, (word32)sigAlgoType, certSignCtx->digest,
&typeH, &digestSz, 0, NULL, INVALID_DEVID);
&certSignCtx->typeH, &certSignCtx->digestSz, 0,
NULL, INVALID_DEVID);
certSignCtx->state = CERTSIGN_STATE_ENCODE;
if (ret != 0) {
goto exit_ms;
@@ -34044,8 +34075,10 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf,
goto exit_ms;
}
#endif
/* typeH was stored in certSignCtx by HashForSignature */
certSignCtx->encSigSz = (int)wc_EncodeSignature(certSignCtx->encSig,
certSignCtx->digest, (word32)digestSz, typeH);
certSignCtx->digest, (word32)certSignCtx->digestSz,
certSignCtx->typeH);
}
#endif /* !NO_RSA */
FALL_THROUGH;
@@ -34065,10 +34098,17 @@ static int MakeSignatureCb(CertSignCtx* certSignCtx, const byte* buf,
#endif /* !NO_RSA */
{
/* ECC: pass raw hash */
ret = signCb(certSignCtx->digest, (word32)digestSz,
ret = signCb(certSignCtx->digest, (word32)certSignCtx->digestSz,
sig, &outLen, sigAlgoType, keyType, signCtx);
}
#ifdef WOLFSSL_ASYNC_CRYPT
/* If callback returns WC_PENDING_E, preserve state for re-entry */
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
return ret;
}
#endif
if (ret == 0) {
ret = (int)outLen;
}
@@ -34089,6 +34129,8 @@ exit_ms:
/* reset state */
certSignCtx->state = CERTSIGN_STATE_BEGIN;
certSignCtx->digestSz = 0;
certSignCtx->typeH = 0;
if (ret < 0) {
WOLFSSL_ERROR_VERBOSE(ret);
@@ -34402,16 +34444,22 @@ int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz,
* This allows external signing implementations (e.g., TPM, HSM)
* without requiring the crypto callback infrastructure.
*
* NOTE: This function does NOT support async crypto (WOLFSSL_ASYNC_CRYPT).
* The certSignCtx is local to this function and cannot persist across
* async re-entry. Use wc_SignCert or wc_SignCert_ex for async operations.
*
* @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] keyType The type of key (RSA_TYPE or ECC_TYPE only).
* @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 BAD_FUNC_ARG if signCb or buf is NULL, buffSz is 0, or invalid
* keyType.
* @return < 0 on error
*/
#ifdef WOLFSSL_CERT_SIGN_CB
@@ -34423,10 +34471,29 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz,
CertSignCtx certSignCtx_lcl;
CertSignCtx* certSignCtx = &certSignCtx_lcl;
if (signCb == NULL || buf == NULL) {
/* Validate parameters */
if (signCb == NULL || buf == NULL || buffSz == 0) {
return BAD_FUNC_ARG;
}
/* Validate keyType - only RSA and ECC supported */
#if !defined(NO_RSA) && defined(HAVE_ECC)
if (keyType != RSA_TYPE && keyType != ECC_TYPE) {
return BAD_FUNC_ARG;
}
#elif !defined(NO_RSA)
if (keyType != RSA_TYPE) {
return BAD_FUNC_ARG;
}
#elif defined(HAVE_ECC)
if (keyType != ECC_TYPE) {
return BAD_FUNC_ARG;
}
#else
(void)keyType;
return NOT_COMPILED_IN;
#endif
XMEMSET(certSignCtx, 0, sizeof(*certSignCtx));
if (requestSz < 0) {
@@ -34447,13 +34514,23 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz,
#ifdef WOLFSSL_ASYNC_CRYPT
if (sigSz == WC_NO_ERR_TRACE(WC_PENDING_E)) {
/* Not free'ing certSignCtx->sig here because it could still be in use
* with async operations. */
return sigSz;
/* Async crypto not supported with wc_SignCert_cb because certSignCtx
* is local and cannot persist across re-entry. Clean up and return
* error. */
#ifndef WOLFSSL_NO_MALLOC
XFREE(certSignCtx->sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
certSignCtx->sig = NULL;
#endif
return NOT_COMPILED_IN;
}
#endif
if (sigSz >= 0) {
/* Check buffer has room for signature structure. This is an estimate
* using MAX_SEQ_SZ * 2 to account for sequence headers and algorithm
* identifier overhead. For precise sizing, call AddSignature with
* NULL buffer first, but this estimate matches the existing pattern
* used in SignCert. */
if (requestSz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) {
sigSz = BUFFER_E;
}
+1 -1
View File
@@ -250,7 +250,7 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata);
\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 keyType Key type (RSA_TYPE or ECC_TYPE only).
\param ctx User-provided context pointer for callback state.
\return 0 on success.
+2
View File
@@ -2397,6 +2397,8 @@ enum Max_ASN {
#ifndef NO_RSA
int encSigSz;
#endif
int digestSz;
int typeH; /* Hash algorithm type for encoding */
int state; /* enum CertSignState */
} CertSignCtx;