如何验证/验证Python中的X509证书信任链?
我正在致力于实现一个使用API的Web应用程序。 在响应期间,API服务器通过链接发送X509证书(PEM格式,由签名证书和一个或多个中间证书组成的根证书),我必须下载该证书并使用该证书进行进一步验证。
在使用证书之前,我需要确保链中的所有证书组合在一起,为受信任的根CA证书创建一个信任链(以检测并避免任何恶意请求)。 我在python中很难做到这一点,我对这个主题的研究没有产生任何有用的东西。
证书很容易通过请求和M2Crypto抓取和加载
import requests
from M2Crypto import RSA, X509
mypem = requests.get('https://server.com/my_certificate.pem')
cert = X509.load_cert_string(str(mypem.text), X509.FORMAT_PEM)
但是,验证证书链是一个问题。 对于我来说,将证书写入磁盘以便像使用像openssl
这样的命令行实用程序来使用openssl
是不可行的,所以它必须通过python完成。 我也没有任何开放的连接,所以使用基于连接的验证解决方案(如在这个答案/线程中提到:https://stackoverflow.com/a/1088224/4984533)也不起作用。
在关于这个问题的另一个线程上(https://stackoverflow.com/a/4427081),abbot解释说m2crypto不能进行这种验证,并且说他已经写了一个扩展来允许验证(使用模块m2ext
),但是他的补丁从来没有工作,即使我知道它是有效的,总是返回假。
from m2ext import SSL
ctx = SSL.Context()
ctx.load_verify_locations(capath='/etc/ssl/certs/') # I have run c_rehash in this directory to generate a list of cert files with signature based names
if not ctx.validate_certificate(cert): # always happens
print('Invalid certificate!')
还有一个类似的线程在这里回答了这里https://stackoverflow.com/a/9007764/4984533其中约翰马修斯声称有一个补丁写入,将做到这一点,但不幸的是补丁链接现在已经死了 - 无论如何,是对该线程的评论,声明该修补程序不适用于openssl 0.9.8e。
所有有关验证python证书信任链的答案似乎都链接到死补丁或返回m2ext
。
有没有一种简单直接的方法来验证我在Python中的证书信任链?
虽然Avi Das的答复对验证具有单个叶证书的单一信任锚的微小情况有效, 但它将信任置于中间证书中 。 这意味着在发送中间件以及客户端证书的情况下,整个链是可信的。
不要这样做。 在pyOpenSSL的测试中发现的代码是有缺陷的!
我在Python的cryptography-dev邮件列表中找到了这个线程(链接回到这个答案):https://mail.python.org/pipermail/cryptography-dev/2016-August/000676.html
我们看到这个代码没有区分root_cert和中间。 如果我们查看文档,add_cert本身会添加一个可信的证书(也许add_trusted_cert会是一个更好的名字?)。
它包括为什么这是一个可怕的想法的例子。 我无法强调这一点:通过信任中间人来验证您的链条与完全不执行任何检查类似。
说了这么多,你怎么验证Python中的证书链? 我找到的最佳选择是https://github.com/wbond/certvalidator,它似乎可以完成这项工作。
还有一些有缺陷的选择:
这是一些可敬的Python密码库的当前状态:
这两个线程目前看起来都很陈旧。
我知道这与问题的情况不符,但是:如果您在TLS套接字中使用证书验证来构建某些内容,则只需使用Python中已有的模块即可。 不要重新发明车轮,特别是在密码学方面。 加密很难; 关于它的唯一简单的事情就是搞砸了。
我查看了pyopenssl库并发现了这个证书链验证。 以下示例来自他们的测试,并且似乎正在做你想做的事情,它正在验证信任链对受信任的根证书的影响。 以下是X509Store和X509StoreContext的相关文档
from OpenSSL.crypto import load_certificate, load_privatekey
from OpenSSL.crypto import X509Store, X509StoreContext
from six import u, b, binary_type, PY3
root_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU
ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2
NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM
MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U
ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL
urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy
2xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF
1dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE
FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn
VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE
BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS
b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB
AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi
hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY
w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
-----END CERTIFICATE-----
""")
intermediate_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICVzCCAcCgAwIBAgIRAMPzhm6//0Y/g2pmnHR2C4cwDQYJKoZIhvcNAQENBQAw
WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAw
DgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwHhcNMTQw
ODI4MDIwNDA4WhcNMjQwODI1MDIwNDA4WjBmMRUwEwYDVQQDEwxpbnRlcm1lZGlh
dGUxDDAKBgNVBAoTA29yZzERMA8GA1UECxMIb3JnLXVuaXQxCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU2FuIERpZWdvMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmK
FGIbljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT
21H2qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwID
AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAPIWSkLX
QRMApOjjyC+tMxumT5e2pMqChHmxobQK4NMdrf2VCx+cRT6EmY8sK3/Xl/X8UBQ+
9n5zXb1ZwhW/sTWgUvmOceJ4/XVs9FkdWOOn1J0XBch9ZIiFe/s5ASIgG7fUdcUF
9mAWS6FK2ca3xIh5kIupCXOFa0dPvlw/YUFT
-----END CERTIFICATE-----
""")
intermediate_server_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICWDCCAcGgAwIBAgIRAPQFY9jfskSihdiNSNdt6GswDQYJKoZIhvcNAQENBQAw
ZjEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
biBEaWVnbzAeFw0xNDA4MjgwMjEwNDhaFw0yNDA4MjUwMjEwNDhaMG4xHTAbBgNV
BAMTFGludGVybWVkaWF0ZS1zZXJ2aWNlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
biBEaWVnbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqpJZygd+w1faLOr1
iOAmbBhx5SZWcTCZ/ZjHQTJM7GuPT624QkqsixFghRKdDROwpwnAP7gMRukLqiy4
+kRuGT5OfyGggL95i2xqA+zehjj08lSTlvGHpePJgCyTavIy5+Ljsj4DKnKyuhxm
biXTRrH83NDgixVkObTEmh/OVK0CAwEAATANBgkqhkiG9w0BAQ0FAAOBgQBa0Npw
UkzjaYEo1OUE1sTI6Mm4riTIHMak4/nswKh9hYup//WVOlr/RBSBtZ7Q/BwbjobN
3bfAtV7eSAqBsfxYXyof7G1ALANQERkq3+oyLP1iVt08W1WOUlIMPhdCF/QuCwy6
x9MJLhUCGLJPM+O2rAPWVD9wCmvq10ALsiH3yA==
-----END CERTIFICATE-----
""")
root_cert = load_certificate(FILETYPE_PEM, root_cert_pem)
intermediate_cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem)
intermediate_server_cert = load_certificate(FILETYPE_PEM, intermediate_server_cert_pem)
store = X509Store()
store.add_cert(root_cert)
store.add_cert(intermediate_cert)
store_ctx = X509StoreContext(store, intermediate_server_cert)
print(store_ctx.verify_certificate())
链接地址: http://www.djcxy.com/p/85551.html
上一篇: How to validate / verify an X509 Certificate chain of trust in Python?
下一篇: How do I change the external editor for GitHub client on MAC or Windows?