1

目前使用一个非常简单的 TwistedNameVirtualHost和一些 JSON 配置文件来在一个Site对象中提供非常基本的内容。Twisted 提供的资源都是烧瓶中内置的 WSGI 对象。

我想知道如何使用 包装与这些域的连接SSLContext,因为reactor.listenSSL只需要一个上下文,因此如何为每个域/子域赋予它自己的 crt/key 对并不明显。有没有办法为每个不需要代理的域设置带有 ssl 的命名虚拟主机?我找不到任何NameVirtualHost与 SSL 一起使用的 Twisted 示例,而我唯一能做的事情就是在只有一个域的上下文的情况下挂上侦听端口 443 的反应器?

我想知道是否有人尝试过这个?

我的简单服务器没有任何 SSL 处理:

https://github.com/DeaconDesperado/twsrv/blob/master/service.py

4

3 回答 3

6

TLS(取代 SSL 的现代协议的名称)最近才支持您正在寻找的功能。该功能称为服务器名称指示(或SNI)。现代平台上的现代浏览器支持它,但不支持一些较旧但仍广泛使用的平台(有关支持的浏览器列表,请参见维基百科页面)。

Twisted 对此没有特定的内置支持。但是,它不需要任何东西。Twisted 的 SSL 支持所基于的 pyOpenSSL 确实支持 SNI。

set_tlsext_servername_callback pyOpenSSL API 为您提供了构建所需行为的基本机制。这使您可以定义一个回调,该回调可以访问客户端请求的服务器名称。此时,您可以指定要用于连接的密钥/证书对。您可以在 pyOpenSSL 的示例目录中找到演示如何使用此 API的示例。

这是该示例的摘录,可为您提供要点:

def pick_certificate(connection):
    try:
        key, cert = certificates[connection.get_servername()]
    except KeyError:
        pass
    else:
        new_context = Context(TLSv1_METHOD)
        new_context.use_privatekey(key)
        new_context.use_certificate(cert)
        connection.set_context(new_context)

server_context = Context(TLSv1_METHOD)
server_context.set_tlsext_servername_callback(pick_certificate)

您可以将此方法合并到自定义上下文工厂中,然后将该上下文工厂提供给listenSSL调用。

于 2012-08-28T18:26:41.343 回答
3

只是为了给这个添加一些闭包,为了将来的搜索,这里是来自打印 SNI 的示例中的 echo 服务器的示例代码:

from twisted.internet import ssl, reactor
from twisted.internet.protocol import Factory, Protocol

class Echo(Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

def pick_cert(connection):
    print('Received SNI: ', connection.get_servername())

if __name__ == '__main__':
    factory = Factory()
    factory.protocol = Echo

    with open("keys/ca.pem") as certAuthCertFile:
        certAuthCert = ssl.Certificate.loadPEM(certAuthCertFile.read())

    with open("keys/server.key") as keyFile:
        with open("keys/server.crt") as certFile:
            serverCert = ssl.PrivateCertificate.loadPEM(
                keyFile.read() + certFile.read())

    contextFactory = serverCert.options(certAuthCert)

    ctx = contextFactory.getContext()
    ctx.set_tlsext_servername_callback(pick_cert)

    reactor.listenSSL(8000, factory, contextFactory)
    reactor.run()

而且因为让 OpenSSL 工作总是很棘手,所以您可以使用以下 OpenSSL 语句来连接它:

openssl s_client -connect localhost:8000 -servername hello_world -cert keys/client.crt -key keys/client.key

针对 pyOpenSSL==0.13 运行上面的 python 代码,然后运行上面的 s_client 命令,将把它打印到屏幕上:

('Received SNI: ', 'hello_world')
于 2013-12-29T05:36:17.953 回答
0

现在有一个 txsni 项目负责根据请求查找正确的证书。https://github.com/glyph/txsni

于 2019-04-02T17:01:13.837 回答