Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8abdb8a

Browse files
committed
Issue #13634: Add support for querying and disabling SSL compression.
1 parent 3563b18 commit 8abdb8a

6 files changed

Lines changed: 83 additions & 0 deletions

File tree

Doc/library/ssl.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,15 @@ Constants
436436

437437
.. versionadded:: 3.3
438438

439+
.. data:: OP_NO_COMPRESSION
440+
441+
Disable compression on the SSL channel. This is useful if the application
442+
protocol supports its own compression scheme.
443+
444+
This option is only available with OpenSSL 1.0.0 and later.
445+
446+
.. versionadded:: 3.3
447+
439448
.. data:: HAS_SNI
440449

441450
Whether the OpenSSL library has built-in support for the *Server Name
@@ -561,6 +570,16 @@ SSL sockets also have the following additional methods and attributes:
561570
version of the SSL protocol that defines its use, and the number of secret
562571
bits being used. If no connection has been established, returns ``None``.
563572

573+
.. method:: SSLSocket.compression()
574+
575+
Return the compression algorithm being used as a string, or ``None``
576+
if the connection isn't compressed.
577+
578+
If the higher-level protocol supports its own compression mechanism,
579+
you can use :data:`OP_NO_COMPRESSION` to disable SSL-level compression.
580+
581+
.. versionadded:: 3.3
582+
564583
.. method:: SSLSocket.get_channel_binding(cb_type="tls-unique")
565584

566585
Get channel binding data for current connection, as a bytes object. Returns

Lib/ssl.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@
7070
OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1,
7171
OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_ECDH_USE,
7272
)
73+
try:
74+
from _ssl import OP_NO_COMPRESSION
75+
except ImportError:
76+
pass
7377
from _ssl import RAND_status, RAND_egd, RAND_add, RAND_bytes, RAND_pseudo_bytes
7478
from _ssl import (
7579
SSL_ERROR_ZERO_RETURN,
@@ -330,6 +334,13 @@ def cipher(self):
330334
else:
331335
return self._sslobj.cipher()
332336

337+
def compression(self):
338+
self._checkClosed()
339+
if not self._sslobj:
340+
return None
341+
else:
342+
return self._sslobj.compression()
343+
333344
def send(self, data, flags=0):
334345
self._checkClosed()
335346
if self._sslobj:

Lib/test/ssl_servers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def do_GET(self, send_body=True):
9797
stats = {
9898
'session_cache': context.session_stats(),
9999
'cipher': sock.cipher(),
100+
'compression': sock.compression(),
100101
}
101102
body = pprint.pformat(stats)
102103
body = body.encode('utf-8')

Lib/test/test_ssl.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def test_constants(self):
100100
ssl.CERT_REQUIRED
101101
ssl.OP_CIPHER_SERVER_PREFERENCE
102102
ssl.OP_SINGLE_ECDH_USE
103+
if ssl.OPENSSL_VERSION_INFO >= (1, 0):
104+
ssl.OP_NO_COMPRESSION
103105
self.assertIn(ssl.HAS_SNI, {True, False})
104106

105107
def test_random(self):
@@ -1185,7 +1187,12 @@ def server_params_test(client_context, server_context, indata=b"FOO\n",
11851187
if connectionchatty:
11861188
if support.verbose:
11871189
sys.stdout.write(" client: closing connection.\n")
1190+
stats = {
1191+
'compression': s.compression(),
1192+
'cipher': s.cipher(),
1193+
}
11881194
s.close()
1195+
return stats
11891196
finally:
11901197
server.stop()
11911198
server.join()
@@ -1814,6 +1821,25 @@ def test_tls_unique_channel_binding(self):
18141821
server.stop()
18151822
server.join()
18161823

1824+
def test_compression(self):
1825+
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1826+
context.load_cert_chain(CERTFILE)
1827+
stats = server_params_test(context, context,
1828+
chatty=True, connectionchatty=True)
1829+
if support.verbose:
1830+
sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
1831+
self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
1832+
1833+
@unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
1834+
"ssl.OP_NO_COMPRESSION needed for this test")
1835+
def test_compression_disabled(self):
1836+
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
1837+
context.load_cert_chain(CERTFILE)
1838+
stats = server_params_test(context, context,
1839+
chatty=True, connectionchatty=True)
1840+
self.assertIs(stats['compression'], None)
1841+
1842+
18171843
def test_main(verbose=False):
18181844
if support.verbose:
18191845
plats = {

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ Core and Builtins
419419
Library
420420
-------
421421

422+
- Issue #13634: Add support for querying and disabling SSL compression.
423+
422424
- Issue #13627: Add support for SSL Elliptic Curve-based Diffie-Hellman
423425
key exchange, through the SSLContext.set_ecdh_curve() method and the
424426
ssl.OP_SINGLE_ECDH_USE option.

Modules/_ssl.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,25 @@ static PyObject *PySSL_cipher (PySSLSocket *self) {
999999
return NULL;
10001000
}
10011001

1002+
static PyObject *PySSL_compression(PySSLSocket *self) {
1003+
#ifdef OPENSSL_NO_COMP
1004+
Py_RETURN_NONE;
1005+
#else
1006+
const COMP_METHOD *comp_method;
1007+
const char *short_name;
1008+
1009+
if (self->ssl == NULL)
1010+
Py_RETURN_NONE;
1011+
comp_method = SSL_get_current_compression(self->ssl);
1012+
if (comp_method == NULL || comp_method->type == NID_undef)
1013+
Py_RETURN_NONE;
1014+
short_name = OBJ_nid2sn(comp_method->type);
1015+
if (short_name == NULL)
1016+
Py_RETURN_NONE;
1017+
return PyUnicode_DecodeFSDefault(short_name);
1018+
#endif
1019+
}
1020+
10021021
static void PySSL_dealloc(PySSLSocket *self)
10031022
{
10041023
if (self->peer_cert) /* Possible not to have one? */
@@ -1452,6 +1471,7 @@ static PyMethodDef PySSLMethods[] = {
14521471
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
14531472
PySSL_peercert_doc},
14541473
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
1474+
{"compression", (PyCFunction)PySSL_compression, METH_NOARGS},
14551475
{"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
14561476
PySSL_SSLshutdown_doc},
14571477
#if HAVE_OPENSSL_FINISHED
@@ -2482,6 +2502,10 @@ PyInit__ssl(void)
24822502
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
24832503
SSL_OP_CIPHER_SERVER_PREFERENCE);
24842504
PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
2505+
#ifdef SSL_OP_NO_COMPRESSION
2506+
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
2507+
SSL_OP_NO_COMPRESSION);
2508+
#endif
24852509

24862510
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
24872511
r = Py_True;

0 commit comments

Comments
 (0)