summaryrefslogtreecommitdiff
path: root/OpenSSL/SSL.py
diff options
context:
space:
mode:
authorCory Benfield <lukasaoz@gmail.com>2014-03-31 20:30:25 +0100
committerCory Benfield <lukasaoz@gmail.com>2014-05-10 09:46:02 +0100
commit84a121ee4b1cbc2daea1f50f57eb2cef7d0b8413 (patch)
treefaa1e6ac0512247420b2c38076f84f0fa6e39abf /OpenSSL/SSL.py
parent06ddbf309a878ddd25934127d8ec8652538e5b47 (diff)
downloadpyopenssl-84a121ee4b1cbc2daea1f50f57eb2cef7d0b8413.tar.gz
Add support for Next Protocol Negotiation.
Diffstat (limited to 'OpenSSL/SSL.py')
-rw-r--r--OpenSSL/SSL.py75
1 files changed, 75 insertions, 0 deletions
diff --git a/OpenSSL/SSL.py b/OpenSSL/SSL.py
index 7b1cbc1..e754a7e 100644
--- a/OpenSSL/SSL.py
+++ b/OpenSSL/SSL.py
@@ -293,6 +293,10 @@ class Context(object):
self._info_callback = None
self._tlsext_servername_callback = None
self._app_data = None
+ self._npn_advertise_callback = None
+ self._npn_advertise_callback_args = None
+ self._npn_select_callback = None
+ self._npn_select_callback_args = None
# SSL_CTX_set_app_data(self->ctx, self);
# SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
@@ -809,6 +813,64 @@ class Context(object):
_lib.SSL_CTX_set_tlsext_servername_callback(
self._context, self._tlsext_servername_callback)
+
+ def set_npn_advertise_callback(self, callback):
+ """
+ Specify a callback function that will be called when offering Next
+ Protocol Negotiation.
+
+ :param callback: The callback function. It will be invoked with one
+ argument, the Connection instance. It should return a Python
+ bytestring, like b'\\x08http/1.1\\x06spdy/2'.
+ """
+ @wraps(callback)
+ def wrapper(ssl, out, outlen, arg):
+ outstr = callback(Connection._reverse_mapping[ssl])
+ self._npn_advertise_callback_args = [
+ _ffi.new("unsigned int *", len(outstr)),
+ _ffi.new("unsigned char[]", outstr),
+ ]
+ outlen[0] = self._npn_advertise_callback_args[0][0]
+ out[0] = self._npn_advertise_callback_args[1]
+ return 0
+
+ self._npn_advertise_callback = _ffi.callback(
+ "int (*)(SSL *, const unsigned char **, unsigned int *, void *)",
+ wrapper)
+ _lib.SSL_CTX_set_next_protos_advertised_cb(
+ self._context, self._npn_advertise_callback, _ffi.NULL)
+
+
+ def set_npn_select_callback(self, callback):
+ """
+ Specify a callback function that will be called when a server offers
+ Next Protocol Negotiation options.
+
+ :param callback: The callback function. It will be invoked with two
+ arguments: the Connection, and a list of offered protocols as
+ length-prefixed strings in a bytestring, e.g.
+ b'\\x08http/1.1\\x06spdy/2'. It should return one of those
+ bytestrings, the chosen protocol.
+ """
+ @wraps(callback)
+ def wrapper(ssl, out, outlen, in_, inlen, arg):
+ outstr = callback(
+ Connection._reverse_mapping[ssl], _ffi.string(in_))
+ self._npn_select_callback_args = [
+ _ffi.new("unsigned char *", len(outstr)),
+ _ffi.new("unsigned char[]", outstr),
+ ]
+ outlen[0] = self._npn_select_callback_args[0][0]
+ out[0] = self._npn_select_callback_args[1]
+ return 0
+
+ self._npn_select_callback = _ffi.callback(
+ "int (*)(SSL *, unsigned char **, unsigned char *, "
+ "const unsigned char *, unsigned int, void *)",
+ wrapper)
+ _lib.SSL_CTX_set_next_proto_select_cb(
+ self._context, self._npn_select_callback, _ffi.NULL)
+
ContextType = Context
@@ -1550,6 +1612,19 @@ class Connection(object):
version =_ffi.string(_lib.SSL_CIPHER_get_version(cipher))
return version.decode("utf-8")
+ def get_next_proto_negotiated(self):
+ """
+ Get the protocol that was negotiated by NPN.
+ """
+ data = _ffi.new("unsigned char **")
+ data_len = _ffi.new("unsigned int *")
+
+ _lib.SSL_get0_next_proto_negotiated(self._ssl, data, data_len)
+
+ if not data_len[0]:
+ return ""
+ else:
+ return _ffi.string(data[0])
ConnectionType = Connection