【发布时间】:2012-11-30 11:51:45
【问题描述】:
我目前正在尝试编写一个 python 服务器脚本,该脚本应根据其公钥对当前客户端进行身份验证。由于我使用的是 twisted,example in the twisted documenteation 让我开始使用。
虽然我可以使用示例代码生成密钥、连接和通信,但我还没有找到以可用格式获取客户端公钥的方法。在this stackexchange question 中,有人从OpenSSL.crypto.PKey 对象中提取公钥,但无法将其转换为可读格式。因为我可以通过verifyCallback 方法或通过我的协议的任何方法中的self.transport.getPeerCertificate() 访问x509 证书的PKey 对象,所以这将是一个不错的方法。 (不接受)答案建议尝试crypto.dump_privatekey(PKey)。不幸的是,这并没有真正产生预期的结果:
虽然答案中的BEGIN PRIVATE KEY 和BEGIN PRIVATE KEY 可以通过简单的文本替换功能来修复,但base64 字符串似乎与公钥不匹配。如here 所述,我使用openssl rsa -in client.key -pubout > client.pub 提取了公钥。它与dump_privatekey 函数的结果不匹配。
虽然还有一个open bug towards OpenSSL on launchpad,但它还没有修复。这是 19 个月前报道的,最近(2012 年 10 月)有一些活动,我不希望在回购中快速修复。
您是否有任何其他想法,我可以如何以与我上面提到的client.pub 文件相当的格式获取公钥?也许有一个扭曲的或 OpenSSL 连接特定的对象来保存这些信息。请注意,我必须将公钥存储在协议对象中,以便以后可以访问它。
为什么不接受任何答案?
J.F. Sebastian 的 M2Crypto
抱歉,我没有想到我无法将证书与连接关联起来的可能性。我添加了必须将公钥存储在协议实例中的要求。因此,按照 J.F. Sebastian 的建议,在 postConnectionCheck 函数中使用 peerX509.as_pem() 不起作用。此外,至少在 python-m2crypto 的 0.21.1-2ubuntu3 版本中,我必须调用 peerX509.get_rsa().as_pem() 才能获得正确的公钥。使用peerX509.as_pem(None)(因为peerX509.as_pem() 仍然需要密码)产生与PyOpenSSL 中的crypto.dump_privatekey(PKey) 完全相同的输出。也许有一个错误。
除此之外,答案向我展示了一种使用以下Echo 协议类编写另一种解决方法的可能方法:
class Echo(Protocol):
def dataReceived(self, data):
"""As soon as any data is received, write it back."""
if self.transport.checked and not self.pubkeyStored:
self.pubkeyStored = True
x509 = m2.ssl_get_peer_cert(self.transport.ssl._ptr())
if x509 is not None:
x509 = X509.X509(x509, 1)
pk = x509.get_pubkey()
self.pubkey = pk.get_rsa().as_pem()
print pk.as_pem(None)
print self.pubkey
self.transport.write(data)
如您所见,这使用了一些我想阻止的内部类。我正在犹豫是否提交一个小补丁,它将在 M2Crypto.SSL.TwistedProtocolWrapper 的 TLSProtocolWrapper 类中添加一个 getCert 方法。即使它被上游接受,它也会破坏我的脚本与除了最先进的 m2crypto 版本之外的任何脚本的兼容性。你会怎么做?
我的外部 OpenSSL 调用
嗯,这是一个基于外部系统命令的丑陋解决方法,在我看来,这比访问非公共属性更糟糕。
【问题讨论】:
标签: python twisted public-key pyopenssl