From 2f4cd41edccd41a1c8d626ffec7e4dfe1b9ea4a2 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:20:21 -0700 Subject: [PATCH 1/3] Add TPM support for wc_SignCert_cb callback API --- examples/csr/csr.c | 24 +++++ src/tpm2_wrap.c | 232 +++++++++++++++++++++++++++++++++++++++++++- wolftpm/tpm2_wrap.h | 16 +++ 3 files changed, 267 insertions(+), 5 deletions(-) diff --git a/examples/csr/csr.c b/examples/csr/csr.c index 2fa3dad5..3b655bc0 100644 --- a/examples/csr/csr.c +++ b/examples/csr/csr.c @@ -67,6 +67,30 @@ static const char* gClientCertEccFile = ECC_CERT_PEM; /* --- BEGIN TPM2 CSR Example -- */ /******************************************************************************/ +/* Certificate/CSR Signing with TPM: + * + * wolfTPM supports two approaches for TPM-based certificate signing: + * + * 1. NEW CALLBACK-BASED APPROACH (Recommended for FIPS): + * When devId is INVALID_DEVID, wolfTPM2_CSR_MakeAndSign_ex() uses the new + * wc_SignCert_cb() API which calls TPM signing functions directly without + * requiring wolfCrypt crypto callbacks. This approach: + * - Uses TPM crypto directly (no wolfCrypt offloading) + * - Is FIPS-compliant (doesn't rely on wolfCrypt crypto callbacks) + * - Simplifies the code path + * + * 2. CRYPTO CALLBACK APPROACH (Legacy/Backward Compatible): + * When devId is set via wolfTPM2_SetCryptoDevCb(), the legacy crypto + * callback infrastructure is used. This approach: + * - Uses wc_SignCert_ex() which offloads crypto operations to TPM + * - Maintains backward compatibility + * - Requires crypto callback setup + * + * This example demonstrates the crypto callback approach. To use the new + * callback-based approach, pass INVALID_DEVID instead of tpmDevId when calling + * TPM2_CSR_Generate() or wolfTPM2_CSR_MakeAndSign_ex(). + */ + static int TPM2_CSR_Generate(WOLFTPM2_DEV* dev, int keyType, WOLFTPM2_KEY* key, const char* outputPemFile, int makeSelfSignedCert, int devId, int sigType) { diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ed0d7b51..6a16854c 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -7332,6 +7332,105 @@ typedef struct CSRKey { TpmCryptoDevCtx tpmCtx; } CSRKey; +/* + * Internal callback function for wc_SignCert_cb that uses TPM for signing. + * + * This callback implements the wc_SignCertCb interface to perform certificate + * and CSR signing using the TPM. It is used internally by CSR_MakeAndSign_Cb + * when the callback-based signing approach is selected. + * + * For RSA keys: + * - Input is PKCS#1 v1.5 padded digest (already encoded by wolfSSL) + * - Uses wolfTPM2_RsaDecrypt with TPM_ALG_NULL (no padding) to perform + * the private key operation for signing + * + * For ECC keys: + * - Input is the raw hash to sign + * - Uses wolfTPM2_SignHash to sign with TPM + * - Converts TPM's R||S format to DER-encoded ECDSA signature + * + * Parameters: + * in - Data to sign (encoded for RSA, raw hash for ECC) + * inLen - Length of input data + * out - Output buffer for signature + * outLen - Input: buffer size, Output: signature size + * sigAlgo - Signature algorithm (not used, determined by keyType) + * keyType - Key type (RSA_TYPE or ECC_TYPE) + * ctx - TpmSignCbCtx containing TPM device and key + * + * Returns: + * 0 on success + * BAD_FUNC_ARG on invalid parameters + * NOT_COMPILED_IN if key type not supported + * Other negative values on TPM errors + */ +static int wolfTPM2_SignCertCb(const byte* in, word32 inLen, + byte* out, word32* outLen, int sigAlgo, int keyType, void* ctx) +{ + int rc; + TpmSignCbCtx* tpmCtx = (TpmSignCbCtx*)ctx; + + if (tpmCtx == NULL || tpmCtx->dev == NULL || tpmCtx->key == NULL) { + return BAD_FUNC_ARG; + } + + (void)sigAlgo; /* Algorithm determined by key type */ + + if (keyType == ECC_TYPE) { +#ifdef HAVE_ECC + byte sigRS[MAX_ECC_BYTES * 2]; + int rsLen = (int)sizeof(sigRS); + word32 keySz; + + /* Get key size for proper R/S formatting */ + keySz = TPM2_GetCurveSize( + tpmCtx->key->pub.publicArea.parameters.eccDetail.curveID); + + /* Sign using TPM */ + rc = wolfTPM2_SignHash(tpmCtx->dev, tpmCtx->key, + in, inLen, sigRS, &rsLen); + + if (rc == 0) { + byte *r, *s; + word32 rLen, sLen; + + /* Split R and S from concatenated signature */ + rLen = sLen = rsLen / 2; + r = &sigRS[0]; + s = &sigRS[rLen]; + + /* Encode as DER ECDSA signature */ + rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outLen); + } +#else + rc = NOT_COMPILED_IN; +#endif + } + else if (keyType == RSA_TYPE) { +#ifndef NO_RSA + int outSz = (int)*outLen; + + /* For RSA, input is already PKCS#1 v1.5 padded digest + * Use RSA decrypt (private key operation) for signing */ + rc = wolfTPM2_RsaDecrypt(tpmCtx->dev, tpmCtx->key, + TPM_ALG_NULL, /* No padding - input is pre-padded */ + in, inLen, out, &outSz); + + if (rc == 0) { + *outLen = (word32)outSz; + } +#else + rc = NOT_COMPILED_IN; +#endif + } + else { + rc = BAD_FUNC_ARG; + } + + return rc; +} + + static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key, int outFormat, byte* out, int outSz, int selfSignCert) { @@ -7382,6 +7481,96 @@ static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key, return rc; } +/* + * Internal function for CSR/Certificate generation and signing using the + * callback-based approach. + * + * This function generates and signs a Certificate Signing Request (CSR) or + * self-signed certificate using the new wc_SignCert_cb() API. Unlike the + * legacy CSR_MakeAndSign() function which requires crypto callback setup, + * this function calls TPM signing directly via wolfTPM2_SignCertCb(). + * + * Advantages of this approach: + * - FIPS compliant (no wolfCrypt crypto offloading) + * - Simpler code path (no crypto callback infrastructure) + * - Direct TPM signing without intermediate key structures + * + * Parameters: + * dev - Initialized TPM device + * csr - CSR structure with subject, extensions, etc. + * key - TPM key to use for signing + * keyType - Key type (RSA_TYPE or ECC_TYPE) + * outFormat - Output format (ENCODING_TYPE_PEM or ENCODING_TYPE_ASN1) + * out - Output buffer + * outSz - Size of output buffer + * selfSignCert - 1 to create self-signed cert, 0 for CSR + * + * Returns: + * Positive value: size of generated CSR/certificate + * BAD_FUNC_ARG: invalid parameters + * BUFFER_E: output buffer too small + * Other negative: error code from wolfSSL or TPM + */ +static int CSR_MakeAndSign_Cb(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, + WOLFTPM2_KEY* key, int keyType, int outFormat, byte* out, int outSz, + int selfSignCert) +{ + int rc = 0; + TpmSignCbCtx signCtx; + + if (dev == NULL || csr == NULL || key == NULL || out == NULL) { + return BAD_FUNC_ARG; + } + + /* Setup signing context */ + signCtx.dev = dev; + signCtx.key = key; + + /* Create certificate body */ + if (selfSignCert) { +#ifdef WOLFSSL_CERT_GEN + rc = wc_MakeCert_ex(&csr->req, out, outSz, keyType, NULL, + wolfTPM2_GetRng(dev)); +#else + rc = NOT_COMPILED_IN; +#endif + } + else { + rc = wc_MakeCertReq_ex(&csr->req, out, outSz, keyType, NULL); + } + + /* Sign using TPM via callback */ + if (rc >= 0) { + rc = wc_SignCert_cb(csr->req.bodySz, csr->req.sigType, out, + (word32)outSz, keyType, wolfTPM2_SignCertCb, &signCtx, + wolfTPM2_GetRng(dev)); + } + + /* Optionally convert to PEM */ + if (rc >= 0 && outFormat == ENCODING_TYPE_PEM) { +#ifdef WOLFSSL_DER_TO_PEM + byte tmp[MAX_CONTEXT_SIZE]; + if (rc > (int)sizeof(tmp)) { + rc = BUFFER_E; + } + else { + XMEMCPY(tmp, out, rc); + XMEMSET(out, 0, outSz); + rc = wc_DerToPem(tmp, (word32)rc, out, outSz, + selfSignCert ? CERT_TYPE : CERTREQ_TYPE); + } +#else + #ifdef DEBUG_WOLFTPM + printf("CSR_MakeAndSign_Cb PEM not supported\n"); + #endif + rc = NOT_COMPILED_IN; +#endif + } + + return rc; +} + + static int CSR_KeySetup(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, WOLFTPM2_KEY* key, CSRKey* csrKey, int sigType, int devId) { @@ -7576,12 +7765,36 @@ int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, int sigType, int selfSignCert, int devId) { int rc; - CSRKey csrKey; + int keyType; if (dev == NULL || key == NULL || csr == NULL || out == NULL) { return BAD_FUNC_ARG; } + /* Determine key type from TPM key */ + if (key->pub.publicArea.type == TPM_ALG_ECC) { + keyType = ECC_TYPE; + } + else if (key->pub.publicArea.type == TPM_ALG_RSA) { + keyType = RSA_TYPE; + } + else { + return BAD_FUNC_ARG; + } + + /* Set signature type if not specified */ + if (sigType == 0) { + if (keyType == RSA_TYPE) { + csr->req.sigType = CTC_SHA256wRSA; + } + else if (keyType == ECC_TYPE) { + csr->req.sigType = CTC_SHA256wECDSA; + } + } + else { + csr->req.sigType = sigType; + } + /* Set version to 2 for self-signed certificates, 0 for regular CSRs per RFC2986 */ if (selfSignCert) { csr->req.version = 2; @@ -7590,12 +7803,21 @@ int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, csr->req.version = 0; } - rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId); - if (rc == 0) { - rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz, + /* Use new callback-based signing if devId not specified */ + if (devId == INVALID_DEVID) { + rc = CSR_MakeAndSign_Cb(dev, csr, key, keyType, outFormat, out, outSz, selfSignCert); } - CSR_KeyCleanup(dev, &csrKey); + else { + /* Fall back to crypto callback approach for backward compatibility */ + CSRKey csrKey; + rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId); + if (rc == 0) { + rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz, + selfSignCert); + } + CSR_KeyCleanup(dev, &csrKey); + } return rc; } diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 8d709baa..7de76558 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -109,6 +109,22 @@ typedef struct WOLFTPM2_HMAC { typedef struct WOLFTPM2_CSR { Cert req; } WOLFTPM2_CSR; + +/*! + \ingroup wolfTPM2_Wrappers + \brief Context structure for TPM-based certificate signing callback. + + This structure holds the TPM device and key references needed for the + certificate signing callback (wc_SignCertCb). It is used internally by + wolfTPM2_CSR_MakeAndSign_ex when using the callback-based signing approach. + + \sa wolfTPM2_CSR_MakeAndSign_ex + \sa wc_SignCert_cb +*/ +typedef struct TpmSignCbCtx { + WOLFTPM2_DEV* dev; /*!< Pointer to initialized TPM device */ + WOLFTPM2_KEY* key; /*!< Pointer to TPM key used for signing */ +} TpmSignCbCtx; #endif /* buffer similar to TPM2B_MAX_BUFFER that can be used */ From c3f8702afb19ed438fcc48d07f7372793586975b Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Thu, 8 Jan 2026 15:30:45 -0700 Subject: [PATCH 2/3] Fix NULL for the key parameter --- src/tpm2_wrap.c | 65 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 6a16854c..abd5fb9d 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -7517,26 +7517,65 @@ static int CSR_MakeAndSign_Cb(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, { int rc = 0; TpmSignCbCtx signCtx; + union { + #ifndef NO_RSA + RsaKey rsa; + #endif + #ifdef HAVE_ECC + ecc_key ecc; + #endif + } wolfKey; if (dev == NULL || csr == NULL || key == NULL || out == NULL) { return BAD_FUNC_ARG; } + XMEMSET(&wolfKey, 0, sizeof(wolfKey)); + + /* Extract public key from TPM key into wolfCrypt key structure */ + if (keyType == ECC_TYPE) { + #ifdef HAVE_ECC + rc = wc_ecc_init(&wolfKey.ecc); + if (rc == 0) { + /* load public portion of key into wolf ECC Key */ + rc = wolfTPM2_EccKey_TpmToWolf(dev, key, &wolfKey.ecc); + } + #else + rc = NOT_COMPILED_IN; + #endif + } + else if (keyType == RSA_TYPE) { + #ifndef NO_RSA + rc = wc_InitRsaKey(&wolfKey.rsa, NULL); + if (rc == 0) { + /* load public portion of key into wolf RSA Key */ + rc = wolfTPM2_RsaKey_TpmToWolf(dev, key, &wolfKey.rsa); + } + #else + rc = NOT_COMPILED_IN; + #endif + } + else { + rc = BAD_FUNC_ARG; + } + /* Setup signing context */ - signCtx.dev = dev; - signCtx.key = key; + if (rc == 0) { + signCtx.dev = dev; + signCtx.key = key; + } - /* Create certificate body */ - if (selfSignCert) { + /* Create certificate body with public key */ + if (rc == 0 && selfSignCert) { #ifdef WOLFSSL_CERT_GEN - rc = wc_MakeCert_ex(&csr->req, out, outSz, keyType, NULL, + rc = wc_MakeCert_ex(&csr->req, out, outSz, keyType, &wolfKey, wolfTPM2_GetRng(dev)); #else rc = NOT_COMPILED_IN; #endif } - else { - rc = wc_MakeCertReq_ex(&csr->req, out, outSz, keyType, NULL); + if (rc == 0 && !selfSignCert) { + rc = wc_MakeCertReq_ex(&csr->req, out, outSz, keyType, &wolfKey); } /* Sign using TPM via callback */ @@ -7567,6 +7606,18 @@ static int CSR_MakeAndSign_Cb(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, #endif } + /* Cleanup wolfCrypt key structure */ + if (keyType == ECC_TYPE) { + #ifdef HAVE_ECC + wc_ecc_free(&wolfKey.ecc); + #endif + } + else if (keyType == RSA_TYPE) { + #ifndef NO_RSA + wc_FreeRsaKey(&wolfKey.rsa); + #endif + } + return rc; } From e83c89046fd4e59a97846a4a40bd76c411fa3360 Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Fri, 9 Jan 2026 16:21:19 -0700 Subject: [PATCH 3/3] Fix: key size --- src/tpm2_wrap.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index abd5fb9d..e9abdc73 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -7380,11 +7380,6 @@ static int wolfTPM2_SignCertCb(const byte* in, word32 inLen, #ifdef HAVE_ECC byte sigRS[MAX_ECC_BYTES * 2]; int rsLen = (int)sizeof(sigRS); - word32 keySz; - - /* Get key size for proper R/S formatting */ - keySz = TPM2_GetCurveSize( - tpmCtx->key->pub.publicArea.parameters.eccDetail.curveID); /* Sign using TPM */ rc = wolfTPM2_SignHash(tpmCtx->dev, tpmCtx->key,