【问题标题】:Validating client certificates in PyOpenSSL在 PyOpenSSL 中验证客户端证书
【发布时间】:2012-02-23 18:53:09
【问题描述】:

我正在编写一个需要在客户端浏览器中安装证书的应用程序。我在“上下文”对象的 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 的完全跛足、幼稚和/或根本缺乏理解,请不要太粗鲁!

谢谢:)

罗杰

【问题讨论】:

    标签: python validation ssl client-certificates pyopenssl


    【解决方案1】:

    在OpenSSL documentation对应set_verify()中,你关心的关键是返回码:

    回调应该有五个参数:一个 Connection 对象,一个 X509 对象和三个整数变量,这反过来又是潜在的错误 编号、错误深度和返回码。回调应该返回 true 如果验证通过,否则为 false。

    有一个完整的工作示例或多或少地显示了您想要做什么:When are client certificates verified?

    基本上你可以忽略前 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. 前缀。

    【讨论】:

    • 在本例中,正进行零验证。事实上,这个例子你可以完全省略set_verify 并具有完全相同的安全特性。问题是ok 实际上是用于预验证的“返回码”(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT | VERIFY_CLIENT_ONCE 的结果),但是在回调中完全没有实现客户端认证验证——它只是按原样返回。如果您没有尝试实际实施客户端身份验证验证,则可以只执行 ctx.verify_mode 而不是 ctx.set_verify
    • @stof 如果我明白你在说什么,请将ctx.setverify(...) 替换为ctx.verify_mode = ssl.CERT_NONE(并删除不再需要的verify_callback()),如本答案所述:stackoverflow.com/a/28048260/462302跨度>
    猜你喜欢
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多