16

我正在编写一个需要在客户端浏览器中安装证书的应用程序。我在“上下文”对象的 PyOpenSSL 文档中找到了这一点,但我看不到任何关于回调应该如何验证证书的信息,只是它应该以某种方式验证。

   set_verify(模式,回调)
      将此 Context 对象的验证标志设置为 mode 和
      指定回调应该用于验证回调。
      模式应该是 VERIFY_NONE 和 VERIFY_PEER 之一。如果
      使用 VERIFY_PEER,模式可以是 OR:ed
      VERIFY_FAIL_IF_NO_PEER_CERT 和 VERIFY_CLIENT_ONCE 进一步
      控制行为。回调应该有五个参数:A
      连接对象、一个 X509 对象和三个整数变量,
      依次是潜在错误数、错误深度和返回
      代码。如果验证通过,回调应该返回 true 并且
      否则为假。

我告诉 Context 对象我的(自签名)密钥在哪里(见下文),所以我想我不明白为什么这还不足以让库检查客户端提供的证书是否有效。在这个回调函数中应该做什么?

class SecureAJAXServer(PlainAJAXServer):
    def __init__(self, server_address, HandlerClass):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = SSL.Context(SSL.SSLv23_METHOD)
        ctx.use_privatekey_file ('keys/server.key')
        ctx.use_certificate_file('keys/server.crt')
        ctx.set_session_id("My_experimental_AJAX_Server")
        ctx.set_verify( SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT | SSL.VERIFY_CLIENT_ONCE, callback_func )
        self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))
        self.server_bind()
        self.server_activate()

警告:在这里编码是为了好玩,绝对不是专业人士,所以如果我的 Q 揭示了我对 SSL 的完全跛足、幼稚和/或根本缺乏理解,请不要太粗鲁!

谢谢 :)

罗杰

4

1 回答 1

5

OpenSSL 文档set_verify(),您关心的关键是返回码

callback 应该有五个参数:一个 Connection 对象、一个 X509 对象和三个整数变量,它们依次是潜在错误号、错误深度和返回码。如果验证通过,回调应该返回 true,否则返回 false。

有一个完整的工作示例或多或少地显示了您想要做什么:何时验证客户端证书?

本质上,您可以忽略前 4 个参数,只检查第五个参数中的返回码值,如下所示:

from OpenSSL.SSL import Context, Connection, SSLv23_METHOD
from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE

class SecureAJAXServer(BaseServer):
    def verify_callback(connection, x509, errnum, errdepth, ok):
        if not ok:
            print "Bad Certs"
        else:
            print "Certs are fine"
        return ok

    def __init__(self, server_address, HandlerClass):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = Context(SSLv23_METHOD)
        ctx.use_privatekey_file ('keys/server.key')
        ctx.use_certificate_file('keys/server.crt')
        ctx.set_session_id("My_experimental_AJAX_Server")
        ctx.set_verify( VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT | VERIFY_CLIENT_ONCE, verify_callback )
        self.socket = Connection(ctx, socket.socket(self.address_family, self.socket_type))
        self.server_bind()
        self.server_activate()

注意:我进行了另一项更改,即from OpenSSL.SSL import ...在测试时稍微简化您的代码,这样您就不会SSL.在每个导入符号前面都有前缀。

于 2012-02-02T03:18:49.420 回答