mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Merged revisions 80151 via svnmerge from
svn+ssh://pythondev@svn.python.org/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. ........
This commit is contained in:
parent
ec8dfeb27e
commit
2d9cb9c1cb
5 changed files with 72 additions and 17 deletions
|
@ -47,7 +47,7 @@ Functions, Constants, and Exceptions
|
||||||
is a subtype of :exc:`socket.error`, which in turn is a subtype of
|
is a subtype of :exc:`socket.error`, which in turn is a subtype of
|
||||||
:exc:`IOError`.
|
:exc:`IOError`.
|
||||||
|
|
||||||
.. 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)
|
.. 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)
|
||||||
|
|
||||||
Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance
|
Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance
|
||||||
of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps
|
of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps
|
||||||
|
@ -110,14 +110,23 @@ Functions, Constants, and Exceptions
|
||||||
======================== ========= ========= ========== =========
|
======================== ========= ========= ========== =========
|
||||||
*client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1**
|
*client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1**
|
||||||
------------------------ --------- --------- ---------- ---------
|
------------------------ --------- --------- ---------- ---------
|
||||||
*SSLv2* yes no yes* no
|
*SSLv2* yes no yes no
|
||||||
*SSLv3* yes yes yes no
|
*SSLv3* yes yes yes no
|
||||||
*SSLv23* yes no yes no
|
*SSLv23* yes no yes no
|
||||||
*TLSv1* no no yes yes
|
*TLSv1* no no yes yes
|
||||||
======================== ========= ========= ========== =========
|
======================== ========= ========= ========== =========
|
||||||
|
|
||||||
In some older versions of OpenSSL (for instance, 0.9.7l on OS X 10.4), an
|
.. note::
|
||||||
SSLv2 client could not connect to an SSLv23 server.
|
|
||||||
|
This information varies depending on the version of OpenSSL.
|
||||||
|
For instance, in some older versions of OpenSSL (such as 0.9.7l on
|
||||||
|
OS X 10.4), an SSLv2 client could not connect to an SSLv23 server.
|
||||||
|
Conversely, starting from 1.0.0, an SSLv23 client will actually
|
||||||
|
try the SSLv3 protocol unless you explicitly enable SSLv2 ciphers.
|
||||||
|
|
||||||
|
The parameter ``ciphers`` sets the available ciphers for this SSL object.
|
||||||
|
It should be a string in the `OpenSSL cipher list format
|
||||||
|
<http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_.
|
||||||
|
|
||||||
The parameter ``do_handshake_on_connect`` specifies whether to do the SSL
|
The parameter ``do_handshake_on_connect`` specifies whether to do the SSL
|
||||||
handshake automatically after doing a :meth:`socket.connect`, or whether the
|
handshake automatically after doing a :meth:`socket.connect`, or whether the
|
||||||
|
@ -132,6 +141,9 @@ Functions, Constants, and Exceptions
|
||||||
normal EOF in response to unexpected EOF errors raised from the underlying
|
normal EOF in response to unexpected EOF errors raised from the underlying
|
||||||
socket; if :const:`False`, it will raise the exceptions back to the caller.
|
socket; if :const:`False`, it will raise the exceptions back to the caller.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.7
|
||||||
|
New optional argument *ciphers*.
|
||||||
|
|
||||||
.. function:: RAND_status()
|
.. function:: RAND_status()
|
||||||
|
|
||||||
Returns True if the SSL pseudo-random number generator has been seeded with
|
Returns True if the SSL pseudo-random number generator has been seeded with
|
||||||
|
|
14
Lib/ssl.py
14
Lib/ssl.py
|
@ -94,7 +94,7 @@ class SSLSocket(socket):
|
||||||
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
||||||
do_handshake_on_connect=True,
|
do_handshake_on_connect=True,
|
||||||
family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
|
family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
|
||||||
suppress_ragged_eofs=True):
|
suppress_ragged_eofs=True, ciphers=None):
|
||||||
|
|
||||||
if sock is not None:
|
if sock is not None:
|
||||||
socket.__init__(self,
|
socket.__init__(self,
|
||||||
|
@ -123,7 +123,8 @@ class SSLSocket(socket):
|
||||||
try:
|
try:
|
||||||
self._sslobj = _ssl.sslwrap(self, server_side,
|
self._sslobj = _ssl.sslwrap(self, server_side,
|
||||||
keyfile, certfile,
|
keyfile, certfile,
|
||||||
cert_reqs, ssl_version, ca_certs)
|
cert_reqs, ssl_version, ca_certs,
|
||||||
|
ciphers)
|
||||||
if do_handshake_on_connect:
|
if do_handshake_on_connect:
|
||||||
timeout = self.gettimeout()
|
timeout = self.gettimeout()
|
||||||
if timeout == 0.0:
|
if timeout == 0.0:
|
||||||
|
@ -140,6 +141,7 @@ class SSLSocket(socket):
|
||||||
self.cert_reqs = cert_reqs
|
self.cert_reqs = cert_reqs
|
||||||
self.ssl_version = ssl_version
|
self.ssl_version = ssl_version
|
||||||
self.ca_certs = ca_certs
|
self.ca_certs = ca_certs
|
||||||
|
self.ciphers = ciphers
|
||||||
self.do_handshake_on_connect = do_handshake_on_connect
|
self.do_handshake_on_connect = do_handshake_on_connect
|
||||||
self.suppress_ragged_eofs = suppress_ragged_eofs
|
self.suppress_ragged_eofs = suppress_ragged_eofs
|
||||||
|
|
||||||
|
@ -325,7 +327,7 @@ class SSLSocket(socket):
|
||||||
socket.connect(self, addr)
|
socket.connect(self, addr)
|
||||||
self._sslobj = _ssl.sslwrap(self, False, self.keyfile, self.certfile,
|
self._sslobj = _ssl.sslwrap(self, False, self.keyfile, self.certfile,
|
||||||
self.cert_reqs, self.ssl_version,
|
self.cert_reqs, self.ssl_version,
|
||||||
self.ca_certs)
|
self.ca_certs, self.ciphers)
|
||||||
try:
|
try:
|
||||||
if self.do_handshake_on_connect:
|
if self.do_handshake_on_connect:
|
||||||
self.do_handshake()
|
self.do_handshake()
|
||||||
|
@ -345,6 +347,7 @@ class SSLSocket(socket):
|
||||||
cert_reqs=self.cert_reqs,
|
cert_reqs=self.cert_reqs,
|
||||||
ssl_version=self.ssl_version,
|
ssl_version=self.ssl_version,
|
||||||
ca_certs=self.ca_certs,
|
ca_certs=self.ca_certs,
|
||||||
|
ciphers=self.ciphers,
|
||||||
do_handshake_on_connect=
|
do_handshake_on_connect=
|
||||||
self.do_handshake_on_connect),
|
self.do_handshake_on_connect),
|
||||||
addr)
|
addr)
|
||||||
|
@ -358,13 +361,14 @@ def wrap_socket(sock, keyfile=None, certfile=None,
|
||||||
server_side=False, cert_reqs=CERT_NONE,
|
server_side=False, cert_reqs=CERT_NONE,
|
||||||
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
||||||
do_handshake_on_connect=True,
|
do_handshake_on_connect=True,
|
||||||
suppress_ragged_eofs=True):
|
suppress_ragged_eofs=True, ciphers=None):
|
||||||
|
|
||||||
return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
|
return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
|
||||||
server_side=server_side, cert_reqs=cert_reqs,
|
server_side=server_side, cert_reqs=cert_reqs,
|
||||||
ssl_version=ssl_version, ca_certs=ca_certs,
|
ssl_version=ssl_version, ca_certs=ca_certs,
|
||||||
do_handshake_on_connect=do_handshake_on_connect,
|
do_handshake_on_connect=do_handshake_on_connect,
|
||||||
suppress_ragged_eofs=suppress_ragged_eofs)
|
suppress_ragged_eofs=suppress_ragged_eofs,
|
||||||
|
ciphers=ciphers)
|
||||||
|
|
||||||
# some utility functions
|
# some utility functions
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,23 @@ class BasicTests(unittest.TestCase):
|
||||||
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
|
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
|
||||||
(s, t))
|
(s, t))
|
||||||
|
|
||||||
|
def test_ciphers(self):
|
||||||
|
if not support.is_resource_enabled('network'):
|
||||||
|
return
|
||||||
|
remote = ("svn.python.org", 443)
|
||||||
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
|
||||||
|
cert_reqs=ssl.CERT_NONE, ciphers="ALL")
|
||||||
|
s.connect(remote)
|
||||||
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
|
||||||
|
cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
|
||||||
|
s.connect(remote)
|
||||||
|
# Error checking occurs when connecting, because the SSL context
|
||||||
|
# isn't created before.
|
||||||
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
|
||||||
|
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
|
||||||
|
with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
|
||||||
|
s.connect(remote)
|
||||||
|
|
||||||
|
|
||||||
class NetworkedTests(unittest.TestCase):
|
class NetworkedTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -234,7 +251,8 @@ else:
|
||||||
certfile=self.server.certificate,
|
certfile=self.server.certificate,
|
||||||
ssl_version=self.server.protocol,
|
ssl_version=self.server.protocol,
|
||||||
ca_certs=self.server.cacerts,
|
ca_certs=self.server.cacerts,
|
||||||
cert_reqs=self.server.certreqs)
|
cert_reqs=self.server.certreqs,
|
||||||
|
ciphers=self.server.ciphers)
|
||||||
except:
|
except:
|
||||||
if self.server.chatty:
|
if self.server.chatty:
|
||||||
handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
|
handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
|
||||||
|
@ -333,7 +351,8 @@ else:
|
||||||
|
|
||||||
def __init__(self, certificate, ssl_version=None,
|
def __init__(self, certificate, ssl_version=None,
|
||||||
certreqs=None, cacerts=None, expect_bad_connects=False,
|
certreqs=None, cacerts=None, expect_bad_connects=False,
|
||||||
chatty=True, connectionchatty=False, starttls_server=False):
|
chatty=True, connectionchatty=False, starttls_server=False,
|
||||||
|
ciphers=None):
|
||||||
if ssl_version is None:
|
if ssl_version is None:
|
||||||
ssl_version = ssl.PROTOCOL_TLSv1
|
ssl_version = ssl.PROTOCOL_TLSv1
|
||||||
if certreqs is None:
|
if certreqs is None:
|
||||||
|
@ -342,6 +361,7 @@ else:
|
||||||
self.protocol = ssl_version
|
self.protocol = ssl_version
|
||||||
self.certreqs = certreqs
|
self.certreqs = certreqs
|
||||||
self.cacerts = cacerts
|
self.cacerts = cacerts
|
||||||
|
self.ciphers = ciphers
|
||||||
self.expect_bad_connects = expect_bad_connects
|
self.expect_bad_connects = expect_bad_connects
|
||||||
self.chatty = chatty
|
self.chatty = chatty
|
||||||
self.connectionchatty = connectionchatty
|
self.connectionchatty = connectionchatty
|
||||||
|
@ -648,12 +668,13 @@ else:
|
||||||
def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
|
def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
|
||||||
client_certfile, client_protocol=None,
|
client_certfile, client_protocol=None,
|
||||||
indata="FOO\n",
|
indata="FOO\n",
|
||||||
chatty=False, connectionchatty=False):
|
ciphers=None, chatty=False, connectionchatty=False):
|
||||||
|
|
||||||
server = ThreadedEchoServer(certfile,
|
server = ThreadedEchoServer(certfile,
|
||||||
certreqs=certreqs,
|
certreqs=certreqs,
|
||||||
ssl_version=protocol,
|
ssl_version=protocol,
|
||||||
cacerts=cacertsfile,
|
cacerts=cacertsfile,
|
||||||
|
ciphers=ciphers,
|
||||||
chatty=chatty,
|
chatty=chatty,
|
||||||
connectionchatty=False)
|
connectionchatty=False)
|
||||||
flag = threading.Event()
|
flag = threading.Event()
|
||||||
|
@ -669,6 +690,7 @@ else:
|
||||||
certfile=client_certfile,
|
certfile=client_certfile,
|
||||||
ca_certs=cacertsfile,
|
ca_certs=cacertsfile,
|
||||||
cert_reqs=certreqs,
|
cert_reqs=certreqs,
|
||||||
|
ciphers=ciphers,
|
||||||
ssl_version=client_protocol)
|
ssl_version=client_protocol)
|
||||||
s.connect((HOST, server.port))
|
s.connect((HOST, server.port))
|
||||||
except ssl.SSLError as x:
|
except ssl.SSLError as x:
|
||||||
|
@ -723,8 +745,12 @@ else:
|
||||||
ssl.get_protocol_name(server_protocol),
|
ssl.get_protocol_name(server_protocol),
|
||||||
certtype))
|
certtype))
|
||||||
try:
|
try:
|
||||||
|
# NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
|
||||||
|
# will send an SSLv3 hello (rather than SSLv2) starting from
|
||||||
|
# OpenSSL 1.0.0 (see issue #8322).
|
||||||
serverParamsTest(CERTFILE, server_protocol, certsreqs,
|
serverParamsTest(CERTFILE, server_protocol, certsreqs,
|
||||||
CERTFILE, CERTFILE, client_protocol,
|
CERTFILE, CERTFILE, client_protocol,
|
||||||
|
ciphers="ALL",
|
||||||
chatty=False, connectionchatty=False)
|
chatty=False, connectionchatty=False)
|
||||||
except support.TestFailed:
|
except support.TestFailed:
|
||||||
if expectedToWork:
|
if expectedToWork:
|
||||||
|
|
|
@ -315,6 +315,9 @@ C-API
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
- Issue #8393: subprocess accepts bytes, bytearray and str with surrogates for
|
- Issue #8393: subprocess accepts bytes, bytearray and str with surrogates for
|
||||||
the current working directory.
|
the current working directory.
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
|
||||||
enum py_ssl_server_or_client socket_type,
|
enum py_ssl_server_or_client socket_type,
|
||||||
enum py_ssl_cert_requirements certreq,
|
enum py_ssl_cert_requirements certreq,
|
||||||
enum py_ssl_version proto_version,
|
enum py_ssl_version proto_version,
|
||||||
char *cacerts_file)
|
char *cacerts_file, char *ciphers)
|
||||||
{
|
{
|
||||||
PySSLObject *self;
|
PySSLObject *self;
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
|
@ -310,6 +310,14 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ciphers != NULL) {
|
||||||
|
ret = SSL_CTX_set_cipher_list(self->ctx, ciphers);
|
||||||
|
if (ret == 0) {
|
||||||
|
errstr = ERRSTR("No cipher can be selected.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (certreq != PY_SSL_CERT_NONE) {
|
if (certreq != PY_SSL_CERT_NONE) {
|
||||||
if (cacerts_file == NULL) {
|
if (cacerts_file == NULL) {
|
||||||
errstr = ERRSTR("No root certificates specified for "
|
errstr = ERRSTR("No root certificates specified for "
|
||||||
|
@ -408,14 +416,15 @@ PySSL_sslwrap(PyObject *self, PyObject *args)
|
||||||
char *key_file = NULL;
|
char *key_file = NULL;
|
||||||
char *cert_file = NULL;
|
char *cert_file = NULL;
|
||||||
char *cacerts_file = NULL;
|
char *cacerts_file = NULL;
|
||||||
|
char *ciphers = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O!i|zziiz:sslwrap",
|
if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap",
|
||||||
PySocketModule.Sock_Type,
|
PySocketModule.Sock_Type,
|
||||||
&Sock,
|
&Sock,
|
||||||
&server_side,
|
&server_side,
|
||||||
&key_file, &cert_file,
|
&key_file, &cert_file,
|
||||||
&verification_mode, &protocol,
|
&verification_mode, &protocol,
|
||||||
&cacerts_file))
|
&cacerts_file, &ciphers))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -428,12 +437,13 @@ PySSL_sslwrap(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
|
return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
|
||||||
server_side, verification_mode,
|
server_side, verification_mode,
|
||||||
protocol, cacerts_file);
|
protocol, cacerts_file,
|
||||||
|
ciphers);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(ssl_doc,
|
PyDoc_STRVAR(ssl_doc,
|
||||||
"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n"
|
"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n"
|
||||||
" cacertsfile]) -> sslobject");
|
" cacertsfile, ciphers]) -> sslobject");
|
||||||
|
|
||||||
/* SSL object methods */
|
/* SSL object methods */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue