As I was testing the PKCS1v1.5 implementation inside RELIC, it appears to me that it might be susceptible to a Bleichenbacher-style small exponent signature forgery.
In a nut shell, there are mainly 2 issues in the code (both in relic_cp_rsa.c) that enables the attack:
The checks on the first 2 bytes to see whether they are indeed 0x00 | 0x01 actually doesn't lead to rejection of malformed inputs. Although line 345 and line 351 will set result = RLC_ERR if the prefix bytes do not match the expectation, the result variable is never checked later and will get overwritten on line 374, hence the first 2 bytes can take any arbitrary values and the signature verification will still go through.
More importantly, the do{ ... } while loop on line 357 only checks that the padding has not been terminated with a zero, but it doesn't actually require the each of the padding bytes to be 0xFF, and because of this, the padding can take arbitrary non-zero values and the signature verification will still go through.
Together, this opens up the possibility of a Bleichenbacher-style small exponent signature forgery.
Here is a proof-of-concept forgery attack, based on the test_cp.c given in the source tree:
For convenience I used a somewhat unconventional sized (2496-bit long) modulus. I used OpenSSL to generate it, but you can try it with a different 2496-bit long modulus and the forged signature should still work. The forgery algorithm should also work against "regular" sized (e.g. 2048-bit and 4096-bit long) moduli, though I have yet to have a chance to work on that, and I think the above proof-of-concept already serves the purpose.
Such a forgery should only work when e is small enough (which in most cases means e = 3), and although RELIC by default doesn't generate RSA keys with e = 3, there is a possibility that someone might use e = 3 for specific application & interoperability needs, and nothing in the API is prohibiting the programming from doing it.
In any case, unless the plan is to completely drop the support of PKCS1v1.5, I'd suggest to have the issues in relic_cp_rsa.c fixed, as it is definitely possible (and not really that difficult) to make the signature verification much more robust.
More details on the Bleichenbacher-style signature forgery can be found in academic papers like this and this.
Finally, though it shouldn't matter much, this is the script I used (preset/debug.sh) to configure the build:
Thanks! This code is probably the most embarrassing part of the library. It was written ages ago for a performance experiment and never really rewritten. I suspect there are many more issues hanging in there.
I want to take the opportunity to discontinue support for PKCS 1.5, but first I need to check about practical deployments. In any case, I improved the implementation by inverting the padding logic (assuming it fails first and toggle return in case it passes) and checking more rigorously the pass conditions.
Hi there,
As I was testing the PKCS1v1.5 implementation inside RELIC, it appears to me that it might be susceptible to a Bleichenbacher-style small exponent signature forgery.
In a nut shell, there are mainly 2 issues in the code (both in
relic_cp_rsa.c) that enables the attack:0x00 | 0x01actually doesn't lead to rejection of malformed inputs. Although line 345 and line 351 will setresult = RLC_ERRif the prefix bytes do not match the expectation, theresultvariable is never checked later and will get overwritten on line 374, hence the first 2 bytes can take any arbitrary values and the signature verification will still go through.do{ ... } whileloop on line 357 only checks that the padding has not been terminated with a zero, but it doesn't actually require the each of the padding bytes to be0xFF, and because of this, the padding can take arbitrary non-zero values and the signature verification will still go through.Together, this opens up the possibility of a Bleichenbacher-style small exponent signature forgery.
Here is a proof-of-concept forgery attack, based on the
test_cp.cgiven in the source tree:For convenience I used a somewhat unconventional sized (2496-bit long) modulus. I used OpenSSL to generate it, but you can try it with a different 2496-bit long modulus and the forged signature should still work. The forgery algorithm should also work against "regular" sized (e.g. 2048-bit and 4096-bit long) moduli, though I have yet to have a chance to work on that, and I think the above proof-of-concept already serves the purpose.
Such a forgery should only work when
eis small enough (which in most cases meanse = 3), and although RELIC by default doesn't generate RSA keys withe = 3, there is a possibility that someone might usee = 3for specific application & interoperability needs, and nothing in the API is prohibiting the programming from doing it.In any case, unless the plan is to completely drop the support of PKCS1v1.5, I'd suggest to have the issues in
relic_cp_rsa.cfixed, as it is definitely possible (and not really that difficult) to make the signature verification much more robust.More details on the Bleichenbacher-style signature forgery can be found in academic papers like this and this.
Finally, though it shouldn't matter much, this is the script I used (
preset/debug.sh) to configure the build:The text was updated successfully, but these errors were encountered: