Python SSL标准库load_cert_chain-加载PEM证书链失败

时间:2019-04-12 22:20:57

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

运行Python3.6。

我有一个 pem 格式的证书捆绑包,即服务器证书及其CA证书。 ssl上下文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命令行工具能够与该捆绑包配合使用-将元数据作为文本转储。

顺便说一句,我也愿意打赌请求库可以满足我的需求,但是我正在处理一个不需要安装其他软件包的情况。

1 个答案:

答案 0 :(得分:2)

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

查看文档:

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

加载私钥和相应的证书。 certfile字符串必须是PEM格式的单个文件的路径   包含证书以及任意数量的CA证书   需要建立证书的真实性。密钥文件   字符串(如果存在)必须指向包含私钥的文件   in。否则,私钥也将从certfile中获取。看到   有关证书的更多信息,请参见证书的讨论。   证书存储在证书文件中。

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

您没有在呼叫中提供密钥,因此它将在您的“证书”文件中搜索它,而找不到它,它会被驳倒,以获取我在下面发现的较长解释,然后才意识到您没有使用适当的方法。

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

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

_ssl.c内的先前诊断以了解错误

看看Python 3.6.8的来源,_ssl.chttps://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)

同样,我完全逃避了为什么那些库的开发人员以及库之上的包装程序决定决定创建如此隐秘的错误消息,只是迫使所有用户痛苦不堪。基本上,如果不学习源代码,就不可能了解正在发生的事情... 即便如此,源代码中也绝对没有注释,但是无论如何它可能是在某些部分自动生成的。