使用TLS和Python进行身份验证
我想为一个运行在Raspberry Pi上的软件编写一个小的更新脚本,它的工作方式类似于本地服务器。它应该连接到web中的主服务器,以获取软件更新,并验证软件的许可证。 为此,我设置了两个python脚本。我想让它们通过TLS插座连接。然后客户端检查服务器证书,服务器检查它是否是授权客户端之一。我使用twisted on找到了解决方案 现在还剩下一个问题。我想知道哪个客户端(取决于证书)正在建立连接。在Python3中使用twisted有没有办法做到这一点使用TLS和Python进行身份验证,python,authentication,ssl,twisted,Python,Authentication,Ssl,Twisted,我想为一个运行在Raspberry Pi上的软件编写一个小的更新脚本,它的工作方式类似于本地服务器。它应该连接到web中的主服务器,以获取软件更新,并验证软件的许可证。 为此,我设置了两个python脚本。我想让它们通过TLS插座连接。然后客户端检查服务器证书,服务器检查它是否是授权客户端之一。我使用twisted on找到了解决方案 现在还剩下一个问题。我想知道哪个客户端(取决于证书)正在建立连接。在Python3中使用twisted有没有办法做到这一点 我对每个答案都很满意。一句话:是的,这
我对每个答案都很满意。一句话:是的,这是完全可能的,所有必要的东西都是 移植到Python3上-我在Mac上的Python3.4下测试了以下所有内容,它似乎 干得好 简单的回答是 "" 但考虑到要达到这一点需要大量的准备工作 可能的话,我已经构建了一个完整的工作示例,您应该能够 试一试,并以此为基础 对于后代,您首先需要生成一些客户端证书 由同一CA签署。您可能已经这样做了,但其他人也可以这样做 理解答案并自己尝试(这样我就可以测试我的答案) 回答我自己;-)),他们需要这样的代码:
# newcert.py
from twisted.python.filepath import FilePath
from twisted.internet.ssl import PrivateCertificate, KeyPair, DN
def getCAPrivateCert():
privatePath = FilePath(b"ca-private-cert.pem")
if privatePath.exists():
return PrivateCertificate.loadPEM(privatePath.getContent())
else:
caKey = KeyPair.generate(size=4096)
caCert = caKey.selfSignedCert(1, CN="the-authority")
privatePath.setContent(caCert.dumpPEM())
return caCert
def clientCertFor(name):
signingCert = getCAPrivateCert()
clientKey = KeyPair.generate(size=4096)
csr = clientKey.requestObject(DN(CN=name), "sha1")
clientCert = signingCert.signRequestObject(
csr, serialNumber=1, digestAlgorithm="sha1")
return PrivateCertificate.fromCertificateAndKeyPair(clientCert, clientKey)
if __name__ == '__main__':
import sys
name = sys.argv[1]
pem = clientCertFor(name.encode("utf-8")).dumpPEM()
FilePath(name.encode("utf-8") + b".client.private.pem").setContent(pem)
使用此程序,您可以创建一些证书,如下所示:
$ python newcert.py a
$ python newcert.py b
现在,您应该有一些可以使用的文件:
$ ls -1 *.pem
a.client.private.pem
b.client.private.pem
ca-private-cert.pem
然后您需要一个使用这些证书之一的客户端,并发送一些
数据:
最后,一个能够区分它们的服务器:
# whichclient.py
from twisted.python.filepath import FilePath
from twisted.internet.endpoints import SSL4ServerEndpoint
from twisted.internet.ssl import PrivateCertificate, Certificate
from twisted.internet.defer import Deferred
from twisted.internet.task import react
from twisted.internet.protocol import Protocol, Factory
class ReportWhichClient(Protocol):
def dataReceived(self, data):
peerCertificate = Certificate.peerFromTransport(self.transport)
print(peerCertificate.getSubject().commonName.decode('utf-8'))
self.transport.loseConnection()
def main(reactor):
pemBytes = FilePath(b"ca-private-cert.pem").getContent()
certificateAuthority = Certificate.loadPEM(pemBytes)
myCertificate = PrivateCertificate.loadPEM(pemBytes)
serverEndpoint = SSL4ServerEndpoint(
reactor, 4321, myCertificate.options(certificateAuthority)
)
serverEndpoint.listen(Factory.forProtocol(ReportWhichClient))
return Deferred()
react(main, [])
为了简单起见,我们只需将CA自己的证书重新用于
服务器,但在更现实的场景中,您显然希望
适当的证书
现在可以在一个窗口中运行whichclient.py
,然后运行pythontlsclient.py;
python tlsclient.py b
在另一个窗口中,并查看打印出来的whichclient.py
a
和b
分别通过commonName
证书主题中的字段
这里需要注意的一点是,您最初可能希望将该调用提交给
Certificate.peerFromTransport
到一个connectionMade
方法中;那不会的
工作
;
希望它最终会实现,但在它实现之前,你必须等到你成功
从对等方接收到一些经过身份验证的数据,以确保握手成功
完整的。对于几乎所有的应用程序,这都很好,因为
已收到执行任何操作的指示(在您的情况下,下载更新)
同行必须已经发送了证书。感谢您提供了这一伟大而完整的解决方案以及您的快速帮助。这是向我的脚本的最终解决方案迈出的一大步。@Glyph是否可以让客户端在Windows上使用类似pyinstaller的东西?还是twisted不再支持windows?你的站点的windows部分已经过时了:(@nsij22 Twisted在windows上仍然完全受支持,事实上,我最近一直在投入大量精力。最新的版本更容易“
pip安装”
”例如,在Windows上。是的,类似pyinstaller的东西应该可以工作。如果不行,请报告问题并在扭曲列表上讨论(或者在这里问另一个问题,一个问题的评论太小,无法适当讨论)。@Glyph删除了我的旧评论并发表了一篇新文章
# whichclient.py
from twisted.python.filepath import FilePath
from twisted.internet.endpoints import SSL4ServerEndpoint
from twisted.internet.ssl import PrivateCertificate, Certificate
from twisted.internet.defer import Deferred
from twisted.internet.task import react
from twisted.internet.protocol import Protocol, Factory
class ReportWhichClient(Protocol):
def dataReceived(self, data):
peerCertificate = Certificate.peerFromTransport(self.transport)
print(peerCertificate.getSubject().commonName.decode('utf-8'))
self.transport.loseConnection()
def main(reactor):
pemBytes = FilePath(b"ca-private-cert.pem").getContent()
certificateAuthority = Certificate.loadPEM(pemBytes)
myCertificate = PrivateCertificate.loadPEM(pemBytes)
serverEndpoint = SSL4ServerEndpoint(
reactor, 4321, myCertificate.options(certificateAuthority)
)
serverEndpoint.listen(Factory.forProtocol(ReportWhichClient))
return Deferred()
react(main, [])