From 40a19a963ec33d3c5cdd105a40abab4df09fa649 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:20:00 -0700 Subject: [PATCH 01/12] Add wc_SignCert_cb API for external signing callbacks --- tests/api.c | 611 +++++++++++++++++++++++++++++++++ wolfcrypt/src/asn.c | 162 +++++++++ wolfssl/wolfcrypt/asn_public.h | 103 ++++++ 3 files changed, 876 insertions(+) diff --git a/tests/api.c b/tests/api.c index f2e3401e0f4..826b1d074e1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19611,6 +19611,617 @@ 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; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) + WOLFSSL_RSA* rsa = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_EVP_PKEY_CTX* ctx = NULL; + const char* in = "What is easy to do is easy not to do."; + size_t inlen = XSTRLEN(in); + size_t outEncLen = 0; + byte* outEnc = NULL; + byte* outDec = NULL; + size_t outDecLen = 0; + size_t rsaKeySz = 2048/8; /* Bytes */ +#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) + byte* inTmp = NULL; + byte* outEncTmp = NULL; + byte* outDecTmp = NULL; +#endif + + ExpectNotNull(outEnc = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (outEnc != NULL) { + XMEMSET(outEnc, 0, rsaKeySz); + } + ExpectNotNull(outDec = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (outDec != NULL) { + XMEMSET(outDec, 0, rsaKeySz); + } + + ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); + ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); + ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); + if (EXPECT_FAIL()) { + RSA_free(rsa); + } + ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); + ExpectIntEQ(EVP_PKEY_encrypt_init(ctx), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), + WOLFSSL_SUCCESS); + + /* Test pkey references count is decremented. pkey shouldn't be destroyed + since ctx uses it.*/ + ExpectIntEQ(pkey->ref.count, 2); + EVP_PKEY_free(pkey); + ExpectIntEQ(pkey->ref.count, 1); + + /* Encrypt data */ + /* Check that we can get the required output buffer length by passing in a + * NULL output buffer. */ + ExpectIntEQ(EVP_PKEY_encrypt(ctx, NULL, &outEncLen, + (const unsigned char*)in, inlen), WOLFSSL_SUCCESS); + ExpectIntEQ(rsaKeySz, outEncLen); + /* Now do the actual encryption. */ + ExpectIntEQ(EVP_PKEY_encrypt(ctx, outEnc, &outEncLen, + (const unsigned char*)in, inlen), WOLFSSL_SUCCESS); + + /* Decrypt data */ + ExpectIntEQ(EVP_PKEY_decrypt_init(ctx), WOLFSSL_SUCCESS); + /* Check that we can get the required output buffer length by passing in a + * NULL output buffer. */ + ExpectIntEQ(EVP_PKEY_decrypt(ctx, NULL, &outDecLen, outEnc, outEncLen), + WOLFSSL_SUCCESS); + ExpectIntEQ(rsaKeySz, outDecLen); + /* Now do the actual decryption. */ + ExpectIntEQ(EVP_PKEY_decrypt(ctx, outDec, &outDecLen, outEnc, outEncLen), + WOLFSSL_SUCCESS); + + ExpectIntEQ(XMEMCMP(in, outDec, outDecLen), 0); + +#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) + /* The input length must be the same size as the RSA key.*/ + ExpectNotNull(inTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (inTmp != NULL) { + XMEMSET(inTmp, 9, rsaKeySz); + } + ExpectNotNull(outEncTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (outEncTmp != NULL) { + XMEMSET(outEncTmp, 0, rsaKeySz); + } + ExpectNotNull(outDecTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (outDecTmp != NULL) { + XMEMSET(outDecTmp, 0, rsaKeySz); + } + ExpectIntEQ(EVP_PKEY_encrypt_init(ctx), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_encrypt(ctx, outEncTmp, &outEncLen, inTmp, rsaKeySz), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_decrypt_init(ctx), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_decrypt(ctx, outDecTmp, &outDecLen, outEncTmp, + outEncLen), WOLFSSL_SUCCESS); + ExpectIntEQ(XMEMCMP(inTmp, outDecTmp, outDecLen), 0); +#endif + EVP_PKEY_CTX_free(ctx); + XFREE(outEnc, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outDec, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) + XFREE(inTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outEncTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(outDecTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif +#endif + return EXPECT_RESULT(); +} + +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #endif +#endif +#endif +#if defined(OPENSSL_EXTRA) +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #endif +#endif +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY + #endif +#endif +#endif + +#ifdef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY +static int test_wolfSSL_EVP_PKEY_sign_verify(int keyType) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + WOLFSSL_RSA* rsa = NULL; +#endif +#endif +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + WOLFSSL_DSA* dsa = NULL; +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + WOLFSSL_EC_KEY* ecKey = NULL; +#endif +#endif + WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_EVP_PKEY_CTX* ctx = NULL; + WOLFSSL_EVP_PKEY_CTX* ctx_verify = NULL; + const char* in = "What is easy to do is easy not to do."; + size_t inlen = XSTRLEN(in); + byte hash[SHA256_DIGEST_LENGTH] = {0}; + byte zero[SHA256_DIGEST_LENGTH] = {0}; + SHA256_CTX c; + byte* sig = NULL; + byte* sigVerify = NULL; + size_t siglen; + size_t siglenOnlyLen; + size_t keySz = 2048/8; /* Bytes */ + + ExpectNotNull(sig = + (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(sigVerify = + (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); + + siglen = keySz; + ExpectNotNull(XMEMSET(sig, 0, keySz)); + ExpectNotNull(XMEMSET(sigVerify, 0, keySz)); + + /* Generate hash */ + SHA256_Init(&c); + SHA256_Update(&c, in, inlen); + SHA256_Final(hash, &c); +#ifdef WOLFSSL_SMALL_STACK_CACHE + /* workaround for small stack cache case */ + wc_Sha256Free((wc_Sha256*)&c); +#endif + + /* Generate key */ + ExpectNotNull(pkey = EVP_PKEY_new()); + switch (keyType) { + case EVP_PKEY_RSA: +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + { + ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); + ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); + } +#endif +#endif + break; + case EVP_PKEY_DSA: +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + ExpectNotNull(dsa = DSA_new()); + ExpectIntEQ(DSA_generate_parameters_ex(dsa, 2048, + NULL, 0, NULL, NULL, NULL), 1); + ExpectIntEQ(DSA_generate_key(dsa), 1); + ExpectIntEQ(EVP_PKEY_set1_DSA(pkey, dsa), WOLFSSL_SUCCESS); +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ + break; + case EVP_PKEY_EC: +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + { + ExpectNotNull(ecKey = EC_KEY_new()); + ExpectIntEQ(EC_KEY_generate_key(ecKey), 1); + ExpectIntEQ( + EVP_PKEY_assign_EC_KEY(pkey, ecKey), WOLFSSL_SUCCESS); + if (EXPECT_FAIL()) { + EC_KEY_free(ecKey); + } + } +#endif +#endif + break; + } + ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); + ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + if (keyType == EVP_PKEY_RSA) + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), + WOLFSSL_SUCCESS); +#endif +#endif + + /* Check returning only length */ + ExpectIntEQ(EVP_PKEY_sign(ctx, NULL, &siglenOnlyLen, hash, + SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); + ExpectIntGT(siglenOnlyLen, 0); + /* Sign data */ + ExpectIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, hash, + SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); + ExpectIntGE(siglenOnlyLen, siglen); + + /* Verify signature */ + ExpectNotNull(ctx_verify = EVP_PKEY_CTX_new(pkey, NULL)); + ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + if (keyType == EVP_PKEY_RSA) + ExpectIntEQ( + EVP_PKEY_CTX_set_rsa_padding(ctx_verify, RSA_PKCS1_PADDING), + WOLFSSL_SUCCESS); +#endif +#endif + ExpectIntEQ(EVP_PKEY_verify( + ctx_verify, sig, siglen, hash, SHA256_DIGEST_LENGTH), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_verify( + ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + if (keyType == EVP_PKEY_RSA) { + #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) + /* Try RSA sign/verify with no padding. */ + ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_sign(ctx, sigVerify, &siglen, sig, + siglen), WOLFSSL_SUCCESS); + ExpectIntGE(siglenOnlyLen, siglen); + ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, + RSA_NO_PADDING), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_verify(ctx_verify, sigVerify, siglen, sig, + siglen), WOLFSSL_SUCCESS); + #endif + + /* Wrong padding schemes. */ + ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, + RSA_PKCS1_OAEP_PADDING), WOLFSSL_SUCCESS); + ExpectIntNE(EVP_PKEY_sign(ctx, sigVerify, &siglen, sig, + siglen), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, + RSA_PKCS1_OAEP_PADDING), WOLFSSL_SUCCESS); + ExpectIntNE(EVP_PKEY_verify(ctx_verify, sigVerify, siglen, sig, + siglen), WOLFSSL_SUCCESS); + + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, + RSA_PKCS1_PADDING), WOLFSSL_SUCCESS); + } +#endif +#endif + + /* error cases */ + siglen = keySz; /* Reset because sig size may vary slightly */ + ExpectIntNE(EVP_PKEY_sign_init(NULL), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); + ExpectIntNE(EVP_PKEY_sign(NULL, sig, &siglen, (byte*)in, inlen), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, (byte*)in, inlen), + WOLFSSL_SUCCESS); + + EVP_PKEY_free(pkey); + pkey = NULL; +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + DSA_free(dsa); + dsa = NULL; +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ + EVP_PKEY_CTX_free(ctx_verify); + ctx_verify = NULL; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigVerify, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif /* OPENSSL_EXTRA */ + return EXPECT_RESULT(); +} +#endif + +static int test_wolfSSL_EVP_PKEY_sign_verify_rsa(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_RSA), TEST_SUCCESS); +#endif +#endif + return EXPECT_RESULT(); +} +static int test_wolfSSL_EVP_PKEY_sign_verify_dsa(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_DSA), TEST_SUCCESS); +#endif +#endif + return EXPECT_RESULT(); +} +static int test_wolfSSL_EVP_PKEY_sign_verify_ec(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_EC), TEST_SUCCESS); +#endif +#endif + return EXPECT_RESULT(); +} + +static int test_EVP_PKEY_rsa(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) + WOLFSSL_RSA* rsa = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + + ExpectNotNull(rsa = wolfSSL_RSA_new()); + ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); + ExpectIntEQ(EVP_PKEY_assign_RSA(NULL, rsa), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); + if (EXPECT_FAIL()) { + wolfSSL_RSA_free(rsa); + } + ExpectPtrEq(EVP_PKEY_get0_RSA(pkey), rsa); + wolfSSL_EVP_PKEY_free(pkey); +#endif + return EXPECT_RESULT(); +} + +static int test_EVP_PKEY_ec(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + WOLFSSL_EC_KEY* ecKey = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + + ExpectNotNull(ecKey = wolfSSL_EC_KEY_new()); + ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); + ExpectIntEQ(EVP_PKEY_assign_EC_KEY(NULL, ecKey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + /* Should fail since ecKey is empty */ + ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, ecKey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), 1); + ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, ecKey), WOLFSSL_SUCCESS); + if (EXPECT_FAIL()) { + wolfSSL_EC_KEY_free(ecKey); + } + wolfSSL_EVP_PKEY_free(pkey); +#endif +#endif + return EXPECT_RESULT(); +} + +static int test_EVP_PKEY_cmp(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) + EVP_PKEY *a = NULL; + EVP_PKEY *b = NULL; + const unsigned char *in; + +#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048) + in = client_key_der_2048; + ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, + &in, (long)sizeof_client_key_der_2048)); + in = client_key_der_2048; + ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, + &in, (long)sizeof_client_key_der_2048)); + + /* Test success case RSA */ +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ExpectIntEQ(EVP_PKEY_cmp(a, b), 1); +#else + ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); +#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ + + EVP_PKEY_free(b); + b = NULL; + EVP_PKEY_free(a); + a = NULL; +#endif + +#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) + in = ecc_clikey_der_256; + ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, + &in, (long)sizeof_ecc_clikey_der_256)); + in = ecc_clikey_der_256; + ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, + &in, (long)sizeof_ecc_clikey_der_256)); + + /* Test success case ECC */ +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ExpectIntEQ(EVP_PKEY_cmp(a, b), 1); +#else + ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); +#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ + + EVP_PKEY_free(b); + b = NULL; + EVP_PKEY_free(a); + a = NULL; +#endif + + /* Test failure cases */ +#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048) && \ + defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) + + in = client_key_der_2048; + ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, + &in, (long)sizeof_client_key_der_2048)); + in = ecc_clikey_der_256; + ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, + &in, (long)sizeof_ecc_clikey_der_256)); + +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ExpectIntEQ(EVP_PKEY_cmp(a, b), -1); +#else + ExpectIntNE(EVP_PKEY_cmp(a, b), 0); +#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ + EVP_PKEY_free(b); + b = NULL; + EVP_PKEY_free(a); + a = NULL; +#endif + + /* invalid or empty failure cases */ + a = EVP_PKEY_new(); + b = EVP_PKEY_new(); +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ExpectIntEQ(EVP_PKEY_cmp(NULL, NULL), 0); + ExpectIntEQ(EVP_PKEY_cmp(a, NULL), 0); + ExpectIntEQ(EVP_PKEY_cmp(NULL, b), 0); +#ifdef NO_RSA + /* Type check will fail since RSA is the default EVP key type */ + ExpectIntEQ(EVP_PKEY_cmp(a, b), -2); +#else + ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); +#endif +#else + ExpectIntNE(EVP_PKEY_cmp(NULL, NULL), 0); + ExpectIntNE(EVP_PKEY_cmp(a, NULL), 0); + ExpectIntNE(EVP_PKEY_cmp(NULL, b), 0); + ExpectIntNE(EVP_PKEY_cmp(a, b), 0); +#endif + EVP_PKEY_free(b); + EVP_PKEY_free(a); + + (void)in; +#endif + return EXPECT_RESULT(); +} + static int test_ERR_load_crypto_strings(void) { #if defined(OPENSSL_ALL) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 31466ca846d..ada657d3cdb 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33865,6 +33865,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, @@ -34163,6 +34260,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 4067062e0c5b03c206488c32c25d2997e7217156 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:57:42 -0700 Subject: [PATCH 02/12] 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 826b1d074e1..6531eafe571 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19628,7 +19628,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 */ @@ -31693,6 +31692,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 0c14c340a0f0e39a8f01c7f2db9778201b624438 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Fri, 9 Jan 2026 10:21:39 -0700 Subject: [PATCH 03/12] 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 6531eafe571..fa8c3661410 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19613,13 +19613,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; } @@ -19627,7 +19634,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 */ @@ -19641,11 +19648,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; } @@ -19669,11 +19676,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); @@ -19696,16 +19705,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 15df776404d5a2178d1ec2bb770b6d6af1d0f2a6 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Fri, 9 Jan 2026 11:08:34 -0700 Subject: [PATCH 04/12] 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 ada657d3cdb..85c8e20e183 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33893,7 +33893,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 2a6ef311b88db5f85579357fc4e67a12854355c5 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 14:43:38 -0700 Subject: [PATCH 05/12] 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 788b29a8118..a0abe441210 100644 --- a/configure.ac +++ b/configure.ac @@ -4588,6 +4588,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 85c8e20e183..ccc82bb4273 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -31980,23 +31980,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; @@ -32005,161 +32110,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); } @@ -34276,6 +34325,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) @@ -34322,6 +34372,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 5bab5c396f1edf5405dfef53318d42248ef79969 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 15:16:24 -0700 Subject: [PATCH 06/12] 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 fa8c3661410..9a680893244 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19612,7 +19612,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 */ @@ -19667,6 +19667,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; @@ -19727,6 +19728,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) @@ -31705,7 +31707,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 c444d9ff772052bc02305e2e60f06dde0970818e Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 14 Jan 2026 16:16:35 -0700 Subject: [PATCH 07/12] 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 ccc82bb4273..81ed5292c1a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33952,6 +33952,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, @@ -33964,6 +33965,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: @@ -33971,12 +33973,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); @@ -33990,10 +33995,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 7e7e637b688b0796833a69669db5cbe0d69afcf7 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 15 Jan 2026 12:27:20 -0700 Subject: [PATCH 08/12] 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 9a680893244..47ceb8fac0d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19637,8 +19637,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 81ed5292c1a..e6780c80e37 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33928,7 +33928,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: @@ -33982,7 +33984,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 8e28ab29e97969420f172be56c4e38bafe13f2a1 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 15 Jan 2026 16:47:57 -0700 Subject: [PATCH 09/12] 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 e6780c80e37..9ad7e896269 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -31981,7 +31981,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, @@ -32037,25 +32039,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 */ @@ -32064,8 +32064,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 */ @@ -32075,8 +32075,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 */ From 1aeb5d67de1c28534fc410b40dfe62dcf3855303 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Mon, 19 Jan 2026 15:47:53 -0700 Subject: [PATCH 10/12] remove duplicate test functions --- tests/api.c | 506 ---------------------------------------------------- 1 file changed, 506 deletions(-) diff --git a/tests/api.c b/tests/api.c index 47ceb8fac0d..e1bd8ff74f7 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19730,512 +19730,6 @@ static int test_wc_SignCert_cb(void) } #endif /* WOLFSSL_CERT_SIGN_CB */ - -static int test_wolfSSL_EVP_PKEY_encrypt(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) - WOLFSSL_RSA* rsa = NULL; - WOLFSSL_EVP_PKEY* pkey = NULL; - WOLFSSL_EVP_PKEY_CTX* ctx = NULL; - const char* in = "What is easy to do is easy not to do."; - size_t inlen = XSTRLEN(in); - size_t outEncLen = 0; - byte* outEnc = NULL; - byte* outDec = NULL; - size_t outDecLen = 0; - size_t rsaKeySz = 2048/8; /* Bytes */ -#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) - byte* inTmp = NULL; - byte* outEncTmp = NULL; - byte* outDecTmp = NULL; -#endif - - ExpectNotNull(outEnc = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER)); - if (outEnc != NULL) { - XMEMSET(outEnc, 0, rsaKeySz); - } - ExpectNotNull(outDec = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER)); - if (outDec != NULL) { - XMEMSET(outDec, 0, rsaKeySz); - } - - ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); - ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); - ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); - if (EXPECT_FAIL()) { - RSA_free(rsa); - } - ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); - ExpectIntEQ(EVP_PKEY_encrypt_init(ctx), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), - WOLFSSL_SUCCESS); - - /* Test pkey references count is decremented. pkey shouldn't be destroyed - since ctx uses it.*/ - ExpectIntEQ(pkey->ref.count, 2); - EVP_PKEY_free(pkey); - ExpectIntEQ(pkey->ref.count, 1); - - /* Encrypt data */ - /* Check that we can get the required output buffer length by passing in a - * NULL output buffer. */ - ExpectIntEQ(EVP_PKEY_encrypt(ctx, NULL, &outEncLen, - (const unsigned char*)in, inlen), WOLFSSL_SUCCESS); - ExpectIntEQ(rsaKeySz, outEncLen); - /* Now do the actual encryption. */ - ExpectIntEQ(EVP_PKEY_encrypt(ctx, outEnc, &outEncLen, - (const unsigned char*)in, inlen), WOLFSSL_SUCCESS); - - /* Decrypt data */ - ExpectIntEQ(EVP_PKEY_decrypt_init(ctx), WOLFSSL_SUCCESS); - /* Check that we can get the required output buffer length by passing in a - * NULL output buffer. */ - ExpectIntEQ(EVP_PKEY_decrypt(ctx, NULL, &outDecLen, outEnc, outEncLen), - WOLFSSL_SUCCESS); - ExpectIntEQ(rsaKeySz, outDecLen); - /* Now do the actual decryption. */ - ExpectIntEQ(EVP_PKEY_decrypt(ctx, outDec, &outDecLen, outEnc, outEncLen), - WOLFSSL_SUCCESS); - - ExpectIntEQ(XMEMCMP(in, outDec, outDecLen), 0); - -#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) - /* The input length must be the same size as the RSA key.*/ - ExpectNotNull(inTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER)); - if (inTmp != NULL) { - XMEMSET(inTmp, 9, rsaKeySz); - } - ExpectNotNull(outEncTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER)); - if (outEncTmp != NULL) { - XMEMSET(outEncTmp, 0, rsaKeySz); - } - ExpectNotNull(outDecTmp = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER)); - if (outDecTmp != NULL) { - XMEMSET(outDecTmp, 0, rsaKeySz); - } - ExpectIntEQ(EVP_PKEY_encrypt_init(ctx), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_encrypt(ctx, outEncTmp, &outEncLen, inTmp, rsaKeySz), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_decrypt_init(ctx), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_decrypt(ctx, outDecTmp, &outDecLen, outEncTmp, - outEncLen), WOLFSSL_SUCCESS); - ExpectIntEQ(XMEMCMP(inTmp, outDecTmp, outDecLen), 0); -#endif - EVP_PKEY_CTX_free(ctx); - XFREE(outEnc, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(outDec, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); -#if !defined(HAVE_FIPS) && defined(WC_RSA_NO_PADDING) - XFREE(inTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(outEncTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(outDecTmp, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); -#endif -#endif - return EXPECT_RESULT(); -} - -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #endif -#endif -#endif -#if defined(OPENSSL_EXTRA) -#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) - #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #endif -#endif -#endif -#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - #ifndef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #define TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY - #endif -#endif -#endif - -#ifdef TEST_WOLFSSL_EVP_PKEY_SIGN_VERIFY -static int test_wolfSSL_EVP_PKEY_sign_verify(int keyType) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - WOLFSSL_RSA* rsa = NULL; -#endif -#endif -#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) - WOLFSSL_DSA* dsa = NULL; -#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ -#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - WOLFSSL_EC_KEY* ecKey = NULL; -#endif -#endif - WOLFSSL_EVP_PKEY* pkey = NULL; - WOLFSSL_EVP_PKEY_CTX* ctx = NULL; - WOLFSSL_EVP_PKEY_CTX* ctx_verify = NULL; - const char* in = "What is easy to do is easy not to do."; - size_t inlen = XSTRLEN(in); - byte hash[SHA256_DIGEST_LENGTH] = {0}; - byte zero[SHA256_DIGEST_LENGTH] = {0}; - SHA256_CTX c; - byte* sig = NULL; - byte* sigVerify = NULL; - size_t siglen; - size_t siglenOnlyLen; - size_t keySz = 2048/8; /* Bytes */ - - ExpectNotNull(sig = - (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); - ExpectNotNull(sigVerify = - (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); - - siglen = keySz; - ExpectNotNull(XMEMSET(sig, 0, keySz)); - ExpectNotNull(XMEMSET(sigVerify, 0, keySz)); - - /* Generate hash */ - SHA256_Init(&c); - SHA256_Update(&c, in, inlen); - SHA256_Final(hash, &c); -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* workaround for small stack cache case */ - wc_Sha256Free((wc_Sha256*)&c); -#endif - - /* Generate key */ - ExpectNotNull(pkey = EVP_PKEY_new()); - switch (keyType) { - case EVP_PKEY_RSA: -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - { - ExpectNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); - ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); - } -#endif -#endif - break; - case EVP_PKEY_DSA: -#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) - ExpectNotNull(dsa = DSA_new()); - ExpectIntEQ(DSA_generate_parameters_ex(dsa, 2048, - NULL, 0, NULL, NULL, NULL), 1); - ExpectIntEQ(DSA_generate_key(dsa), 1); - ExpectIntEQ(EVP_PKEY_set1_DSA(pkey, dsa), WOLFSSL_SUCCESS); -#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ - break; - case EVP_PKEY_EC: -#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - { - ExpectNotNull(ecKey = EC_KEY_new()); - ExpectIntEQ(EC_KEY_generate_key(ecKey), 1); - ExpectIntEQ( - EVP_PKEY_assign_EC_KEY(pkey, ecKey), WOLFSSL_SUCCESS); - if (EXPECT_FAIL()) { - EC_KEY_free(ecKey); - } - } -#endif -#endif - break; - } - ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); - ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - if (keyType == EVP_PKEY_RSA) - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), - WOLFSSL_SUCCESS); -#endif -#endif - - /* Check returning only length */ - ExpectIntEQ(EVP_PKEY_sign(ctx, NULL, &siglenOnlyLen, hash, - SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); - ExpectIntGT(siglenOnlyLen, 0); - /* Sign data */ - ExpectIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, hash, - SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); - ExpectIntGE(siglenOnlyLen, siglen); - - /* Verify signature */ - ExpectNotNull(ctx_verify = EVP_PKEY_CTX_new(pkey, NULL)); - ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - if (keyType == EVP_PKEY_RSA) - ExpectIntEQ( - EVP_PKEY_CTX_set_rsa_padding(ctx_verify, RSA_PKCS1_PADDING), - WOLFSSL_SUCCESS); -#endif -#endif - ExpectIntEQ(EVP_PKEY_verify( - ctx_verify, sig, siglen, hash, SHA256_DIGEST_LENGTH), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_verify( - ctx_verify, sig, siglen, zero, SHA256_DIGEST_LENGTH), - WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - if (keyType == EVP_PKEY_RSA) { - #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) - /* Try RSA sign/verify with no padding. */ - ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_sign(ctx, sigVerify, &siglen, sig, - siglen), WOLFSSL_SUCCESS); - ExpectIntGE(siglenOnlyLen, siglen); - ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, - RSA_NO_PADDING), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_verify(ctx_verify, sigVerify, siglen, sig, - siglen), WOLFSSL_SUCCESS); - #endif - - /* Wrong padding schemes. */ - ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, - RSA_PKCS1_OAEP_PADDING), WOLFSSL_SUCCESS); - ExpectIntNE(EVP_PKEY_sign(ctx, sigVerify, &siglen, sig, - siglen), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, - RSA_PKCS1_OAEP_PADDING), WOLFSSL_SUCCESS); - ExpectIntNE(EVP_PKEY_verify(ctx_verify, sigVerify, siglen, sig, - siglen), WOLFSSL_SUCCESS); - - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx_verify, - RSA_PKCS1_PADDING), WOLFSSL_SUCCESS); - } -#endif -#endif - - /* error cases */ - siglen = keySz; /* Reset because sig size may vary slightly */ - ExpectIntNE(EVP_PKEY_sign_init(NULL), WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); - ExpectIntNE(EVP_PKEY_sign(NULL, sig, &siglen, (byte*)in, inlen), - WOLFSSL_SUCCESS); - ExpectIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, (byte*)in, inlen), - WOLFSSL_SUCCESS); - - EVP_PKEY_free(pkey); - pkey = NULL; -#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) - DSA_free(dsa); - dsa = NULL; -#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ - EVP_PKEY_CTX_free(ctx_verify); - ctx_verify = NULL; - EVP_PKEY_CTX_free(ctx); - ctx = NULL; - - XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(sigVerify, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); -#endif /* OPENSSL_EXTRA */ - return EXPECT_RESULT(); -} -#endif - -static int test_wolfSSL_EVP_PKEY_sign_verify_rsa(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_RSA), TEST_SUCCESS); -#endif -#endif - return EXPECT_RESULT(); -} -static int test_wolfSSL_EVP_PKEY_sign_verify_dsa(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) -#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) - ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_DSA), TEST_SUCCESS); -#endif -#endif - return EXPECT_RESULT(); -} -static int test_wolfSSL_EVP_PKEY_sign_verify_ec(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - ExpectIntEQ(test_wolfSSL_EVP_PKEY_sign_verify(EVP_PKEY_EC), TEST_SUCCESS); -#endif -#endif - return EXPECT_RESULT(); -} - -static int test_EVP_PKEY_rsa(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) - WOLFSSL_RSA* rsa = NULL; - WOLFSSL_EVP_PKEY* pkey = NULL; - - ExpectNotNull(rsa = wolfSSL_RSA_new()); - ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); - ExpectIntEQ(EVP_PKEY_assign_RSA(NULL, rsa), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - ExpectIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); - if (EXPECT_FAIL()) { - wolfSSL_RSA_free(rsa); - } - ExpectPtrEq(EVP_PKEY_get0_RSA(pkey), rsa); - wolfSSL_EVP_PKEY_free(pkey); -#endif - return EXPECT_RESULT(); -} - -static int test_EVP_PKEY_ec(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - WOLFSSL_EC_KEY* ecKey = NULL; - WOLFSSL_EVP_PKEY* pkey = NULL; - - ExpectNotNull(ecKey = wolfSSL_EC_KEY_new()); - ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new()); - ExpectIntEQ(EVP_PKEY_assign_EC_KEY(NULL, ecKey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - /* Should fail since ecKey is empty */ - ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, ecKey), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - ExpectIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), 1); - ExpectIntEQ(EVP_PKEY_assign_EC_KEY(pkey, ecKey), WOLFSSL_SUCCESS); - if (EXPECT_FAIL()) { - wolfSSL_EC_KEY_free(ecKey); - } - wolfSSL_EVP_PKEY_free(pkey); -#endif -#endif - return EXPECT_RESULT(); -} - -static int test_EVP_PKEY_cmp(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) - EVP_PKEY *a = NULL; - EVP_PKEY *b = NULL; - const unsigned char *in; - -#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048) - in = client_key_der_2048; - ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, - &in, (long)sizeof_client_key_der_2048)); - in = client_key_der_2048; - ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, - &in, (long)sizeof_client_key_der_2048)); - - /* Test success case RSA */ -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - ExpectIntEQ(EVP_PKEY_cmp(a, b), 1); -#else - ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); -#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ - - EVP_PKEY_free(b); - b = NULL; - EVP_PKEY_free(a); - a = NULL; -#endif - -#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) - in = ecc_clikey_der_256; - ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, - &in, (long)sizeof_ecc_clikey_der_256)); - in = ecc_clikey_der_256; - ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, - &in, (long)sizeof_ecc_clikey_der_256)); - - /* Test success case ECC */ -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - ExpectIntEQ(EVP_PKEY_cmp(a, b), 1); -#else - ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); -#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ - - EVP_PKEY_free(b); - b = NULL; - EVP_PKEY_free(a); - a = NULL; -#endif - - /* Test failure cases */ -#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048) && \ - defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) - - in = client_key_der_2048; - ExpectNotNull(a = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL, - &in, (long)sizeof_client_key_der_2048)); - in = ecc_clikey_der_256; - ExpectNotNull(b = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, - &in, (long)sizeof_ecc_clikey_der_256)); - -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - ExpectIntEQ(EVP_PKEY_cmp(a, b), -1); -#else - ExpectIntNE(EVP_PKEY_cmp(a, b), 0); -#endif /* WOLFSSL_ERROR_CODE_OPENSSL */ - EVP_PKEY_free(b); - b = NULL; - EVP_PKEY_free(a); - a = NULL; -#endif - - /* invalid or empty failure cases */ - a = EVP_PKEY_new(); - b = EVP_PKEY_new(); -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - ExpectIntEQ(EVP_PKEY_cmp(NULL, NULL), 0); - ExpectIntEQ(EVP_PKEY_cmp(a, NULL), 0); - ExpectIntEQ(EVP_PKEY_cmp(NULL, b), 0); -#ifdef NO_RSA - /* Type check will fail since RSA is the default EVP key type */ - ExpectIntEQ(EVP_PKEY_cmp(a, b), -2); -#else - ExpectIntEQ(EVP_PKEY_cmp(a, b), 0); -#endif -#else - ExpectIntNE(EVP_PKEY_cmp(NULL, NULL), 0); - ExpectIntNE(EVP_PKEY_cmp(a, NULL), 0); - ExpectIntNE(EVP_PKEY_cmp(NULL, b), 0); - ExpectIntNE(EVP_PKEY_cmp(a, b), 0); -#endif - EVP_PKEY_free(b); - EVP_PKEY_free(a); - - (void)in; -#endif - return EXPECT_RESULT(); -} - static int test_ERR_load_crypto_strings(void) { #if defined(OPENSSL_ALL) From 52f4bd26e8eb949b65eb538c0ac24157a634ad81 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Mon, 19 Jan 2026 17:03:56 -0700 Subject: [PATCH 11/12] format fixes --- tests/api.c | 10 +++++----- wolfcrypt/src/asn.c | 2 +- wolfssl/wolfcrypt/asn_public.h | 30 +++++++++++++++--------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/api.c b/tests/api.c index e1bd8ff74f7..bbe1793de14 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19625,7 +19625,7 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, int ret = 0; MockSignCtx* signCtx = (MockSignCtx*)ctx; - if (signCtx == NULL || signCtx->key == NULL || in == NULL || + if (signCtx == NULL || signCtx->key == NULL || in == NULL || out == NULL || outLen == NULL) { return BAD_FUNC_ARG; } @@ -19636,7 +19636,7 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, 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) { @@ -19650,7 +19650,7 @@ static int mockSignCb(const byte* in, word32 inLen, byte* out, word32* outLen, 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) { @@ -19705,11 +19705,11 @@ 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, &signCtx, &rng), 0); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 9ad7e896269..e31c4c8922a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -32013,7 +32013,7 @@ 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; + int ret = WC_NO_ERR_TRACE(ALGO_ID_E); (void)sigAlgo; /* Algorithm determined by key type */ diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index bf58c787140..57e7386b02a 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -235,14 +235,14 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); #ifdef WOLFSSL_CERT_SIGN_CB /*! - \ingroup CertManager + \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 DER-encoded digest (DigestInfo structure with algorithm identifier). For ECC, this is the raw hash to sign. @@ -253,20 +253,20 @@ typedef int (wc_pem_password_cb)(char* passwd, int sz, int rw, void* userdata); 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, + 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 + /* Perform signing using external device/HSM */ return myDevice_Sign(myCtx->device, in, inLen, out, outLen); } \endcode @@ -597,15 +597,15 @@ WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, byte derBuf[4096]; int derSz; MySignCtx myCtx; - - // Initialize cert and set subject, etc. + + /* Initialize cert and set subject, etc. */ wc_InitCert(&cert); - // ... set cert fields ... - - // Make certificate body + /* ... set cert fields ... */ + + /* Make certificate body */ derSz = wc_MakeCert(&cert, derBuf, sizeof(derBuf), NULL, NULL, &rng); - - // Sign using callback + + /* Sign using callback */ derSz = wc_SignCert_cb(cert.bodySz, cert.sigType, derBuf, sizeof(derBuf), RSA_TYPE, mySignCallback, &myCtx, &rng); if (derSz > 0) { From 4dd06e1b7bcc3d7f739323c729733d874bc1e9ea Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Mon, 19 Jan 2026 17:16:31 -0700 Subject: [PATCH 12/12] Stray comment --- wolfssl/wolfcrypt/asn_public.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 57e7386b02a..d4eb0d1935a 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -555,20 +555,20 @@ WOLFSSL_API int wc_SignCert_ex(int requestSz, int sType, byte* buf, WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng); /*! - \ingroup CertManager + \ingroup CertManager \brief Sign a certificate or CSR using a callback function. - - This function signs a certificate or Certificate Signing Request (CSR) + + 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). @@ -578,19 +578,19 @@ WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, \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; @@ -611,8 +611,7 @@ WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, 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,