示例#1
0
    def test_readinto(self, server_cert, ca_cert, load_chain):
        """
        A Server and Client context that successfully handshake can write
        bytes into buffers.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            certificate_chain=cert_chain,
            validate_certificates=False,
        )
        client, server = assert_configs_work(self.BACKEND, client_config,
                                             server_config)

        # Firstly, test that if we send some data to the server, we can use
        # readinto to read it. We'll allocate a buffer that's too big and
        # check that it gets filled.
        message_size = len(HTTP_REQUEST)
        test_buffer = bytearray(message_size * 2)
        write_until_complete(client, server, HTTP_REQUEST)
        read_length = server.readinto(test_buffer, message_size * 2)
        assert read_length == message_size
        assert test_buffer[:message_size] == HTTP_REQUEST

        # Next, test that if we ask for more data than the buffer can hold we
        # just get the amount that fills the buffer.
        message_size = len(HTTP_RESPONSE)
        test_buffer = bytearray(message_size // 2)
        write_until_complete(server, client, HTTP_RESPONSE)
        read_length = client.readinto(test_buffer, message_size * 2)
        assert read_length == (message_size // 2)
        assert (test_buffer[:message_size //
                            2] == HTTP_RESPONSE[:message_size // 2])
示例#2
0
    def test_snicallback_fires_with_data(self, server_cert, ca_cert,
                                         load_chain, hostname):
        """
        In a basic, successful TLS negotiation, the SNI callback will be fired
        and will provide the appropriate data.
        """
        callback_args = []

        def callback(*args):
            callback_args.append(args)
            return args[-1]

        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(certificate_chain=cert_chain,
                                                validate_certificates=False,
                                                sni_callback=callback)
        client, server = assert_configs_work(self.BACKEND,
                                             client_config,
                                             server_config,
                                             hostname=hostname)

        assert len(callback_args) == 1
        conn_object, name, config = callback_args[0]

        assert conn_object is server
        assert config == server_config
        assert name == hostname
示例#3
0
 def test_no_validation(self, server_cert, load_chain):
     """
     A Server and Client context that both have their validation settings
     disabled and otherwise use the default configuration can handshake.
     """
     cert_chain = load_chain(self.BACKEND, server_cert)
     client_config = pep543.TLSConfiguration(validate_certificates=False)
     server_config = pep543.TLSConfiguration(
         validate_certificates=False,
         certificate_chain=cert_chain,
     )
     assert_configs_work(self.BACKEND, client_config, server_config)
示例#4
0
    def test_server_validation(self, server_cert, ca_cert, load_chain):
        """
        A Server and Client context, where the Client context is set to
        validate the server, and otherwise use the default configuration,
        can handshake.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            validate_certificates=False,
            certificate_chain=cert_chain,
        )
        assert_configs_work(self.BACKEND, client_config, server_config)
示例#5
0
    def test_cipher_suite_not_in_enum(self, monkeypatch, context):
        """
        When a buffer object returns a cipher that is not in the PEP543
        CipherSuite enum object, it returns the cipher suite ID instead.
        """
        # We try this with the cipher suite NULL-MD5. This may not work on all
        # OpenSSL versions, so if this test breaks investigate and maybe change
        # to a different one.
        EXTRA_CIPHER_ID = 0x0001
        EXTRA_CIPHER_NAME = 'NULL-MD5'

        def md5_cipher(*args):
            return (EXTRA_CIPHER_NAME, None, None)

        monkeypatch.setattr('ssl.SSLObject.cipher', md5_cipher)

        cipher_list = pep543.DEFAULT_CIPHER_LIST + [EXTRA_CIPHER_ID]

        config = pep543.TLSConfiguration(
            trust_store=pep543.stdlib.STDLIB_BACKEND.trust_store.system(),
            ciphers=cipher_list)
        ctx = context(config)
        buffer = wrap_buffers(ctx)

        suite = buffer.cipher()
        assert not isinstance(suite, pep543.CipherSuite)
        assert suite == EXTRA_CIPHER_ID
示例#6
0
    def test_client_context_returns_configuration(self, ca_cert):
        """
        A Client context initialized with a given configuration will return the
        configuration it was initialized with.
        """
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])
        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        client_context = self.BACKEND.client_context(client_config)

        assert client_context.configuration is client_config
示例#7
0
    def test_mutual_validation(self, client_cert, server_cert, ca_cert,
                               load_chain):
        """
        A Server and Client context, where each context is configured to verify
        the other, can handshake.
        """
        server_certchain = load_chain(self.BACKEND, server_cert)
        client_certchain = load_chain(self.BACKEND, client_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(
            certificate_chain=client_certchain,
            trust_store=trust_store,
        )
        server_config = pep543.TLSConfiguration(
            certificate_chain=server_certchain,
            trust_store=trust_store,
        )
        assert_configs_work(self.BACKEND, client_config, server_config)
示例#8
0
 def test_bad_values_for_versions_client(self, lowest, highest, context):
     """
     Using TLSConfiguration objects with a bad value for their minimum or
     maximum version raises a TLSError with Client contexts.
     """
     config = pep543.TLSConfiguration(validate_certificates=False,
                                      lowest_supported_version=lowest,
                                      highest_supported_version=highest)
     ctx = context(config)
     with pytest.raises(pep543.TLSError):
         wrap_buffers(ctx)
示例#9
0
    def test_client_validation(self, client_cert, server_cert, ca_cert,
                               load_chain):
        """
        A Server and Client context, where the Server context is set to
        validate the client, and the client does not validate, and the client
        presents a cert chain, can handshake.
        """
        server_certchain = load_chain(self.BACKEND, server_cert)
        client_certchain = load_chain(self.BACKEND, client_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(
            validate_certificates=False,
            certificate_chain=client_certchain,
        )
        server_config = pep543.TLSConfiguration(
            certificate_chain=server_certchain,
            trust_store=trust_store,
        )
        assert_configs_work(self.BACKEND, client_config, server_config)
示例#10
0
    def test_can_detect_tls_protocol(self, server_cert, ca_cert, load_chain):
        """
        A Server and Client context that successfully handshake will report the
        same TLS version.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            certificate_chain=cert_chain,
            validate_certificates=False,
        )
        client, server = assert_configs_work(self.BACKEND, client_config,
                                             server_config)

        assert client.negotiated_tls_version() in pep543.TLSVersion
        assert server.negotiated_tls_version() in pep543.TLSVersion
        assert (
            client.negotiated_tls_version() == server.negotiated_tls_version())
示例#11
0
    def test_can_detect_cipher(self, server_cert, ca_cert, load_chain):
        """
        A Server and Client context that successfully handshake will report the
        same cipher.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            certificate_chain=cert_chain,
            validate_certificates=False,
        )
        client, server = assert_configs_work(self.BACKEND, client_config,
                                             server_config)

        # The cipher should be either a CipherSuite or an int, and should match
        # the server.
        assert isinstance(client.cipher(), (pep543.CipherSuite, int))
        assert isinstance(server.cipher(), (pep543.CipherSuite, int))
        assert client.cipher() == server.cipher()
示例#12
0
    def test_no_tls_protocol_before_handhake(self, server_cert, ca_cert,
                                             load_chain):
        """
        Before the TLS handshake is done, no TLS protocols is available.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            certificate_chain=cert_chain,
            validate_certificates=False,
        )
        client_context = self.BACKEND.client_context(client_config)
        server_context = self.BACKEND.server_context(server_config)

        client_buffer = client_context.wrap_buffers(None)
        server_buffer = server_context.wrap_buffers()

        print(client_buffer.negotiated_tls_version())
        assert client_buffer.negotiated_tls_version() is None
        assert server_buffer.negotiated_tls_version() is None
示例#13
0
    def assert_negotiated_protocol(self, context, negotiated_protocol):
        """
        Test that the protocol negotiated is as expected.
        """
        if negotiated_protocol is not None:
            negotiated_protocol = pep543.NextProtocol(negotiated_protocol)

        config = pep543.TLSConfiguration(
            validate_certificates=False,
            inner_protocols=(pep543.NextProtocol.H2, ))
        ctx = context(config)
        buffer = wrap_buffers(ctx)
        assert (buffer.negotiated_protocol() == negotiated_protocol)
示例#14
0
    def test_no_supported_cipher_suites(self, context):
        """
        Using TLSConfiguration objects that have only unsupported cipher suites
        raises a TLSError.
        """
        # We assume that no cipher suite will be defined with the code eeee.
        config = pep543.TLSConfiguration(
            ciphers=[0xeeee],
            trust_store=pep543.stdlib.STDLIB_BACKEND.trust_store.system())
        ctx = context(config)
        with pytest.raises(pep543.TLSError) as e:
            wrap_buffers(ctx)

        assert "supported ciphers" in str(e)
示例#15
0
    def test_server_context_returns_configuration(self, server_cert,
                                                  load_chain):
        """
        A Server context initialized with a given configuration will return the
        configuration it was initialized with.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        server_config = pep543.TLSConfiguration(
            validate_certificates=False,
            certificate_chain=cert_chain,
        )
        server_context = self.BACKEND.server_context(server_config)

        assert server_context.configuration is server_config
示例#16
0
    def test_snicallback_fails_with_exception(self, server_cert, ca_cert,
                                              load_chain):
        """
        If the SNI callback raises an exception, the handshake fails.
        """
        callback_args = []

        def callback(*args):
            callback_args.append(args)
            raise ValueError("Whoops!")

        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(certificate_chain=cert_chain,
                                                validate_certificates=False,
                                                sni_callback=callback)
        # TODO: This is really overbroad, this error could come from anywhere.
        # We allow either the underlying error or TLSError here.
        with pytest.raises((pep543.TLSError, ValueError)):
            assert_configs_work(self.BACKEND, client_config, server_config)

        assert callback_args
示例#17
0
    def test_snicallback_fails_with_none(self, server_cert, ca_cert,
                                         load_chain, rval):
        """
        If the SNI callback returns any non TLSConfiguration value, the
        handshake fails.
        """
        callback_args = []

        def callback(*args):
            callback_args.append(args)
            return rval

        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(certificate_chain=cert_chain,
                                                validate_certificates=False,
                                                sni_callback=callback)
        # TODO: This is really overbroad, this error could come from anywhere.
        with pytest.raises(pep543.TLSError):
            assert_configs_work(self.BACKEND, client_config, server_config)

        assert callback_args
示例#18
0
    def test_can_cleanly_shutdown(self, server_cert, ca_cert, load_chain):
        """
        A Server and Client context that successfully handshake can succesfully
        perform a shutdown.
        """
        cert_chain = load_chain(self.BACKEND, server_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(trust_store=trust_store)
        server_config = pep543.TLSConfiguration(
            certificate_chain=cert_chain,
            validate_certificates=False,
        )
        client, server = assert_configs_work(self.BACKEND, client_config,
                                             server_config)

        # We want to perform a shutdown now.
        loop_until_success(client, server, 'shutdown')

        # At this point, we should read EOF from both client and server.
        assert not client.read(8192)
        assert not server.read(8192)

        # We should also check that readinto returns EOF.
        reference_buffer = bytearray(8192)
        buffer = bytearray(8192)
        assert not client.readinto(buffer, 8192)
        assert buffer == reference_buffer
        assert not server.readinto(buffer, 8192)
        assert buffer == reference_buffer

        # And writes should raise errors.
        with pytest.raises(pep543.TLSError):
            client.write(b'will fail')
        with pytest.raises(pep543.TLSError):
            server.write(b'will fail')
示例#19
0
    def test_inner_protocol_overlap(self, client_cert, server_cert, ca_cert,
                                    inner_protocols, result, load_chain):
        """
        A Server and Client context, when both contexts support the same inner
        protocols, either successfully negotiate an inner protocol or don't
        negotiate anything.
        """
        server_certchain = load_chain(self.BACKEND, server_cert)
        client_certchain = load_chain(self.BACKEND, client_cert)
        trust_store = self.BACKEND.trust_store.from_pem_file(ca_cert['cert'])

        client_config = pep543.TLSConfiguration(
            certificate_chain=client_certchain,
            trust_store=trust_store,
            inner_protocols=inner_protocols)
        server_config = pep543.TLSConfiguration(
            certificate_chain=server_certchain,
            trust_store=trust_store,
            inner_protocols=inner_protocols)
        client, server = assert_configs_work(self.BACKEND, client_config,
                                             server_config)

        assert client.negotiated_protocol() in (result, None)
        assert server.negotiated_protocol() in (result, None)
示例#20
0
    def test_unknown_cipher_suites(self, monkeypatch, context):
        """
        When a buffer object returns a cipher that doesn't appear to be
        suppported by the given OpenSSL implementation, a TLSError is raised.
        """
        def unknown_cipher(*args):
            return ('not_a_tls_cipher_suite', None, None)

        monkeypatch.setattr('ssl.SSLObject.cipher', unknown_cipher)

        config = pep543.TLSConfiguration(
            trust_store=pep543.stdlib.STDLIB_BACKEND.trust_store.system())
        ctx = context(config)
        buffer = wrap_buffers(ctx)

        with pytest.raises(pep543.TLSError):
            buffer.cipher()
示例#21
0
    def test_system_trust_store_loads(self, monkeypatch, context):
        """
        When a context is instructed to load the system trust store, it calls
        load_default_certs.
        """
        calls = 0

        def load_default_certs(*args):
            nonlocal calls
            calls += 1

        monkeypatch.setattr('ssl.SSLContext.load_default_certs',
                            load_default_certs)

        config = pep543.TLSConfiguration(
            trust_store=pep543.stdlib.STDLIB_BACKEND.trust_store.system())
        ctx = context(config)
        wrap_buffers(ctx)

        assert calls == 1