diff options
Diffstat (limited to 'OpenSSL/test/test_ssl.py')
-rw-r--r-- | OpenSSL/test/test_ssl.py | 648 |
1 files changed, 486 insertions, 162 deletions
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py index 2ab67fd..3e4e3da 100644 --- a/OpenSSL/test/test_ssl.py +++ b/OpenSSL/test/test_ssl.py @@ -2,7 +2,7 @@ # See LICENSE for details. """ -Unit tests for L{OpenSSL.SSL}. +Unit tests for :py:obj:`OpenSSL.SSL`. """ from gc import collect @@ -10,7 +10,7 @@ from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK from sys import platform, version_info from socket import error, socket from os import makedirs -from os.path import join +from os.path import join, dirname from unittest import main from weakref import ref @@ -26,9 +26,16 @@ from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE from OpenSSL.SSL import ( VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE, VERIFY_NONE) + +from OpenSSL.SSL import ( + SESS_CACHE_OFF, SESS_CACHE_CLIENT, SESS_CACHE_SERVER, SESS_CACHE_BOTH, + SESS_CACHE_NO_AUTO_CLEAR, SESS_CACHE_NO_INTERNAL_LOOKUP, + SESS_CACHE_NO_INTERNAL_STORE, SESS_CACHE_NO_INTERNAL) + from OpenSSL.SSL import ( Error, SysCallError, WantReadError, ZeroReturnError, SSLeay_version) -from OpenSSL.SSL import Context, ContextType, Connection, ConnectionType +from OpenSSL.SSL import ( + Context, ContextType, Session, Connection, ConnectionType) from OpenSSL.test.util import TestCase, bytes, b from OpenSSL.test.test_crypto import ( @@ -50,6 +57,16 @@ try: except ImportError: OP_NO_TICKET = None +try: + from OpenSSL.SSL import OP_NO_COMPRESSION +except ImportError: + OP_NO_COMPRESSION = None + +try: + from OpenSSL.SSL import MODE_RELEASE_BUFFERS +except ImportError: + MODE_RELEASE_BUFFERS = 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, @@ -172,16 +189,30 @@ class _LoopbackMixin: Helper mixin which defines methods for creating a connected socket pair and for forcing two connected SSL sockets to talk to each other via memory BIOs. """ - def _loopback(self): - (server, client) = socket_pair() + def _loopbackClientFactory(self, socket): + client = Connection(Context(TLSv1_METHOD), socket) + client.set_connect_state() + return client + + def _loopbackServerFactory(self, socket): ctx = Context(TLSv1_METHOD) ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) - server = Connection(ctx, server) + server = Connection(ctx, socket) server.set_accept_state() - client = Connection(Context(TLSv1_METHOD), client) - client.set_connect_state() + return server + + + def _loopback(self, serverFactory=None, clientFactory=None): + if serverFactory is None: + serverFactory = self._loopbackServerFactory + if clientFactory is None: + clientFactory = self._loopbackClientFactory + + (server, client) = socket_pair() + server = serverFactory(server) + client = clientFactory(client) handshake(client, server) @@ -192,10 +223,10 @@ class _LoopbackMixin: def _interactInMemory(self, client_conn, server_conn): """ - Try to read application bytes from each of the two L{Connection} + Try to read application bytes from each of the two :py:obj:`Connection` objects. Copy bytes back and forth between their send/receive buffers for as long as there is anything to copy. When there is nothing more - to copy, return C{None}. If one of them actually manages to deliver + to copy, return :py:obj:`None`. If one of them actually manages to deliver some application bytes, return a two-tuple of the connection from which the bytes were read and the bytes themselves. """ @@ -241,12 +272,12 @@ class _LoopbackMixin: class VersionTests(TestCase): """ Tests for version information exposed by - L{OpenSSL.SSL.SSLeay_version} and - L{OpenSSL.SSL.OPENSSL_VERSION_NUMBER}. + :py:obj:`OpenSSL.SSL.SSLeay_version` and + :py:obj:`OpenSSL.SSL.OPENSSL_VERSION_NUMBER`. """ def test_OPENSSL_VERSION_NUMBER(self): """ - L{OPENSSL_VERSION_NUMBER} is an integer with status in the low + :py:obj:`OPENSSL_VERSION_NUMBER` is an integer with status in the low byte and the patch, fix, minor, and major versions in the nibbles above that. """ @@ -255,7 +286,7 @@ class VersionTests(TestCase): def test_SSLeay_version(self): """ - L{SSLeay_version} takes a version type indicator and returns + :py:obj:`SSLeay_version` takes a version type indicator and returns one of a number of version strings based on that indicator. """ versions = {} @@ -270,19 +301,19 @@ class VersionTests(TestCase): class ContextTests(TestCase, _LoopbackMixin): """ - Unit tests for L{OpenSSL.SSL.Context}. + Unit tests for :py:obj:`OpenSSL.SSL.Context`. """ def test_method(self): """ - L{Context} can be instantiated with one of L{SSLv2_METHOD}, - L{SSLv3_METHOD}, L{SSLv23_METHOD}, or L{TLSv1_METHOD}. + :py:obj:`Context` can be instantiated with one of :py:obj:`SSLv2_METHOD`, + :py:obj:`SSLv3_METHOD`, :py:obj:`SSLv23_METHOD`, or :py:obj:`TLSv1_METHOD`. """ for meth in [SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]: Context(meth) try: Context(SSLv2_METHOD) - except ValueError: + except (Error, ValueError): # Some versions of OpenSSL have SSLv2, some don't. # Difficult to say in advance. pass @@ -293,7 +324,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_type(self): """ - L{Context} and L{ContextType} refer to the same type object and can be + :py:obj:`Context` and :py:obj:`ContextType` refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(Context, ContextType) @@ -302,7 +333,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_use_privatekey(self): """ - L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance. + :py:obj:`Context.use_privatekey` takes an :py:obj:`OpenSSL.crypto.PKey` instance. """ key = PKey() key.generate_key(TYPE_RSA, 128) @@ -313,7 +344,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_app_data_wrong_args(self): """ - L{Context.set_app_data} raises L{TypeError} if called with other than + :py:obj:`Context.set_app_data` raises :py:obj:`TypeError` if called with other than one argument. """ context = Context(TLSv1_METHOD) @@ -323,7 +354,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_get_app_data_wrong_args(self): """ - L{Context.get_app_data} raises L{TypeError} if called with any + :py:obj:`Context.get_app_data` raises :py:obj:`TypeError` if called with any arguments. """ context = Context(TLSv1_METHOD) @@ -332,8 +363,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_app_data(self): """ - L{Context.set_app_data} stores an object for later retrieval using - L{Context.get_app_data}. + :py:obj:`Context.set_app_data` stores an object for later retrieval using + :py:obj:`Context.get_app_data`. """ app_data = object() context = Context(TLSv1_METHOD) @@ -343,8 +374,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_options_wrong_args(self): """ - L{Context.set_options} raises L{TypeError} if called with the wrong - number of arguments or a non-C{int} argument. + :py:obj:`Context.set_options` raises :py:obj:`TypeError` if called with the wrong + number of arguments or a non-:py:obj:`int` argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_options) @@ -352,10 +383,34 @@ class ContextTests(TestCase, _LoopbackMixin): self.assertRaises(TypeError, context.set_options, 1, None) + def test_set_mode_wrong_args(self): + """ + :py:obj:`Context.set`mode} raises :py:obj:`TypeError` if called with the wrong + number of arguments or a non-:py:obj:`int` argument. + """ + context = Context(TLSv1_METHOD) + self.assertRaises(TypeError, context.set_mode) + self.assertRaises(TypeError, context.set_mode, None) + self.assertRaises(TypeError, context.set_mode, 1, None) + + + if MODE_RELEASE_BUFFERS is not None: + def test_set_mode(self): + """ + :py:obj:`Context.set_mode` accepts a mode bitvector and returns the newly + set mode. + """ + context = Context(TLSv1_METHOD) + self.assertTrue( + MODE_RELEASE_BUFFERS & context.set_mode(MODE_RELEASE_BUFFERS)) + else: + "MODE_RELEASE_BUFFERS unavailable - OpenSSL version may be too old" + + def test_set_timeout_wrong_args(self): """ - L{Context.set_timeout} raises L{TypeError} if called with the wrong - number of arguments or a non-C{int} argument. + :py:obj:`Context.set_timeout` raises :py:obj:`TypeError` if called with the wrong + number of arguments or a non-:py:obj:`int` argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_timeout) @@ -365,7 +420,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_get_timeout_wrong_args(self): """ - L{Context.get_timeout} raises L{TypeError} if called with any arguments. + :py:obj:`Context.get_timeout` raises :py:obj:`TypeError` if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_timeout, None) @@ -373,8 +428,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_timeout(self): """ - L{Context.set_timeout} sets the session timeout for all connections - created using the context object. L{Context.get_timeout} retrieves this + :py:obj:`Context.set_timeout` sets the session timeout for all connections + created using the context object. :py:obj:`Context.get_timeout` retrieves this value. """ context = Context(TLSv1_METHOD) @@ -384,8 +439,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_verify_depth_wrong_args(self): """ - L{Context.set_verify_depth} raises L{TypeError} if called with the wrong - number of arguments or a non-C{int} argument. + :py:obj:`Context.set_verify_depth` raises :py:obj:`TypeError` if called with the wrong + number of arguments or a non-:py:obj:`int` argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_verify_depth) @@ -395,7 +450,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_get_verify_depth_wrong_args(self): """ - L{Context.get_verify_depth} raises L{TypeError} if called with any arguments. + :py:obj:`Context.get_verify_depth` raises :py:obj:`TypeError` if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_verify_depth, None) @@ -403,9 +458,9 @@ class ContextTests(TestCase, _LoopbackMixin): def test_verify_depth(self): """ - L{Context.set_verify_depth} sets the number of certificates in a chain + :py:obj:`Context.set_verify_depth` sets the number of certificates in a chain to follow before giving up. The value can be retrieved with - L{Context.get_verify_depth}. + :py:obj:`Context.get_verify_depth`. """ context = Context(TLSv1_METHOD) context.set_verify_depth(11) @@ -429,7 +484,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_passwd_cb_wrong_args(self): """ - L{Context.set_passwd_cb} raises L{TypeError} if called with the + :py:obj:`Context.set_passwd_cb` raises :py:obj:`TypeError` if called with the wrong arguments or with a non-callable first argument. """ context = Context(TLSv1_METHOD) @@ -440,7 +495,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_passwd_cb(self): """ - L{Context.set_passwd_cb} accepts a callable which will be invoked when + :py:obj:`Context.set_passwd_cb` accepts a callable which will be invoked when a private key is loaded from an encrypted PEM. """ passphrase = b("foobar") @@ -460,7 +515,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_passwd_callback_exception(self): """ - L{Context.use_privatekey_file} propagates any exception raised by the + :py:obj:`Context.use_privatekey_file` propagates any exception raised by the passphrase callback. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) @@ -474,7 +529,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_passwd_callback_false(self): """ - L{Context.use_privatekey_file} raises L{OpenSSL.SSL.Error} if the + :py:obj:`Context.use_privatekey_file` raises :py:obj:`OpenSSL.SSL.Error` if the passphrase callback returns a false value. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) @@ -488,7 +543,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_passwd_callback_non_string(self): """ - L{Context.use_privatekey_file} raises L{OpenSSL.SSL.Error} if the + :py:obj:`Context.use_privatekey_file` raises :py:obj:`OpenSSL.SSL.Error` if the passphrase callback returns a true non-string value. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) @@ -521,7 +576,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_info_callback(self): """ - L{Context.set_info_callback} accepts a callable which will be invoked + :py:obj:`Context.set_info_callback` accepts a callable which will be invoked when certain information about an SSL connection is available. """ (server, client) = socket_pair() @@ -556,8 +611,8 @@ class ContextTests(TestCase, _LoopbackMixin): def _load_verify_locations_test(self, *args): """ Create a client context which will verify the peer certificate and call - its C{load_verify_locations} method with C{*args}. Then connect it to a - server and ensure that the handshake succeeds. + its :py:obj:`load_verify_locations` method with the given arguments. + Then connect it to a server and ensure that the handshake succeeds. """ (server, client) = socket_pair() @@ -593,7 +648,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_verify_file(self): """ - L{Context.load_verify_locations} accepts a file name and uses the + :py:obj:`Context.load_verify_locations` accepts a file name and uses the certificates within for verification purposes. """ cafile = self.mktemp() @@ -606,7 +661,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_verify_invalid_file(self): """ - L{Context.load_verify_locations} raises L{Error} when passed a + :py:obj:`Context.load_verify_locations` raises :py:obj:`Error` when passed a non-existent cafile. """ clientContext = Context(TLSv1_METHOD) @@ -616,7 +671,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_verify_directory(self): """ - L{Context.load_verify_locations} accepts a directory name and uses + :py:obj:`Context.load_verify_locations` accepts a directory name and uses the certificates within for verification purposes. """ capath = self.mktemp() @@ -635,8 +690,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_verify_locations_wrong_args(self): """ - L{Context.load_verify_locations} raises L{TypeError} if called with - the wrong number of arguments or with non-C{str} arguments. + :py:obj:`Context.load_verify_locations` raises :py:obj:`TypeError` if called with + the wrong number of arguments or with non-:py:obj:`str` arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.load_verify_locations) @@ -651,7 +706,7 @@ class ContextTests(TestCase, _LoopbackMixin): else: def test_set_default_verify_paths(self): """ - L{Context.set_default_verify_paths} causes the platform-specific CA + :py:obj:`Context.set_default_verify_paths` causes the platform-specific CA certificate locations to be used for verification purposes. """ # Testing this requires a server with a certificate signed by one of @@ -680,8 +735,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_default_verify_paths_signature(self): """ - L{Context.set_default_verify_paths} takes no arguments and raises - L{TypeError} if given any. + :py:obj:`Context.set_default_verify_paths` takes no arguments and raises + :py:obj:`TypeError` if given any. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_default_verify_paths, None) @@ -691,9 +746,9 @@ class ContextTests(TestCase, _LoopbackMixin): def test_add_extra_chain_cert_invalid_cert(self): """ - L{Context.add_extra_chain_cert} raises L{TypeError} if called with + :py:obj:`Context.add_extra_chain_cert` raises :py:obj:`TypeError` if called with other than one argument or if called with an object which is not an - instance of L{X509}. + instance of :py:obj:`X509`. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.add_extra_chain_cert) @@ -726,10 +781,10 @@ class ContextTests(TestCase, _LoopbackMixin): def test_add_extra_chain_cert(self): """ - L{Context.add_extra_chain_cert} accepts an L{X509} instance to add to + :py:obj:`Context.add_extra_chain_cert` accepts an :py:obj:`X509` instance to add to the certificate chain. - See L{_create_certificate_chain} for the details of the certificate + See :py:obj:`_create_certificate_chain` for the details of the certificate chain tested. The chain is tested by starting a server with scert and connecting @@ -770,7 +825,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_use_certificate_chain_file(self): """ - L{Context.use_certificate_chain_file} reads a certificate chain from + :py:obj:`Context.use_certificate_chain_file` reads a certificate chain from the specified file. The chain is tested by starting a server with scert and connecting @@ -809,7 +864,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_get_verify_mode_wrong_args(self): """ - L{Context.get_verify_mode} raises L{TypeError} if called with any + :py:obj:`Context.get_verify_mode` raises :py:obj:`TypeError` if called with any arguments. """ context = Context(TLSv1_METHOD) @@ -818,8 +873,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_get_verify_mode(self): """ - L{Context.get_verify_mode} returns the verify mode flags previously - passed to L{Context.set_verify}. + :py:obj:`Context.get_verify_mode` returns the verify mode flags previously + passed to :py:obj:`Context.set_verify`. """ context = Context(TLSv1_METHOD) self.assertEquals(context.get_verify_mode(), 0) @@ -831,8 +886,8 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_tmp_dh_wrong_args(self): """ - L{Context.load_tmp_dh} raises L{TypeError} if called with the wrong - number of arguments or with a non-C{str} argument. + :py:obj:`Context.load_tmp_dh` raises :py:obj:`TypeError` if called with the wrong + number of arguments or with a non-:py:obj:`str` argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.load_tmp_dh) @@ -842,7 +897,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_tmp_dh_missing_file(self): """ - L{Context.load_tmp_dh} raises L{OpenSSL.SSL.Error} if the specified file + :py:obj:`Context.load_tmp_dh` raises :py:obj:`OpenSSL.SSL.Error` if the specified file does not exist. """ context = Context(TLSv1_METHOD) @@ -851,7 +906,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_load_tmp_dh(self): """ - L{Context.load_tmp_dh} loads Diffie-Hellman parameters from the + :py:obj:`Context.load_tmp_dh` loads Diffie-Hellman parameters from the specified file. """ context = Context(TLSv1_METHOD) @@ -865,7 +920,7 @@ class ContextTests(TestCase, _LoopbackMixin): def test_set_cipher_list(self): """ - L{Context.set_cipher_list} accepts a C{str} naming the ciphers which + :py:obj:`Context.set_cipher_list` accepts a :py:obj:`str` naming the ciphers which connections created with the context object will be able to choose from. """ context = Context(TLSv1_METHOD) @@ -874,15 +929,46 @@ class ContextTests(TestCase, _LoopbackMixin): self.assertEquals(conn.get_cipher_list(), ["EXP-RC4-MD5"]) + def test_set_session_cache_mode_wrong_args(self): + """ + L{Context.set_session_cache_mode} raises L{TypeError} if called with + other than one integer argument. + """ + context = Context(TLSv1_METHOD) + self.assertRaises(TypeError, context.set_session_cache_mode) + self.assertRaises(TypeError, context.set_session_cache_mode, object()) + + + def test_get_session_cache_mode_wrong_args(self): + """ + L{Context.get_session_cache_mode} raises L{TypeError} if called with any + arguments. + """ + context = Context(TLSv1_METHOD) + self.assertRaises(TypeError, context.get_session_cache_mode, 1) + + + def test_session_cache_mode(self): + """ + L{Context.set_session_cache_mode} specifies how sessions are cached. + The setting can be retrieved via L{Context.get_session_cache_mode}. + """ + context = Context(TLSv1_METHOD) + old = context.set_session_cache_mode(SESS_CACHE_OFF) + off = context.set_session_cache_mode(SESS_CACHE_BOTH) + self.assertEqual(SESS_CACHE_OFF, off) + self.assertEqual(SESS_CACHE_BOTH, context.get_session_cache_mode()) + + class ServerNameCallbackTests(TestCase, _LoopbackMixin): """ - Tests for L{Context.set_tlsext_servername_callback} and its interaction with - L{Connection}. + Tests for :py:obj:`Context.set_tlsext_servername_callback` and its interaction with + :py:obj:`Connection`. """ def test_wrong_args(self): """ - L{Context.set_tlsext_servername_callback} raises L{TypeError} if called + :py:obj:`Context.set_tlsext_servername_callback` raises :py:obj:`TypeError` if called with other than one argument. """ context = Context(TLSv1_METHOD) @@ -892,7 +978,7 @@ class ServerNameCallbackTests(TestCase, _LoopbackMixin): def test_old_callback_forgotten(self): """ - If L{Context.set_tlsext_servername_callback} is used to specify a new + If :py:obj:`Context.set_tlsext_servername_callback` is used to specify a new callback, the one it replaces is dereferenced. """ def callback(connection): @@ -915,8 +1001,8 @@ class ServerNameCallbackTests(TestCase, _LoopbackMixin): def test_no_servername(self): """ When a client specifies no server name, the callback passed to - L{Context.set_tlsext_servername_callback} is invoked and the result of - L{Connection.get_servername} is C{None}. + :py:obj:`Context.set_tlsext_servername_callback` is invoked and the result of + :py:obj:`Connection.get_servername` is :py:obj:`None`. """ args = [] def servername(conn): @@ -948,8 +1034,8 @@ class ServerNameCallbackTests(TestCase, _LoopbackMixin): def test_servername(self): """ When a client specifies a server name in its hello message, the callback - passed to L{Contexts.set_tlsext_servername_callback} is invoked and the - result of L{Connection.get_servername} is that server name. + passed to :py:obj:`Contexts.set_tlsext_servername_callback` is invoked and the + result of :py:obj:`Connection.get_servername` is that server name. """ args = [] def servername(conn): @@ -975,9 +1061,33 @@ class ServerNameCallbackTests(TestCase, _LoopbackMixin): +class SessionTests(TestCase): + """ + Unit tests for :py:obj:`OpenSSL.SSL.Session`. + """ + def test_construction(self): + """ + :py:class:`Session` can be constructed with no arguments, creating a new + instance of that type. + """ + new_session = Session() + self.assertTrue(isinstance(new_session, Session)) + + + def test_construction_wrong_args(self): + """ + If any arguments are passed to :py:class:`Session`, :py:obj:`TypeError` + is raised. + """ + self.assertRaises(TypeError, Session, 123) + self.assertRaises(TypeError, Session, "hello") + self.assertRaises(TypeError, Session, object()) + + + class ConnectionTests(TestCase, _LoopbackMixin): """ - Unit tests for L{OpenSSL.SSL.Connection}. + Unit tests for :py:obj:`OpenSSL.SSL.Connection`. """ # XXX want_write # XXX want_read @@ -999,7 +1109,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_type(self): """ - L{Connection} and L{ConnectionType} refer to the same type object and + :py:obj:`Connection` and :py:obj:`ConnectionType` refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(Connection, ConnectionType) @@ -1009,8 +1119,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_context(self): """ - L{Connection.get_context} returns the L{Context} instance used to - construct the L{Connection} instance. + :py:obj:`Connection.get_context` returns the :py:obj:`Context` instance used to + construct the :py:obj:`Connection` instance. """ context = Context(TLSv1_METHOD) connection = Connection(context, None) @@ -1019,7 +1129,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_context_wrong_args(self): """ - L{Connection.get_context} raises L{TypeError} if called with any + :py:obj:`Connection.get_context` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1028,8 +1138,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_set_context_wrong_args(self): """ - L{Connection.set_context} raises L{TypeError} if called with a - non-L{Context} instance argument or with any number of arguments other + :py:obj:`Connection.set_context` raises :py:obj:`TypeError` if called with a + non-:py:obj:`Context` instance argument or with any number of arguments other than 1. """ ctx = Context(TLSv1_METHOD) @@ -1046,7 +1156,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_set_context(self): """ - L{Connection.set_context} specifies a new L{Context} instance to be used + :py:obj:`Connection.set_context` specifies a new :py:obj:`Context` instance to be used for the connection. """ original = Context(SSLv23_METHOD) @@ -1062,9 +1172,9 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_set_tlsext_host_name_wrong_args(self): """ - If L{Connection.set_tlsext_host_name} is called with a non-byte string + If :py:obj:`Connection.set_tlsext_host_name` is called with a non-byte string argument or a byte string with an embedded NUL or other than one - argument, L{TypeError} is raised. + argument, :py:obj:`TypeError` is raised. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, conn.set_tlsext_host_name) @@ -1082,7 +1192,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_servername_wrong_args(self): """ - L{Connection.get_servername} raises L{TypeError} if called with any + :py:obj:`Connection.get_servername` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1093,7 +1203,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_pending(self): """ - L{Connection.pending} returns the number of bytes available for + :py:obj:`Connection.pending` returns the number of bytes available for immediate read. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1102,7 +1212,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_pending_wrong_args(self): """ - L{Connection.pending} raises L{TypeError} if called with any arguments. + :py:obj:`Connection.pending` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.pending, None) @@ -1110,7 +1220,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_connect_wrong_args(self): """ - L{Connection.connect} raises L{TypeError} if called with a non-address + :py:obj:`Connection.connect` raises :py:obj:`TypeError` if called with a non-address argument or with the wrong number of arguments. """ connection = Connection(Context(TLSv1_METHOD), socket()) @@ -1121,7 +1231,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_connect_refused(self): """ - L{Connection.connect} raises L{socket.error} if the underlying socket + :py:obj:`Connection.connect` raises :py:obj:`socket.error` if the underlying socket connect method raises it. """ client = socket() @@ -1133,7 +1243,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_connect(self): """ - L{Connection.connect} establishes a connection to the specified address. + :py:obj:`Connection.connect` establishes a connection to the specified address. """ port = socket() port.bind(('', 0)) @@ -1149,7 +1259,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): else: def test_connect_ex(self): """ - If there is a connection error, L{Connection.connect_ex} returns the + If there is a connection error, :py:obj:`Connection.connect_ex` returns the errno instead of raising an exception. """ port = socket() @@ -1166,7 +1276,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_accept_wrong_args(self): """ - L{Connection.accept} raises L{TypeError} if called with any arguments. + :py:obj:`Connection.accept` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), socket()) self.assertRaises(TypeError, connection.accept, None) @@ -1174,8 +1284,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_accept(self): """ - L{Connection.accept} accepts a pending connection attempt and returns a - tuple of a new L{Connection} (the accepted client) and the address the + :py:obj:`Connection.accept` accepts a pending connection attempt and returns a + tuple of a new :py:obj:`Connection` (the accepted client) and the address the connection originated from. """ ctx = Context(TLSv1_METHOD) @@ -1201,7 +1311,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_shutdown_wrong_args(self): """ - L{Connection.shutdown} raises L{TypeError} if called with the wrong + :py:obj:`Connection.shutdown` raises :py:obj:`TypeError` if called with the wrong number of arguments or with arguments other than integers. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1214,7 +1324,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_shutdown(self): """ - L{Connection.shutdown} performs an SSL-level connection shutdown. + :py:obj:`Connection.shutdown` performs an SSL-level connection shutdown. """ server, client = self._loopback() self.assertFalse(server.shutdown()) @@ -1229,7 +1339,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_set_shutdown(self): """ - L{Connection.set_shutdown} sets the state of the SSL connection shutdown + :py:obj:`Connection.set_shutdown` sets the state of the SSL connection shutdown process. """ connection = Connection(Context(TLSv1_METHOD), socket()) @@ -1239,8 +1349,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_app_data_wrong_args(self): """ - L{Connection.set_app_data} raises L{TypeError} if called with other than - one argument. L{Connection.get_app_data} raises L{TypeError} if called + :py:obj:`Connection.set_app_data` raises :py:obj:`TypeError` if called with other than + one argument. :py:obj:`Connection.get_app_data` raises :py:obj:`TypeError` if called with any arguments. """ conn = Connection(Context(TLSv1_METHOD), None) @@ -1252,8 +1362,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_app_data(self): """ Any object can be set as app data by passing it to - L{Connection.set_app_data} and later retrieved with - L{Connection.get_app_data}. + :py:obj:`Connection.set_app_data` and later retrieved with + :py:obj:`Connection.get_app_data`. """ conn = Connection(Context(TLSv1_METHOD), None) app_data = object() @@ -1263,8 +1373,8 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_makefile(self): """ - L{Connection.makefile} is not implemented and calling that method raises - L{NotImplementedError}. + :py:obj:`Connection.makefile` is not implemented and calling that method raises + :py:obj:`NotImplementedError`. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(NotImplementedError, conn.makefile) @@ -1272,7 +1382,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_peer_cert_chain_wrong_args(self): """ - L{Connection.get_peer_cert_chain} raises L{TypeError} if called with any + :py:obj:`Connection.get_peer_cert_chain` raises :py:obj:`TypeError` if called with any arguments. """ conn = Connection(Context(TLSv1_METHOD), None) @@ -1284,7 +1394,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_peer_cert_chain(self): """ - L{Connection.get_peer_cert_chain} returns a list of certificates which + :py:obj:`Connection.get_peer_cert_chain` returns a list of certificates which the connected server returned for the certification verification. """ chain = _create_certificate_chain() @@ -1318,7 +1428,7 @@ class ConnectionTests(TestCase, _LoopbackMixin): def test_get_peer_cert_chain_none(self): """ - L{Connection.get_peer_cert_chain} returns C{None} if the peer sends no + :py:obj:`Connection.get_peer_cert_chain` returns :py:obj:`None` if the peer sends no certificate chain. """ ctx = Context(TLSv1_METHOD) @@ -1332,14 +1442,151 @@ class ConnectionTests(TestCase, _LoopbackMixin): self.assertIdentical(None, server.get_peer_cert_chain()) + def test_get_session_wrong_args(self): + """ + :py:obj:`Connection.get_session` raises :py:obj:`TypeError` if called + with any arguments. + """ + ctx = Context(TLSv1_METHOD) + server = Connection(ctx, None) + self.assertRaises(TypeError, server.get_session, 123) + self.assertRaises(TypeError, server.get_session, "hello") + self.assertRaises(TypeError, server.get_session, object()) + + + def test_get_session_unconnected(self): + """ + :py:obj:`Connection.get_session` returns :py:obj:`None` when used with + an object which has not been connected. + """ + ctx = Context(TLSv1_METHOD) + server = Connection(ctx, None) + session = server.get_session() + self.assertIdentical(None, session) + + + def test_server_get_session(self): + """ + On the server side of a connection, :py:obj:`Connection.get_session` + returns a :py:class:`Session` instance representing the SSL session for + that connection. + """ + server, client = self._loopback() + session = server.get_session() + self.assertTrue(session, Session) + + + def test_client_get_session(self): + """ + On the client side of a connection, :py:obj:`Connection.get_session` + returns a :py:class:`Session` instance representing the SSL session for + that connection. + """ + server, client = self._loopback() + session = client.get_session() + self.assertTrue(session, Session) + + + def test_set_session_wrong_args(self): + """ + If called with an object that is not an instance of :py:class:`Session`, + or with other than one argument, :py:obj:`Connection.set_session` raises + :py:obj:`TypeError`. + """ + ctx = Context(TLSv1_METHOD) + connection = Connection(ctx, None) + self.assertRaises(TypeError, connection.set_session) + self.assertRaises(TypeError, connection.set_session, 123) + self.assertRaises(TypeError, connection.set_session, "hello") + self.assertRaises(TypeError, connection.set_session, object()) + self.assertRaises( + TypeError, connection.set_session, Session(), Session()) + + + def test_client_set_session(self): + """ + :py:obj:`Connection.set_session`, when used prior to a connection being + established, accepts a :py:class:`Session` instance and causes an + attempt to re-use the session it represents when the SSL handshake is + performed. + """ + key = load_privatekey(FILETYPE_PEM, server_key_pem) + cert = load_certificate(FILETYPE_PEM, server_cert_pem) + ctx = Context(TLSv1_METHOD) + ctx.use_privatekey(key) + ctx.use_certificate(cert) + ctx.set_session_id("unity-test") + + def makeServer(socket): + server = Connection(ctx, socket) + server.set_accept_state() + return server + + originalServer, originalClient = self._loopback( + serverFactory=makeServer) + originalSession = originalClient.get_session() + + def makeClient(socket): + client = self._loopbackClientFactory(socket) + client.set_session(originalSession) + return client + resumedServer, resumedClient = self._loopback( + serverFactory=makeServer, + clientFactory=makeClient) + + # This is a proxy: in general, we have no access to any unique + # identifier for the session (new enough versions of OpenSSL expose a + # hash which could be usable, but "new enough" is very, very new). + # Instead, exploit the fact that the master key is re-used if the + # session is re-used. As long as the master key for the two connections + # is the same, the session was re-used! + self.assertEqual( + originalServer.master_key(), resumedServer.master_key()) + + + def test_set_session_wrong_method(self): + """ + If :py:obj:`Connection.set_session` is passed a :py:class:`Session` + instance associated with a context using a different SSL method than the + :py:obj:`Connection` is using, a :py:class:`OpenSSL.SSL.Error` is + raised. + """ + key = load_privatekey(FILETYPE_PEM, server_key_pem) + cert = load_certificate(FILETYPE_PEM, server_cert_pem) + ctx = Context(TLSv1_METHOD) + ctx.use_privatekey(key) + ctx.use_certificate(cert) + ctx.set_session_id("unity-test") + + def makeServer(socket): + server = Connection(ctx, socket) + server.set_accept_state() + return server + + originalServer, originalClient = self._loopback( + serverFactory=makeServer) + originalSession = originalClient.get_session() + + def makeClient(socket): + # Intentionally use a different, incompatible method here. + client = Connection(Context(SSLv3_METHOD), socket) + client.set_connect_state() + client.set_session(originalSession) + return client + + self.assertRaises( + Error, + self._loopback, clientFactory=makeClient, serverFactory=makeServer) + + class ConnectionGetCipherListTests(TestCase): """ - Tests for L{Connection.get_cipher_list}. + Tests for :py:obj:`Connection.get_cipher_list`. """ def test_wrong_args(self): """ - L{Connection.get_cipher_list} raises L{TypeError} if called with any + :py:obj:`Connection.get_cipher_list` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1348,7 +1595,7 @@ class ConnectionGetCipherListTests(TestCase): def test_result(self): """ - L{Connection.get_cipher_list} returns a C{list} of C{str} giving the + :py:obj:`Connection.get_cipher_list` returns a :py:obj:`list` of :py:obj:`str` giving the names of the ciphers which might be used. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1361,12 +1608,12 @@ class ConnectionGetCipherListTests(TestCase): class ConnectionSendTests(TestCase, _LoopbackMixin): """ - Tests for L{Connection.send} + Tests for :py:obj:`Connection.send` """ def test_wrong_args(self): """ When called with arguments other than a single string, - L{Connection.send} raises L{TypeError}. + :py:obj:`Connection.send` raises :py:obj:`TypeError`. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.send) @@ -1376,7 +1623,7 @@ class ConnectionSendTests(TestCase, _LoopbackMixin): def test_short_bytes(self): """ - When passed a short byte string, L{Connection.send} transmits all of it + When passed a short byte string, :py:obj:`Connection.send` transmits all of it and returns the number of bytes sent. """ server, client = self._loopback() @@ -1392,7 +1639,7 @@ class ConnectionSendTests(TestCase, _LoopbackMixin): def test_short_memoryview(self): """ When passed a memoryview onto a small number of bytes, - L{Connection.send} transmits all of them and returns the number of + :py:obj:`Connection.send` transmits all of them and returns the number of bytes sent. """ server, client = self._loopback() @@ -1404,12 +1651,12 @@ class ConnectionSendTests(TestCase, _LoopbackMixin): class ConnectionSendallTests(TestCase, _LoopbackMixin): """ - Tests for L{Connection.sendall}. + Tests for :py:obj:`Connection.sendall`. """ def test_wrong_args(self): """ When called with arguments other than a single string, - L{Connection.sendall} raises L{TypeError}. + :py:obj:`Connection.sendall` raises :py:obj:`TypeError`. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.sendall) @@ -1419,7 +1666,7 @@ class ConnectionSendallTests(TestCase, _LoopbackMixin): def test_short(self): """ - L{Connection.sendall} transmits all of the bytes in the string passed to + :py:obj:`Connection.sendall` transmits all of the bytes in the string passed to it. """ server, client = self._loopback() @@ -1435,7 +1682,7 @@ class ConnectionSendallTests(TestCase, _LoopbackMixin): def test_short_memoryview(self): """ When passed a memoryview onto a small number of bytes, - L{Connection.sendall} transmits all of them. + :py:obj:`Connection.sendall` transmits all of them. """ server, client = self._loopback() server.sendall(memoryview(b('x'))) @@ -1444,7 +1691,7 @@ class ConnectionSendallTests(TestCase, _LoopbackMixin): def test_long(self): """ - L{Connection.sendall} transmits all of the bytes in the string passed to + :py:obj:`Connection.sendall` transmits all of the bytes in the string passed to it even if this requires multiple calls of an underlying write function. """ server, client = self._loopback() @@ -1464,7 +1711,7 @@ class ConnectionSendallTests(TestCase, _LoopbackMixin): def test_closed(self): """ - If the underlying socket is closed, L{Connection.sendall} propagates the + If the underlying socket is closed, :py:obj:`Connection.sendall` propagates the write error from the low level write call. """ server, client = self._loopback() @@ -1479,7 +1726,7 @@ class ConnectionRenegotiateTests(TestCase, _LoopbackMixin): """ def test_renegotiate_wrong_args(self): """ - L{Connection.renegotiate} raises L{TypeError} if called with any + :py:obj:`Connection.renegotiate` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1488,7 +1735,7 @@ class ConnectionRenegotiateTests(TestCase, _LoopbackMixin): def test_total_renegotiations_wrong_args(self): """ - L{Connection.total_renegotiations} raises L{TypeError} if called with + :py:obj:`Connection.total_renegotiations` raises :py:obj:`TypeError` if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1497,7 +1744,7 @@ class ConnectionRenegotiateTests(TestCase, _LoopbackMixin): def test_total_renegotiations(self): """ - L{Connection.total_renegotiations} returns C{0} before any + :py:obj:`Connection.total_renegotiations` returns :py:obj:`0` before any renegotiations have happened. """ connection = Connection(Context(TLSv1_METHOD), None) @@ -1528,11 +1775,11 @@ class ConnectionRenegotiateTests(TestCase, _LoopbackMixin): class ErrorTests(TestCase): """ - Unit tests for L{OpenSSL.SSL.Error}. + Unit tests for :py:obj:`OpenSSL.SSL.Error`. """ def test_type(self): """ - L{Error} is an exception type. + :py:obj:`Error` is an exception type. """ self.assertTrue(issubclass(Error, Exception)) self.assertEqual(Error.__name__, 'Error') @@ -1541,7 +1788,7 @@ class ErrorTests(TestCase): class ConstantsTests(TestCase): """ - Tests for the values of constants exposed in L{OpenSSL.SSL}. + Tests for the values of constants exposed in :py:obj:`OpenSSL.SSL`. These are values defined by OpenSSL intended only to be used as flags to OpenSSL APIs. The only assertions it seems can be made about them is @@ -1551,8 +1798,8 @@ class ConstantsTests(TestCase): if OP_NO_QUERY_MTU is not None: def test_op_no_query_mtu(self): """ - The value of L{OpenSSL.SSL.OP_NO_QUERY_MTU} is 0x1000, the value of - I{SSL_OP_NO_QUERY_MTU} defined by I{openssl/ssl.h}. + The value of :py:obj:`OpenSSL.SSL.OP_NO_QUERY_MTU` is 0x1000, the value of + :py:const:`SSL_OP_NO_QUERY_MTU` defined by :file:`openssl/ssl.h`. """ self.assertEqual(OP_NO_QUERY_MTU, 0x1000) else: @@ -1562,8 +1809,8 @@ class ConstantsTests(TestCase): if OP_COOKIE_EXCHANGE is not None: def test_op_cookie_exchange(self): """ - The value of L{OpenSSL.SSL.OP_COOKIE_EXCHANGE} is 0x2000, the value - of I{SSL_OP_COOKIE_EXCHANGE} defined by I{openssl/ssl.h}. + The value of :py:obj:`OpenSSL.SSL.OP_COOKIE_EXCHANGE` is 0x2000, the value + of :py:const:`SSL_OP_COOKIE_EXCHANGE` defined by :file:`openssl/ssl.h`. """ self.assertEqual(OP_COOKIE_EXCHANGE, 0x2000) else: @@ -1573,23 +1820,100 @@ class ConstantsTests(TestCase): if OP_NO_TICKET is not None: def test_op_no_ticket(self): """ - The value of L{OpenSSL.SSL.OP_NO_TICKET} is 0x4000, the value of - I{SSL_OP_NO_TICKET} defined by I{openssl/ssl.h}. + The value of :py:obj:`OpenSSL.SSL.OP_NO_TICKET` is 0x4000, the value of + :py:const:`SSL_OP_NO_TICKET` defined by :file:`openssl/ssl.h`. """ self.assertEqual(OP_NO_TICKET, 0x4000) else: "OP_NO_TICKET unavailable - OpenSSL version may be too old" + if OP_NO_COMPRESSION is not None: + def test_op_no_compression(self): + """ + The value of :py:obj:`OpenSSL.SSL.OP_NO_COMPRESSION` is 0x20000, the value + of :py:const:`SSL_OP_NO_COMPRESSION` defined by :file:`openssl/ssl.h`. + """ + self.assertEqual(OP_NO_COMPRESSION, 0x20000) + else: + "OP_NO_COMPRESSION unavailable - OpenSSL version may be too old" + + + def test_sess_cache_off(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_OFF} 0x0, the value of + L{SSL_SESS_CACHE_OFF} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x0, SESS_CACHE_OFF) + + + def test_sess_cache_client(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_CLIENT} 0x1, the value of + L{SSL_SESS_CACHE_CLIENT} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x1, SESS_CACHE_CLIENT) + + + def test_sess_cache_server(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_SERVER} 0x2, the value of + L{SSL_SESS_CACHE_SERVER} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x2, SESS_CACHE_SERVER) + + + def test_sess_cache_both(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_BOTH} 0x3, the value of + L{SSL_SESS_CACHE_BOTH} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x3, SESS_CACHE_BOTH) + + + def test_sess_cache_no_auto_clear(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_NO_AUTO_CLEAR} 0x80, the value of + L{SSL_SESS_CACHE_NO_AUTO_CLEAR} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x80, SESS_CACHE_NO_AUTO_CLEAR) + + + def test_sess_cache_no_internal_lookup(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL_LOOKUP} 0x100, the + value of L{SSL_SESS_CACHE_NO_INTERNAL_LOOKUP} defined by + I{openssl/ssl.h}. + """ + self.assertEqual(0x100, SESS_CACHE_NO_INTERNAL_LOOKUP) + + + def test_sess_cache_no_internal_store(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL_STORE} 0x200, the + value of L{SSL_SESS_CACHE_NO_INTERNAL_STORE} defined by + I{openssl/ssl.h}. + """ + self.assertEqual(0x200, SESS_CACHE_NO_INTERNAL_STORE) + + + def test_sess_cache_no_internal(self): + """ + The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL} 0x300, the value of + L{SSL_SESS_CACHE_NO_INTERNAL} defined by I{openssl/ssl.h}. + """ + self.assertEqual(0x300, SESS_CACHE_NO_INTERNAL) + + class MemoryBIOTests(TestCase, _LoopbackMixin): """ - Tests for L{OpenSSL.SSL.Connection} using a memory BIO. + Tests for :py:obj:`OpenSSL.SSL.Connection` using a memory BIO. """ def _server(self, sock): """ - Create a new server-side SSL L{Connection} object wrapped around - C{sock}. + Create a new server-side SSL :py:obj:`Connection` object wrapped around + :py:obj:`sock`. """ # Create the server side Connection. This is mostly setup boilerplate # - use TLSv1, use a particular certificate, etc. @@ -1610,8 +1934,8 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def _client(self, sock): """ - Create a new client-side SSL L{Connection} object wrapped around - C{sock}. + Create a new client-side SSL :py:obj:`Connection` object wrapped around + :py:obj:`sock`. """ # Now create the client side Connection. Similar boilerplate to the # above. @@ -1630,7 +1954,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_memoryConnect(self): """ - Two L{Connection}s which use memory BIOs can be manually connected by + Two :py:obj:`Connection`s which use memory BIOs can be manually connected by reading from the output of each and writing those bytes to the input of the other and in this way establish a connection and exchange application-level bytes with each other. @@ -1674,10 +1998,10 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_socketConnect(self): """ - Just like L{test_memoryConnect} but with an actual socket. + Just like :py:obj:`test_memoryConnect` but with an actual socket. This is primarily to rule out the memory BIO code as the source of - any problems encountered while passing data over a L{Connection} (if + any problems encountered while passing data over a :py:obj:`Connection` (if this test fails, there must be a problem outside the memory BIO code, as no memory BIO is involved here). Even though this isn't a memory BIO test, it's convenient to have it here. @@ -1698,8 +2022,8 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_socketOverridesMemory(self): """ - Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't - work on L{OpenSSL.SSL.Connection}() that use sockets. + Test that :py:obj:`OpenSSL.SSL.bio_read` and :py:obj:`OpenSSL.SSL.bio_write` don't + work on :py:obj:`OpenSSL.SSL.Connection`() that use sockets. """ context = Context(SSLv3_METHOD) client = socket() @@ -1712,7 +2036,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_outgoingOverflow(self): """ If more bytes than can be written to the memory BIO are passed to - L{Connection.send} at once, the number of bytes which were written is + :py:obj:`Connection.send` at once, the number of bytes which were written is returned and that many bytes from the beginning of the input can be read from the other end of the connection. """ @@ -1738,8 +2062,8 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_shutdown(self): """ - L{Connection.bio_shutdown} signals the end of the data stream from - which the L{Connection} reads. + :py:obj:`Connection.bio_shutdown` signals the end of the data stream from + which the :py:obj:`Connection` reads. """ server = self._server(None) server.bio_shutdown() @@ -1751,13 +2075,13 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def _check_client_ca_list(self, func): """ - Verify the return value of the C{get_client_ca_list} method for server and client connections. + Verify the return value of the :py:obj:`get_client_ca_list` method for server and client connections. - @param func: A function which will be called with the server context + :param func: A function which will be called with the server context before the client and server are connected to each other. This function should specify a list of CAs for the server to send to the client and return that same list. The list will be used to verify - that C{get_client_ca_list} returns the proper value at various + that :py:obj:`get_client_ca_list` returns the proper value at various times. """ server = self._server(None) @@ -1775,7 +2099,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_client_ca_list_errors(self): """ - L{Context.set_client_ca_list} raises a L{TypeError} if called with a + :py:obj:`Context.set_client_ca_list` raises a :py:obj:`TypeError` if called with a non-list or a list that contains objects other than X509Names. """ ctx = Context(TLSv1_METHOD) @@ -1786,9 +2110,9 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_empty_ca_list(self): """ - If passed an empty list, L{Context.set_client_ca_list} configures the + If passed an empty list, :py:obj:`Context.set_client_ca_list` configures the context to send no CA names to the client and, on both the server and - client sides, L{Connection.get_client_ca_list} returns an empty list + client sides, :py:obj:`Connection.get_client_ca_list` returns an empty list after the connection is set up. """ def no_ca(ctx): @@ -1800,9 +2124,9 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_one_ca_list(self): """ If passed a list containing a single X509Name, - L{Context.set_client_ca_list} configures the context to send that CA + :py:obj:`Context.set_client_ca_list` configures the context to send that CA name to the client and, on both the server and client sides, - L{Connection.get_client_ca_list} returns a list containing that + :py:obj:`Connection.get_client_ca_list` returns a list containing that X509Name after the connection is set up. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) @@ -1816,9 +2140,9 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_multiple_ca_list(self): """ If passed a list containing multiple X509Name objects, - L{Context.set_client_ca_list} configures the context to send those CA + :py:obj:`Context.set_client_ca_list` configures the context to send those CA names to the client and, on both the server and client sides, - L{Connection.get_client_ca_list} returns a list containing those + :py:obj:`Connection.get_client_ca_list` returns a list containing those X509Names after the connection is set up. """ secert = load_certificate(FILETYPE_PEM, server_cert_pem) @@ -1837,7 +2161,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_reset_ca_list(self): """ If called multiple times, only the X509Names passed to the final call - of L{Context.set_client_ca_list} are used to configure the CA names + of :py:obj:`Context.set_client_ca_list` are used to configure the CA names sent to the client. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) @@ -1857,7 +2181,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_mutated_ca_list(self): """ - If the list passed to L{Context.set_client_ca_list} is mutated + If the list passed to :py:obj:`Context.set_client_ca_list` is mutated afterwards, this does not affect the list of CA names sent to the client. """ @@ -1877,7 +2201,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_add_client_ca_errors(self): """ - L{Context.add_client_ca} raises L{TypeError} if called with a non-X509 + :py:obj:`Context.add_client_ca` raises :py:obj:`TypeError` if called with a non-X509 object or with a number of arguments other than one. """ ctx = Context(TLSv1_METHOD) @@ -1890,7 +2214,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_one_add_client_ca(self): """ A certificate's subject can be added as a CA to be sent to the client - with L{Context.add_client_ca}. + with :py:obj:`Context.add_client_ca`. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) cadesc = cacert.get_subject() @@ -1903,7 +2227,7 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_multiple_add_client_ca(self): """ Multiple CA names can be sent to the client by calling - L{Context.add_client_ca} with multiple X509 objects. + :py:obj:`Context.add_client_ca` with multiple X509 objects. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) @@ -1920,8 +2244,8 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_and_add_client_ca(self): """ - A call to L{Context.set_client_ca_list} followed by a call to - L{Context.add_client_ca} results in using the CA names from the first + A call to :py:obj:`Context.set_client_ca_list` followed by a call to + :py:obj:`Context.add_client_ca` results in using the CA names from the first call and the CA name from the second call. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) @@ -1941,8 +2265,8 @@ class MemoryBIOTests(TestCase, _LoopbackMixin): def test_set_after_add_client_ca(self): """ - A call to L{Context.set_client_ca_list} after a call to - L{Context.add_client_ca} replaces the CA name specified by the former + A call to :py:obj:`Context.set_client_ca_list` after a call to + :py:obj:`Context.add_client_ca` replaces the CA name specified by the former call with the names specified by the latter cal. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) |