From ce1bef6f1ee06ac497ca0c837fbd1c7ef6c2472b Mon Sep 17 00:00:00 2001
From: Alex Gaynor <alex.gaynor@gmail.com>
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 -Nru cryptography-2.9.2.orig/CHANGELOG.rst cryptography-2.9.2/CHANGELOG.rst
--- cryptography-2.9.2.orig/CHANGELOG.rst	2020-04-23 00:27:48.000000000 +0200
+++ cryptography-2.9.2/CHANGELOG.rst	2021-06-15 13:29:28.365749615 +0200
@@ -41,6 +41,14 @@
   response.
 * :class:`~cryptography.x509.NameAttribute` values can now be empty strings.
 
+* **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*
+
 .. _v2-8:
 
 2.8 - 2019-10-16
diff -Nru cryptography-2.9.2.orig/docs/spelling_wordlist.txt cryptography-2.9.2/docs/spelling_wordlist.txt
--- cryptography-2.9.2.orig/docs/spelling_wordlist.txt	2020-04-23 00:27:48.000000000 +0200
+++ cryptography-2.9.2/docs/spelling_wordlist.txt	2021-06-15 13:29:28.365749615 +0200
@@ -6,6 +6,7 @@
 Backends
 backends
 bcrypt
+Bleichenbacher
 Blowfish
 boolean
 Botan
diff -Nru cryptography-2.9.2.orig/src/cryptography/hazmat/backends/openssl/rsa.py cryptography-2.9.2/src/cryptography/hazmat/backends/openssl/rsa.py
--- cryptography-2.9.2.orig/src/cryptography/hazmat/backends/openssl/rsa.py	2020-04-23 00:27:48.000000000 +0200
+++ cryptography-2.9.2/src/cryptography/hazmat/backends/openssl/rsa.py	2021-06-15 13:29:28.365749615 +0200
@@ -117,40 +117,20 @@
 
     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()
-    backend.openssl_assert(errors)
-    backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA)
-    if isinstance(key, _RSAPublicKey):
-        backend.openssl_assert(
-            errors[0].reason == backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE
-        )
-        raise ValueError(
-            "Data too long for key size. Encrypt less data or use a "
-            "larger key size."
-        )
-    else:
-        decoding_errors = [
-            backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
-            backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
-            backend._lib.RSA_R_OAEP_DECODING_ERROR,
-            # Though this error looks similar to the
-            # RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts,
-            # rather than on encrypts
-            backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS,
-        ]
-        if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
-            decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
-
-        backend.openssl_assert(errors[0].reason in decoding_errors)
-        raise ValueError("Decryption failed.")
+        raise ValueError("Encryption/decryption failed.")
+    return resbuf
 
 
 def _rsa_sig_determine_padding(backend, key, padding, algorithm):
