diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2016-09-24 01:52:21 -0400 |
---|---|---|
committer | Hynek Schlawack <hs@ox.cx> | 2016-09-24 07:52:21 +0200 |
commit | 5af32d0d55f5d385e5592e00a2e574a43f0b74fb (patch) | |
tree | 9a2911b0da38417eaf374cf70726bf20646c74d2 | |
parent | 9f9113a7bb736a835f978d27e95603c8d6f52b7c (diff) | |
download | pyopenssl-5af32d0d55f5d385e5592e00a2e574a43f0b74fb.tar.gz |
Test on OpenSSL 1.1.0 with travis. Fixes #524 (#526)
-rw-r--r-- | .travis.yml | 21 | ||||
-rw-r--r-- | src/OpenSSL/SSL.py | 16 | ||||
-rw-r--r-- | src/OpenSSL/crypto.py | 2 | ||||
-rw-r--r-- | tests/test_ssl.py | 58 |
4 files changed, 71 insertions, 26 deletions
diff --git a/.travis.yml b/.travis.yml index d1917aa..2d88525 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,9 @@ matrix: - language: generic os: osx env: TOXENV=py27 + - language: generic + os: osx + env: TOXENV=py27 OPENSSL=1.1.0 - python: "2.6" # these are just to make travis's UI a bit prettier env: TOXENV=py26 - python: "2.7" @@ -90,7 +93,11 @@ install: - | if [[ "$(uname -s)" == 'Darwin' ]]; then brew update - brew upgrade openssl + if [[ "${OPENSSL}" == "1.1.0" ]]; then + brew install openssl@1.1 + else + brew upgrade openssl + fi curl -O https://bootstrap.pypa.io/get-pip.py python get-pip.py --user pip install --user virtualenv @@ -114,9 +121,15 @@ script: if [[ "$(uname -s)" == 'Darwin' ]]; then # set our flags to use homebrew openssl export ARCHFLAGS="-arch x86_64" - export LDFLAGS="-L/usr/local/opt/openssl/lib" - export CFLAGS="-I/usr/local/opt/openssl/include" - export PATH="/usr/local/opt/openssl/bin:$PATH" + if [[ "${OPENSSL}" == "1.1.0" ]]; then + export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" + export CFLAGS="-I/usr/local/opt/openssl@1.1/include" + export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" + else + export LDFLAGS="-L/usr/local/opt/openssl/lib" + export CFLAGS="-I/usr/local/opt/openssl/include" + export PATH="/usr/local/opt/openssl/bin:$PATH" + fi fi # activate the pypy env we installed via our custom pyenv in the install stage if [[ "${TOXENV}" == "pypy" ]]; then diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index 2d76516..7ebf7e0 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -109,10 +109,11 @@ SESS_CACHE_NO_INTERNAL = _lib.SSL_SESS_CACHE_NO_INTERNAL SSL_ST_CONNECT = _lib.SSL_ST_CONNECT SSL_ST_ACCEPT = _lib.SSL_ST_ACCEPT SSL_ST_MASK = _lib.SSL_ST_MASK -SSL_ST_INIT = _lib.SSL_ST_INIT -SSL_ST_BEFORE = _lib.SSL_ST_BEFORE -SSL_ST_OK = _lib.SSL_ST_OK -SSL_ST_RENEGOTIATE = _lib.SSL_ST_RENEGOTIATE +if _lib.Cryptography_HAS_SSL_ST: + SSL_ST_INIT = _lib.SSL_ST_INIT + SSL_ST_BEFORE = _lib.SSL_ST_BEFORE + SSL_ST_OK = _lib.SSL_ST_OK + SSL_ST_RENEGOTIATE = _lib.SSL_ST_RENEGOTIATE SSL_CB_LOOP = _lib.SSL_CB_LOOP SSL_CB_EXIT = _lib.SSL_CB_EXIT @@ -1160,9 +1161,10 @@ class Connection(object): errno = _ffi.getwinerror()[0] else: errno = _ffi.errno - raise SysCallError(errno, errorcode.get(errno)) - else: - raise SysCallError(-1, "Unexpected EOF") + + if errno != 0: + raise SysCallError(errno, errorcode.get(errno)) + raise SysCallError(-1, "Unexpected EOF") else: # TODO: This is untested. _raise_current_error() diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py index d811199..797dfdc 100644 --- a/src/OpenSSL/crypto.py +++ b/src/OpenSSL/crypto.py @@ -820,6 +820,8 @@ class X509Req(object): def __init__(self): req = _lib.X509_REQ_new() self._req = _ffi.gc(req, _lib.X509_REQ_free) + # Default to version 0. + self.set_version(0) def set_pubkey(self, pkey): """ diff --git a/tests/test_ssl.py b/tests/test_ssl.py index a2aad55..2b7e276 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -68,13 +68,19 @@ except ImportError: OP_NO_TLSv1 = OP_NO_TLSv1_1 = OP_NO_TLSv1_2 = None from OpenSSL.SSL import ( - SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_ST_INIT, SSL_ST_BEFORE, - SSL_ST_OK, SSL_ST_RENEGOTIATE, + SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_CB_LOOP, SSL_CB_EXIT, SSL_CB_READ, SSL_CB_WRITE, SSL_CB_ALERT, SSL_CB_READ_ALERT, SSL_CB_WRITE_ALERT, SSL_CB_ACCEPT_LOOP, SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP, SSL_CB_CONNECT_EXIT, SSL_CB_HANDSHAKE_START, SSL_CB_HANDSHAKE_DONE) +try: + from OpenSSL.SSL import ( + SSL_ST_INIT, SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE + ) +except ImportError: + SSL_ST_INIT = SSL_ST_BEFORE = SSL_ST_OK = SSL_ST_RENEGOTIATE = None + from .util import WARNING_TYPE_EXPECTED, NON_ASCII, TestCase from .test_crypto import ( cleartextCertificatePEM, cleartextPrivateKeyPEM, @@ -493,12 +499,11 @@ class ContextTests(TestCase, _LoopbackMixin): :py:obj:`SSLv23_METHOD`, :py:obj:`TLSv1_METHOD`, :py:obj:`TLSv1_1_METHOD`, or :py:obj:`TLSv1_2_METHOD`. """ - methods = [ - SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD] + methods = [SSLv23_METHOD, TLSv1_METHOD] for meth in methods: Context(meth) - maybe = [SSLv2_METHOD, TLSv1_1_METHOD, TLSv1_2_METHOD] + maybe = [SSLv2_METHOD, SSLv3_METHOD, TLSv1_1_METHOD, TLSv1_2_METHOD] for meth in maybe: try: Context(meth) @@ -2437,8 +2442,12 @@ class ConnectionTests(TestCase, _LoopbackMixin): server = self._loopbackServerFactory(server) client = self._loopbackClientFactory(client) - assert b"before/accept initialization" == server.get_state_string() - assert b"before/connect initialization" == client.get_state_string() + assert server.get_state_string() in [ + b"before/accept initialization", b"before SSL initialization" + ] + assert client.get_state_string() in [ + b"before/connect initialization", b"before SSL initialization" + ] def test_app_data_wrong_args(self): """ @@ -2633,9 +2642,19 @@ class ConnectionTests(TestCase, _LoopbackMixin): the :py:obj:`Connection` is using, a :py:class:`OpenSSL.SSL.Error` is raised. """ + # Make this work on both OpenSSL 1.0.0, which doesn't support TLSv1.2 + # and also on OpenSSL 1.1.0 which doesn't support SSLv3. (SSL_ST_INIT + # is a way to check for 1.1.0) + if SSL_ST_INIT is not None: + v1 = TLSv1_METHOD + v2 = SSLv3_METHOD + else: + v1 = TLSv1_2_METHOD + v2 = TLSv1_METHOD + key = load_privatekey(FILETYPE_PEM, server_key_pem) cert = load_certificate(FILETYPE_PEM, server_cert_pem) - ctx = Context(TLSv1_METHOD) + ctx = Context(v1) ctx.use_privatekey(key) ctx.use_certificate(cert) ctx.set_session_id("unity-test") @@ -2645,13 +2664,18 @@ class ConnectionTests(TestCase, _LoopbackMixin): server.set_accept_state() return server + def makeOriginalClient(socket): + client = Connection(Context(v1), socket) + client.set_connect_state() + return client + originalServer, originalClient = self._loopback( - serverFactory=makeServer) + serverFactory=makeServer, clientFactory=makeOriginalClient) originalSession = originalClient.get_session() def makeClient(socket): # Intentionally use a different, incompatible method here. - client = Connection(Context(SSLv3_METHOD), socket) + client = Connection(Context(v2), socket) client.set_connect_state() client.set_session(originalSession) return client @@ -3032,7 +3056,6 @@ class ConnectionRecvIntoTests(TestCase, _LoopbackMixin): self._doesnt_overfill_test(bytearray) def test_peek(self): - server, client = self._loopback() server.send(b'xy') @@ -3533,7 +3556,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): e = self.assertRaises(Error, server.recv, 1024) # We don't want WantReadError or ZeroReturnError or anything - it's a # handshake failure. - self.assertEquals(e.__class__, Error) + assert type(e) in [Error, SysCallError] def test_unexpectedEndOfFile(self): """ @@ -3809,14 +3832,19 @@ class InfoConstantTests(TestCase): info callback matches up with the constant exposed by OpenSSL.SSL. """ for const in [ - SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_ST_INIT, - SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE, + SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_CB_LOOP, SSL_CB_EXIT, SSL_CB_READ, SSL_CB_WRITE, SSL_CB_ALERT, SSL_CB_READ_ALERT, SSL_CB_WRITE_ALERT, SSL_CB_ACCEPT_LOOP, SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP, SSL_CB_CONNECT_EXIT, SSL_CB_HANDSHAKE_START, SSL_CB_HANDSHAKE_DONE ]: - self.assertTrue(isinstance(const, int)) + assert isinstance(const, int) + + # These constants don't exist on OpenSSL 1.1.0 + for const in [ + SSL_ST_INIT, SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE + ]: + assert const is None or isinstance(const, int) class TestRequires(object): |