How to validate / verify an X509 Certificate chain of trust in Python?

I am working on implementing a web application that utilizes an API. During a response, the API server sends over a link to an X509 certificate (in PEM format, composed of a signing certificate and one or more intermediate certificates to a root CA certificate ) that I must download and use to do further verification.

Before using the certificate, I need to ensure that all certificates in the chain combine to create a chain of trust to a trusted root CA certificate (to detect and avoid any malicious requests). I am having a hard time doing this in python and my research into the subject is not yielding anything useful.

The certificate is easily grabbed and loaded using requests and 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)

However, validating the certificate chain is a problem. It is not feasible for me to write the certificate to disk in order to use a command line utility like openssl through something like subprocess, so it must be done through python. I also do not have any open connections and so using a connection based validation solution (like is mentioned in this answer / thread: https://stackoverflow.com/a/1088224/4984533) will not work either.

On another thread about this problem (at https://stackoverflow.com/a/4427081) abbot explains that m2crypto is incapable of doing this validation and says that he has written an extension to allow validation (using the module m2ext ) but his patch never seems work, always returning false even though I know it's valid:

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!') 

There's also this answer on a similar thread here https://stackoverflow.com/a/9007764/4984533 in which John Matthews claims to have a patch written which will do it, but unfortunately the patch link is now dead -- and anyway there is a comment on that thread stating that the patch did not work with openssl 0.9.8e.

All answers relating to validating a certificates chain of trust in python seem to either link to the dead patch or go back to m2ext .

Is there a simple, straightforward way to go about validating my certificates chain of trust in Python?


While the response of Avi Das is valid for the trivial case of verifying a single trust anchor with a single leaf certificate, it places trust in the intermediate certificate . That means that in the case where the intermediate is sent, as well as the client certificate, the entire chain is trusted.

Do not do this. The code found in pyOpenSSL's tests are flawed!

I found this thread on Python's cryptography-dev mailing lists (which links back to this answer): https://mail.python.org/pipermail/cryptography-dev/2016-August/000676.html

We see this code makes no distinction between the root_cert and the intermediate. If we look at the documentation, add_cert itself adds a trusted cert (maybe add_trusted_cert would be a better name?).

It includes examples on why this is a terrible idea. I can not stress this enough: verifying your chain by trusting the intermediates is similar to not performing any check at all.


Having said that, how do you verify a certificate chain in Python? The best alternative I found is https://github.com/wbond/certvalidator, which seems to do the job.

There are also some flawed alternatives:

  • https://github.com/alex/x509-validator, which explicitly states that it is not safe to use.
  • https://github.com/pyca/cryptography/issues/1660#issuecomment-75075319, which does some sort of checking, but I'm not sure it works as intended
  • This is the current state for some respectable Python cryptography libraries:

  • https://github.com/pyca/pyopenssl/pull/473 discusses a pull request to incorporate chain verification in pyopenssl, which has not been merged yet.
  • https://github.com/pyca/cryptography/issues/2381 is an issue requesting a similar feature to the cryptography module, but it is still unresolved
  • Both threads seem stale at this time.

    I know this does not match the question's case, but: if you are building something using certificate validation in TLS sockets, just use the modules already available in Python. Never re-invent the wheel, especially regarding cryptography. Crypto is hard; the only easy thing about it is messing it up.


    I looked into pyopenssl library and found this for certificate chain validation. The following example is from their tests and seem to do what you want, which is validating chain of trust to a trusted root certificate. Here are the relevant docs for X509Store and 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/85552.html

    上一篇: 如何有条件地将样式应用于Kendo UI网格“行”?

    下一篇: 如何验证/验证Python中的X509证书信任链?