Description
The existing API for RSAES-PKCS1-v1_5 decryption, the RSACryptoServiceProvider.Decrypt
, raises an exception in case the padding is incorrect. This makes users of the API potentially vulnerable to side-channel attacks, like when the attacker is able to provide custom ciphertexts and measure the processing time of them. I.e. if this API is used to implement CMS, XMLenc, JWE, etc. in an online context.
More details of the vulnerability are available on the Marvin Attack page.
There are more-or-less three ways to fix this vulnerability:
- remove the API and support for RSAES-PKCS1-v1_5 decryption completely.
- Upside: can't have bugs in code that doesn't exist: i.e. the issue is definitely resolved
- Downside: Complete API/ABI break, applications that depend on it will simply stop working
- Don't change the API, but slightly alter the behaviour, by making the API return a random but deterministic message in case padding checks fail (implicit rejection, a.k.a. Marvin workaround)
- Upside: Application don't have to be changed, they become automatically protected when when new runtime is used
- Downside: the implicit rejection requires access to the private key, as such, if the key resides on a smartcard or HSM, the protection is not provided unless the smartcard or HSM implements implicit rejection
- Downside: applications that expect the ciphertext to fail RSA decryption when it's decrypted with wrong key may misbehave (it should be noted though that even without implicit rejection there's a non-insignificant chance that a random ciphertext will decrypt to a message). That solution was rejected for the existing API.
- Provide a completely new API that will allocate constant amount of memory and return error state through a variable, not exception, independent of correctness of the RSAES-PKCS#1-v1.5 padding
- Upside: the API can be made side-channel free
- Downside: the applications would need to migrate to use it
- Downside: using such APIs is extremely hard (as illustrated by over a dozen CVEs on the Marvin page for users of exactly such an API from OpenSSL) as it requires side-channel free code on the caller side too
Just for completeness, the solutions can be mixed-and-matched. Adding a new API can be just a first step in removing an API. Providing implicit rejection could be also provided as an alternative padding mode (as a quick and easy fix for existing code). In other words, I don't consider them exclusive options.