Size cert signature buffers from the key and check sig type vs key

MAX_ENCODED_SIG_SZ grows to ~50KB once SLH-DSA is enabled, yet it was
used to size PKCS#1/signature scratch and output buffers across the
library, wasting stack and heap even for classic RSA/ECC operations.

- Add MAX_ENCODED_CLASSIC_SIG_SZ for RSA/DSA/ECC DigestInfo buffers that
  can never hold a PQC signature.
- Size the certificate/CSR signing output buffer from the signing key at
  runtime instead of the worst-case macro.
- Add overridable WOLFSSL_MAX_SIG_SZ for the WOLFSSL_NO_MALLOC buffer.
- Reject a signature type that does not match the signing key.
This commit is contained in:
Tobias Frauenschläger
2026-06-08 20:14:46 +02:00
parent e05a453944
commit 09b288000c
7 changed files with 459 additions and 109 deletions
+23 -11
View File
@@ -33825,12 +33825,14 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
}
#endif
if (IsAtLeastTLSv1_2(ssl)) {
/* DigestInfo encoding for RSA, never a PQC
* signature -- size to the classic tier. */
WC_DECLARE_VAR(encodedSig, byte,
MAX_ENCODED_SIG_SZ, 0);
MAX_ENCODED_CLASSIC_SIG_SZ, 0);
word32 encSigSz;
WC_ALLOC_VAR_EX(encodedSig, byte,
MAX_ENCODED_SIG_SZ, ssl->heap,
MAX_ENCODED_CLASSIC_SIG_SZ, ssl->heap,
DYNAMIC_TYPE_SIGNATURE,
ERROR_OUT(MEMORY_E,exit_dske));
@@ -33840,7 +33842,9 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
TypeHash(ssl->options.peerHashAlgo));
if (encSigSz != args->sigSz || !args->output ||
XMEMCMP(args->output, encodedSig,
min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) {
min(encSigSz,
MAX_ENCODED_CLASSIC_SIG_SZ))
!= 0) {
ret = VERIFY_SIGN_ERROR;
}
WC_FREE_VAR_EX(encodedSig, ssl->heap,
@@ -35141,9 +35145,14 @@ int SendCertificateVerify(WOLFSSL* ssl)
args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ];
args->extraSz = 0; /* tls 1.2 hash/sig */
/* build encoded signature buffer */
ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ;
ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ,
/* Build encoded signature buffer. This is TLS 1.2 and earlier
* (TLS 1.3 uses SendTls13CertificateVerify), so the signature is
* always classic (RSA/ECC/EdDSA), never PQC -- size to the classic
* tier rather than the (potentially huge) PQC worst case. This
* comfortably holds an ECC/EdDSA signature written directly, or the
* PKCS#1 DigestInfo that is the input to RsaSign. */
ssl->buffers.sig.length = MAX_ENCODED_CLASSIC_SIG_SZ;
ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_SIGNATURE);
if (ssl->buffers.sig.buffer == NULL) {
ERROR_OUT(MEMORY_E, exit_scv);
@@ -36354,8 +36363,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
static int ReEncodeSig(WOLFSSL* ssl)
{ /* For TLS 1.2 re-encode signature */
if (IsAtLeastTLSv1_2(ssl)) {
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap,
DYNAMIC_TYPE_DIGEST);
/* DigestInfo encoding for RSA, never a PQC signature. */
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_DIGEST);
if (encodedSig == NULL)
return MEMORY_E;
ssl->buffers.digest.length =
@@ -39489,10 +39499,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
else
#endif
{
/* DigestInfo encoding for RSA */
#ifndef WOLFSSL_SMALL_STACK
byte encodedSig[MAX_ENCODED_SIG_SZ];
byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#else
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ,
byte* encodedSig =
(byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_SIGNATURE);
if (encodedSig == NULL) {
ERROR_OUT(MEMORY_E, exit_dcv);
@@ -39507,7 +39519,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (args->sendSz != args->sigSz || !args->output ||
XMEMCMP(args->output, encodedSig,
min(args->sigSz, MAX_ENCODED_SIG_SZ)) != 0) {
min(args->sigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) {
ret = VERIFY_CERT_ERROR;
}
+4 -4
View File
@@ -3117,7 +3117,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash,
#else
WC_RNG _tmpRng[1];
WC_RNG* tmpRng = _tmpRng;
byte encodedSig[MAX_ENCODED_SIG_SZ];
byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
unsigned int encSz = 0;
@@ -3158,7 +3158,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash,
#ifdef WOLFSSL_SMALL_STACK
if (ret == 1) {
/* Allocate encoded signature buffer if doing PKCS#1 padding. */
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, NULL,
DYNAMIC_TYPE_SIGNATURE);
if (encodedSig == NULL) {
ret = 0;
@@ -3314,10 +3314,10 @@ int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash,
#ifdef WOLFSSL_SMALL_STACK
unsigned char* encodedSig = NULL;
#else
unsigned char encodedSig[MAX_ENCODED_SIG_SZ];
unsigned char encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
unsigned char* sigDec = NULL;
unsigned int len = MAX_ENCODED_SIG_SZ;
unsigned int len = MAX_ENCODED_CLASSIC_SIG_SZ;
int verLen = 0;
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST)
enum wc_HashType hType = WC_HASH_TYPE_NONE;
+19
View File
@@ -23304,6 +23304,11 @@ static int test_wc_SignCert_cb(void)
/* Invalid keyType for ECC signature */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED25519_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* sigType/key family mismatch: an RSA signature OID against an ECC
* key must be rejected with ALGO_ID_E before any signing happens. */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wRSA, der,
FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
#endif
ret = wc_ecc_free(&key);
@@ -23390,6 +23395,11 @@ static int test_wc_SignCert_cb(void)
/* Invalid keyType */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED448_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* sigType/key family mismatch: an ECDSA signature OID against an RSA
* key must be rejected with ALGO_ID_E before any signing happens. */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wECDSA, der,
FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
#endif
ret = wc_FreeRsaKey(&key);
@@ -24329,6 +24339,15 @@ static int test_wc_MakeCRL_max_crlnum(void)
ExpectIntGT(crlSz, 0);
}
/* --- Negative: a sigType whose family does not match the signing key
* must be rejected before any signature is produced. The RSA key here
* paired with an ECDSA OID must return ALGO_ID_E. --- */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wc_SignCRL_ex(tbsBuf, tbsSz, CTC_SHA256wECDSA,
crlBuf, (word32)bufSz, &rsaKey, NULL, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
}
/* --- Decode the CRL and verify CRL number --- */
if (EXPECT_SUCCESS()) {
ExpectNotNull(decodedCrl = d2i_X509_CRL(NULL, crlBuf, crlSz));
+368 -73
View File
@@ -17030,7 +17030,9 @@ int ConfirmSignature(SignatureCtx* sigCtx,
ERROR_OUT(MEMORY_E, exit_cs);
}
#endif
if (sigSz > MAX_ENCODED_SIG_SZ) {
/* RSA signature copied into sigCpy, which under
* WOLFSSL_NO_MALLOC is sized to MAX_ENCODED_CLASSIC_SIG_SZ. */
if (sigSz > MAX_ENCODED_CLASSIC_SIG_SZ) {
WOLFSSL_MSG("Verify Signature is too big");
ERROR_OUT(BUFFER_E, exit_cs);
}
@@ -17058,7 +17060,7 @@ int ConfirmSignature(SignatureCtx* sigCtx,
WOLFSSL_MSG("Verify Signature is too small");
ERROR_OUT(BUFFER_E, exit_cs);
}
else if (sigSz > MAX_ENCODED_SIG_SZ) {
else if (sigSz > MAX_ENCODED_CLASSIC_SIG_SZ) {
WOLFSSL_MSG("Verify Signature is too big");
ERROR_OUT(BUFFER_E, exit_cs);
}
@@ -17747,13 +17749,15 @@ int ConfirmSignature(SignatureCtx* sigCtx,
if (sigCtx->CertAtt.verifyByTSIP_SCE == 1) break;
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ,
/* Holds a PKCS#1 DigestInfo encoding for RSA verification,
* never a PQC signature -- size to the classic tier. */
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
sigCtx->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (encodedSig == NULL) {
ERROR_OUT(MEMORY_E, exit_cs);
}
#else
byte encodedSig[MAX_ENCODED_SIG_SZ];
byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
verifySz = ret;
@@ -28380,6 +28384,270 @@ static int InternalSignCb(const byte* in, word32 inLen,
#endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ */
/* Return the buffer size needed to hold the raw signature that
* MakeSignature() will produce for the provided key, or a negative error code
* if it cannot be determined. The per-algorithm branches mirror the dispatch
* in MakeSignature() so the two stay in agreement; exactly one key pointer is
* expected to be non-NULL.
*
* Sizing the signature buffer from the key (rather than the worst-case
* MAX_ENCODED_SIG_SZ) avoids allocating tens of KB for classic keys in builds
* that merely enable a PQC algorithm, and is required for LMS/XMSS whose
* parameter-dependent signatures can exceed MAX_ENCODED_SIG_SZ. */
static int GetSignatureBufferSz(RsaKey* rsaKey, ecc_key* eccKey,
ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey,
wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey,
XmssKey* xmssKey)
{
int sigSz = ALGO_ID_E;
(void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key;
(void)falconKey; (void)mldsaKey; (void)slhDsaKey; (void)lmsKey;
(void)xmssKey;
#ifndef NO_RSA
if (rsaKey != NULL)
sigSz = wc_RsaEncryptSize(rsaKey);
#endif
#ifdef HAVE_ECC
if (eccKey != NULL)
sigSz = wc_ecc_sig_size(eccKey);
#endif
#if defined(HAVE_ED25519)
if (ed25519Key != NULL)
sigSz = wc_ed25519_sig_size(ed25519Key);
#endif
#if defined(HAVE_ED448)
if (ed448Key != NULL)
sigSz = wc_ed448_sig_size(ed448Key);
#endif
#if defined(HAVE_FALCON)
if (falconKey != NULL)
sigSz = wc_falcon_sig_size(falconKey);
#endif
#if defined(WOLFSSL_HAVE_MLDSA)
if (mldsaKey != NULL) {
int len = 0;
int rc = wc_MlDsaKey_GetSigLen(mldsaKey, &len);
sigSz = (rc == 0) ? len : rc;
}
#endif
#if defined(WOLFSSL_HAVE_SLHDSA)
if (slhDsaKey != NULL)
sigSz = wc_SlhDsaKey_SigSize(slhDsaKey);
#endif
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
if (lmsKey != NULL) {
word32 len = 0;
int rc = wc_LmsKey_GetSigLen(lmsKey, &len);
sigSz = (rc == 0) ? (int)len : rc;
}
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if (xmssKey != NULL) {
word32 len = 0;
int rc = wc_XmssKey_GetSigLen(xmssKey, &len);
sigSz = (rc == 0) ? (int)len : rc;
}
#endif
/* sigSz still ALGO_ID_E means no (compiled-in) key matched; a getter
* returning 0 means the matched key was not usable. */
if (sigSz == 0)
sigSz = BAD_FUNC_ARG;
return sigSz;
}
#ifndef NO_RSA
/* True if sType is an RSA signature-algorithm OID (any hash, incl. PSS). */
static int IsRsaSigType(int sType)
{
switch (sType) {
case CTC_MD2wRSA:
case CTC_MD5wRSA:
case CTC_SHAwRSA:
case CTC_SHA224wRSA:
case CTC_SHA256wRSA:
case CTC_SHA384wRSA:
case CTC_SHA512wRSA:
case CTC_SHA3_224wRSA:
case CTC_SHA3_256wRSA:
case CTC_SHA3_384wRSA:
case CTC_SHA3_512wRSA:
case CTC_RSASSAPSS:
return 1;
default:
return 0;
}
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
/* True if sType is an ECDSA (or SM2) signature-algorithm OID (any hash). */
static int IsEccSigType(int sType)
{
switch (sType) {
case CTC_SHAwECDSA:
case CTC_SHA224wECDSA:
case CTC_SHA256wECDSA:
case CTC_SHA384wECDSA:
case CTC_SHA512wECDSA:
case CTC_SHA3_224wECDSA:
case CTC_SHA3_256wECDSA:
case CTC_SHA3_384wECDSA:
case CTC_SHA3_512wECDSA:
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case CTC_SM3wSM2:
#endif
return 1;
default:
return 0;
}
}
#endif /* HAVE_ECC */
/* Return the heap hint of whichever signing key is set, or NULL if none does
* (falcon_key has no heap member). Centralizes the lookup shared by the
* certificate/CSR signing entry points. */
static void* GetSigningKeyHeap(RsaKey* rsaKey, ecc_key* eccKey,
ed25519_key* ed25519Key, ed448_key* ed448Key, wc_MlDsaKey* mldsaKey,
SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey)
{
(void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key;
(void)mldsaKey; (void)slhDsaKey; (void)lmsKey; (void)xmssKey;
#ifndef NO_RSA
if (rsaKey != NULL)
return rsaKey->heap;
#endif
#ifdef HAVE_ECC
if (eccKey != NULL)
return eccKey->heap;
#endif
#ifdef HAVE_ED25519
if (ed25519Key != NULL)
return ed25519Key->heap;
#endif
#ifdef HAVE_ED448
if (ed448Key != NULL)
return ed448Key->heap;
#endif
#ifdef WOLFSSL_HAVE_MLDSA
if (mldsaKey != NULL)
return mldsaKey->heap;
#endif
#ifdef WOLFSSL_HAVE_SLHDSA
if (slhDsaKey != NULL)
return slhDsaKey->heap;
#endif
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
if (lmsKey != NULL)
return lmsKey->heap;
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if (xmssKey != NULL)
return xmssKey->heap;
#endif
return NULL;
}
/* Verify that the requested signature type -- which becomes the certificate's
* signatureAlgorithm OID -- is consistent with the signing key. The signature
* is produced by dispatching on the key while the OID is written from sType,
* so a mismatch would emit a certificate whose advertised algorithm
* contradicts the key that signed it (e.g. leaving the wc_InitCert default of
* CTC_SHA256wRSA on a non-RSA key). For RSA/ECC the hash is free to vary, so
* the whole signature-algorithm family is accepted; the remaining algorithms
* have a single (level/parameter-determined) OID. Returns 0 if consistent or
* if there is no key to check, ALGO_ID_E on a mismatch. */
static int CheckSigTypeForKey(int sType, RsaKey* rsaKey, ecc_key* eccKey,
ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey,
wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey,
XmssKey* xmssKey)
{
(void)sType;
(void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key;
(void)falconKey; (void)mldsaKey; (void)slhDsaKey; (void)lmsKey;
(void)xmssKey;
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* sigType 0 indicates preTBS encoding: no signatureAlgorithm to validate. */
if (sType == 0)
return 0;
#endif
#ifndef NO_RSA
if (rsaKey != NULL)
return IsRsaSigType(sType) ? 0 : ALGO_ID_E;
#endif
#ifdef HAVE_ECC
if (eccKey != NULL)
return IsEccSigType(sType) ? 0 : ALGO_ID_E;
#endif
#ifdef HAVE_ED25519
if (ed25519Key != NULL)
return (sType == CTC_ED25519) ? 0 : ALGO_ID_E;
#endif
#ifdef HAVE_ED448
if (ed448Key != NULL)
return (sType == CTC_ED448) ? 0 : ALGO_ID_E;
#endif
#ifdef HAVE_FALCON
if (falconKey != NULL) {
if (falconKey->level == 1)
return (sType == CTC_FALCON_LEVEL1) ? 0 : ALGO_ID_E;
if (falconKey->level == 5)
return (sType == CTC_FALCON_LEVEL5) ? 0 : ALGO_ID_E;
return ALGO_ID_E;
}
#endif
#ifdef WOLFSSL_HAVE_MLDSA
if (mldsaKey != NULL) {
if (mldsaKey->params == NULL)
return ALGO_ID_E;
#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
if (mldsaKey->params->level == WC_ML_DSA_44_DRAFT)
return (sType == CTC_DILITHIUM_LEVEL2) ? 0 : ALGO_ID_E;
if (mldsaKey->params->level == WC_ML_DSA_65_DRAFT)
return (sType == CTC_DILITHIUM_LEVEL3) ? 0 : ALGO_ID_E;
if (mldsaKey->params->level == WC_ML_DSA_87_DRAFT)
return (sType == CTC_DILITHIUM_LEVEL5) ? 0 : ALGO_ID_E;
#endif
if (mldsaKey->level == WC_ML_DSA_44)
return (sType == CTC_ML_DSA_44) ? 0 : ALGO_ID_E;
if (mldsaKey->level == WC_ML_DSA_65)
return (sType == CTC_ML_DSA_65) ? 0 : ALGO_ID_E;
if (mldsaKey->level == WC_ML_DSA_87)
return (sType == CTC_ML_DSA_87) ? 0 : ALGO_ID_E;
return ALGO_ID_E;
}
#endif
#ifdef WOLFSSL_HAVE_SLHDSA
if (slhDsaKey != NULL) {
/* SLH-DSA uses one OID per parameter set for both the key and the
* signature, so the key OID sum equals the CTC signature value. */
int oid;
if (slhDsaKey->params == NULL)
return ALGO_ID_E;
oid = wc_SlhDsaParamToOid(slhDsaKey->params->param);
if (oid < 0)
return ALGO_ID_E;
return (sType == oid) ? 0 : ALGO_ID_E;
}
#endif
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
if (lmsKey != NULL)
return (sType == CTC_HSS_LMS) ? 0 : ALGO_ID_E;
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if (xmssKey != NULL) {
if (xmssKey->is_xmssmt)
return (sType == CTC_XMSSMT) ? 0 : ALGO_ID_E;
return (sType == CTC_XMSS) ? 0 : ALGO_ID_E;
}
#endif
return 0;
}
/* 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
@@ -29658,29 +29926,25 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz,
LmsKey* lmsKey, XmssKey* xmssKey, WC_RNG* rng)
{
int sigSz = 0;
int ret;
void* heap = NULL;
/* The signature buffer must hold the largest signature any supported key
* type can produce. LMS/XMSS signatures are parameter-dependent and can
* exceed MAX_ENCODED_SIG_SZ, so size them from the key at runtime. */
word32 maxSigSz = MAX_ENCODED_SIG_SZ;
/* The signature buffer is sized from the key at runtime. */
int maxSigSz;
CertSignCtx certSignCtx_lcl;
CertSignCtx* certSignCtx = &certSignCtx_lcl;
(void)lmsKey;
(void)xmssKey;
XMEMSET(certSignCtx, 0, sizeof(*certSignCtx));
if (requestSz < 0)
return requestSz;
/* locate ctx */
/* Async crypto reuses the signing key's embedded CertSignCtx; only RSA and
* ECC keys carry one. */
if (rsaKey) {
#ifndef NO_RSA
#ifdef WOLFSSL_ASYNC_CRYPT
certSignCtx = &rsaKey->certSignCtx;
#endif
heap = rsaKey->heap;
#else
return NOT_COMPILED_IN;
#endif /* NO_RSA */
@@ -29690,67 +29954,49 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz,
#ifdef WOLFSSL_ASYNC_CRYPT
certSignCtx = &eccKey->certSignCtx;
#endif
heap = eccKey->heap;
#else
return NOT_COMPILED_IN;
#endif /* HAVE_ECC */
}
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
else if (lmsKey) {
word32 lmsSigSz = 0;
/* The signature algorithm OID is written from sType. Reject a
* mismatch so we never emit a cert whose signatureAlgorithm
* contradicts its HSS/LMS public key. */
if (sType != CTC_HSS_LMS) {
WOLFSSL_MSG("LMS key requires CTC_HSS_LMS signature type");
return ALGO_ID_E;
}
heap = lmsKey->heap;
if (wc_LmsKey_GetSigLen(lmsKey, &lmsSigSz) != 0)
return BAD_FUNC_ARG;
if (lmsSigSz > maxSigSz)
maxSigSz = lmsSigSz;
heap = GetSigningKeyHeap(rsaKey, eccKey, ed25519Key, ed448Key, mldsaKey,
slhDsaKey, lmsKey, xmssKey);
/* The signatureAlgorithm OID is written from sType while the signature is
* produced from the key, so reject a mismatch rather than emit a cert
* whose advertised algorithm contradicts the signing key. */
ret = CheckSigTypeForKey(sType, rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey);
if (ret != 0) {
WOLFSSL_MSG("Signature type does not match signing key");
return ret;
}
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
else if (xmssKey) {
word32 xmssSigSz = 0;
/* sType must match the tree variant (XMSS vs XMSS^MT) so the
* signatureAlgorithm OID agrees with the XMSS public key OID that
* MakeAnyCert derived from key->is_xmssmt. */
if (xmssKey->is_xmssmt ? (sType != CTC_XMSSMT)
: (sType != CTC_XMSS)) {
WOLFSSL_MSG("XMSS signature type does not match key variant");
return ALGO_ID_E;
}
heap = xmssKey->heap;
if (wc_XmssKey_GetSigLen(xmssKey, &xmssSigSz) != 0)
return BAD_FUNC_ARG;
if (xmssSigSz > maxSigSz)
maxSigSz = xmssSigSz;
}
#endif
/* Size the signature buffer from the key in use. */
maxSigSz = GetSignatureBufferSz(rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey);
if (maxSigSz <= 0)
return (maxSigSz < 0) ? maxSigSz : ALGO_ID_E;
#ifndef WOLFSSL_NO_MALLOC
if (certSignCtx->sig == NULL) {
certSignCtx->sig = (byte*)XMALLOC(maxSigSz, heap,
certSignCtx->sig = (byte*)XMALLOC((word32)maxSigSz, heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (certSignCtx->sig == NULL)
return MEMORY_E;
}
#else
/* Without dynamic memory the signature buffer is a fixed
* MAX_ENCODED_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are
* WOLFSSL_MAX_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are
* parameter-dependent and can be larger, so reject rather than overflow
* the fixed buffer. */
if (maxSigSz > MAX_ENCODED_SIG_SZ) {
WOLFSSL_MSG("LMS/XMSS signature larger than fixed CertSignCtx buffer");
if ((word32)maxSigSz > WOLFSSL_MAX_SIG_SZ) {
WOLFSSL_MSG("Signature larger than fixed CertSignCtx buffer");
return BUFFER_E;
}
#endif
sigSz = MakeSignature(certSignCtx, buf, (word32)requestSz, certSignCtx->sig,
maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key,
(word32)maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, rng, (word32)sType,
heap);
#ifdef WOLFSSL_ASYNC_CRYPT
@@ -29805,6 +30051,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf,
SlhDsaKey* slhDsaKey = NULL;
int ret = 0;
int headerSz;
int maxSigSz;
void* heap = NULL;
CertSignCtx certSignCtx_lcl;
CertSignCtx* certSignCtx = &certSignCtx_lcl;
@@ -29865,13 +30112,13 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf,
return BAD_FUNC_ARG;
}
/* locate ctx */
/* Async crypto reuses the signing key's embedded CertSignCtx; only RSA and
* ECC keys carry one. */
if (rsaKey) {
#ifndef NO_RSA
#ifdef WOLFSSL_ASYNC_CRYPT
certSignCtx = &rsaKey->certSignCtx;
#endif
heap = rsaKey->heap;
#else
return NOT_COMPILED_IN;
#endif /* NO_RSA */
@@ -29881,23 +30128,45 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf,
#ifdef WOLFSSL_ASYNC_CRYPT
certSignCtx = &eccKey->certSignCtx;
#endif
heap = eccKey->heap;
#else
return NOT_COMPILED_IN;
#endif /* HAVE_ECC */
}
heap = GetSigningKeyHeap(rsaKey, eccKey, ed25519Key, ed448Key, mldsaKey,
slhDsaKey, NULL, NULL);
/* The signatureAlgorithm OID is written from sType while the signature is
* produced from the key, so reject a mismatch rather than emit a cert
* whose advertised algorithm contradicts the signing key. */
ret = CheckSigTypeForKey(sType, rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, NULL, NULL);
if (ret != 0) {
WOLFSSL_MSG("Signature type does not match signing key");
return ret;
}
/* Size the signature buffer from the key in use. */
maxSigSz = GetSignatureBufferSz(rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, NULL, NULL);
if (maxSigSz <= 0)
return (maxSigSz < 0) ? maxSigSz : ALGO_ID_E;
#ifndef WOLFSSL_NO_MALLOC
if (certSignCtx->sig == NULL) {
certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap,
certSignCtx->sig = (byte*)XMALLOC((word32)maxSigSz, heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (certSignCtx->sig == NULL)
return MEMORY_E;
}
#else
if ((word32)maxSigSz > WOLFSSL_MAX_SIG_SZ) {
WOLFSSL_MSG("Signature larger than fixed CertSignCtx buffer");
return BUFFER_E;
}
#endif
ret = MakeSignature(certSignCtx, buf, (word32)bufSz, certSignCtx->sig,
MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key,
(word32)maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key,
falconKey, mldsaKey, slhDsaKey, NULL, NULL, rng, (word32)sType, heap);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
@@ -30050,6 +30319,7 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz,
WC_RNG* rng)
{
int sigSz = 0;
word32 sigCap = MAX_ENCODED_CLASSIC_SIG_SZ;
CertSignCtx certSignCtx_lcl;
CertSignCtx* certSignCtx = &certSignCtx_lcl;
@@ -30076,22 +30346,40 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz,
return NOT_COMPILED_IN;
#endif
/* The callback produces the signature for keyType while the cert's
* signatureAlgorithm OID is written from sType, so reject a family
* mismatch (e.g. an ECDSA OID with an RSA key). */
#ifndef NO_RSA
if (keyType == RSA_TYPE && !IsRsaSigType(sType))
return ALGO_ID_E;
#endif
#ifdef HAVE_ECC
if (keyType == ECC_TYPE && !IsEccSigType(sType))
return ALGO_ID_E;
#endif
XMEMSET(certSignCtx, 0, sizeof(*certSignCtx));
if (requestSz < 0) {
return requestSz;
}
/* keyType is restricted to RSA_TYPE/ECC_TYPE above, so the signature is
* a classic (non-PQC) one and fits MAX_ENCODED_CLASSIC_SIG_SZ. */
#ifndef WOLFSSL_NO_MALLOC
certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (certSignCtx->sig == NULL) {
return MEMORY_E;
}
#else
/* Don't claim more capacity than the fixed sig buffer really has. */
if (sigCap > (word32)sizeof(certSignCtx->sig))
sigCap = (word32)sizeof(certSignCtx->sig);
#endif
sigSz = MakeSignatureCb(certSignCtx, buf, (word32)requestSz,
certSignCtx->sig, MAX_ENCODED_SIG_SZ, sType, keyType,
certSignCtx->sig, sigCap, sType, keyType,
signCb, signCtx, rng, NULL);
#ifdef WOLFSSL_ASYNC_CRYPT
@@ -36611,6 +36899,7 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType,
{
int ret;
int sigSz;
word32 sigCap = MAX_ENCODED_CLASSIC_SIG_SZ;
CertSignCtx certSignCtx_lcl;
CertSignCtx* certSignCtx = &certSignCtx_lcl;
void* heap = NULL;
@@ -36622,38 +36911,44 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType,
if (rsaKey != NULL && eccKey != NULL)
return BAD_FUNC_ARG;
/* The CRL's signatureAlgorithm OID is written from sType while the
* signature is produced from the key, so reject a mismatch. */
ret = CheckSigTypeForKey(sType, rsaKey, eccKey, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
if (ret != 0) {
WOLFSSL_MSG("Signature type does not match signing key");
return ret;
}
XMEMSET(certSignCtx, 0, sizeof(*certSignCtx));
#ifndef NO_RSA
if (rsaKey != NULL) {
heap = rsaKey->heap;
}
#endif
#ifdef HAVE_ECC
if (eccKey != NULL) {
heap = eccKey->heap;
}
#endif
heap = GetSigningKeyHeap(rsaKey, eccKey, NULL, NULL, NULL, NULL, NULL, NULL);
/* Copy TBS to output buffer first */
if ((word32)tbsSz > bufSz)
return BUFFER_E;
XMEMCPY(buf, tbsBuf, (size_t)tbsSz);
/* Only RSA/ECC keys are accepted above, so the signature is a classic
* (non-PQC) one and fits MAX_ENCODED_CLASSIC_SIG_SZ. */
#ifndef WOLFSSL_NO_MALLOC
certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap,
certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (certSignCtx->sig == NULL)
return MEMORY_E;
/* Initialize first byte to avoid static analysis warnings about using
* uninitialized memory if MakeSignature fails before writing sig. */
certSignCtx->sig[0] = 0;
#else
/* Don't claim more capacity than the fixed sig buffer really has. */
if (sigCap > (word32)sizeof(certSignCtx->sig))
sigCap = (word32)sizeof(certSignCtx->sig);
#endif
/* Create signature */
sigSz = MakeSignature(certSignCtx, buf, (word32)tbsSz, certSignCtx->sig,
MAX_ENCODED_SIG_SZ, rsaKey, eccKey, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, rng, (word32)sType, heap);
sigCap, rsaKey, eccKey, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, rng, (word32)sType, heap);
if (sigSz < 0) {
#ifndef WOLFSSL_NO_MALLOC
XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER);
+5 -3
View File
@@ -46,8 +46,10 @@
#ifndef MAX_DER_DIGEST_ASN_SZ
#define MAX_DER_DIGEST_ASN_SZ 36
#endif
#ifndef MAX_ENCODED_SIG_SZ
#define MAX_ENCODED_SIG_SZ 1024 /* Supports 8192 bit keys */
/* Fallback when asn.h (which defines MAX_ENCODED_CLASSIC_SIG_SZ) is not
* available. Sized to hold an RSA-modulus signature. */
#ifndef MAX_ENCODED_CLASSIC_SIG_SZ
#define MAX_ENCODED_CLASSIC_SIG_SZ 1024 /* Supports 8192 bit keys */
#endif
#endif
@@ -289,7 +291,7 @@ int wc_SignatureVerifyHash(
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte *plain_data;
#else
ALIGN64 byte plain_data[MAX_ENCODED_SIG_SZ];
ALIGN64 byte plain_data[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
/* Make sure the plain text output is at least key size */
+3 -1
View File
@@ -1541,7 +1541,9 @@ struct SignatureCtx {
#endif
#if !defined(NO_RSA) || !defined(NO_DSA)
#ifdef WOLFSSL_NO_MALLOC
byte sigCpy[MAX_ENCODED_SIG_SZ];
/* Holds a copy of the RSA/DSA signature being verified, which is at most
* an RSA-modulus-sized value -- never a (much larger) PQC signature. */
byte sigCpy[MAX_ENCODED_CLASSIC_SIG_SZ];
#else
byte* sigCpy;
#endif
+37 -17
View File
@@ -2375,29 +2375,39 @@ enum Max_ASN {
DSA_INTS = 5, /* DSA ints in private key */
MAX_SALT_SIZE = 64, /* MAX PKCS Salt length */
MAX_IV_SIZE = 64, /* MAX PKCS Iv length */
/* Max classic sig (RSA/DSA/ECC); separate from MAX_ENCODED_SIG_SZ so
* PKCS#1/verify buffers stay small when PQC is enabled for verify-only. */
#if !defined(NO_RSA)
#if defined(USE_FAST_MATH) && defined(FP_MAX_BITS)
MAX_ENCODED_CLASSIC_SIG_SZ = FP_MAX_BITS / 16,
#elif (defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) && \
defined(SP_INT_BITS)
MAX_ENCODED_CLASSIC_SIG_SZ = WC_BITS_TO_BYTES(SP_INT_BITS),
#elif defined(WOLFSSL_HAPROXY)
MAX_ENCODED_CLASSIC_SIG_SZ = 1024, /* Supports 8192 bit keys */
#else
MAX_ENCODED_CLASSIC_SIG_SZ = 512, /* Supports 4096 bit keys */
#endif
#elif defined(HAVE_ECC)
MAX_ENCODED_CLASSIC_SIG_SZ = 140,
#elif defined(HAVE_ED448)
MAX_ENCODED_CLASSIC_SIG_SZ = 114, /* Ed448 signature is 114 bytes */
#else
MAX_ENCODED_CLASSIC_SIG_SZ = 64, /* Ed25519 signature is 64 bytes */
#endif
/* Largest signature any enabled algorithm can produce. Used to size the
* actual signature-output buffers. PQC signatures are large, so prefer
* runtime sizing (see GetSignatureBufferSz in asn.c) where the key is
* available. */
#ifdef WOLFSSL_HAVE_SLHDSA
/* Largest raw SLH-DSA signature (SHAKE-256f) is 49856 bytes; round up
* to leave headroom for ASN.1 wrapping (BIT STRING tag + length). */
MAX_ENCODED_SIG_SZ = 51200,
#elif defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA)
MAX_ENCODED_SIG_SZ = 5120,
#elif !defined(NO_RSA)
#if defined(USE_FAST_MATH) && defined(FP_MAX_BITS)
MAX_ENCODED_SIG_SZ = FP_MAX_BITS / 16,
#elif (defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) && \
defined(SP_INT_BITS)
MAX_ENCODED_SIG_SZ = WC_BITS_TO_BYTES(SP_INT_BITS),
#elif defined(WOLFSSL_HAPROXY)
MAX_ENCODED_SIG_SZ = 1024, /* Supports 8192 bit keys */
#else
MAX_ENCODED_SIG_SZ = 512, /* Supports 4096 bit keys */
#endif
#elif defined(HAVE_ECC)
MAX_ENCODED_SIG_SZ = 140,
#elif defined(HAVE_CURVE448)
MAX_ENCODED_SIG_SZ = 114,
#else
MAX_ENCODED_SIG_SZ = 64,
MAX_ENCODED_SIG_SZ = MAX_ENCODED_CLASSIC_SIG_SZ,
#endif
MAX_ALGO_SZ = 20,
MAX_LENGTH_SZ = WOLFSSL_ASN_MAX_LENGTH_SZ, /* Max length size for DER encoding */
@@ -2457,6 +2467,16 @@ enum Max_ASN {
#define MAX_SIG_SZ MAX_ENCODED_SIG_SZ
/* Size of the fixed signature buffer embedded in CertSignCtx under
* WOLFSSL_NO_MALLOC, and the reject threshold used by the cert/CSR signing
* paths when dynamic memory is unavailable. Defaults to the largest signature
* any enabled algorithm can produce. Override (e.g. via user_settings.h) to
* fit a specific LMS/XMSS parameter set, or to shrink builds that only sign
* with classic/compact algorithms. */
#ifndef WOLFSSL_MAX_SIG_SZ
#define WOLFSSL_MAX_SIG_SZ MAX_ENCODED_SIG_SZ
#endif
#if defined(WOLFSSL_CERT_GEN) || defined(HAVE_OCSP_RESPONDER)
/* Used in asn.c MakeSignature for ECC and RSA non-blocking/async */
enum CertSignState {
@@ -2468,7 +2488,7 @@ enum Max_ASN {
typedef struct CertSignCtx {
#ifdef WOLFSSL_NO_MALLOC
byte sig[MAX_ENCODED_SIG_SZ];
byte sig[WOLFSSL_MAX_SIG_SZ];
byte digest[WC_MAX_DIGEST_SIZE];
#ifndef NO_RSA
byte encSig[MAX_DER_DIGEST_SZ];