Python ssl 标准库 load_cert_chain - 加载 PEM 证书链失败
Python ssl standard library load_cert_chain - fails on loading PEM cert chain
运行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 命令行工具能够很好地处理该包 - 将元数据转储为文本。
顺便说一句,我愿意打赌请求库可以满足我的需求,但我正在处理一个不需要安装额外包的上下文。
您可能需要使用 load_verify_locations
而不是 load_cert_chain
。
查看文档:
SSLContext.load_cert_chain(certfile, keyfile=None, password=None)
Load a private key and the corresponding certificate. The certfile string must be the path to a single file in PEM format
containing the certificate as well as any number of CA certificates
needed to establish the certificate’s authenticity. The keyfile
string, if present, must point to a file containing the private key
in. Otherwise the private key will be taken from certfile as well. See
the discussion of Certificates for more information on how the
certificate is stored in the certfile.
注意:加载私钥和对应的证书。
你没有在你的调用中提供密钥,所以它会在你的 "certificate" 文件中搜索它但没有找到它,它会呕吐,因为我在下面写的更长的解释才意识到你没有使用适当的方法。
顺便说一句,您实际上可能将 load_cert_chain
与 load_verify_locations
混在一起了。 load_cert_chain
是加载您的证书(附加了可选的 CA 证书)及其关联的私钥,而不是加载 CA/intermediate 证书,这是通过 load_verify_locations
.[=28 完成的=]
您的 "bundle" 不是您的证书,或者不包含私钥。从它的名字来看,我想它实际上是 CA/intermediate 证书,而不是你的证书,这就是为什么我认为你混合了两种不同的方法。
之前诊断里面_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)
再一次,我完全不明白为什么那些库和库之上的包装器的开发人员只是决定创建如此神秘的错误消息,除了给所有用户带来痛苦。基本上不研究源码,是无法理解发生了什么的……
即便如此,源代码中绝对没有注释,但无论如何它可能已经在某些部分自动生成了。
运行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 命令行工具能够很好地处理该包 - 将元数据转储为文本。
顺便说一句,我愿意打赌请求库可以满足我的需求,但我正在处理一个不需要安装额外包的上下文。
您可能需要使用 load_verify_locations
而不是 load_cert_chain
。
查看文档:
SSLContext.load_cert_chain(certfile, keyfile=None, password=None)
Load a private key and the corresponding certificate. The certfile string must be the path to a single file in PEM format containing the certificate as well as any number of CA certificates needed to establish the certificate’s authenticity. The keyfile string, if present, must point to a file containing the private key in. Otherwise the private key will be taken from certfile as well. See the discussion of Certificates for more information on how the certificate is stored in the certfile.
注意:加载私钥和对应的证书。
你没有在你的调用中提供密钥,所以它会在你的 "certificate" 文件中搜索它但没有找到它,它会呕吐,因为我在下面写的更长的解释才意识到你没有使用适当的方法。
顺便说一句,您实际上可能将 load_cert_chain
与 load_verify_locations
混在一起了。 load_cert_chain
是加载您的证书(附加了可选的 CA 证书)及其关联的私钥,而不是加载 CA/intermediate 证书,这是通过 load_verify_locations
.[=28 完成的=]
您的 "bundle" 不是您的证书,或者不包含私钥。从它的名字来看,我想它实际上是 CA/intermediate 证书,而不是你的证书,这就是为什么我认为你混合了两种不同的方法。
之前诊断里面_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)
再一次,我完全不明白为什么那些库和库之上的包装器的开发人员只是决定创建如此神秘的错误消息,除了给所有用户带来痛苦。基本上不研究源码,是无法理解发生了什么的…… 即便如此,源代码中绝对没有注释,但无论如何它可能已经在某些部分自动生成了。