Add TPM support for wc_SignCert_cb callback API

pull/450/head
jackctj117 2026-01-08 15:20:21 -07:00
parent 1458001858
commit 2f4cd41edc
3 changed files with 267 additions and 5 deletions

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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 */