Skip to content

Commit 2f4cd41

Browse files
committed
Add TPM support for wc_SignCert_cb callback API
1 parent 1458001 commit 2f4cd41

3 files changed

Lines changed: 267 additions & 5 deletions

File tree

examples/csr/csr.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,30 @@ static const char* gClientCertEccFile = ECC_CERT_PEM;
6767
/* --- BEGIN TPM2 CSR Example -- */
6868
/******************************************************************************/
6969

70+
/* Certificate/CSR Signing with TPM:
71+
*
72+
* wolfTPM supports two approaches for TPM-based certificate signing:
73+
*
74+
* 1. NEW CALLBACK-BASED APPROACH (Recommended for FIPS):
75+
* When devId is INVALID_DEVID, wolfTPM2_CSR_MakeAndSign_ex() uses the new
76+
* wc_SignCert_cb() API which calls TPM signing functions directly without
77+
* requiring wolfCrypt crypto callbacks. This approach:
78+
* - Uses TPM crypto directly (no wolfCrypt offloading)
79+
* - Is FIPS-compliant (doesn't rely on wolfCrypt crypto callbacks)
80+
* - Simplifies the code path
81+
*
82+
* 2. CRYPTO CALLBACK APPROACH (Legacy/Backward Compatible):
83+
* When devId is set via wolfTPM2_SetCryptoDevCb(), the legacy crypto
84+
* callback infrastructure is used. This approach:
85+
* - Uses wc_SignCert_ex() which offloads crypto operations to TPM
86+
* - Maintains backward compatibility
87+
* - Requires crypto callback setup
88+
*
89+
* This example demonstrates the crypto callback approach. To use the new
90+
* callback-based approach, pass INVALID_DEVID instead of tpmDevId when calling
91+
* TPM2_CSR_Generate() or wolfTPM2_CSR_MakeAndSign_ex().
92+
*/
93+
7094
static int TPM2_CSR_Generate(WOLFTPM2_DEV* dev, int keyType, WOLFTPM2_KEY* key,
7195
const char* outputPemFile, int makeSelfSignedCert, int devId, int sigType)
7296
{

src/tpm2_wrap.c

Lines changed: 227 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7332,6 +7332,105 @@ typedef struct CSRKey {
73327332
TpmCryptoDevCtx tpmCtx;
73337333
} CSRKey;
73347334

7335+
/*
7336+
* Internal callback function for wc_SignCert_cb that uses TPM for signing.
7337+
*
7338+
* This callback implements the wc_SignCertCb interface to perform certificate
7339+
* and CSR signing using the TPM. It is used internally by CSR_MakeAndSign_Cb
7340+
* when the callback-based signing approach is selected.
7341+
*
7342+
* For RSA keys:
7343+
* - Input is PKCS#1 v1.5 padded digest (already encoded by wolfSSL)
7344+
* - Uses wolfTPM2_RsaDecrypt with TPM_ALG_NULL (no padding) to perform
7345+
* the private key operation for signing
7346+
*
7347+
* For ECC keys:
7348+
* - Input is the raw hash to sign
7349+
* - Uses wolfTPM2_SignHash to sign with TPM
7350+
* - Converts TPM's R||S format to DER-encoded ECDSA signature
7351+
*
7352+
* Parameters:
7353+
* in - Data to sign (encoded for RSA, raw hash for ECC)
7354+
* inLen - Length of input data
7355+
* out - Output buffer for signature
7356+
* outLen - Input: buffer size, Output: signature size
7357+
* sigAlgo - Signature algorithm (not used, determined by keyType)
7358+
* keyType - Key type (RSA_TYPE or ECC_TYPE)
7359+
* ctx - TpmSignCbCtx containing TPM device and key
7360+
*
7361+
* Returns:
7362+
* 0 on success
7363+
* BAD_FUNC_ARG on invalid parameters
7364+
* NOT_COMPILED_IN if key type not supported
7365+
* Other negative values on TPM errors
7366+
*/
7367+
static int wolfTPM2_SignCertCb(const byte* in, word32 inLen,
7368+
byte* out, word32* outLen, int sigAlgo, int keyType, void* ctx)
7369+
{
7370+
int rc;
7371+
TpmSignCbCtx* tpmCtx = (TpmSignCbCtx*)ctx;
7372+
7373+
if (tpmCtx == NULL || tpmCtx->dev == NULL || tpmCtx->key == NULL) {
7374+
return BAD_FUNC_ARG;
7375+
}
7376+
7377+
(void)sigAlgo; /* Algorithm determined by key type */
7378+
7379+
if (keyType == ECC_TYPE) {
7380+
#ifdef HAVE_ECC
7381+
byte sigRS[MAX_ECC_BYTES * 2];
7382+
int rsLen = (int)sizeof(sigRS);
7383+
word32 keySz;
7384+
7385+
/* Get key size for proper R/S formatting */
7386+
keySz = TPM2_GetCurveSize(
7387+
tpmCtx->key->pub.publicArea.parameters.eccDetail.curveID);
7388+
7389+
/* Sign using TPM */
7390+
rc = wolfTPM2_SignHash(tpmCtx->dev, tpmCtx->key,
7391+
in, inLen, sigRS, &rsLen);
7392+
7393+
if (rc == 0) {
7394+
byte *r, *s;
7395+
word32 rLen, sLen;
7396+
7397+
/* Split R and S from concatenated signature */
7398+
rLen = sLen = rsLen / 2;
7399+
r = &sigRS[0];
7400+
s = &sigRS[rLen];
7401+
7402+
/* Encode as DER ECDSA signature */
7403+
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outLen);
7404+
}
7405+
#else
7406+
rc = NOT_COMPILED_IN;
7407+
#endif
7408+
}
7409+
else if (keyType == RSA_TYPE) {
7410+
#ifndef NO_RSA
7411+
int outSz = (int)*outLen;
7412+
7413+
/* For RSA, input is already PKCS#1 v1.5 padded digest
7414+
* Use RSA decrypt (private key operation) for signing */
7415+
rc = wolfTPM2_RsaDecrypt(tpmCtx->dev, tpmCtx->key,
7416+
TPM_ALG_NULL, /* No padding - input is pre-padded */
7417+
in, inLen, out, &outSz);
7418+
7419+
if (rc == 0) {
7420+
*outLen = (word32)outSz;
7421+
}
7422+
#else
7423+
rc = NOT_COMPILED_IN;
7424+
#endif
7425+
}
7426+
else {
7427+
rc = BAD_FUNC_ARG;
7428+
}
7429+
7430+
return rc;
7431+
}
7432+
7433+
73357434
static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key,
73367435
int outFormat, byte* out, int outSz, int selfSignCert)
73377436
{
@@ -7382,6 +7481,96 @@ static int CSR_MakeAndSign(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, CSRKey* key,
73827481
return rc;
73837482
}
73847483

7484+
/*
7485+
* Internal function for CSR/Certificate generation and signing using the
7486+
* callback-based approach.
7487+
*
7488+
* This function generates and signs a Certificate Signing Request (CSR) or
7489+
* self-signed certificate using the new wc_SignCert_cb() API. Unlike the
7490+
* legacy CSR_MakeAndSign() function which requires crypto callback setup,
7491+
* this function calls TPM signing directly via wolfTPM2_SignCertCb().
7492+
*
7493+
* Advantages of this approach:
7494+
* - FIPS compliant (no wolfCrypt crypto offloading)
7495+
* - Simpler code path (no crypto callback infrastructure)
7496+
* - Direct TPM signing without intermediate key structures
7497+
*
7498+
* Parameters:
7499+
* dev - Initialized TPM device
7500+
* csr - CSR structure with subject, extensions, etc.
7501+
* key - TPM key to use for signing
7502+
* keyType - Key type (RSA_TYPE or ECC_TYPE)
7503+
* outFormat - Output format (ENCODING_TYPE_PEM or ENCODING_TYPE_ASN1)
7504+
* out - Output buffer
7505+
* outSz - Size of output buffer
7506+
* selfSignCert - 1 to create self-signed cert, 0 for CSR
7507+
*
7508+
* Returns:
7509+
* Positive value: size of generated CSR/certificate
7510+
* BAD_FUNC_ARG: invalid parameters
7511+
* BUFFER_E: output buffer too small
7512+
* Other negative: error code from wolfSSL or TPM
7513+
*/
7514+
static int CSR_MakeAndSign_Cb(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
7515+
WOLFTPM2_KEY* key, int keyType, int outFormat, byte* out, int outSz,
7516+
int selfSignCert)
7517+
{
7518+
int rc = 0;
7519+
TpmSignCbCtx signCtx;
7520+
7521+
if (dev == NULL || csr == NULL || key == NULL || out == NULL) {
7522+
return BAD_FUNC_ARG;
7523+
}
7524+
7525+
/* Setup signing context */
7526+
signCtx.dev = dev;
7527+
signCtx.key = key;
7528+
7529+
/* Create certificate body */
7530+
if (selfSignCert) {
7531+
#ifdef WOLFSSL_CERT_GEN
7532+
rc = wc_MakeCert_ex(&csr->req, out, outSz, keyType, NULL,
7533+
wolfTPM2_GetRng(dev));
7534+
#else
7535+
rc = NOT_COMPILED_IN;
7536+
#endif
7537+
}
7538+
else {
7539+
rc = wc_MakeCertReq_ex(&csr->req, out, outSz, keyType, NULL);
7540+
}
7541+
7542+
/* Sign using TPM via callback */
7543+
if (rc >= 0) {
7544+
rc = wc_SignCert_cb(csr->req.bodySz, csr->req.sigType, out,
7545+
(word32)outSz, keyType, wolfTPM2_SignCertCb, &signCtx,
7546+
wolfTPM2_GetRng(dev));
7547+
}
7548+
7549+
/* Optionally convert to PEM */
7550+
if (rc >= 0 && outFormat == ENCODING_TYPE_PEM) {
7551+
#ifdef WOLFSSL_DER_TO_PEM
7552+
byte tmp[MAX_CONTEXT_SIZE];
7553+
if (rc > (int)sizeof(tmp)) {
7554+
rc = BUFFER_E;
7555+
}
7556+
else {
7557+
XMEMCPY(tmp, out, rc);
7558+
XMEMSET(out, 0, outSz);
7559+
rc = wc_DerToPem(tmp, (word32)rc, out, outSz,
7560+
selfSignCert ? CERT_TYPE : CERTREQ_TYPE);
7561+
}
7562+
#else
7563+
#ifdef DEBUG_WOLFTPM
7564+
printf("CSR_MakeAndSign_Cb PEM not supported\n");
7565+
#endif
7566+
rc = NOT_COMPILED_IN;
7567+
#endif
7568+
}
7569+
7570+
return rc;
7571+
}
7572+
7573+
73857574
static int CSR_KeySetup(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr, WOLFTPM2_KEY* key,
73867575
CSRKey* csrKey, int sigType, int devId)
73877576
{
@@ -7576,12 +7765,36 @@ int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
75767765
int sigType, int selfSignCert, int devId)
75777766
{
75787767
int rc;
7579-
CSRKey csrKey;
7768+
int keyType;
75807769

75817770
if (dev == NULL || key == NULL || csr == NULL || out == NULL) {
75827771
return BAD_FUNC_ARG;
75837772
}
75847773

7774+
/* Determine key type from TPM key */
7775+
if (key->pub.publicArea.type == TPM_ALG_ECC) {
7776+
keyType = ECC_TYPE;
7777+
}
7778+
else if (key->pub.publicArea.type == TPM_ALG_RSA) {
7779+
keyType = RSA_TYPE;
7780+
}
7781+
else {
7782+
return BAD_FUNC_ARG;
7783+
}
7784+
7785+
/* Set signature type if not specified */
7786+
if (sigType == 0) {
7787+
if (keyType == RSA_TYPE) {
7788+
csr->req.sigType = CTC_SHA256wRSA;
7789+
}
7790+
else if (keyType == ECC_TYPE) {
7791+
csr->req.sigType = CTC_SHA256wECDSA;
7792+
}
7793+
}
7794+
else {
7795+
csr->req.sigType = sigType;
7796+
}
7797+
75857798
/* Set version to 2 for self-signed certificates, 0 for regular CSRs per RFC2986 */
75867799
if (selfSignCert) {
75877800
csr->req.version = 2;
@@ -7590,12 +7803,21 @@ int wolfTPM2_CSR_MakeAndSign_ex(WOLFTPM2_DEV* dev, WOLFTPM2_CSR* csr,
75907803
csr->req.version = 0;
75917804
}
75927805

7593-
rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId);
7594-
if (rc == 0) {
7595-
rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz,
7806+
/* Use new callback-based signing if devId not specified */
7807+
if (devId == INVALID_DEVID) {
7808+
rc = CSR_MakeAndSign_Cb(dev, csr, key, keyType, outFormat, out, outSz,
75967809
selfSignCert);
75977810
}
7598-
CSR_KeyCleanup(dev, &csrKey);
7811+
else {
7812+
/* Fall back to crypto callback approach for backward compatibility */
7813+
CSRKey csrKey;
7814+
rc = CSR_KeySetup(dev, csr, key, &csrKey, sigType, devId);
7815+
if (rc == 0) {
7816+
rc = CSR_MakeAndSign(dev, csr, &csrKey, outFormat, out, outSz,
7817+
selfSignCert);
7818+
}
7819+
CSR_KeyCleanup(dev, &csrKey);
7820+
}
75997821

76007822
return rc;
76017823
}

wolftpm/tpm2_wrap.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ typedef struct WOLFTPM2_HMAC {
109109
typedef struct WOLFTPM2_CSR {
110110
Cert req;
111111
} WOLFTPM2_CSR;
112+
113+
/*!
114+
\ingroup wolfTPM2_Wrappers
115+
\brief Context structure for TPM-based certificate signing callback.
116+
117+
This structure holds the TPM device and key references needed for the
118+
certificate signing callback (wc_SignCertCb). It is used internally by
119+
wolfTPM2_CSR_MakeAndSign_ex when using the callback-based signing approach.
120+
121+
\sa wolfTPM2_CSR_MakeAndSign_ex
122+
\sa wc_SignCert_cb
123+
*/
124+
typedef struct TpmSignCbCtx {
125+
WOLFTPM2_DEV* dev; /*!< Pointer to initialized TPM device */
126+
WOLFTPM2_KEY* key; /*!< Pointer to TPM key used for signing */
127+
} TpmSignCbCtx;
112128
#endif
113129

114130
/* buffer similar to TPM2B_MAX_BUFFER that can be used */

0 commit comments

Comments
 (0)