Skip to content

Commit b0e115e

Browse files
committed
add signature negative verify tests
1 parent 4143a11 commit b0e115e

3 files changed

Lines changed: 100 additions & 0 deletions

File tree

tests/api/test_dsa.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,19 @@ int test_wc_DsaSignVerify(void)
117117
ExpectIntEQ(wc_DsaVerify(hash, signature, NULL, &answer), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
118118
ExpectIntEQ(wc_DsaVerify(hash, signature, &key, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
119119

120+
/* Negative: tampered hash deterministically reaches the
121+
* mp_cmp(r, v) == MP_EQ check — r and s are unmodified so the
122+
* sanity-range gate is passed and verify math produces v != r. */
123+
{
124+
byte badHash[WC_SHA_DIGEST_SIZE];
125+
126+
XMEMCPY(badHash, hash, sizeof(badHash));
127+
badHash[0] ^= 0x01;
128+
answer = 1;
129+
ExpectIntEQ(wc_DsaVerify(badHash, signature, &key, &answer), 0);
130+
ExpectIntEQ(answer, 0);
131+
}
132+
120133
#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && defined(WOLFSSL_PUBLIC_MP)
121134
/* hard set q to 0 and test fail case */
122135
mp_free(&key.q);

tests/api/test_rsa.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,91 @@ int test_wc_RsaPSS_Verify(void)
491491
return EXPECT_RESULT();
492492
} /* END test_wc_RsaPSS_Verify */
493493

494+
/*
495+
* Negative test for the 0xbc terminator check in RsaUnPad_PSS.
496+
*
497+
* Positive KAT tests catch a constant change (0xbc -> 0xbd), but a subtle
498+
* mutation of the returned error code would survive tests that only check
499+
* for any nonzero return. Here we construct a signature whose recovered
500+
* encoded message has a wrong terminator byte and assert the exact return
501+
* value is BAD_PADDING_E.
502+
*
503+
* Method: sign a message, use wc_RsaDirect with RSA_PUBLIC_DECRYPT to
504+
* recover the encoded message, flip the terminator byte, then use
505+
* wc_RsaDirect with RSA_PRIVATE_ENCRYPT to re-sign. wc_RsaPSS_Verify on
506+
* the re-signed block must return BAD_PADDING_E from the terminator check
507+
* (which runs before the MGF/salt consistency checks).
508+
*/
509+
int test_wc_RsaPSS_BadTerminator(void)
510+
{
511+
EXPECT_DECLS;
512+
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && !defined(HAVE_SELFTEST) && \
513+
!defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) && defined(WC_RSA_PSS) && \
514+
(defined(WC_RSA_DIRECT) || defined(WC_RSA_NO_PADDING) || \
515+
defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
516+
RsaKey key;
517+
WC_RNG rng;
518+
const char* msg = "This is the string to be signed";
519+
unsigned char sig[2048/8];
520+
unsigned char em[2048/8];
521+
unsigned char badSig[2048/8];
522+
unsigned char verifyOut[2048/8];
523+
int sigLen = 0;
524+
word32 emSz = sizeof(em);
525+
word32 badSigSz = sizeof(badSig);
526+
527+
XMEMSET(&key, 0, sizeof(RsaKey));
528+
XMEMSET(&rng, 0, sizeof(WC_RNG));
529+
XMEMSET(em, 0, sizeof(em));
530+
XMEMSET(sig, 0, sizeof(sig));
531+
XMEMSET(badSig, 0, sizeof(badSig));
532+
533+
ExpectIntEQ(wc_InitRsaKey(&key, HEAP_HINT), 0);
534+
ExpectIntEQ(wc_InitRng(&rng), 0);
535+
ExpectIntEQ(wc_RsaSetRNG(&key, &rng), 0);
536+
ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0);
537+
538+
ExpectIntGT(sigLen = wc_RsaPSS_Sign((const byte*)msg,
539+
(word32)XSTRLEN(msg) + 1, sig, sizeof(sig),
540+
WC_HASH_TYPE_SHA256, WC_MGF1SHA256, &key, &rng), 0);
541+
542+
/* Recover encoded message from signature using public key. */
543+
ExpectIntGT(wc_RsaDirect(sig, (word32)sigLen, em, &emSz, &key,
544+
RSA_PUBLIC_DECRYPT, NULL), 0);
545+
546+
/* Assert that RSA_PUBLIC_DECRYPT recovered a well-formed PSS block
547+
* terminated with 0xbc - a failure here indicates a layout change in
548+
* PSS encoding or in wc_RsaDirect, and the whole premise of this
549+
* negative test would be wrong. */
550+
ExpectTrue(emSz > 0);
551+
if (emSz > 0) {
552+
ExpectIntEQ((int)em[emSz - 1], 0xbc);
553+
}
554+
555+
/* Gate the tamper+verify path on the recovered byte matching 0xbc so
556+
* a failure of the sanity check above surfaces once rather than
557+
* cascading into the verify assertion. */
558+
if (emSz > 0 && em[emSz - 1] == 0xbc) {
559+
/* Flip the terminator byte from 0xbc to 0xbd. */
560+
em[emSz - 1] = 0xbd;
561+
562+
/* Re-sign the tampered encoded message. */
563+
ExpectIntGT(wc_RsaDirect(em, emSz, badSig, &badSigSz, &key,
564+
RSA_PRIVATE_ENCRYPT, &rng), 0);
565+
566+
/* Verify must fail with BAD_PADDING_E from the terminator check. */
567+
ExpectIntEQ(wc_RsaPSS_Verify(badSig, badSigSz, verifyOut,
568+
sizeof(verifyOut),
569+
WC_HASH_TYPE_SHA256, WC_MGF1SHA256, &key),
570+
WC_NO_ERR_TRACE(BAD_PADDING_E));
571+
}
572+
573+
DoExpectIntEQ(wc_FreeRsaKey(&key), 0);
574+
DoExpectIntEQ(wc_FreeRng(&rng), 0);
575+
#endif
576+
return EXPECT_RESULT();
577+
} /* END test_wc_RsaPSS_BadTerminator */
578+
494579
/*
495580
* Testing wc_RsaPSS_VerifyCheck()
496581
*/

tests/api/test_rsa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int test_wc_RsaPrivateKeyDecodeRaw(void);
3232
int test_wc_MakeRsaKey(void);
3333
int test_wc_CheckProbablePrime(void);
3434
int test_wc_RsaPSS_Verify(void);
35+
int test_wc_RsaPSS_BadTerminator(void);
3536
int test_wc_RsaPSS_VerifyCheck(void);
3637
int test_wc_RsaPSS_VerifyCheckInline(void);
3738
int test_wc_RsaKeyToDer(void);
@@ -52,6 +53,7 @@ int test_wc_RsaDecrypt_BoundsCheck(void);
5253
TEST_DECL_GROUP("rsa", test_wc_MakeRsaKey), \
5354
TEST_DECL_GROUP("rsa", test_wc_CheckProbablePrime), \
5455
TEST_DECL_GROUP("rsa", test_wc_RsaPSS_Verify), \
56+
TEST_DECL_GROUP("rsa", test_wc_RsaPSS_BadTerminator), \
5557
TEST_DECL_GROUP("rsa", test_wc_RsaPSS_VerifyCheck), \
5658
TEST_DECL_GROUP("rsa", test_wc_RsaPSS_VerifyCheckInline), \
5759
TEST_DECL_GROUP("rsa", test_wc_RsaKeyToDer), \

0 commit comments

Comments
 (0)