-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CVE-2020-25658 - Bleichenbacher-style timing oracle in PKCS#1 v1.5 decryption code #165
Comments
The code is basically unchanged for at least 10 years: Lines 120 to 135 in 3f8c551
so we can be reasonably sure that all released versions since 2.1 (the first version that included RSA decryption API) are vulnerable |
Hey guys, this seems like a critical security issue. We've been working with python-jose which depends on this repo. |
|
Thanks for the quick reply. |
Hi @tomato42
Snyk apparently calculated the score here, see here: https://app.snyk.io/vuln/SNYK-PYTHON-RSA-1038401 |
For one, as it's timing based, so it's harder to exploit than issues like https://nvd.nist.gov/vuln/detail/CVE-2017-13098 (https://snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-32031) So I don't think that rating is consistent with other similar issues. |
Thanks for the report & the interest, people, it's much appreciated. How about this approach, would that be a proper fix for this issue? def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
blocksize = common.byte_size(priv_key.n)
encrypted = transform.bytes2int(crypto)
decrypted = priv_key.blinded_decrypt(encrypted)
cleartext = transform.int2bytes(decrypted, blocksize)
# Detect leading zeroes in the crypto. These are not reflected in the
# encrypted value (as leading zeroes do not influence the value of an
# integer). This fixes CVE-2020-13757.
crypto_len_bad = len(crypto) > blocksize
# If we can't find the cleartext marker, decryption failed.
cleartext_marker_bad = not compare_digest(cleartext[:2], b'\x00\x02')
# Find the 00 separator between the padding and the message
try:
sep_idx = cleartext.index(b'\x00', 2)
except ValueError:
sep_idx = -1
sep_idx_bad = sep_idx < 0
anything_bad = crypto_len_bad | cleartext_marker_bad | sep_idx_bad
if anything_bad:
raise DecryptionError('Decryption failed')
return cleartext[sep_idx + 1:] The weakest spot here I think is the call to |
the fact that second, in case of failure we definitely can't return part of |
How about using
Oh geesh, that shouldn't have been in here. The exception was just disabled to make it possible to do a timing test, and certainly won't be in the final code ;-) |
yes, that does make for nice and clean code, but again, I don't expect it to have any better timing characteristic than for example of code that attempts side-channel free behaviour see here: https://github.com/openssl/openssl/blob/d8701e25239dc3d0c9d871e53873f592420f71d0/crypto/rsa/rsa_pk1.c#L170-L278 |
Yeah, I made something similar, but looping over each byte and doing some operations there is much slower than what we have now. |
from my previous work on this, I've noticed that subscripting strings and arrays is very expensive (like |
I'm quite sure that the code in dae8ce0 does not fix it. |
Hi, |
|
Thanks @tomato42
How did you end up resolving this issue for you? |
I don't see
I would advise against monkey-patching this code, writing side-channel secure cryptographic code is hard, you really should have any changes around it audited by a cryptographer
I'm not using python-rsa, I just noticed that it's vulnerable and widely used |
Yes, by https in Django for the servers
Let me check once again.
Okay. Will do that for sure.
Ah. I see. |
@sybrenstuvel Thanks for the fix! Could you please release a new version? |
@tomato42 thanks. Then it is quite misleading to have this issue closed. |
Hi, Thanks in advance ! |
@NicoleG25 This is definitely not addressed. Why: the supposed fix dae8ce0 was committed on Nov 15, 2020, but the latest release of this library is 4.6 released at Jun 12, 2020 (see https://pypi.org/project/rsa/#history). I am not a security expert, but as @tomato42 's #165 (comment) above: "I'm quite sure that the code in dae8ce0 does not fix it." Good news is that at least google-auth does not use this problematic decrypt method (see above), so it can be considered false-positive in my use-case. |
Version 4.7 has just been released to pypi. |
Issue still being flagged in scanning for version 4.7 |
What does that mean @dalesit ? |
I can’t say if @dalesit mean the same thing, but here’s what I’m getting from Gitlab Dependency Scanning ( |
Info about the fixed version was never added into the gemnasium vulnerability database https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/pypi/rsa/CVE-2020-25658.yml#L11 |
- Update from 4.0 to 4.8 - Update of rootfile - Changelog - Switch to [Poetry](https://python-poetry.org/) for dependency and release management. - Compatibility with Python 3.10. - Chain exceptions using `raise new_exception from old_exception` ([#157](sybrenstuvel/python-rsa#157)) - Added marker file for PEP 561. This will allow type checking tools in dependent projects to use type annotations from Python-RSA ([#136](sybrenstuvel/python-rsa#136)). - Use the Chinese Remainder Theorem when decrypting with a private key. This makes decryption 2-4x faster ([#163](sybrenstuvel/python-rsa#163)). - Fix picking/unpickling issue introduced in 4.7 ([#173](sybrenstuvel/python-rsa#173)) - Fix threading issue introduced in 4.7 ([#173](sybrenstuvel/python-rsa#173)) - Fix [#165](sybrenstuvel/python-rsa#165): CVE-2020-25658 - Bleichenbacher-style timing oracle in PKCS#1 v1.5 decryption code - Add padding length check as described by PKCS#1 v1.5 (Fixes [#164](sybrenstuvel/python-rsa#164)) - Reuse of blinding factors to speed up blinding operations. Fixes [#162](sybrenstuvel/python-rsa#162). - Declare & test support for Python 3.9 Version 4.4 and 4.6 are almost a re-tagged release of version 4.2. It requires Python 3.5+. To avoid older Python installations from trying to upgrade to RSA 4.4, this is now made explicit in the `python_requires` argument in `setup.py`. There was a mistake releasing 4.4 as "3.5+ only", which made it necessary to retag 4.4 as 4.6 as well. No functional changes compared to version 4.2. Version 4.3 and 4.5 are almost a re-tagged release of version 4.0. It is the last to support Python 2.7. This is now made explicit in the `python_requires` argument in `setup.py`. Python 3.4 is not supported by this release. There was a mistake releasing 4.4 as "3.5+ only", which made it necessary to retag 4.3 as 4.5 as well. Two security fixes have also been backported, so 4.3 = 4.0 + these two fixes. - Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. - Reject cyphertexts (when decrypting) and signatures (when verifying) that have been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks Carnil for pointing this out. - Rolled back the switch to Poetry, and reverted back to using Pipenv + setup.py for dependency management. There apparently is an issue no-binary installs of packages build with Poetry. This fixes [#148](sybrenstuvel/python-rsa#148) - Limited SHA3 support to those Python versions (3.6+) that support it natively. The third-party library that adds support for this to Python 3.5 is a binary package, and thus breaks the pure-Python nature of Python-RSA. This should fix [#147](sybrenstuvel/python-rsa#147). - Added support for Python 3.8. - Dropped support for Python 2 and 3.4. - Added type annotations to the source code. This will make Python-RSA easier to use in your IDE, and allows better type checking. - Added static type checking via [MyPy](http://mypy-lang.org/). - Fix [#129](sybrenstuvel/python-rsa#129) Installing from source gives UnicodeDecodeError. - Switched to using [Poetry](https://poetry.eustace.io/) for package management. - Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This is natively supported by Python 3.6+ and supported via a third-party library on Python 3.5. - Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. - Reject cyphertexts (when decrypting) and signatures (when verifying) that have been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks Adelapie for pointing this out. Signed-off-by: Adolf Belka <adolf.belka@ipfire.org> Reviewed-by: Peter Müller <peter.mueller@ipfire.org>
Morning, just to note that the potential vuln has raised it's head again, with CVE-2020-25658 has been updated with: -
Not sure if there's anything that can be done, apart from to be aware ? |
There are two solutions:
|
Thanks @tomato42 appreciate the assist - I think Put it this way, it's the inclusion of kubernetes-client/python` from PyPi which is then throwing up the CVE, Sonatype scan etc. Thanks again, my friend, you rule 🙇 |
This is correct! We have a couple of open PRs with PKCS#1 v2.0+ functionality, including OAEP, but they haven't seen much activity lately. If you're interested in bringing python-rsa up-to-date and increasing it's security, it would be great if you could take a look!
|
Pardon me if I am not understanding the status here, but is CVE-2020-25658 able to be remediated or not? I am trying to get my arms around all of the collateral and comments on this (not only github, but several other sites as well), but can't seem to get there. I have a NEW CVE alert that just today popped up out of the blue on a few of my AWS Linux2 servers. (CVE-2020-25658 that is). I have been trying to follow the threads on how to remediate, but can't gain any traction. Can someone shed some light please? Not sure what package or fix my be the correct one to mitigate this particular CVE. Thanks! |
the solution to CVE-2020-25658 is not to use python-rsa |
WHAAAAAAAAAAAAAAAAAAAAAAT ?!!?!?!?!?!? :-) |
so. seriously. I shouldn't use it at all? How do I change that package on my production AWS EC2 linux boxes? |
@jevbrowser, dae8ce0 attempts to mitigate Bleichenbacher-style timing attacks. The README.md (6f59ff0) and mitigation-patch (dae8ce0) suggest that pure-Python cannot prevent such timing attacks. (the |
@sybrenstuvel, renaming this issue to Since your README states that timing attacks are a known issue to pure-Python projects, you may want to push back on the CVE assignment (by talking to your CNA--Red Hat). LXD's security policy is a good example for defining what qualifies as a security issue, if that's something you're interested in. |
The addition of the statement that the code is intrinsically insecure against side channels was the result of the CVE, not predating it. Also, you're linking pycryptodome docs, not python-rsa docs... |
oh, sorry @tomato42 I misunderstood what you said about Having the statement in the README because of the report is great. Users need to be aware of the risk. There are a lot of downstream projects that should be wary (:fire::fox_face:). CVEs unfortunately have the double role of communication tool and credit of work. I'm really grateful that issues in python are pointed out so that we can improve. I don't believe this CVE assignment makes sense today as a communication tool. The issue is not something that can be fixed with pure-Python and the risk is communicated near the top of the README. Perhaps this is a broader vulnerability in Python? |
respectfully disagree, while seeing the CVE report may be a false positive (if your code doesn't use
Not really, Python provides generic numerical library, not a cryptographic numerical library. At no point did Python promise that It's an application bug, like if it was using Now, would it be nice to be able to write side-channel secure code from python? sure, but that's a whole another problem (if you're interested in that, I suggest looking into exposing |
Thanks for clarifying. This project is explicitly pure-Python, so I could see this issue as outside the projects security scope. On the other hand, it's helpful to tag downstreams that are affected by a CVE. In either case, it should be clear that timing attacks are not prevented with dae8ce0 and a Fix is not expected. |
Fix sybrenstuvel#165: CVE-2020-25658 - Bleichenbacher-style timing oracle Use as many constant-time comparisons as practical in the `rsa.pkcs1.decrypt` function. `cleartext.index(b'\x00', 2)` will still be non-constant-time. The alternative would be to iterate over all the data byte by byte in Python, which is several orders of magnitude slower. Given that a perfect constant-time implementation is very hard or even impossible to do in Python [1], I chose the more performant option here. [1]: https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/
Fix sybrenstuvel#165: CVE-2020-25658 - Bleichenbacher-style timing oracle Use as many constant-time comparisons as practical in the `rsa.pkcs1.decrypt` function. `cleartext.index(b'\x00', 2)` will still be non-constant-time. The alternative would be to iterate over all the data byte by byte in Python, which is several orders of magnitude slower. Given that a perfect constant-time implementation is very hard or even impossible to do in Python [1], I chose the more performant option here. [1]: https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/
As I've said above, the existing fix doesn't remove the side channel, see issue #230 |
Current PKCS#1 v1.5 decryption code:
python-rsa/rsa/pkcs1.py
Lines 246 to 267 in 6f59ff0
performs the checks on the decrypted value in turn, aborting as soon as first error is found, it also raises an exception in case of errors. This likely provides enough of a timing side channel to mount a Bleichenbacher style attack.
While it's unlikely that a completely side-channel free implementation is possible (see https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ ), it should be possible to minimise the side-channel by making at least the execution path the same irrespective of previous checks and by providing an API that returns a randomly generated secret in case of error (instead of leaking the timing side-channel by rising an exception) for uses that decrypted value directly as an input to a hash or use it as a symmetric key.
The text was updated successfully, but these errors were encountered: