@@ -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 */
0 commit comments