Beispiel #1
0
    def test_gateway_accepts_valid_email(self):
        """
        Test if SMTP server responds correctly for valid interaction.
        """

        SMTP_ANSWERS = ['220 ' + IP_OR_HOST_REGEX +
                        ' NO UCE NO UBE NO RELAY PROBES',
                        '250 ' + IP_OR_HOST_REGEX + ' Hello ' +
                        IP_OR_HOST_REGEX + ', nice to meet you',
                        '250 Sender address accepted',
                        '250 Recipient address accepted',
                        '354 Continue']

        # XXX this bit can be refactored away in a helper
        # method...
        proto = SMTPFactory(
            u'*****@*****.**',
            self._km,
            self._config['encrypted_only'],
            outgoing_mail=Mock()).buildProtocol(('127.0.0.1', 0))
        # snip...
        transport = proto_helpers.StringTransport()
        proto.makeConnection(transport)
        reply = ""
        for i, line in enumerate(self.EMAIL_DATA):
            reply += yield self.getReply(line + '\r\n', proto, transport)
        self.assertMatch(reply, '\r\n'.join(SMTP_ANSWERS),
                         'Did not get expected answer from gateway.')
        proto.setTimeout(None)
Beispiel #2
0
 def test_missing_key_accepts_address(self):
     """
     Test if server accepts to send unencrypted when 'encrypted_only' is
     False.
     """
     # remove key from key manager
     pubkey = yield self._km.get_key(ADDRESS, openpgp.OpenPGPKey)
     pgp = openpgp.OpenPGPScheme(
         self._soledad, gpgbinary=self.GPG_BINARY_PATH)
     yield pgp.delete_key(pubkey)
     # mock the key fetching
     self._km._fetch_keys_from_server = Mock(
         return_value=fail(errors.KeyNotFound()))
     # prepare the SMTP factory with encrypted only equal to false
     proto = SMTPFactory(
         u'*****@*****.**',
         self._km,
         False, outgoing_mail=Mock()).buildProtocol(('127.0.0.1', 0))
     transport = proto_helpers.StringTransport()
     proto.makeConnection(transport)
     yield self.getReply(self.EMAIL_DATA[0] + '\r\n', proto, transport)
     yield self.getReply(self.EMAIL_DATA[1] + '\r\n', proto, transport)
     reply = yield self.getReply(self.EMAIL_DATA[2] + '\r\n',
                                 proto, transport)
     # ensure the address was accepted
     self.assertEqual(
         '250 Recipient address accepted\r\n',
         reply,
         'Address should have been accepted with appropriate message.')
     proto.setTimeout(None)
Beispiel #3
0
    def test_gateway_accepts_valid_email(self):
        """
        Test if SMTP server responds correctly for valid interaction.
        """

        SMTP_ANSWERS = [
            '220 ' + IP_OR_HOST_REGEX + ' NO UCE NO UBE NO RELAY PROBES',
            '250 ' + IP_OR_HOST_REGEX + ' Hello ' + IP_OR_HOST_REGEX +
            ', nice to meet you', '250 Sender address accepted',
            '250 Recipient address accepted', '354 Continue'
        ]

        # XXX this bit can be refactored away in a helper
        # method...
        proto = SMTPFactory(u'*****@*****.**', self._km,
                            self._config['host'], self._config['port'],
                            self._config['cert'], self._config['key'],
                            self._config['encrypted_only']).buildProtocol(
                                ('127.0.0.1', 0))
        # snip...
        transport = proto_helpers.StringTransport()
        proto.makeConnection(transport)
        for i, line in enumerate(self.EMAIL_DATA):
            proto.lineReceived(line + '\r\n')
            self.assertMatch(transport.value(),
                             '\r\n'.join(SMTP_ANSWERS[0:i + 1]),
                             'Did not get expected answer from gateway.')
        proto.setTimeout(None)
Beispiel #4
0
 def test_missing_key_accepts_address(self):
     """
     Test if server accepts to send unencrypted when 'encrypted_only' is
     False.
     """
     # remove key from key manager
     pubkey = self._km.get_key(ADDRESS, openpgp.OpenPGPKey)
     pgp = openpgp.OpenPGPScheme(self._soledad,
                                 gpgbinary=self.GPG_BINARY_PATH)
     pgp.delete_key(pubkey)
     # mock the key fetching
     self._km.fetch_keys_from_server = Mock(return_value=[])
     # prepare the SMTP factory with encrypted only equal to false
     proto = SMTPFactory(u'*****@*****.**', self._km,
                         self._config['host'], self._config['port'],
                         self._config['cert'], self._config['key'],
                         False).buildProtocol(('127.0.0.1', 0))
     transport = proto_helpers.StringTransport()
     proto.makeConnection(transport)
     proto.lineReceived(self.EMAIL_DATA[0] + '\r\n')
     proto.lineReceived(self.EMAIL_DATA[1] + '\r\n')
     proto.lineReceived(self.EMAIL_DATA[2] + '\r\n')
     # ensure the address was accepted
     lines = transport.value().rstrip().split('\n')
     self.assertEqual(
         '250 Recipient address accepted', lines[-1],
         'Address should have been accepted with appropriate message.')
 def test_missing_key_accepts_address(self):
     """
     Test if server accepts to send unencrypted when 'encrypted_only' is
     False.
     """
     # remove key from key manager
     pubkey = self._km.get_key(ADDRESS, openpgp.OpenPGPKey)
     pgp = openpgp.OpenPGPScheme(
         self._soledad, gpgbinary=self.GPG_BINARY_PATH)
     pgp.delete_key(pubkey)
     # mock the key fetching
     self._km.fetch_keys_from_server = Mock(return_value=[])
     # prepare the SMTP factory with encrypted only equal to false
     proto = SMTPFactory(
         u'*****@*****.**',
         self._km, self._config['host'],
         self._config['port'],
         self._config['cert'], self._config['key'],
         False).buildProtocol(('127.0.0.1', 0))
     transport = proto_helpers.StringTransport()
     proto.makeConnection(transport)
     proto.lineReceived(self.EMAIL_DATA[0] + '\r\n')
     proto.lineReceived(self.EMAIL_DATA[1] + '\r\n')
     proto.lineReceived(self.EMAIL_DATA[2] + '\r\n')
     # ensure the address was accepted
     lines = transport.value().rstrip().split('\n')
     self.assertEqual(
         '250 Recipient address accepted',
         lines[-1],
         'Address should have been accepted with appropriate message.')
Beispiel #6
0
 def test_message_sign(self):
     """
     Test if message is signed with sender key.
     """
     # mock the key fetching
     self._km.fetch_keys_from_server = Mock(return_value=[])
     proto = SMTPFactory(u'*****@*****.**', self._km,
                         self._config['host'], self._config['port'],
                         self._config['cert'], self._config['key'],
                         self._config['encrypted_only']).buildProtocol(
                             ('127.0.0.1', 0))
     user = User('*****@*****.**', 'gateway.leap.se', proto,
                 ADDRESS)
     fromAddr = Address(ADDRESS_2)
     m = EncryptedMessage(fromAddr, user, self._km, self._config['host'],
                          self._config['port'], self._config['cert'],
                          self._config['key'])
     for line in self.EMAIL_DATA[4:12]:
         m.lineReceived(line)
     # trigger signing
     #m.eomReceived()  # this includes a defer, so we avoid calling it here
     m.lines.append('')  # add a trailing newline
     # we need to call the following explicitelly because it was deferred
     # inside the previous method
     m._maybe_encrypt_and_sign()
     # assert structure of signed message
     self.assertTrue('Content-Type' in m._msg)
     self.assertEqual('multipart/signed', m._msg.get_content_type())
     self.assertEqual('application/pgp-signature',
                      m._msg.get_param('protocol'))
     self.assertEqual('pgp-sha512', m._msg.get_param('micalg'))
     # assert content of message
     self.assertEqual(
         '\r\n'.join(self.EMAIL_DATA[9:13]) + '\r\n--\r\n' +
         'I prefer encrypted email - https://leap.se/key/anotheruser\r\n',
         m._msg.get_payload(0).get_payload(decode=True))
     # assert content of signature
     self.assertTrue(
         m._msg.get_payload(1).get_payload().startswith(
             '-----BEGIN PGP SIGNATURE-----\n'),
         'Message does not start with signature header.')
     self.assertTrue(
         m._msg.get_payload(1).get_payload().endswith(
             '-----END PGP SIGNATURE-----\n'),
         'Message does not end with signature footer.')
     # assert signature is valid
     pubkey = self._km.get_key(ADDRESS_2, openpgp.OpenPGPKey)
     # replace EOL before verifying (according to rfc3156)
     signed_text = re.sub('\r?\n', '\r\n',
                          m._msg.get_payload(0).as_string())
     self.assertTrue(
         self._km.verify(signed_text,
                         pubkey,
                         detached_sig=m._msg.get_payload(1).get_payload()),
         'Signature could not be verified.')
Beispiel #7
0
 def init_outgoing_and_proto(_):
     self.outgoing_mail = OutgoingMail(self.fromAddr, self._km,
                                       self._config['cert'],
                                       self._config['key'],
                                       self._config['host'],
                                       self._config['port'])
     self.proto = SMTPFactory(u'*****@*****.**', self._km,
                              self._config['encrypted_only'],
                              self.outgoing_mail).buildProtocol(
                                  ('127.0.0.1', 0))
     self.dest = User(ADDRESS, 'gateway.leap.se', self.proto, ADDRESS_2)
Beispiel #8
0
 def test_missing_key_rejects_address(self):
     """
     Test if server rejects to send unencrypted when 'encrypted_only' is
     True.
     """
     # remove key from key manager
     pubkey = yield self._km.get_key(ADDRESS, openpgp.OpenPGPKey)
     pgp = openpgp.OpenPGPScheme(self._soledad,
                                 gpgbinary=self.GPG_BINARY_PATH)
     yield pgp.delete_key(pubkey)
     # mock the key fetching
     self._km._fetch_keys_from_server = Mock(
         return_value=fail(errors.KeyNotFound()))
     # prepare the SMTP factory
     proto = SMTPFactory(u'*****@*****.**',
                         self._km,
                         self._config['encrypted_only'],
                         outgoing_mail=Mock()).buildProtocol(
                             ('127.0.0.1', 0))
     transport = proto_helpers.StringTransport()
     proto.makeConnection(transport)
     yield self.getReply(self.EMAIL_DATA[0] + '\r\n', proto, transport)
     yield self.getReply(self.EMAIL_DATA[1] + '\r\n', proto, transport)
     reply = yield self.getReply(self.EMAIL_DATA[2] + '\r\n', proto,
                                 transport)
     # ensure the address was rejected
     self.assertEqual(
         '550 Cannot receive for specified address\r\n', reply,
         'Address should have been rejecetd with appropriate message.')
     proto.setTimeout(None)
Beispiel #9
0
def setup_smtp_gateway(port, userid, keymanager, smtp_host, smtp_port,
                       smtp_cert, smtp_key, encrypted_only):
    """
    Setup SMTP gateway to run with Twisted.

    This function sets up the SMTP gateway configuration and the Twisted
    reactor.

    :param port: The port in which to run the server.
    :type port: int
    :param userid: The user currently logged in
    :type userid: str
    :param keymanager: A Key Manager from where to get recipients' public
                       keys.
    :type keymanager: leap.common.keymanager.KeyManager
    :param smtp_host: The hostname of the remote SMTP server.
    :type smtp_host: str
    :param smtp_port: The port of the remote SMTP server.
    :type smtp_port: int
    :param smtp_cert: The client certificate for authentication.
    :type smtp_cert: str
    :param smtp_key: The client key for authentication.
    :type smtp_key: str
    :param encrypted_only: Whether the SMTP gateway should send unencrypted
                           mail or not.
    :type encrypted_only: bool

    :returns: tuple of SMTPFactory, twisted.internet.tcp.Port
    """
    # configure the use of this service with twistd
    outgoing_mail = OutgoingMail(userid, keymanager, smtp_cert, smtp_key,
                                 smtp_host, smtp_port)
    factory = SMTPFactory(userid, keymanager, encrypted_only, outgoing_mail)
    try:
        tport = reactor.listenTCP(port, factory, interface="localhost")
        emit(catalog.SMTP_SERVICE_STARTED, str(port))
        return factory, tport
    except CannotListenError:
        logger.error("STMP Service failed to start: "
                     "cannot listen in port %s" % port)
        emit(catalog.SMTP_SERVICE_FAILED_TO_START, str(port))
    except Exception as exc:
        logger.error("Unhandled error while launching smtp gateway service")
        logger.exception(exc)
Beispiel #10
0
 def test_message_encrypt_sign(self):
     """
     Test if message gets encrypted to destination email and signed with
     sender key.
     """
     proto = SMTPFactory(u'*****@*****.**', self._km,
                         self._config['host'], self._config['port'],
                         self._config['cert'], self._config['key'],
                         self._config['encrypted_only']).buildProtocol(
                             ('127.0.0.1', 0))
     user = User(ADDRESS, 'gateway.leap.se', proto, ADDRESS)
     fromAddr = Address(ADDRESS_2)
     m = EncryptedMessage(fromAddr, user, self._km, self._config['host'],
                          self._config['port'], self._config['cert'],
                          self._config['key'])
     for line in self.EMAIL_DATA[4:12]:
         m.lineReceived(line)
     # trigger encryption and signing
     #m.eomReceived()  # this includes a defer, so we avoid calling it here
     m.lines.append('')  # add a trailing newline
     # we need to call the following explicitelly because it was deferred
     # inside the previous method
     m._maybe_encrypt_and_sign()
     # assert structure of encrypted message
     self.assertTrue('Content-Type' in m._msg)
     self.assertEqual('multipart/encrypted', m._msg.get_content_type())
     self.assertEqual('application/pgp-encrypted',
                      m._msg.get_param('protocol'))
     self.assertEqual(2, len(m._msg.get_payload()))
     self.assertEqual('application/pgp-encrypted',
                      m._msg.get_payload(0).get_content_type())
     self.assertEqual('application/octet-stream',
                      m._msg.get_payload(1).get_content_type())
     # decrypt and verify
     privkey = self._km.get_key(ADDRESS, openpgp.OpenPGPKey, private=True)
     pubkey = self._km.get_key(ADDRESS_2, openpgp.OpenPGPKey)
     decrypted = self._km.decrypt(m._msg.get_payload(1).get_payload(),
                                  privkey,
                                  verify=pubkey)
     self.assertEqual(
         '\n' + '\r\n'.join(self.EMAIL_DATA[9:12]) + '\r\n\r\n--\r\n' +
         'I prefer encrypted email - https://leap.se/key/anotheruser\r\n',
         decrypted, 'Decrypted text differs from plaintext.')