mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 15:50:51 +02:00
Add wc_SignCert_cb API for external signing callbacks
This commit is contained in:
@@ -4591,6 +4591,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)])],
|
||||
|
||||
+122
@@ -19987,6 +19987,125 @@ static int test_MakeCertWithCaFalse(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Mock callback for testing wc_SignCert_cb */
|
||||
#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 */
|
||||
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;
|
||||
MockSignCtx* signCtx = (MockSignCtx*)ctx;
|
||||
|
||||
if (signCtx == NULL || signCtx->key == NULL || in == NULL ||
|
||||
out == NULL || outLen == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
(void)sigAlgo;
|
||||
|
||||
#ifndef NO_RSA
|
||||
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) {
|
||||
*outLen = (word32)ret;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_ECC
|
||||
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) {
|
||||
*outLen = outSz;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_CERT_SIGN_CB
|
||||
static int test_wc_SignCert_cb(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && !defined(NO_ASN_TIME)
|
||||
Cert cert;
|
||||
byte der[FOURK_BUF];
|
||||
int derSize = 0;
|
||||
WC_RNG rng;
|
||||
ecc_key key;
|
||||
MockSignCtx signCtx;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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, &signCtx, &rng), BAD_FUNC_ARG);
|
||||
|
||||
ret = wc_ecc_free(&key);
|
||||
ExpectIntEQ(ret, 0);
|
||||
ret = wc_FreeRng(&rng);
|
||||
ExpectIntEQ(ret, 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif /* WOLFSSL_CERT_SIGN_CB */
|
||||
|
||||
static int test_ERR_load_crypto_strings(void)
|
||||
{
|
||||
#if defined(OPENSSL_ALL)
|
||||
@@ -31467,6 +31586,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),
|
||||
|
||||
+360
-149
@@ -32079,23 +32079,110 @@ 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)
|
||||
/* 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 {
|
||||
void* key;
|
||||
int keyType;
|
||||
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 = WC_NO_ERR_TRACE(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->key) {
|
||||
/* For RSA, input is already encoded digest */
|
||||
ret = wc_RsaSSL_Sign(in, inLen, out, *outLen,
|
||||
(RsaKey*)signCtx->key, 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->key) {
|
||||
/* For ECC, input is the raw hash */
|
||||
ret = wc_ecc_sign_hash(in, inLen, out, outLen,
|
||||
signCtx->rng, (ecc_key*)signCtx->key);
|
||||
}
|
||||
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
|
||||
|
||||
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN)
|
||||
if (keyType == ED25519_TYPE && signCtx->key) {
|
||||
/* 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->key) {
|
||||
/* 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) &&
|
||||
signCtx->key) {
|
||||
/* Falcon signs messages, not hashes - cannot use callback path */
|
||||
ret = SIG_TYPE_E;
|
||||
}
|
||||
#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) && signCtx->key) {
|
||||
/* Dilithium signs messages, not hashes - cannot use callback path */
|
||||
ret = SIG_TYPE_E;
|
||||
}
|
||||
#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) &&
|
||||
signCtx->key) {
|
||||
/* Sphincs signs messages, not hashes - cannot use callback path */
|
||||
ret = SIG_TYPE_E;
|
||||
}
|
||||
#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;
|
||||
int ret = 0;
|
||||
|
||||
(void)digestSz;
|
||||
(void)typeH;
|
||||
(void)buf;
|
||||
(void)sz;
|
||||
(void)sig;
|
||||
(void)sigSz;
|
||||
(void)rsaKey;
|
||||
(void)eccKey;
|
||||
(void)ed25519Key;
|
||||
(void)ed448Key;
|
||||
(void)falconKey;
|
||||
@@ -32104,161 +32191,104 @@ 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:
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
/* Setup internal signing context */
|
||||
XMEMSET(&signCtx, 0, sizeof(signCtx));
|
||||
signCtx.rng = rng;
|
||||
|
||||
/* Determine key type and set key pointer */
|
||||
if (rsaKey) {
|
||||
signCtx.key = rsaKey;
|
||||
signCtx.keyType = RSA_TYPE;
|
||||
}
|
||||
#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) {
|
||||
else if (eccKey) {
|
||||
signCtx.key = eccKey;
|
||||
signCtx.keyType = ECC_TYPE;
|
||||
}
|
||||
else {
|
||||
ret = BAD_FUNC_ARG;
|
||||
goto exit_ms;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
|
||||
case CERTSIGN_STATE_ENCODE:
|
||||
#ifndef NO_RSA
|
||||
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);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
|
||||
|
||||
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_SIGN)
|
||||
if (!rsaKey && !eccKey && 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;
|
||||
|
||||
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 (!rsaKey && !eccKey && !ed25519Key && !ed448Key && 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_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);
|
||||
if (ret == 0)
|
||||
ret = outSz;
|
||||
}
|
||||
#endif /* HAVE_SPHINCS */
|
||||
|
||||
if (ret == -1)
|
||||
ret = ALGO_ID_E;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
exit_ms:
|
||||
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
||||
return ret;
|
||||
/* Use unified callback path */
|
||||
ret = MakeSignatureCb(certSignCtx, buf, sz, sig, sigSz,
|
||||
(int)sigAlgoType, signCtx.keyType,
|
||||
InternalSignCb, &signCtx, rng, heap);
|
||||
goto exit_ms;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_NO_MALLOC
|
||||
#ifndef NO_RSA
|
||||
if (rsaKey) {
|
||||
XFREE(certSignCtx->encSig, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
certSignCtx->encSig = NULL;
|
||||
/* 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. */
|
||||
|
||||
#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 /* !NO_RSA */
|
||||
#endif /* HAVE_ED25519 && HAVE_ED25519_SIGN */
|
||||
|
||||
XFREE(certSignCtx->digest, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
certSignCtx->digest = NULL;
|
||||
#endif /* !WOLFSSL_NO_MALLOC */
|
||||
#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 */
|
||||
|
||||
/* reset state */
|
||||
certSignCtx->state = CERTSIGN_STATE_BEGIN;
|
||||
#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_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;
|
||||
}
|
||||
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 (sphincsKey) {
|
||||
word32 outSz = sigSz;
|
||||
ret = wc_sphincs_sign_msg(buf, sz, sig, &outSz, sphincsKey, rng);
|
||||
if (ret == 0)
|
||||
ret = outSz;
|
||||
}
|
||||
#endif /* HAVE_SPHINCS */
|
||||
|
||||
if (ret == -1)
|
||||
ret = ALGO_ID_E;
|
||||
|
||||
exit_ms:
|
||||
if (ret < 0) {
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
}
|
||||
@@ -33964,6 +33994,112 @@ 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;
|
||||
#ifdef WOLFSSL_NO_MALLOC
|
||||
(void)heap;
|
||||
#endif
|
||||
|
||||
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, (word32)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 */
|
||||
#ifndef NO_RSA
|
||||
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);
|
||||
}
|
||||
#endif /* !NO_RSA */
|
||||
FALL_THROUGH;
|
||||
|
||||
case CERTSIGN_STATE_DO:
|
||||
certSignCtx->state = CERTSIGN_STATE_DO;
|
||||
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
|
||||
#endif /* !NO_RSA */
|
||||
{
|
||||
/* ECC: pass raw hash */
|
||||
ret = signCb(certSignCtx->digest, (word32)digestSz,
|
||||
sig, &outLen, sigAlgoType, keyType, signCtx);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = (int)outLen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* 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,
|
||||
@@ -34262,6 +34398,81 @@ 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
|
||||
*/
|
||||
#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)
|
||||
{
|
||||
int sigSz = 0;
|
||||
CertSignCtx certSignCtx_lcl;
|
||||
CertSignCtx* certSignCtx = &certSignCtx_lcl;
|
||||
|
||||
if (signCb == NULL || buf == 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);
|
||||
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (sigSz == WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
||||
/* Not free'ing certSignCtx->sig here because it could still be in use
|
||||
* with async operations. */
|
||||
return sigSz;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
#endif /* WOLFSSL_CERT_SIGN_CB */
|
||||
|
||||
|
||||
|
||||
|
||||
WOLFSSL_ABI
|
||||
int wc_MakeSelfCert(Cert* cert, byte* buf, word32 buffSz,
|
||||
|
||||
@@ -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 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.
|
||||
\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;
|
||||
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,67 @@ WOLFSSL_API int wc_SignCert_ex(int requestSz, int sType, byte* buf,
|
||||
WC_RNG* rng);
|
||||
WOLFSSL_API int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz,
|
||||
RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng);
|
||||
/*!
|
||||
\ingroup CertManager
|
||||
\brief Sign a certificate or CSR using a callback function.
|
||||
|
||||
This function signs a certificate or Certificate Signing Request (CSR)
|
||||
using a user-provided signing callback. This allows external signing
|
||||
implementations (e.g., TPM, HSM) without requiring the crypto callback
|
||||
infrastructure, making it suitable for FIPS-compliant applications.
|
||||
|
||||
The function performs the following:
|
||||
1. Hashes the certificate/CSR body according to the signature algorithm
|
||||
2. Encodes the hash (RSA) or prepares it for signing (ECC)
|
||||
3. Calls the user-provided callback to perform the actual signing
|
||||
4. Encodes the signature into the certificate/CSR DER structure
|
||||
|
||||
\param requestSz Size of the certificate body to sign (from Cert.bodySz).
|
||||
\param sType Signature algorithm type (e.g., CTC_SHA256wRSA,
|
||||
CTC_SHA256wECDSA).
|
||||
\param buf Buffer containing the certificate/CSR DER data to sign.
|
||||
\param buffSz Total size of the buffer (must be large enough for signature).
|
||||
\param keyType Type of key used for signing (RSA_TYPE, ECC_TYPE, etc.).
|
||||
\param signCb User-provided signing callback function.
|
||||
\param signCtx Context pointer passed to the signing callback.
|
||||
\param rng Random number generator (may be NULL if not needed).
|
||||
|
||||
\return Size of the signed certificate/CSR on success.
|
||||
\return BAD_FUNC_ARG if signCb is NULL or other parameters are invalid.
|
||||
\return BUFFER_E if the buffer is too small for the signed certificate.
|
||||
\return MEMORY_E if memory allocation fails.
|
||||
\return Negative error code on other failures.
|
||||
|
||||
\sa wc_SignCertCb
|
||||
\sa wc_SignCert
|
||||
\sa wc_SignCert_ex
|
||||
\sa wc_MakeCert
|
||||
\sa wc_MakeCertReq
|
||||
|
||||
_Example_
|
||||
\code
|
||||
Cert cert;
|
||||
byte derBuf[4096];
|
||||
int derSz;
|
||||
MySignCtx myCtx;
|
||||
|
||||
wc_InitCert(&cert);
|
||||
|
||||
derSz = wc_MakeCert(&cert, derBuf, sizeof(derBuf), NULL, NULL, &rng);
|
||||
|
||||
derSz = wc_SignCert_cb(cert.bodySz, cert.sigType, derBuf, sizeof(derBuf),
|
||||
RSA_TYPE, mySignCallback, &myCtx, &rng);
|
||||
if (derSz > 0) {
|
||||
printf("Signed certificate is %d bytes\n", derSz);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#ifdef WOLFSSL_CERT_SIGN_CB
|
||||
WOLFSSL_API int wc_SignCert_cb(int requestSz, int sType, byte* buf,
|
||||
word32 buffSz, int keyType,
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user