Kaydet (Commit) 2d9cb9c1 authored tarafından Antoine Pitrou's avatar Antoine Pitrou

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.
........
üst ec8dfeb2
...@@ -47,7 +47,7 @@ Functions, Constants, and Exceptions ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -94,7 +94,7 @@ class SSLSocket(socket): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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, ...@@ -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): ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment