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

Skip to content

Commit 2d9cb9c

Browse files
committed
Merged revisions 80151 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r80151 | antoine.pitrou | 2010-04-17 19:10:38 +0200 (sam., 17 avril 2010) | 4 lines Issue #8322: Add a *ciphers* argument to SSL sockets, so as to change the available cipher list. Helps fix test_ssl with OpenSSL 1.0.0. ........
1 parent ec8dfeb commit 2d9cb9c

5 files changed

Lines changed: 72 additions & 17 deletions

File tree

Doc/library/ssl.rst

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Functions, Constants, and Exceptions
4747
is a subtype of :exc:`socket.error`, which in turn is a subtype of
4848
:exc:`IOError`.
4949

50-
.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True)
50+
.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)
5151

5252
Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance
5353
of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps
@@ -110,14 +110,23 @@ Functions, Constants, and Exceptions
110110
======================== ========= ========= ========== =========
111111
*client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1**
112112
------------------------ --------- --------- ---------- ---------
113-
*SSLv2* yes no yes* no
113+
*SSLv2* yes no yes no
114114
*SSLv3* yes yes yes no
115115
*SSLv23* yes no yes no
116116
*TLSv1* no no yes yes
117117
======================== ========= ========= ========== =========
118118

119-
In some older versions of OpenSSL (for instance, 0.9.7l on OS X 10.4), an
120-
SSLv2 client could not connect to an SSLv23 server.
119+
.. note::
120+
121+
This information varies depending on the version of OpenSSL.
122+
For instance, in some older versions of OpenSSL (such as 0.9.7l on
123+
OS X 10.4), an SSLv2 client could not connect to an SSLv23 server.
124+
Conversely, starting from 1.0.0, an SSLv23 client will actually
125+
try the SSLv3 protocol unless you explicitly enable SSLv2 ciphers.
126+
127+
The parameter ``ciphers`` sets the available ciphers for this SSL object.
128+
It should be a string in the `OpenSSL cipher list format
129+
<http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_.
121130

122131
The parameter ``do_handshake_on_connect`` specifies whether to do the SSL
123132
handshake automatically after doing a :meth:`socket.connect`, or whether the
@@ -132,6 +141,9 @@ Functions, Constants, and Exceptions
132141
normal EOF in response to unexpected EOF errors raised from the underlying
133142
socket; if :const:`False`, it will raise the exceptions back to the caller.
134143

144+
.. versionchanged:: 2.7
145+
New optional argument *ciphers*.
146+
135147
.. function:: RAND_status()
136148

137149
Returns True if the SSL pseudo-random number generator has been seeded with

Lib/ssl.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
9494
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
9595
do_handshake_on_connect=True,
9696
family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
97-
suppress_ragged_eofs=True):
97+
suppress_ragged_eofs=True, ciphers=None):
9898

9999
if sock is not None:
100100
socket.__init__(self,
@@ -123,7 +123,8 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
123123
try:
124124
self._sslobj = _ssl.sslwrap(self, server_side,
125125
keyfile, certfile,
126-
cert_reqs, ssl_version, ca_certs)
126+
cert_reqs, ssl_version, ca_certs,
127+
ciphers)
127128
if do_handshake_on_connect:
128129
timeout = self.gettimeout()
129130
if timeout == 0.0:
@@ -140,6 +141,7 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
140141
self.cert_reqs = cert_reqs
141142
self.ssl_version = ssl_version
142143
self.ca_certs = ca_certs
144+
self.ciphers = ciphers
143145
self.do_handshake_on_connect = do_handshake_on_connect
144146
self.suppress_ragged_eofs = suppress_ragged_eofs
145147

@@ -325,7 +327,7 @@ def connect(self, addr):
325327
socket.connect(self, addr)
326328
self._sslobj = _ssl.sslwrap(self, False, self.keyfile, self.certfile,
327329
self.cert_reqs, self.ssl_version,
328-
self.ca_certs)
330+
self.ca_certs, self.ciphers)
329331
try:
330332
if self.do_handshake_on_connect:
331333
self.do_handshake()
@@ -345,6 +347,7 @@ def accept(self):
345347
cert_reqs=self.cert_reqs,
346348
ssl_version=self.ssl_version,
347349
ca_certs=self.ca_certs,
350+
ciphers=self.ciphers,
348351
do_handshake_on_connect=
349352
self.do_handshake_on_connect),
350353
addr)
@@ -358,13 +361,14 @@ def wrap_socket(sock, keyfile=None, certfile=None,
358361
server_side=False, cert_reqs=CERT_NONE,
359362
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
360363
do_handshake_on_connect=True,
361-
suppress_ragged_eofs=True):
364+
suppress_ragged_eofs=True, ciphers=None):
362365

363366
return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
364367
server_side=server_side, cert_reqs=cert_reqs,
365368
ssl_version=ssl_version, ca_certs=ca_certs,
366369
do_handshake_on_connect=do_handshake_on_connect,
367-
suppress_ragged_eofs=suppress_ragged_eofs)
370+
suppress_ragged_eofs=suppress_ragged_eofs,
371+
ciphers=ciphers)
368372

369373
# some utility functions
370374

Lib/test/test_ssl.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,23 @@ def test_openssl_version(self):
121121
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
122122
(s, t))
123123

124+
def test_ciphers(self):
125+
if not support.is_resource_enabled('network'):
126+
return
127+
remote = ("svn.python.org", 443)
128+
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
129+
cert_reqs=ssl.CERT_NONE, ciphers="ALL")
130+
s.connect(remote)
131+
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
132+
cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
133+
s.connect(remote)
134+
# Error checking occurs when connecting, because the SSL context
135+
# isn't created before.
136+
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
137+
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
138+
with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
139+
s.connect(remote)
140+
124141

125142
class NetworkedTests(unittest.TestCase):
126143

@@ -234,7 +251,8 @@ def wrap_conn (self):
234251
certfile=self.server.certificate,
235252
ssl_version=self.server.protocol,
236253
ca_certs=self.server.cacerts,
237-
cert_reqs=self.server.certreqs)
254+
cert_reqs=self.server.certreqs,
255+
ciphers=self.server.ciphers)
238256
except:
239257
if self.server.chatty:
240258
handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
@@ -333,7 +351,8 @@ def run (self):
333351

334352
def __init__(self, certificate, ssl_version=None,
335353
certreqs=None, cacerts=None, expect_bad_connects=False,
336-
chatty=True, connectionchatty=False, starttls_server=False):
354+
chatty=True, connectionchatty=False, starttls_server=False,
355+
ciphers=None):
337356
if ssl_version is None:
338357
ssl_version = ssl.PROTOCOL_TLSv1
339358
if certreqs is None:
@@ -342,6 +361,7 @@ def __init__(self, certificate, ssl_version=None,
342361
self.protocol = ssl_version
343362
self.certreqs = certreqs
344363
self.cacerts = cacerts
364+
self.ciphers = ciphers
345365
self.expect_bad_connects = expect_bad_connects
346366
self.chatty = chatty
347367
self.connectionchatty = connectionchatty
@@ -648,12 +668,13 @@ def badCertTest (certfile):
648668
def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
649669
client_certfile, client_protocol=None,
650670
indata="FOO\n",
651-
chatty=False, connectionchatty=False):
671+
ciphers=None, chatty=False, connectionchatty=False):
652672

653673
server = ThreadedEchoServer(certfile,
654674
certreqs=certreqs,
655675
ssl_version=protocol,
656676
cacerts=cacertsfile,
677+
ciphers=ciphers,
657678
chatty=chatty,
658679
connectionchatty=False)
659680
flag = threading.Event()
@@ -669,6 +690,7 @@ def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
669690
certfile=client_certfile,
670691
ca_certs=cacertsfile,
671692
cert_reqs=certreqs,
693+
ciphers=ciphers,
672694
ssl_version=client_protocol)
673695
s.connect((HOST, server.port))
674696
except ssl.SSLError as x:
@@ -723,8 +745,12 @@ def tryProtocolCombo (server_protocol,
723745
ssl.get_protocol_name(server_protocol),
724746
certtype))
725747
try:
748+
# NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
749+
# will send an SSLv3 hello (rather than SSLv2) starting from
750+
# OpenSSL 1.0.0 (see issue #8322).
726751
serverParamsTest(CERTFILE, server_protocol, certsreqs,
727752
CERTFILE, CERTFILE, client_protocol,
753+
ciphers="ALL",
728754
chatty=False, connectionchatty=False)
729755
except support.TestFailed:
730756
if expectedToWork:

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,9 @@ C-API
315315
Library
316316
-------
317317

318+
- Issue #8322: Add a *ciphers* argument to SSL sockets, so as to change the
319+
available cipher list. Helps fix test_ssl with OpenSSL 1.0.0.
320+
318321
- Issue #8393: subprocess accepts bytes, bytearray and str with surrogates for
319322
the current working directory.
320323

Modules/_ssl.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
262262
enum py_ssl_server_or_client socket_type,
263263
enum py_ssl_cert_requirements certreq,
264264
enum py_ssl_version proto_version,
265-
char *cacerts_file)
265+
char *cacerts_file, char *ciphers)
266266
{
267267
PySSLObject *self;
268268
char *errstr = NULL;
@@ -310,6 +310,14 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
310310
goto fail;
311311
}
312312

313+
if (ciphers != NULL) {
314+
ret = SSL_CTX_set_cipher_list(self->ctx, ciphers);
315+
if (ret == 0) {
316+
errstr = ERRSTR("No cipher can be selected.");
317+
goto fail;
318+
}
319+
}
320+
313321
if (certreq != PY_SSL_CERT_NONE) {
314322
if (cacerts_file == NULL) {
315323
errstr = ERRSTR("No root certificates specified for "
@@ -408,14 +416,15 @@ PySSL_sslwrap(PyObject *self, PyObject *args)
408416
char *key_file = NULL;
409417
char *cert_file = NULL;
410418
char *cacerts_file = NULL;
419+
char *ciphers = NULL;
411420

412-
if (!PyArg_ParseTuple(args, "O!i|zziiz:sslwrap",
421+
if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap",
413422
PySocketModule.Sock_Type,
414423
&Sock,
415424
&server_side,
416425
&key_file, &cert_file,
417426
&verification_mode, &protocol,
418-
&cacerts_file))
427+
&cacerts_file, &ciphers))
419428
return NULL;
420429

421430
/*
@@ -428,12 +437,13 @@ PySSL_sslwrap(PyObject *self, PyObject *args)
428437

429438
return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
430439
server_side, verification_mode,
431-
protocol, cacerts_file);
440+
protocol, cacerts_file,
441+
ciphers);
432442
}
433443

434444
PyDoc_STRVAR(ssl_doc,
435445
"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n"
436-
" cacertsfile]) -> sslobject");
446+
" cacertsfile, ciphers]) -> sslobject");
437447

438448
/* SSL object methods */
439449

0 commit comments

Comments
 (0)