summaryrefslogtreecommitdiffstats
path: root/contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py')
-rw-r--r--contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py390
1 files changed, 299 insertions, 91 deletions
diff --git a/contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py b/contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py
index e71b044cc02..dfbd1094e9d 100644
--- a/contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py
+++ b/contrib/python/pyOpenSSL/py3/OpenSSL/SSL.py
@@ -1,12 +1,10 @@
import os
import socket
+from errno import errorcode
+from functools import partial, wraps
+from itertools import chain, count
from sys import platform
-from functools import wraps, partial
-from itertools import count, chain
from weakref import WeakValueDictionary
-from errno import errorcode
-
-from six import integer_types, int2byte, indexbytes
from OpenSSL._util import (
UNSPECIFIED as _UNSPECIFIED,
@@ -14,19 +12,17 @@ from OpenSSL._util import (
ffi as _ffi,
lib as _lib,
make_assert as _make_assert,
- native as _native,
- path_string as _path_string,
- text_to_bytes_and_warn as _text_to_bytes_and_warn,
no_zero_allocator as _no_zero_allocator,
+ path_bytes as _path_bytes,
+ text_to_bytes_and_warn as _text_to_bytes_and_warn,
)
-
from OpenSSL.crypto import (
FILETYPE_PEM,
- _PassphraseHelper,
PKey,
- X509Name,
X509,
+ X509Name,
X509Store,
+ _PassphraseHelper,
)
__all__ = [
@@ -36,10 +32,13 @@ __all__ = [
"SSLEAY_PLATFORM",
"SSLEAY_DIR",
"SSLEAY_BUILT_ON",
+ "OPENSSL_VERSION",
+ "OPENSSL_CFLAGS",
+ "OPENSSL_PLATFORM",
+ "OPENSSL_DIR",
+ "OPENSSL_BUILT_ON",
"SENT_SHUTDOWN",
"RECEIVED_SHUTDOWN",
- "SSLv2_METHOD",
- "SSLv3_METHOD",
"SSLv23_METHOD",
"TLSv1_METHOD",
"TLSv1_1_METHOD",
@@ -47,6 +46,9 @@ __all__ = [
"TLS_METHOD",
"TLS_SERVER_METHOD",
"TLS_CLIENT_METHOD",
+ "DTLS_METHOD",
+ "DTLS_SERVER_METHOD",
+ "DTLS_CLIENT_METHOD",
"SSL3_VERSION",
"TLS1_VERSION",
"TLS1_1_VERSION",
@@ -57,7 +59,6 @@ __all__ = [
"OP_NO_TLSv1",
"OP_NO_TLSv1_1",
"OP_NO_TLSv1_2",
- "OP_NO_TLSv1_3",
"MODE_RELEASE_BUFFERS",
"OP_SINGLE_DH_USE",
"OP_SINGLE_ECDH_USE",
@@ -124,26 +125,17 @@ __all__ = [
"Connection",
]
-try:
- _buffer = buffer
-except NameError:
-
- class _buffer(object):
- pass
-
OPENSSL_VERSION_NUMBER = _lib.OPENSSL_VERSION_NUMBER
-SSLEAY_VERSION = _lib.SSLEAY_VERSION
-SSLEAY_CFLAGS = _lib.SSLEAY_CFLAGS
-SSLEAY_PLATFORM = _lib.SSLEAY_PLATFORM
-SSLEAY_DIR = _lib.SSLEAY_DIR
-SSLEAY_BUILT_ON = _lib.SSLEAY_BUILT_ON
+OPENSSL_VERSION = SSLEAY_VERSION = _lib.OPENSSL_VERSION
+OPENSSL_CFLAGS = SSLEAY_CFLAGS = _lib.OPENSSL_CFLAGS
+OPENSSL_PLATFORM = SSLEAY_PLATFORM = _lib.OPENSSL_PLATFORM
+OPENSSL_DIR = SSLEAY_DIR = _lib.OPENSSL_DIR
+OPENSSL_BUILT_ON = SSLEAY_BUILT_ON = _lib.OPENSSL_BUILT_ON
SENT_SHUTDOWN = _lib.SSL_SENT_SHUTDOWN
RECEIVED_SHUTDOWN = _lib.SSL_RECEIVED_SHUTDOWN
-SSLv2_METHOD = 1
-SSLv3_METHOD = 2
SSLv23_METHOD = 3
TLSv1_METHOD = 4
TLSv1_1_METHOD = 5
@@ -151,6 +143,9 @@ TLSv1_2_METHOD = 6
TLS_METHOD = 7
TLS_SERVER_METHOD = 8
TLS_CLIENT_METHOD = 9
+DTLS_METHOD = 10
+DTLS_SERVER_METHOD = 11
+DTLS_CLIENT_METHOD = 12
try:
SSL3_VERSION = _lib.SSL3_VERSION
@@ -174,6 +169,7 @@ OP_NO_TLSv1_1 = _lib.SSL_OP_NO_TLSv1_1
OP_NO_TLSv1_2 = _lib.SSL_OP_NO_TLSv1_2
try:
OP_NO_TLSv1_3 = _lib.SSL_OP_NO_TLSv1_3
+ __all__.append("OP_NO_TLSv1_3")
except AttributeError:
pass
@@ -208,6 +204,18 @@ OP_NO_QUERY_MTU = _lib.SSL_OP_NO_QUERY_MTU
OP_COOKIE_EXCHANGE = _lib.SSL_OP_COOKIE_EXCHANGE
OP_NO_TICKET = _lib.SSL_OP_NO_TICKET
+try:
+ OP_NO_RENEGOTIATION = _lib.SSL_OP_NO_RENEGOTIATION
+ __all__.append("OP_NO_RENEGOTIATION")
+except AttributeError:
+ pass
+
+try:
+ OP_IGNORE_UNEXPECTED_EOF = _lib.SSL_OP_IGNORE_UNEXPECTED_EOF
+ __all__.append("OP_IGNORE_UNEXPECTED_EOF")
+except AttributeError:
+ pass
+
OP_ALL = _lib.SSL_OP_ALL
VERIFY_PEER = _lib.SSL_VERIFY_PEER
@@ -257,8 +265,8 @@ _CERTIFICATE_PATH_LOCATIONS = [
# These values are compared to output from cffi's ffi.string so they must be
# byte strings.
-_CRYPTOGRAPHY_MANYLINUX1_CA_DIR = b"/opt/pyca/cryptography/openssl/certs"
-_CRYPTOGRAPHY_MANYLINUX1_CA_FILE = b"/opt/pyca/cryptography/openssl/cert.pem"
+_CRYPTOGRAPHY_MANYLINUX_CA_DIR = b"/opt/pyca/cryptography/openssl/certs"
+_CRYPTOGRAPHY_MANYLINUX_CA_FILE = b"/opt/pyca/cryptography/openssl/cert.pem"
class Error(Exception):
@@ -291,7 +299,7 @@ class SysCallError(Error):
pass
-class _CallbackExceptionHelper(object):
+class _CallbackExceptionHelper:
"""
A base class for wrapper classes that allow for intelligent exception
handling in OpenSSL callbacks.
@@ -381,7 +389,7 @@ class _ALPNSelectHelper(_CallbackExceptionHelper):
instr = _ffi.buffer(in_, inlen)[:]
protolist = []
while instr:
- encoded_len = indexbytes(instr, 0)
+ encoded_len = instr[0]
proto = instr[1 : encoded_len + 1]
protolist.append(proto)
instr = instr[encoded_len + 1 :]
@@ -549,17 +557,59 @@ class _OCSPClientCallbackHelper(_CallbackExceptionHelper):
self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper)
+class _CookieGenerateCallbackHelper(_CallbackExceptionHelper):
+ def __init__(self, callback):
+ _CallbackExceptionHelper.__init__(self)
+
+ @wraps(callback)
+ def wrapper(ssl, out, outlen):
+ try:
+ conn = Connection._reverse_mapping[ssl]
+ cookie = callback(conn)
+ out[0 : len(cookie)] = cookie
+ outlen[0] = len(cookie)
+ return 1
+ except Exception as e:
+ self._problems.append(e)
+ # "a zero return value can be used to abort the handshake"
+ return 0
+
+ self.callback = _ffi.callback(
+ "int (*)(SSL *, unsigned char *, unsigned int *)",
+ wrapper,
+ )
+
+
+class _CookieVerifyCallbackHelper(_CallbackExceptionHelper):
+ def __init__(self, callback):
+ _CallbackExceptionHelper.__init__(self)
+
+ @wraps(callback)
+ def wrapper(ssl, c_cookie, cookie_len):
+ try:
+ conn = Connection._reverse_mapping[ssl]
+ return callback(conn, bytes(c_cookie[0:cookie_len]))
+ except Exception as e:
+ self._problems.append(e)
+ return 0
+
+ self.callback = _ffi.callback(
+ "int (*)(SSL *, unsigned char *, unsigned int)",
+ wrapper,
+ )
+
+
def _asFileDescriptor(obj):
fd = None
- if not isinstance(obj, integer_types):
+ if not isinstance(obj, int):
meth = getattr(obj, "fileno", None)
if meth is not None:
obj = meth()
- if isinstance(obj, integer_types):
+ if isinstance(obj, int):
fd = obj
- if not isinstance(fd, integer_types):
+ if not isinstance(fd, int):
raise TypeError("argument must be an int, or have a fileno() method.")
elif fd < 0:
raise ValueError(
@@ -569,13 +619,16 @@ def _asFileDescriptor(obj):
return fd
-def SSLeay_version(type):
+def OpenSSL_version(type):
"""
Return a string describing the version of OpenSSL in use.
- :param type: One of the :const:`SSLEAY_` constants defined in this module.
+ :param type: One of the :const:`OPENSSL_` constants defined in this module.
"""
- return _ffi.string(_lib.SSLeay_version(type))
+ return _ffi.string(_lib.OpenSSL_version(type))
+
+
+SSLeay_version = OpenSSL_version
def _make_requires(flag, error):
@@ -613,7 +666,7 @@ _requires_keylog = _make_requires(
)
-class Session(object):
+class Session:
"""
A class representing an SSL session. A session defines certain connection
parameters which may be re-used to speed up the setup of subsequent
@@ -625,39 +678,36 @@ class Session(object):
pass
-class Context(object):
+class Context:
"""
:class:`OpenSSL.SSL.Context` instances define the parameters for setting
up new SSL connections.
- :param method: One of TLS_METHOD, TLS_CLIENT_METHOD, or TLS_SERVER_METHOD.
+ :param method: One of TLS_METHOD, TLS_CLIENT_METHOD, TLS_SERVER_METHOD,
+ DTLS_METHOD, DTLS_CLIENT_METHOD, or DTLS_SERVER_METHOD.
SSLv23_METHOD, TLSv1_METHOD, etc. are deprecated and should
not be used.
"""
_methods = {
- SSLv2_METHOD: "SSLv2_method",
- SSLv3_METHOD: "SSLv3_method",
- SSLv23_METHOD: "SSLv23_method",
- TLSv1_METHOD: "TLSv1_method",
- TLSv1_1_METHOD: "TLSv1_1_method",
- TLSv1_2_METHOD: "TLSv1_2_method",
- TLS_METHOD: "TLS_method",
- TLS_SERVER_METHOD: "TLS_server_method",
- TLS_CLIENT_METHOD: "TLS_client_method",
+ SSLv23_METHOD: (_lib.TLS_method, None),
+ TLSv1_METHOD: (_lib.TLS_method, TLS1_VERSION),
+ TLSv1_1_METHOD: (_lib.TLS_method, TLS1_1_VERSION),
+ TLSv1_2_METHOD: (_lib.TLS_method, TLS1_2_VERSION),
+ TLS_METHOD: (_lib.TLS_method, None),
+ TLS_SERVER_METHOD: (_lib.TLS_server_method, None),
+ TLS_CLIENT_METHOD: (_lib.TLS_client_method, None),
+ DTLS_METHOD: (_lib.DTLS_method, None),
+ DTLS_SERVER_METHOD: (_lib.DTLS_server_method, None),
+ DTLS_CLIENT_METHOD: (_lib.DTLS_client_method, None),
}
- _methods = dict(
- (identifier, getattr(_lib, name))
- for (identifier, name) in _methods.items()
- if getattr(_lib, name, None) is not None
- )
def __init__(self, method):
- if not isinstance(method, integer_types):
+ if not isinstance(method, int):
raise TypeError("method must be an integer")
try:
- method_func = self._methods[method]
+ method_func, version = self._methods[method]
except KeyError:
raise ValueError("No such protocol")
@@ -668,12 +718,6 @@ class Context(object):
_openssl_assert(context != _ffi.NULL)
context = _ffi.gc(context, _lib.SSL_CTX_free)
- # Set SSL_CTX_set_ecdh_auto so that the ECDH curve will be
- # auto-selected. This function was added in 1.0.2 and made a noop in
- # 1.1.0+ (where it is set automatically).
- res = _lib.SSL_CTX_set_ecdh_auto(context, 1)
- _openssl_assert(res == 1)
-
self._context = context
self._passphrase_helper = None
self._passphrase_callback = None
@@ -689,8 +733,13 @@ class Context(object):
self._ocsp_helper = None
self._ocsp_callback = None
self._ocsp_data = None
+ self._cookie_generate_helper = None
+ self._cookie_verify_helper = None
self.set_mode(_lib.SSL_MODE_ENABLE_PARTIAL_WRITE)
+ if version is not None:
+ self.set_min_proto_version(version)
+ self.set_max_proto_version(version)
def set_min_proto_version(self, version):
"""
@@ -737,12 +786,12 @@ class Context(object):
if cafile is None:
cafile = _ffi.NULL
else:
- cafile = _path_string(cafile)
+ cafile = _path_bytes(cafile)
if capath is None:
capath = _ffi.NULL
else:
- capath = _path_string(capath)
+ capath = _path_bytes(capath)
load_result = _lib.SSL_CTX_load_verify_locations(
self._context, cafile, capath
@@ -828,8 +877,8 @@ class Context(object):
# to the exact values we use in our manylinux1 builds. If they are
# then we know to load the fallbacks
if (
- default_dir == _CRYPTOGRAPHY_MANYLINUX1_CA_DIR
- and default_file == _CRYPTOGRAPHY_MANYLINUX1_CA_FILE
+ default_dir == _CRYPTOGRAPHY_MANYLINUX_CA_DIR
+ and default_file == _CRYPTOGRAPHY_MANYLINUX_CA_FILE
):
# This is manylinux1, let's load our fallback paths
self._fallback_default_verify_paths(
@@ -876,7 +925,7 @@ class Context(object):
:return: None
"""
- certfile = _path_string(certfile)
+ certfile = _path_bytes(certfile)
result = _lib.SSL_CTX_use_certificate_chain_file(
self._context, certfile
@@ -896,8 +945,8 @@ class Context(object):
:return: None
"""
- certfile = _path_string(certfile)
- if not isinstance(filetype, integer_types):
+ certfile = _path_bytes(certfile)
+ if not isinstance(filetype, int):
raise TypeError("filetype must be an integer")
use_result = _lib.SSL_CTX_use_certificate_file(
@@ -913,6 +962,7 @@ class Context(object):
:param cert: The X509 object
:return: None
"""
+ # Mirrored at Connection.use_certificate
if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance")
@@ -954,11 +1004,11 @@ class Context(object):
:return: None
"""
- keyfile = _path_string(keyfile)
+ keyfile = _path_bytes(keyfile)
if filetype is _UNSPECIFIED:
filetype = FILETYPE_PEM
- elif not isinstance(filetype, integer_types):
+ elif not isinstance(filetype, int):
raise TypeError("filetype must be an integer")
use_result = _lib.SSL_CTX_use_PrivateKey_file(
@@ -974,6 +1024,7 @@ class Context(object):
:param pkey: The PKey object
:return: None
"""
+ # Mirrored at Connection.use_privatekey
if not isinstance(pkey, PKey):
raise TypeError("pkey must be a PKey instance")
@@ -1035,7 +1086,7 @@ class Context(object):
.. versionadded:: 0.14
"""
- if not isinstance(mode, integer_types):
+ if not isinstance(mode, int):
raise TypeError("mode must be an integer")
return _lib.SSL_CTX_set_session_cache_mode(self._context, mode)
@@ -1070,7 +1121,7 @@ class Context(object):
See SSL_CTX_set_verify(3SSL) for further details.
"""
- if not isinstance(mode, integer_types):
+ if not isinstance(mode, int):
raise TypeError("mode must be an integer")
if callback is None:
@@ -1093,7 +1144,7 @@ class Context(object):
:param depth: An integer specifying the verify depth
:return: None
"""
- if not isinstance(depth, integer_types):
+ if not isinstance(depth, int):
raise TypeError("depth must be an integer")
_lib.SSL_CTX_set_verify_depth(self._context, depth)
@@ -1125,7 +1176,7 @@ class Context(object):
:return: None
"""
- dhfile = _path_string(dhfile)
+ dhfile = _path_bytes(dhfile)
bio = _lib.BIO_new_file(dhfile, b"r")
if bio == _ffi.NULL:
@@ -1253,7 +1304,7 @@ class Context(object):
:param timeout: The timeout in (whole) seconds
:return: The previous session timeout
"""
- if not isinstance(timeout, integer_types):
+ if not isinstance(timeout, int):
raise TypeError("timeout must be an integer")
return _lib.SSL_CTX_set_timeout(self._context, timeout)
@@ -1356,7 +1407,7 @@ class Context(object):
:param options: The options to add.
:return: The new option bitmask.
"""
- if not isinstance(options, integer_types):
+ if not isinstance(options, int):
raise TypeError("options must be an integer")
return _lib.SSL_CTX_set_options(self._context, options)
@@ -1369,7 +1420,7 @@ class Context(object):
:param mode: The mode to add.
:return: The new mode bitmask.
"""
- if not isinstance(mode, integer_types):
+ if not isinstance(mode, int):
raise TypeError("mode must be an integer")
return _lib.SSL_CTX_set_mode(self._context, mode)
@@ -1423,10 +1474,16 @@ class Context(object):
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
+ # Different versions of OpenSSL are inconsistent about how they handle
+ # empty proto lists (see #1043), so we avoid the problem entirely by
+ # rejecting them ourselves.
+ if not protos:
+ raise ValueError("at least one protocol must be specified")
+
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b"".join(
- chain.from_iterable((int2byte(len(p)), p) for p in protos)
+ chain.from_iterable((bytes((len(p),)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
@@ -1523,8 +1580,22 @@ class Context(object):
helper = _OCSPClientCallbackHelper(callback)
self._set_ocsp_callback(helper, data)
+ def set_cookie_generate_callback(self, callback):
+ self._cookie_generate_helper = _CookieGenerateCallbackHelper(callback)
+ _lib.SSL_CTX_set_cookie_generate_cb(
+ self._context,
+ self._cookie_generate_helper.callback,
+ )
+
+ def set_cookie_verify_callback(self, callback):
+ self._cookie_verify_helper = _CookieVerifyCallbackHelper(callback)
+ _lib.SSL_CTX_set_cookie_verify_cb(
+ self._context,
+ self._cookie_verify_helper.callback,
+ )
+
-class Connection(object):
+class Connection:
_reverse_mapping = WeakValueDictionary()
def __init__(self, context, socket=None):
@@ -1560,6 +1631,10 @@ class Connection(object):
self._verify_helper = context._verify_helper
self._verify_callback = context._verify_callback
+ # And likewise for the cookie callbacks
+ self._cookie_generate_helper = context._cookie_generate_helper
+ self._cookie_verify_helper = context._cookie_verify_helper
+
self._reverse_mapping[self._ssl] = self
if socket is None:
@@ -1626,6 +1701,24 @@ class Connection(object):
else:
# TODO: This is untested.
_raise_current_error()
+ elif error == _lib.SSL_ERROR_SSL and _lib.ERR_peek_error() != 0:
+ # In 3.0.x an unexpected EOF no longer triggers syscall error
+ # but we want to maintain compatibility so we check here and
+ # raise syscall if it is an EOF. Since we're not actually sure
+ # what else could raise SSL_ERROR_SSL we check for the presence
+ # of the OpenSSL 3 constant SSL_R_UNEXPECTED_EOF_WHILE_READING
+ # and if it's not present we just raise an error, which matches
+ # the behavior before we added this elif section
+ peeked_error = _lib.ERR_peek_error()
+ reason = _lib.ERR_GET_REASON(peeked_error)
+ if _lib.Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING:
+ _openssl_assert(
+ reason == _lib.SSL_R_UNEXPECTED_EOF_WHILE_READING
+ )
+ _lib.ERR_clear_error()
+ raise SysCallError(-1, "Unexpected EOF")
+ else:
+ _raise_current_error()
elif error == _lib.SSL_ERROR_NONE:
pass
else:
@@ -1668,6 +1761,94 @@ class Connection(object):
return _ffi.string(name)
+ def set_verify(self, mode, callback=None):
+ """
+ Override the Context object's verification flags for this specific
+ connection. See :py:meth:`Context.set_verify` for details.
+ """
+ if not isinstance(mode, int):
+ raise TypeError("mode must be an integer")
+
+ if callback is None:
+ self._verify_helper = None
+ self._verify_callback = None
+ _lib.SSL_set_verify(self._ssl, mode, _ffi.NULL)
+ else:
+ if not callable(callback):
+ raise TypeError("callback must be callable")
+
+ self._verify_helper = _VerifyHelper(callback)
+ self._verify_callback = self._verify_helper.callback
+ _lib.SSL_set_verify(self._ssl, mode, self._verify_callback)
+
+ def get_verify_mode(self):
+ """
+ Retrieve the Connection object's verify mode, as set by
+ :meth:`set_verify`.
+
+ :return: The verify mode
+ """
+ return _lib.SSL_get_verify_mode(self._ssl)
+
+ def use_certificate(self, cert):
+ """
+ Load a certificate from a X509 object
+
+ :param cert: The X509 object
+ :return: None
+ """
+ # Mirrored from Context.use_certificate
+ if not isinstance(cert, X509):
+ raise TypeError("cert must be an X509 instance")
+
+ use_result = _lib.SSL_use_certificate(self._ssl, cert._x509)
+ if not use_result:
+ _raise_current_error()
+
+ def use_privatekey(self, pkey):
+ """
+ Load a private key from a PKey object
+
+ :param pkey: The PKey object
+ :return: None
+ """
+ # Mirrored from Context.use_privatekey
+ if not isinstance(pkey, PKey):
+ raise TypeError("pkey must be a PKey instance")
+
+ use_result = _lib.SSL_use_PrivateKey(self._ssl, pkey._pkey)
+ if not use_result:
+ self._context._raise_passphrase_exception()
+
+ def set_ciphertext_mtu(self, mtu):
+ """
+ For DTLS, set the maximum UDP payload size (*not* including IP/UDP
+ overhead).
+
+ Note that you might have to set :data:`OP_NO_QUERY_MTU` to prevent
+ OpenSSL from spontaneously clearing this.
+
+ :param mtu: An integer giving the maximum transmission unit.
+
+ .. versionadded:: 21.1
+ """
+ _lib.SSL_set_mtu(self._ssl, mtu)
+
+ def get_cleartext_mtu(self):
+ """
+ For DTLS, get the maximum size of unencrypted data you can pass to
+ :meth:`write` without exceeding the MTU (as passed to
+ :meth:`set_ciphertext_mtu`).
+
+ :return: The effective MTU as an integer.
+
+ .. versionadded:: 21.1
+ """
+
+ if not hasattr(_lib, "DTLS_get_data_mtu"):
+ raise NotImplementedError("requires OpenSSL 1.1.1 or better")
+ return _lib.DTLS_get_data_mtu(self._ssl)
+
def set_tlsext_host_name(self, name):
"""
Set the value of the servername extension to send in the client hello.
@@ -1839,7 +2020,7 @@ class Connection(object):
if self._from_ssl is None:
raise TypeError("Connection sock was not None")
- if not isinstance(bufsiz, integer_types):
+ if not isinstance(bufsiz, int):
raise TypeError("bufsiz must be an integer")
buf = _no_zero_allocator("char[]", bufsiz)
@@ -1953,6 +2134,32 @@ class Connection(object):
conn.set_accept_state()
return (conn, addr)
+ def DTLSv1_listen(self):
+ """
+ Call the OpenSSL function DTLSv1_listen on this connection. See the
+ OpenSSL manual for more details.
+
+ :return: None
+ """
+ # Possible future extension: return the BIO_ADDR in some form.
+ bio_addr = _lib.BIO_ADDR_new()
+ try:
+ result = _lib.DTLSv1_listen(self._ssl, bio_addr)
+ finally:
+ _lib.BIO_ADDR_free(bio_addr)
+ # DTLSv1_listen is weird. A zero return value means 'didn't find a
+ # ClientHello with valid cookie, but keep trying'. So basically
+ # WantReadError. But it doesn't work correctly with _raise_ssl_error.
+ # So we raise it manually instead.
+ if self._cookie_generate_helper is not None:
+ self._cookie_generate_helper.raise_if_problem()
+ if self._cookie_verify_helper is not None:
+ self._cookie_verify_helper.raise_if_problem()
+ if result == 0:
+ raise WantReadError()
+ if result < 0:
+ self._raise_ssl_error(self._ssl, result)
+
def bio_shutdown(self):
"""
If the Connection was created with a memory BIO, this method can be
@@ -1994,7 +2201,7 @@ class Connection(object):
result = _lib.SSL_get_cipher_list(self._ssl, i)
if result == _ffi.NULL:
break
- ciphers.append(_native(_ffi.string(result)))
+ ciphers.append(_ffi.string(result).decode("utf-8"))
return ciphers
def get_client_ca_list(self):
@@ -2070,7 +2277,7 @@ class Connection(object):
:param state: bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.
:return: None
"""
- if not isinstance(state, integer_types):
+ if not isinstance(state, int):
raise TypeError("state must be an integer")
_lib.SSL_set_shutdown(self._ssl, state)
@@ -2451,10 +2658,16 @@ class Connection(object):
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
+ # Different versions of OpenSSL are inconsistent about how they handle
+ # empty proto lists (see #1043), so we avoid the problem entirely by
+ # rejecting them ourselves.
+ if not protos:
+ raise ValueError("at least one protocol must be specified")
+
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b"".join(
- chain.from_iterable((int2byte(len(p)), p) for p in protos)
+ chain.from_iterable((bytes((len(p),)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
@@ -2475,7 +2688,7 @@ class Connection(object):
Get the protocol that was negotiated by ALPN.
:returns: A bytestring of the protocol name. If no protocol has been
- negotiated yet, returns an empty string.
+ negotiated yet, returns an empty bytestring.
"""
data = _ffi.new("unsigned char **")
data_len = _ffi.new("unsigned int *")
@@ -2498,8 +2711,3 @@ class Connection(object):
self._ssl, _lib.TLSEXT_STATUSTYPE_ocsp
)
_openssl_assert(rc == 1)
-
-
-# This is similar to the initialization calls at the end of OpenSSL/crypto.py
-# but is exercised mostly by the Context initializer.
-_lib.SSL_library_init()