【问题标题】:Python ssl standard library load_cert_chain - fails on loading PEM cert chainPython ssl 标准库 load_cert_chain - 加载 PEM 证书链失败
【发布时间】:2019-09-03 17:16:29
【问题描述】:

运行 Python3.6。

我有一个 pem 格式的证书包,即服务器证书及其 CA 证书。 ssl context load_cert_chain('aws-bundle.pem') 引发 SSL 错误。其他库(如 urllib)在验证来自 HTTPS 事务的证书时遇到问题。

这是捆绑文件的样子(省略了行):

-----BEGIN CERTIFICATE----- 
MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF
. . .
yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- 
MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF
. . . 
akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==
-----END CERTIFICATE-----

以下是我的 ipython 成绩单的摘录:

In [33]: import ssl

In [34]: context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

In [35]: context.load_cert_chain('aws-bundle.pem')
---------------------------------------------------------------------------
SSLError                                  Traceback (most recent call last)
<ipython-input-38-c955611be04f> in <module>
----> 1 context.load_cert_chain('aws-bundle.pem')

SSLError: [SSL] PEM lib (_ssl.c:3520)

顺便说一句,openssl 命令行工具可以很好地处理该捆绑包 - 将元数据转储为文本。

顺便说一句,我也愿意打赌 requests 库可以满足我的需求,但我正在处理的上下文中,最好不必安装额外的包。

【问题讨论】:

    标签: python python-3.x ssl openssl tls1.2


    【解决方案1】:

    您可能需要使用load_verify_locations 而不是load_cert_chain。

    查看文档:

     SSLContext.load_cert_chain(certfile, keyfile=None, password=None)
    

    加载一个私钥和相应的证书。 certfile 字符串必须是 PEM 格式的单个文件的路径 包含证书以及任意数量的 CA 证书 需要确定证书的真实性。密钥文件 字符串,如果存在,必须指向包含私钥的文件 否则,私钥也将从 certfile 中获取。看 证书的讨论以获取有关如何 证书存储在 certfile 中。

    仔细注意:加载私钥和相应的证书。

    您没有在呼叫中提供密钥,因此它会在您的“证书”文件中搜索它并且找不到它,它会很糟糕,因为我在下面写了更长的解释,然后才意识到您没有使用适当的方法.

    顺便说一句,您实际上可能将load_cert_chain 与load_verify_locations 混合在一起。 load_cert_chain 是加载您的证书(附有可选的 CA 证书)及其关联的私钥,而不是加载 CA/中间证书,这是通过 load_verify_locations 完成的。

    您的“捆绑包”不是您的证书,或者不包含私钥。从它的名字来看,我想它实际上是 CA/中间证书,而不是你的证书,这就是为什么我认为你混合了两种不同的方法。

    之前在_ssl.c里面的诊断了解错误

    查看 Python 3.6.8 的源代码,_ssl.c (https://github.com/python/cpython/blob/3c6b436a57893dd1fae4e072768f41a199076252/Modules/_ssl.c) 的第 3520 行完全匹配错误:

     _setSSLError(NULL, 0, __FILE__, __LINE__);
    

    (为什么在没有任何细节的情况下变得如此神秘只是逃避我)。

    如果你仔细检查,你很可能在你的调用中处于适当的位置,因为它出现的函数是_ssl__SSLContext_load_cert_chain_impl。

    现在,如果您研究上面导致这一行的代码,您会发现:

    r = SSL_CTX_use_PrivateKey_file(self->ctx,
        PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), SSL_FILETYPE_PEM);
    

    这里出了点问题。因此,仅凭它的名称 (SSL_CTX_use_PrivateKey_file),我想问题出在您的证书上附加的私钥上,因此您可以停止查看证书包的内容!

    遗憾的是,我不知道私钥可能有什么问题,但我想你可以开始明显的检查路径:

    • 是通向它的路径吗
    • 文件权限正常
    • 内容没问题

    为什么要在那儿做呢?可能是因为后面的代码会:

     r = SSL_CTX_check_private_key(self->ctx);
    

    因此它确保私钥与您的证书匹配。

    如果您确实对捆绑文件有问题,请在上面完成:

    r = SSL_CTX_use_certificate_chain_file(self->ctx, PyBytes_AS_STRING(certfile_bytes));
    

    如果失败,它将在第 3499 行触发错误,因此您可能会在堆栈跟踪中改为:

    SSLError: [SSL] PEM lib (_ssl.c:3499)
    

    再一次,我完全不明白为什么那些库和库之上的包装器的开发人员只是决定创建如此神秘的错误消息,除非给所有用户带来痛苦。基本上不研究源代码,是无法理解发生了什么的…… 即便如此,源代码中绝对没有 cmets,但它可能已经在某些部分自动生成。

    【讨论】:

    • 感谢您的帮助。出色的侦探工作!我喜欢你对错误信息的批评!
    • 我可以将文件加载为文本而不是实际文件吗?请告知如何
    • @shareef 你的意思是使用内置函数open()?
    猜你喜欢
    • 2014-03-19
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 2019-12-06
    • 1970-01-01
    • 2020-09-30
    相关资源
    最近更新 更多