使用TLS的Twisted Python ESMTP邮件服务器/转储

时间:2014-10-06 14:21:10

标签: python ssl smtp twisted

正如你们有些人最近看到的那样,我正在努力让一个简单的客户端/服务器TCP连接启动并运行,我可以根据https://twistedmatrix.com/documents/14.0.0/core/howto/ssl.html#starttls-server上的Twisted示例在发出命令时切换到TLS ,但修改为使用证书身份验证。嗯,好消息是现在有效!感谢@ Jean-PaulCalderone和@Glyph的帮助。

但是我现在想要将我的服务器端代码扩展/转换为ESMTP服务器 - 即,让客户端连接,然后服务器将STARTTLS作为其EHLO响应的一部分进行通告,如果客户端随后以STARTTLS响应,则协商并切换安全连接。我相信我需要修改" TLSServer"我的服务器代码中的类继承自twisted.mail.smtp.ESMTP而不是twisted.protocols.basic.LineReceiver - 但不是100%肯定在这里。此外,在http://twistedmatrix.com/documents/12.1.0/api/twisted.mail.smtp.ESMTP.html找到的t.m.s.ESMTP的API文档在实际上有点薄(许多未记录的方法)。

任何人都可以a)告诉我是否正确修改现有服务器代码的继承,并且b)提供对do_EHLO和ext_STARTTLS等方法的一些解释?

最终我正在寻找一个接受(安全)客户端连接,从客户端接收邮件并将邮件转储到文件的SMTP服务器。

我现有的服务器代码:

from twisted.internet import ssl, protocol, defer, task, endpoints
from twisted.protocols.basic import LineReceiver
from twisted.python.modules import getModule
from OpenSSL.crypto import load_privatekey, load_certificate, FILETYPE_PEM

class TLSServer(LineReceiver):
    def lineReceived(self, line):
        print("received: " + line)
        if line == "STARTTLS":
            print("-- Switching to TLS")
            self.sendLine('READY')
            self.transport.startTLS(self.factory.options)

def main(reactor):
    caCertFile = open("/some/path/to/cacert.pem","r")
    certFile = open("/some/path/to/server.crt","r")
    keyFile = open("/some/path/to/server.key","r")
    caCertData = caCertFile.read()
    pKeyData = keyFile.read()
    certData = certFile.read()
    caCert = ssl.Certificate.loadPEM(caCertData)
    cert = load_certificate(FILETYPE_PEM, certData)
    pKey = load_privatekey(FILETYPE_PEM, pKeyData)
    factory = protocol.Factory.forProtocol(TLSServer)
    factory.options = ssl.CertificateOptions(privateKey=pKey, certificate=cert, trustRoot=caCert)
    endpoint = endpoints.TCP4ServerEndpoint(reactor, 8000)
    endpoint.listen(factory)
    return defer.Deferred()

if __name__ == '__main__':
    import starttls_server
    task.react(starttls_server.main)

提前致谢!

1 个答案:

答案 0 :(得分:2)

您不应该拥有自己的TLSServer课程。相反,只需直接使用ESMTP作为您的服务器类。您已经确定ext_STARTTLS方法很有趣 - 基本上,它已经实现了TLSServer方法lineReceived中的逻辑。

您需要在构建时传递factory.options = ... ESMTP个参数,而不是contextFactory。最简单的,你可以这样做:

sslCtxFactory = ssl.CertificateOptions(...)
factory = Factory.forProtocol(lambda: ESMTP(contextFactory=sslCtxFactory))

相信默认情况下ESMTP广告STARTTLS作为扩展名 - 至少,这是对{{1}的实施的快速解读方法对我说。