RSA verification accepts signature representatives greater than the modulus
The RSA verification path applies the public operation to the supplied signature MPI without first requiring the representative to be in the canonical interval 0 <= s < n. Modular exponentiation therefore treats s and s + k*n identically. A test confirmed that a valid signature and the non-canonical value s+n are both accepted through the public API.
Vulnerable code
In cipher/rsa.c, the RSA verification routine directly calls public:
/* Do RSA computation and compare. */
result = mpi_new (0);
public (result, sig, &pk);
if (DBG_CIPHER)
log_printmpi ("rsa_verify cmp", result);
if (ctx.verify_cmp)
rc = ctx.verify_cmp (&ctx, result);
else
rc = mpi_cmp (result, data) ? GPG_ERR_BAD_SIGNATURE : 0;Why it matters
RSA signature encodings require an integer representative smaller than the modulus. Accepting larger representatives creates signature malleability and can break systems that assume each accepted signature has a canonical integer form -- for example, caches, replay identifiers, or cross-implementation validation. This does not forge a signature for a new message: the attacker needs an already valid signature and constructs an equivalent representative. Serialization limits in some protocols may also prevent carrying s+n, so the severity is LOW.
Proposed fix
Before public, reject a negative sig and any sig for which mpi_cmp(sig, pk.n) >= 0, returning GPG_ERR_BAD_SIGNATURE consistently with other verification failures. Preserve existing encoding-specific checks. Add public-API regression vectors showing that the original signature succeeds while s+n, s+2n, exactly n, and negative representatives fail; cover each supported RSA padding/encoding path.