mirror of https://github.com/wolfSSL/wolfTPM.git
F-3499 - https://fenrir.wolfssl.com/finding/3499 - wolfTPM2_SignHashScheme/VerifyHashTicket: reject mismatched digest size for RSA, gate ECDSA
pad/truncatepull/496/head
parent
ae4ebe764d
commit
68bf667c91
|
|
@ -4955,10 +4955,6 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
|
|||
/* set session auth for key */
|
||||
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
|
||||
|
||||
/* verify input cannot exceed buffer */
|
||||
if (digestSz > (int)sizeof(signIn.digest.buffer))
|
||||
digestSz = (int)sizeof(signIn.digest.buffer);
|
||||
|
||||
XMEMSET(&signIn, 0, sizeof(signIn));
|
||||
signIn.keyHandle = key->handle.hndl;
|
||||
signIn.digest.size = (UINT16)TPM2_GetHashDigestSize(hashAlg);
|
||||
|
|
@ -4966,13 +4962,30 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
|
|||
signIn.digest.size > sizeof(signIn.digest.buffer)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
/* if digest provided is smaller than key size then zero pad leading */
|
||||
if (digestSz < signIn.digest.size) {
|
||||
XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz], digest,
|
||||
digestSz);
|
||||
/* Hard upper bound: digest must fit the message-buffer. */
|
||||
if (digestSz < 0 || digestSz > (int)sizeof(signIn.digest.buffer)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (key->pub.publicArea.type != TPM_ALG_ECC) {
|
||||
/* RSA: digest size must match the declared hash algorithm.
|
||||
* Silently zero-padding produces a signature over crafted
|
||||
* but incorrect content, so this is a caller error. */
|
||||
if (digestSz != (int)signIn.digest.size) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
XMEMCPY(signIn.digest.buffer, digest, digestSz);
|
||||
}
|
||||
else {
|
||||
XMEMCPY(signIn.digest.buffer, digest, digestSz);
|
||||
/* ECDSA: digests shorter than hashAlg's size are left-padded with
|
||||
* zeros; longer digests are silently truncated to hashAlg's size
|
||||
* (TCG Part 1 - ECDSA admits short or long inputs). */
|
||||
if (digestSz < (int)signIn.digest.size) {
|
||||
XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz],
|
||||
digest, digestSz);
|
||||
}
|
||||
else {
|
||||
XMEMCPY(signIn.digest.buffer, digest, signIn.digest.size);
|
||||
}
|
||||
}
|
||||
signIn.inScheme.scheme = sigAlg;
|
||||
signIn.inScheme.details.any.hashAlg = hashAlg;
|
||||
|
|
@ -5119,10 +5132,6 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
|
|||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* verify input cannot exceed buffer */
|
||||
if (digestSz > (int)sizeof(verifySigIn.digest.buffer))
|
||||
digestSz = (int)sizeof(verifySigIn.digest.buffer);
|
||||
|
||||
/* set session auth for key */
|
||||
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
|
||||
|
||||
|
|
@ -5133,13 +5142,27 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
|
|||
verifySigIn.digest.size > sizeof(verifySigIn.digest.buffer)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
/* if digest provided is smaller than key size then zero pad leading */
|
||||
if (digestSz < verifySigIn.digest.size) {
|
||||
XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size - digestSz],
|
||||
digest, digestSz);
|
||||
/* Hard upper bound: digest must fit the message-buffer. */
|
||||
if (digestSz < 0 || digestSz > (int)sizeof(verifySigIn.digest.buffer)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (key->pub.publicArea.type != TPM_ALG_ECC) {
|
||||
/* RSA: digest size must match the declared hash algorithm. */
|
||||
if (digestSz != (int)verifySigIn.digest.size) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
|
||||
}
|
||||
else {
|
||||
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
|
||||
/* ECDSA: short digests are left-padded with zeros, longer digests
|
||||
* are silently truncated to hashAlg's size. */
|
||||
if (digestSz < (int)verifySigIn.digest.size) {
|
||||
XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size -
|
||||
digestSz], digest, digestSz);
|
||||
}
|
||||
else {
|
||||
XMEMCPY(verifySigIn.digest.buffer, digest, verifySigIn.digest.size);
|
||||
}
|
||||
}
|
||||
verifySigIn.signature.sigAlg = sigAlg;
|
||||
signature->any.hashAlg = hashAlg;
|
||||
|
|
|
|||
|
|
@ -1982,6 +1982,9 @@ static void test_wolfTPM2_LoadEccPublicKey_Ex(void)
|
|||
printf("Test TPM Wrapper:\tLoadEccPublicKey_ex:\tSkipped\n");
|
||||
return;
|
||||
}
|
||||
/* Flush any transient objects left by previous tests so CreatePrimary
|
||||
* does not get TPM_RC_OBJECT_MEMORY on a busy simulator. */
|
||||
(void)wolfTPM2_UnloadHandles_AllTransient(&dev);
|
||||
|
||||
/* Create an ECC SRK to harvest valid P-256 X/Y coordinates from. */
|
||||
XMEMSET(&pub, 0, sizeof(pub));
|
||||
|
|
@ -2031,6 +2034,41 @@ static void test_wolfTPM2_LoadEccPublicKey_Ex(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* wolfTPM2_SignHashScheme must reject digest sizes that don't match the
|
||||
* declared hashAlg for RSA keys, instead of silently zero-padding. The
|
||||
* pad-to-hash-size convention is preserved for ECDSA per spec. */
|
||||
static void test_wolfTPM2_SignHashScheme_DigestSize(void)
|
||||
{
|
||||
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_RSA)
|
||||
int rc;
|
||||
WOLFTPM2_DEV dev;
|
||||
WOLFTPM2_KEY key;
|
||||
byte digest[TPM_MAX_DIGEST_SIZE];
|
||||
byte sig[MAX_RSA_KEY_BYTES];
|
||||
int sigSz = (int)sizeof(sig);
|
||||
|
||||
XMEMSET(&dev, 0, sizeof(dev));
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(digest, 0xCC, sizeof(digest));
|
||||
key.handle.hndl = 0x80000000;
|
||||
key.pub.publicArea.type = TPM_ALG_RSA;
|
||||
|
||||
/* SHA-256 digest (32) but caller declared SHA-512 (64): for RSA this
|
||||
* was previously silently zero-padded; now must return BUFFER_E. */
|
||||
rc = wolfTPM2_SignHashScheme(&dev, &key, digest, 32, sig, &sigSz,
|
||||
TPM_ALG_RSASSA, TPM_ALG_SHA512);
|
||||
AssertIntEQ(rc, BUFFER_E);
|
||||
|
||||
/* Oversized digest (larger than declared hashAlg) is also BUFFER_E. */
|
||||
sigSz = (int)sizeof(sig);
|
||||
rc = wolfTPM2_SignHashScheme(&dev, &key, digest, 64, sig, &sigSz,
|
||||
TPM_ALG_RSASSA, TPM_ALG_SHA256);
|
||||
AssertIntEQ(rc, BUFFER_E);
|
||||
|
||||
printf("Test TPM Wrapper:\tSignHashScheme size:\t\tPassed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* wolfTPM2_RsaEncrypt and wolfTPM2_RsaDecrypt must reject oversized inputs
|
||||
* with BUFFER_E rather than silently truncating to the message buffer
|
||||
* length. The bounds check fires before the TPM is contacted, so this
|
||||
|
|
@ -3482,6 +3520,7 @@ int unit_tests(int argc, char *argv[])
|
|||
test_TPM2_ParseAttest_NvDigest();
|
||||
test_TPM2_BrainpoolCurveMapping();
|
||||
test_wolfTPM2_RsaEncryptDecrypt_OversizedBufferE();
|
||||
test_wolfTPM2_SignHashScheme_DigestSize();
|
||||
test_wolfTPM2_LoadEccPublicKey_Ex();
|
||||
test_TPM2_KeyedHashScheme_XorSerialize();
|
||||
test_TPM2_Signature_EcSchnorrSm2Serialize();
|
||||
|
|
|
|||
Loading…
Reference in New Issue