cpython: be9fe0c66075 (original) (raw)

Mercurial > cpython

changeset 94261:be9fe0c66075

add support for ALPN (closes #20188) [#20188]

Benjamin Peterson benjamin@python.org
date Fri, 23 Jan 2015 16:35:37 -0500
parents 67ebf7ae686d
children eaa38b75cc78
files Doc/library/ssl.rst Lib/ssl.py Lib/test/test_ssl.py Misc/NEWS Modules/_ssl.c
diffstat 5 files changed, 231 insertions(+), 29 deletions(-)[+] [-] Doc/library/ssl.rst 34 Lib/ssl.py 27 Lib/test/test_ssl.py 64 Misc/NEWS 3 Modules/_ssl.c 132

line wrap: on

line diff

--- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -673,6 +673,13 @@ Constants .. versionadded:: 3.3 +.. data:: HAS_ALPN +

.. data:: HAS_ECDH Whether the OpenSSL library has built-in support for Elliptic Curve-based @@ -959,9 +966,18 @@ SSL sockets also have the following addi .. versionadded:: 3.3 +.. method:: SSLSocket.selected_alpn_protocol() +

.. method:: SSLSocket.selected_npn_protocol()

+.. method:: SSLContext.set_alpn_protocols(protocols) +

.. method:: SSLContext.set_npn_protocols(protocols) Specify which protocols the socket should advertise during the SSL/TLS @@ -1200,7 +1230,7 @@ to speed up repeated connections from th Due to the early negotiation phase of the TLS connection, only limited methods and attributes are usable like

--- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -122,7 +122,7 @@ def _import_symbols(prefix): import_symbols('ALERT_DESCRIPTION') import_symbols('SSL_ERROR') -from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN +from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN from _ssl import _OPENSSL_API_VERSION @@ -374,6 +374,17 @@ class SSLContext(_SSLContext): self._set_npn_protocols(protos)

+

+ def _load_windows_store_certs(self, storename, purpose): certs = bytearray() for cert, encoding, trust in enum_certificates(storename): @@ -567,6 +578,13 @@ class SSLObject: if _ssl.HAS_NPN: return self._sslobj.selected_npn_protocol()

+ def cipher(self): """Return the currently selected cipher as a 3-tuple (name,[](#l2.42) ssl_version, secret_bits).""" @@ -783,6 +801,13 @@ class SSLSocket(socket): else: return self._sslobj.selected_npn_protocol()

+ def cipher(self): self._checkClosed() if not self._sslobj:

--- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1761,7 +1761,8 @@ else: try: self.sslconn = self.server.context.wrap_socket( self.sock, server_side=True)

@@ -1869,7 +1870,8 @@ else: def init(self, certificate=None, ssl_version=None, certreqs=None, cacerts=None, chatty=True, connectionchatty=False, starttls_server=False,

@@ -1884,6 +1886,8 @@ else: self.context.load_cert_chain(certificate) if npn_protocols: self.context.set_npn_protocols(npn_protocols)

@@ -1893,7 +1897,8 @@ else: self.port = support.bind_port(self.sock) self.flag = None self.active = False

@@ -2120,11 +2125,13 @@ else: 'compression': s.compression(), 'cipher': s.cipher(), 'peercert': s.getpeercert(),

@@ -3022,6 +3029,55 @@ else: if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: self.fail("Non-DH cipher: " + cipher[0])

+

+

+

+ def test_selected_npn_protocol(self): # selected_npn_protocol() is None unless NPN is used context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -203,6 +203,9 @@ Core and Builtins Library ------- +- Issue #20188: Support Application-Layer Protocol Negotiation (ALPN) in the ssl

--- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -109,6 +109,11 @@ struct py_ssl_library_code {

define HAVE_SNI 0

#endif +/* ALPN added in OpenSSL 1.0.2 / +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +# define HAVE_ALPN +#endif + enum py_ssl_error { / these mirror ssl.h */ PY_SSL_ERROR_NONE, @@ -180,9 +185,13 @@ typedef struct { PyObject_HEAD SSL_CTX *ctx; #ifdef OPENSSL_NPN_NEGOTIATED

#endif +#ifdef HAVE_ALPN

+#endif #ifndef OPENSSL_NO_TLSEXT PyObject *set_hostname; #endif @@ -1460,7 +1469,20 @@ static PyObject *PySSL_selected_npn_prot if (out == NULL) Py_RETURN_NONE;

+} +#endif + +#ifdef HAVE_ALPN +static PyObject *PySSL_selected_alpn_protocol(PySSLSocket *self) {

+

+

} #endif @@ -2054,6 +2076,9 @@ static PyMethodDef PySSLMethods[] = { #ifdef OPENSSL_NPN_NEGOTIATED {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, #endif +#ifdef HAVE_ALPN

+#endif {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, PySSL_SSLshutdown_doc}, @@ -2159,6 +2184,9 @@ context_new(PyTypeObject *type, PyObject #ifdef OPENSSL_NPN_NEGOTIATED self->npn_protocols = NULL; #endif +#ifdef HAVE_ALPN

+#endif #ifndef OPENSSL_NO_TLSEXT self->set_hostname = NULL; #endif @@ -2218,7 +2246,10 @@ context_dealloc(PySSLContext *self) context_clear(self); SSL_CTX_free(self->ctx); #ifdef OPENSSL_NPN_NEGOTIATED

+#endif +#ifdef HAVE_ALPN

#endif Py_TYPE(self)->tp_free(self); } @@ -2244,6 +2275,23 @@ set_ciphers(PySSLContext *self, PyObject Py_RETURN_NONE; } +static int +do_protocol_selection(unsigned char **out, unsigned char *outlen,

+{

+

+

+} + #ifdef OPENSSL_NPN_NEGOTIATED /* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ static int @@ -2254,10 +2302,10 @@ static int PySSLContext *ssl_ctx = (PySSLContext *) args; if (ssl_ctx->npn_protocols == NULL) {

{

-

-

-

-

} #endif @@ -2329,6 +2363,50 @@ static PyObject * #endif } +#ifdef HAVE_ALPN +static int +_selectALPN_cb(SSL *s,

+{

+} +#endif + +static PyObject * +_set_alpn_protocols(PySSLContext *self, PyObject *args) +{ +#ifdef HAVE_ALPN

+

+

+

+

+#else

+#endif +} + static PyObject * get_verify_mode(PySSLContext *self, void *c) { @@ -3307,6 +3385,8 @@ static struct PyMethodDef context_method METH_VARARGS | METH_KEYWORDS, NULL}, {"set_ciphers", (PyCFunction) set_ciphers, METH_VARARGS, NULL},

+#else

+#endif

+ /* Mappings for error codes */ err_codes_to_names = PyDict_New(); err_names_to_codes = PyDict_New();