From cb2b7adfcc41580ed3f87434ba446b4d9cd5a9f5 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 4 Feb 2026 10:45:38 -0700 Subject: [PATCH] Address PR feedback: move doxygen to proper location and add RSA test coverage --- doc/dox_comments/header_files/asn.h | 59 ++++++++ tests/api.c | 156 +++++++++++++++------ tests/test_cert_sign_cb_no_malloc.c | 0 tests/test_cert_sign_cb_no_malloc_simple.c | 0 wolfssl/wolfcrypt/asn_public.h | 55 -------- 5 files changed, 170 insertions(+), 100 deletions(-) create mode 100644 tests/test_cert_sign_cb_no_malloc.c create mode 100644 tests/test_cert_sign_cb_no_malloc_simple.c diff --git a/doc/dox_comments/header_files/asn.h b/doc/dox_comments/header_files/asn.h index a26ac6e539..4ff2c9d6ad 100644 --- a/doc/dox_comments/header_files/asn.h +++ b/doc/dox_comments/header_files/asn.h @@ -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); diff --git a/tests/api.c b/tests/api.c index b754a809ad..d24a35a0a8 100644 --- a/tests/api.c +++ b/tests/api.c @@ -20047,61 +20047,127 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, 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; +#if defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME) - XMEMSET(&rng, 0, sizeof(WC_RNG)); - XMEMSET(&key, 0, sizeof(ecc_key)); - XMEMSET(&cert, 0, sizeof(Cert)); - XMEMSET(&signCtx, 0, sizeof(MockSignCtx)); +#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; - 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); + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&key, 0, sizeof(ecc_key)); + XMEMSET(&cert, 0, sizeof(Cert)); + XMEMSET(&signCtx, 0, sizeof(MockSignCtx)); - (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); + 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); - cert.selfSigned = 1; - cert.isCA = 0; - cert.sigType = CTC_SHA256wECDSA; + (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); - /* Make cert body */ - ExpectIntGT(wc_MakeCert(&cert, der, FOURK_BUF, NULL, &key, &rng), 0); + cert.selfSigned = 1; + cert.isCA = 0; + cert.sigType = CTC_SHA256wECDSA; - /* Setup signing context with key and RNG */ - signCtx.key = &key; - signCtx.rng = &rng; + /* 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, &signCtx, &rng), 0); + /* Setup signing context with key and RNG */ + signCtx.key = &key; + signCtx.rng = &rng; - /* Verify the certificate was created properly */ - ExpectIntGT(derSize, 0); + /* Sign using callback API */ + ExpectIntGT(derSize = wc_SignCert_cb(cert.bodySz, cert.sigType, der, + FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), 0); - /* Test error cases */ - ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der, - FOURK_BUF, ECC_TYPE, NULL, &signCtx, &rng), BAD_FUNC_ARG); + /* Verify the certificate was created properly */ + ExpectIntGT(derSize, 0); - ret = wc_ecc_free(&key); - ExpectIntEQ(ret, 0); - ret = wc_FreeRng(&rng); - ExpectIntEQ(ret, 0); -#endif + /* 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 */ diff --git a/tests/test_cert_sign_cb_no_malloc.c b/tests/test_cert_sign_cb_no_malloc.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_cert_sign_cb_no_malloc_simple.c b/tests/test_cert_sign_cb_no_malloc_simple.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index b2e4991bc0..7425ba8a9b 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -551,61 +551,6 @@ 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; - - 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 -*/ #ifdef WOLFSSL_CERT_SIGN_CB WOLFSSL_API int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, int keyType,