@@ -466,28 +466,44 @@ static int wp_rsaa_decrypt(wp_RsaAsymCtx* ctx, unsigned char* out,
466466 if (ok ) {
467467 byte mask ;
468468 byte negMask ;
469-
470- XMEMSET (out , 0 , outSize );
471- PRIVATE_KEY_UNLOCK ();
472- rc = wc_RsaPrivateDecrypt (in , (word32 )inLen , out ,
473- (word32 )outSize , wp_rsa_get_key (ctx -> rsa ));
474- PRIVATE_KEY_LOCK ();
475-
476- /* Constant time checking of master secret. */
477- mask = wp_ct_byte_mask_eq (out [0 ], ctx -> clientVersion >> 8 );
478- mask &= wp_ct_byte_mask_eq (out [1 ], ctx -> clientVersion );
479- if (ctx -> negVersion > 0 ) {
480- /* Check for negotiated version as well. */
481- negMask = wp_ct_byte_mask_eq (out [0 ], ctx -> negVersion >> 8 );
482- negMask &= wp_ct_byte_mask_eq (out [1 ], ctx -> negVersion );
483- mask |= negMask ;
484- }
485- rc &= (int )(char )mask ;
486-
487- if (rc <= 0 ) {
488- WOLFPROV_MSG_DEBUG_RETCODE (WP_LOG_LEVEL_DEBUG , "wc_RsaPrivateDecrypt TLS padding" , rc );
469+ byte rand [WOLFSSL_MAX_MASTER_KEY_LENGTH ];
470+ int i ;
471+
472+ /* Implicit rejection: always generate random fallback
473+ * to prevent Bleichenbacher-style oracle attacks. */
474+ rc = wc_RNG_GenerateBlock (& ctx -> rng , rand ,
475+ WOLFSSL_MAX_MASTER_KEY_LENGTH );
476+ if (rc != 0 ) {
489477 ok = 0 ;
490478 }
479+ if (ok ) {
480+ XMEMSET (out , 0 , outSize );
481+ PRIVATE_KEY_UNLOCK ();
482+ rc = wc_RsaPrivateDecrypt (in , (word32 )inLen , out ,
483+ (word32 )outSize , wp_rsa_get_key (ctx -> rsa ));
484+ PRIVATE_KEY_LOCK ();
485+
486+ /* Constant time checking of master secret. */
487+ mask = wp_ct_byte_mask_eq (out [0 ],
488+ ctx -> clientVersion >> 8 );
489+ mask &= wp_ct_byte_mask_eq (out [1 ], ctx -> clientVersion );
490+ if (ctx -> negVersion > 0 ) {
491+ negMask = wp_ct_byte_mask_eq (out [0 ],
492+ ctx -> negVersion >> 8 );
493+ negMask &= wp_ct_byte_mask_eq (out [1 ],
494+ ctx -> negVersion );
495+ mask |= negMask ;
496+ }
497+ /* Combine decrypt success with version check. */
498+ mask &= wp_ct_int_mask_gte (rc , 1 );
499+
500+ /* Constant-time select: real result or random fallback. */
501+ for (i = 0 ; i < WOLFSSL_MAX_MASTER_KEY_LENGTH ; i ++ ) {
502+ out [i ] = wp_ct_byte_mask_sel (mask , out [i ], rand [i ]);
503+ }
504+ OPENSSL_cleanse (rand , sizeof (rand ));
505+ rc = WOLFSSL_MAX_MASTER_KEY_LENGTH ;
506+ }
491507 }
492508 }
493509 else if (ctx -> padMode == RSA_NO_PADDING ) {
0 commit comments