我需要分发哪些(密钥,证书)用于Python的SSL-socket连接?

0 投票
1 回答
3701 浏览
提问于 2025-04-16 09:28

我正在尝试写一个通用的服务器-客户端应用程序,能够在服务器之间交换数据。
我看过不少关于OpenSSL的文档,并且成功地建立了自己的证书颁发机构(CA),还为测试创建了一个证书(和私钥)。

不过我现在用的是Python 2.3,所以不能使用标准的“ssl”库。现在只能用PyOpenSSL,虽然它看起来还不错,但网上关于它的文档不多。

我现在的问题不是怎么让它工作,而是对证书的使用和放置位置感到困惑。

这是我两个正常工作的程序:

服务器:

#!/bin/env python

from OpenSSL import SSL
import socket
import pickle

def verify_cb(conn, cert, errnum, depth, ok):
    print('Got cert: %s' % cert.get_subject())
    return ok


ctx = SSL.Context(SSL.TLSv1_METHOD)
ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb)

# ??????
ctx.use_privatekey_file('./Dmgr-key.pem')
ctx.use_certificate_file('Dmgr-cert.pem')
# ??????
ctx.load_verify_locations('./CAcert.pem')

server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))

server.bind(('', 50000))
server.listen(3)

a, b = server.accept()

c = a.recv(1024)
print(c)

客户端:

from OpenSSL import SSL
import socket
import pickle


def verify_cb(conn, cert, errnum, depth, ok):
    print('Got cert: %s' % cert.get_subject())
    return ok

ctx = SSL.Context(SSL.TLSv1_METHOD)
ctx.set_verify(SSL.VERIFY_PEER, verify_cb)

# ??????????
ctx.use_privatekey_file('/home/justin/code/work/CA/private/Dmgr-key.pem')
ctx.use_certificate_file('/home/justin/code/work/CA/Dmgr-cert.pem')
# ?????????
ctx.load_verify_locations('/home/justin/code/work/CA/CAcert.pem')

sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.connect(('10.0.0.3', 50000))

a = Tester(2, 2)
b = pickle.dumps(a)
sock.send("Hello, world")

sock.flush()
sock.send(b)
sock.shutdown()
sock.close()

我从这个链接找到了信息:ftp://ftp.pbone.net/mirror/ftp.pld-linux.org/dists/2.0/PLD/i586/PLD/RPMS/python-pyOpenSSL-examples-0.6-2.i586.rpm,里面有一些示例脚本。

如你所见,我对“# ????????”之间的内容不是很理解。我不明白为什么客户端和服务器都需要证书和私钥。我不确定每个部分应该放在哪里,但我是不是只需要分发一部分密钥(可能是公钥)就可以了?如果每个服务器都需要这两部分,那不就违背了非对称密钥的意义吗?

我尝试在任一端去掉私钥或证书,结果无论去掉哪个,都会出现以下错误:

OpenSSL.SSL.Error: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert handshake failure'), ('SSL routines', 'SSL3_WRITE_BYTES', 'ssl handshake failure')]

有人能解释一下这是否是SSL的预期行为吗?我真的需要把私钥和公证书分发给所有客户端吗?
我想避免任何重大的安全问题,而泄露私钥通常是一个大问题……

谢谢你的帮助!

==================================================================

感谢caf帮我找到了问题。根据他的建议,我创建了两个新的证书对:spaceman和dmgr。然后我把“spaceman”的两个部分(密钥和证书)放在客户端程序里,“dmgr”的密钥也是如此。

基本上,只有客户端中的以下两行发生了变化,虽然在旁边用openssl做了很多工作。

ctx.use_privatekey_file('/home/justin/code/work/CA/private/Dmgr-key.pem')
ctx.use_certificate_file('/home/justin/code/work/CA/Dmgr-cert.pem')

修正后的版本:

ctx.use_privatekey_file('/home/justin/code/work/CA/private/spaceman-key.pem')
ctx.use_certificate_file('/home/justin/code/work/CA/spacemancert.pem')

1 个回答

4

在SSL交易中,双方可以互相提供证书来验证彼此的身份。为了做到这一点,每一方需要拥有与其证书对应的私钥。这意味着双方会有两个不同的证书,所以每一方会有两个不同的私钥。

你通过use_privatekey_file()use_certificate_file()设置的就是这个证书/私钥对。服务器和客户端应该使用不同的证书和私钥对。

在验证对方的证书时,你需要检查以下几点:

  • 证书是否有效(也就是说,它必须是由你信任的证书颁发机构签发的,不能过期,也不能被撤销);
  • 证书是否与对方的身份匹配(也就是说,证书上的身份信息要和对方声称的身份一致)。这个身份信息存储在证书的SubjectName字段中,如何将其映射到对方身份是应用程序特定的(可能是用户登录名、DNS名称或其他什么)。

撰写回答