From ce1bef6f1ee06ac497ca0c837fbd1c7ef6c2472b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 25 Oct 2020 19:01:50 -0400 Subject: [PATCH] Attempt to mitigate Bleichenbacher attacks on RSA decryption --- CHANGELOG.rst | 6 +++++ docs/spelling_wordlist.txt | 1 + .../hazmat/backends/openssl/rsa.py | 26 ++++++++----------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 32a6c8522547..f105465e2eaa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,12 @@ Changelog .. note:: This version is not yet released and is under active development. +* **SECURITY ISSUE:** Attempted to make RSA PKCS#1v1.5 decryption more constant + time, to protect against Bleichenbacher vulnerabilities. Due to limitations + imposed by our API, we cannot completely mitigate this vulnerability and a + future release will contain a new API which is designed to be resilient to + these for contexts where it is required. Credit to **Hubert Kario** for + reporting the issue. *CVE-2020-25659* * Support for OpenSSL 1.0.2 has been removed. Users on older version of OpenSSL will need to upgrade. * Added basic support for PKCS7 signing (including SMIME) via diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 9ec971b36ad2..c8c275142ff7 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -7,6 +7,7 @@ backend Backends backends bcrypt +Bleichenbacher Blowfish boolean Botan diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index 423f6878c124..2c7b0e333e1f 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -119,23 +119,19 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): outlen = backend._ffi.new("size_t *", buf_size) buf = backend._ffi.new("unsigned char[]", buf_size) + # Everything from this line onwards is written with the goal of being as + # constant-time as is practical given the constraints of Python and our + # API. See Bleichenbacher's '98 attack on RSA, and its many many variants. + # As such, you should not attempt to change this (particularly to "clean it + # up") without understanding why it was written this way (see + # Chesterton's Fence), and without measuring to verify you have not + # introduced observable time differences. res = crypt(pkey_ctx, buf, outlen, data, len(data)) + resbuf = backend._ffi.buffer(buf)[: outlen[0]] + backend._lib.ERR_clear_error() if res <= 0: - _handle_rsa_enc_dec_error(backend, key) - - return backend._ffi.buffer(buf)[: outlen[0]] - - -def _handle_rsa_enc_dec_error(backend, key): - errors = backend._consume_errors_with_text() - if isinstance(key, _RSAPublicKey): - raise ValueError( - "Data too long for key size. Encrypt less data or use a " - "larger key size.", - errors, - ) - else: - raise ValueError("Decryption failed.", errors) + raise ValueError("Encryption/decryption failed.") + return resbuf def _rsa_sig_determine_padding(backend, key, padding, algorithm):