From 868dc3c25404d3be232c209ec15f976e434668d5 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 10 Feb 2017 14:56:55 +0100 Subject: Limit SSL_write bufsize to avoid OverflowErrors (#603) * limit SSL_write bufsize to avoid OverflowErrors * fix .send() truncation, add test --- src/OpenSSL/SSL.py | 10 +++++++++- tests/test_ssl.py | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index d4158d4..8bbde5b 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -1455,6 +1455,8 @@ class Connection(object): buf = str(buf) if not isinstance(buf, bytes): raise TypeError("data must be a memoryview, buffer or byte string") + if len(buf) > 2147483647: + raise ValueError("Cannot send more than 2**31-1 bytes at once.") result = _lib.SSL_write(self._ssl, buf, len(buf)) self._raise_ssl_error(self._ssl, result) @@ -1486,7 +1488,13 @@ class Connection(object): data = _ffi.new("char[]", buf) while left_to_send: - result = _lib.SSL_write(self._ssl, data + total_sent, left_to_send) + # SSL_write's num arg is an int, + # so we cannot send more than 2**31-1 bytes at once. + result = _lib.SSL_write( + self._ssl, + data + total_sent, + min(left_to_send, 2147483647) + ) self._raise_ssl_error(self._ssl, result) total_sent += result left_to_send -= result diff --git a/tests/test_ssl.py b/tests/test_ssl.py index d2a56b7..44a042b 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -6,6 +6,7 @@ Unit tests for :mod:`OpenSSL.SSL`. """ import datetime +import sys import uuid from gc import collect, get_referrers @@ -2662,6 +2663,14 @@ class TestConnectionGetCipherList(object): assert isinstance(cipher, str) +class VeryLarge(bytes): + """ + Mock object so that we don't have to allocate 2**31 bytes + """ + def __len__(self): + return 2**31 + + class TestConnectionSend(object): """ Tests for `Connection.send`. @@ -2725,6 +2734,21 @@ class TestConnectionSend(object): assert count == 2 assert client.recv(2) == b'xy' + @pytest.mark.skipif( + sys.maxsize < 2**31, + reason="sys.maxsize < 2**31 - test requires 64 bit" + ) + def test_buf_too_large(self): + """ + When passed a buffer containing >= 2**31 bytes, + `Connection.send` bails out as SSL_write only + accepts an int for the buffer length. + """ + connection = Connection(Context(TLSv1_METHOD), None) + with pytest.raises(ValueError) as exc_info: + connection.send(VeryLarge()) + exc_info.match(r"Cannot send more than .+ bytes at once") + def _make_memoryview(size): """ -- cgit v1.2.1