Example #1
0
def test_configure_with_cert_chain():
    '''
    Just checks that the certs don't error, not that they're actually loaded.
    TODO: improve.
    '''
    context = tls.configure_tls_context(
        client_cert='tests/certs/selfsigned.crt',
        client_key='tests/certs/selfsigned.key')

    assert isinstance(context, ssl.SSLContext)
Example #2
0
    async def connect(self, **kwargs):
        '''
        Open asyncio streams to the server and check response status.

        Accepts all of the same keyword arguments as __init__ (except loop).
        '''
        for kwarg in kwargs.keys():
            if kwarg not in self._connect_kwargs:
                raise TypeError(
                    "connect() got an unexptected keyword argument "
                    "'{}'".format(kwarg))

        if kwargs.get('tls_context') and kwargs.get('client_cert'):
            raise ValueError(
                'Either an SSLContext or a certificate/key must be provided')

        self._connect_kwargs.update(kwargs)

        if self._connect_kwargs['port'] is not None:
            port = self._connect_kwargs['port']
        elif self._connect_kwargs['use_tls']:
            port = SMTP_TLS_PORT
        else:
            port = SMTP_PORT

        if self._connect_kwargs['use_tls']:
            if self._connect_kwargs['tls_context']:
                tls_context = self._connect_kwargs['tls_context']
            else:
                tls_context = configure_tls_context(
                    validate_certs=self._connect_kwargs['validate_certs'],
                    client_cert=self._connect_kwargs['client_cert'],
                    client_key=self._connect_kwargs['client_key'])
        else:
            tls_context = None

        self._source_address = self._connect_kwargs['source_address']
        self._server_state = {}

        return await self._connect(self._connect_kwargs['hostname'], port,
                                   tls_context)
Example #3
0
    async def starttls(self, server_hostname=None, **kwargs):
        '''
        Puts the connection to the SMTP server into TLS mode.

        If there has been no previous EHLO or HELO command this session, this
        method tries ESMTP EHLO first.

        If the server supports TLS, this will encrypt the rest of the SMTP
        session. If you provide the keyfile and certfile parameters,
        the identity of the SMTP server and client can be checked (if
        validate_certs is True). You can also provide a custom SSLContext
        object. If no certs or SSLContext is given, and TLS config was
        provided when initializing the class, STARTTLS will use to that,
        otherwise it will use the Python defaults.

        This method may raise the following exceptions:

         SMTPHeloError            The server didn't reply properly to
                                  the helo greeting.
         ValueError               An unsupported combination of args was
                                  provided.
        '''
        allowed_kwargs = (
            'validate_certs',
            'client_cert',
            'client_key',
            'tls_context',
        )
        for kwarg in kwargs.keys():
            if kwarg not in allowed_kwargs:
                raise TypeError(
                    "connect() got an unexptected keyword argument "
                    "'{}'".format(kwarg))

        if kwargs.get('tls_context') and kwargs.get('client_cert'):
            raise ValueError(
                'Either an SSLContext or a certificate/key must be provided')

        self._connect_kwargs.update(kwargs)

        if server_hostname is None:
            server_hostname = self._connect_kwargs['hostname']

        if self._connect_kwargs['tls_context']:
            tls_context = self._connect_kwargs['tls_context']
        else:
            tls_context = configure_tls_context(
                validate_certs=self._connect_kwargs['validate_certs'],
                client_cert=self._connect_kwargs['client_cert'],
                client_key=self._connect_kwargs['client_key'])

        await self.ehlo_or_helo_if_needed()

        if not self.supports_extension('starttls'):
            raise SMTPException(
                'SMTP STARTTLS extension not supported by server.')

        response = await self.execute_command('STARTTLS')

        if response.code == status.SMTP_220_READY:
            self.protocol, self.transport = await self.writer.start_tls(
                tls_context, server_hostname=server_hostname)

            # RFC 3207 part 4.2:
            # The client MUST discard any knowledge obtained from
            # the server, such as the list of SMTP service extensions,
            # which was not obtained from the TLS negotiation itself.
            self._server_state = {}

        return response
Example #4
0
def test_configure_tls_context_with_no_ssl_module_raises(monkeypatch):
    monkeypatch.setattr(tls, '_has_tls', False)

    with pytest.raises(RuntimeError):
        tls.configure_tls_context()
Example #5
0
def test_configure_without_validate_certs():
    context = tls.configure_tls_context(validate_certs=False)

    assert isinstance(context, ssl.SSLContext)
    assert context.verify_mode == ssl.CERT_NONE
    assert context.check_hostname is False
Example #6
0
def test_configure_with_validate_certs():
    context = tls.configure_tls_context(validate_certs=True)

    assert isinstance(context, ssl.SSLContext)
    assert context.verify_mode == ssl.CERT_REQUIRED
    assert context.check_hostname is True
Example #7
0
def test_configure_with_no_args_works():
    context = tls.configure_tls_context()

    assert isinstance(context, ssl.SSLContext)