diff options
author | Jean-Paul Calderone <exarkun@twistedmatrix.com> | 2013-03-19 22:10:37 -0700 |
---|---|---|
committer | Jean-Paul Calderone <exarkun@twistedmatrix.com> | 2013-03-19 22:10:37 -0700 |
commit | d899af0ab4abde552fdca22c8b1401edd1a24446 (patch) | |
tree | 2e65e3514a095edfcfa0d88bbe0311f4c134f2ee | |
parent | 7e166fe9cbd810ea7441e1e4fed0d600f47950dd (diff) | |
download | pyopenssl-d899af0ab4abde552fdca22c8b1401edd1a24446.tar.gz |
A few more tests, still incomplete
-rw-r--r-- | OpenSSL/SSL.py | 44 | ||||
-rw-r--r-- | OpenSSL/crypto.py | 7 | ||||
-rw-r--r-- | OpenSSL/test/test_ssl.py | 66 |
3 files changed, 104 insertions, 13 deletions
diff --git a/OpenSSL/SSL.py b/OpenSSL/SSL.py index 35ecf7c..e4116e2 100644 --- a/OpenSSL/SSL.py +++ b/OpenSSL/SSL.py @@ -143,6 +143,16 @@ class WantReadError(Error): +class WantWriteError(Error): + pass + + + +class WantX509LookupError(Error): + pass + + + class ZeroReturnError(Error): pass @@ -777,21 +787,27 @@ class Connection(object): error = _api.SSL_get_error(ssl, result) if error == _api.SSL_ERROR_WANT_READ: raise WantReadError() + elif error == _api.SSL_ERROR_WANT_WRITE: + raise WantWriteError() elif error == _api.SSL_ERROR_ZERO_RETURN: raise ZeroReturnError() - elif error == _api.SSL_ERROR_NONE: - pass + elif error == _api.SSL_ERROR_WANT_X509_LOOKUP: + # TODO Untested + 1/0 + raise WantX509LookupError() elif error == _api.SSL_ERROR_SYSCALL: if _api.ERR_peek_error() == 0: if result < 0: raise SysCallError( _api.ffi.errno, errorcode[_api.ffi.errno]) else: - # TODO - raise Exception("unknown syscall error") + raise SysCallError(-1, "Unexpected EOF") else: - # TODO + # TODO Untested + 1/0 _raise_current_error(Error) + elif error == _api.SSL_ERROR_NONE: + pass else: _raise_current_error(Error) @@ -930,7 +946,23 @@ class Connection(object): if _api.BIO_should_retry(bio): if _api.BIO_should_read(bio): raise WantReadError() - 1/0 + elif _api.BIO_should_write(bio): + # TODO Untested + 1/0 + raise WantWriteError() + elif _api.BIO_should_io_special(bio): + 1/0 + # TODO Untested. I think io_special means the socket BIO has a + # not-yet connected socket. + raise ValueError("BIO_should_io_special") + else: + 1/0 + # TODO Untested + raise ValueError("unknown bio failure") + else: + 1/0 + # TODO Untested + _raise_current_error(Error) def bio_read(self, bufsiz): diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py index 23c533c..2fed4b8 100644 --- a/OpenSSL/crypto.py +++ b/OpenSSL/crypto.py @@ -286,8 +286,11 @@ class X509Name(object): if data_length < 0: 1/0 - result = _api.buffer(result_buffer[0], data_length)[:].decode('utf-8') - _api.OPENSSL_free(result_buffer[0]) + try: + result = _api.buffer(result_buffer[0], data_length)[:].decode('utf-8') + finally: + # XXX untested + _api.OPENSSL_free(result_buffer[0]) return result diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py index 8fc17a2..1b2f213 100644 --- a/OpenSSL/test/test_ssl.py +++ b/OpenSSL/test/test_ssl.py @@ -8,7 +8,7 @@ Unit tests for :py:obj:`OpenSSL.SSL`. from gc import collect from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK, EPIPE from sys import platform, version_info -from socket import error, socket +from socket import SHUT_RDWR, error, socket from os import makedirs from os.path import join, dirname from unittest import main @@ -33,9 +33,9 @@ from OpenSSL.SSL import ( SESS_CACHE_NO_INTERNAL_STORE, SESS_CACHE_NO_INTERNAL) from OpenSSL.SSL import ( - Error, SysCallError, WantReadError, ZeroReturnError, SSLeay_version) + Error, SysCallError, WantReadError, WantWriteError, ZeroReturnError) from OpenSSL.SSL import ( - Context, ContextType, Session, Connection, ConnectionType) + Context, ContextType, Session, Connection, ConnectionType, SSLeay_version) from OpenSSL.test.util import TestCase, bytes, b from OpenSSL.test.test_crypto import ( @@ -1239,8 +1239,6 @@ class ConnectionTests(TestCase, _LoopbackMixin): """ Unit tests for :py:obj:`OpenSSL.SSL.Connection`. """ - # XXX want_write - # XXX want_read # XXX get_peer_certificate -> None # XXX sock_shutdown # XXX master_key -> TypeError @@ -1729,6 +1727,36 @@ class ConnectionTests(TestCase, _LoopbackMixin): self._loopback, clientFactory=makeClient, serverFactory=makeServer) + def test_wantWriteError(self): + """ + :py:obj:`Connection` methods which generate output raise + :py:obj:`OpenSSL.SSL.WantWriteError` if writing to the connection's BIO + fail indicating a should-write state. + """ + client_socket, server_socket = socket_pair() + # Fill up the client's send buffer so Connection won't be able to write + # anything. + msg = 'x' * 1024 + for i in range(1024): + try: + client_socket.send(msg) + except error as e: + if e.errno == EWOULDBLOCK: + break + raise + else: + self.fail( + "Failed to fill socket buffer, cannot test BIO want write") + + ctx = Context(TLSv1_METHOD) + conn = Connection(ctx, client_socket) + # Client's speak first, so make it an SSL client + conn.set_connect_state() + self.assertRaises(WantWriteError, conn.do_handshake) + + # XXX want_read + + class ConnectionGetCipherListTests(TestCase): """ @@ -2224,6 +2252,18 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): self.assertEquals(e.__class__, Error) + def test_unexpectedEndOfFile(self): + """ + If the connection is lost before an orderly SSL shutdown occurs, + :py:obj:`OpenSSL.SSL.SysCallError` is raised with a message of + "Unexpected EOF". + """ + server_conn, client_conn = self._loopback() + client_conn.sock_shutdown(SHUT_RDWR) + exc = self.assertRaises(SysCallError, server_conn.recv, 1024) + self.assertEqual(exc.args, (-1, "Unexpected EOF")) + + def _check_client_ca_list(self, func): """ Verify the return value of the :py:obj:`get_client_ca_list` method for server and client connections. @@ -2435,6 +2475,22 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): self._check_client_ca_list(set_replaces_add_ca) + +class ConnectionBIOTests(TestCase): + """ + Tests for :py:obj:`Connection.bio_read` and :py:obj:`Connection.bio_write`. + """ + def test_wantReadError(self): + """ + :py:obj:`Connection.bio_read` raises :py:obj:`OpenSSL.SSL.WantReadError` + if there are no bytes available to be read from the BIO. + """ + ctx = Context(TLSv1_METHOD) + conn = Connection(ctx, None) + self.assertRaises(WantReadError, conn.bio_read, 1024) + + + class InfoConstantTests(TestCase): """ Tests for assorted constants exposed for use in info callbacks. |