如何验证/验证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,它似乎可以完成这项工作。

还有一些有缺陷的选择:

  • https://github.com/alex/x509-validator,它明确指出它不安全使用。
  • https://github.com/pyca/cryptography/issues/1660#issuecomment-75075319,它做了某种检查,但我不确定它是否按预期工作
  • 这是一些可敬的Python密码库的当前状态:

  • https://github.com/pyca/pyopenssl/pull/473讨论了将链式验证合并到pyopenssl中的pull请求,该请求尚未合并。
  • https://github.com/pyca/cryptography/issues/2381是一个问题,要求与加密模块有类似的功能,但它仍然未解决
  • 这两个线程目前看起来都很陈旧。

    我知道这与问题的情况不符,但是:如果您在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?