Search code examples
python-3.xpython-requestscertificate

Python requests using certificate value instead of path


I am using the python request module to makes a POST call:

import requests
response = requests.post( foo_url, 
                          json={"foo":"bar"}, 
                          headers=foo_headers,
                          verify='/path/to/cert' )

This works fine. Though is it possible to use the value of the certificate directly instead of the path to the file that contains the certificate?


Solution

  • TLDR: The answer is definitively "no, the cert must be in a file on disk." And the reason why is because OpenSSL is awful.

    requests is based on urllib3, which is based on ssl. requests takes your top-level cert parameter and splits it up into parameters named cert_file and key_file, which get passed to urllib3. urllib3 passes them on, untouched, to ssl. And ssl expects them to be filenames.

    The specific culprit at the bottom of the Python stack is SSLContext.load_cert_chain from the ssl module. It depends on _SSLContext, which is written in C. The C code for _SSLContext.load_cert_chain is here. And you can see, it really truly 100% needs a filesystem path! Ugh!

    The culprit at the bottom of the C stack is OpenSSL's SSL_CTX_use_certificate_chain_file, which has this signature:

    int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
    

    There are ways of building a cert chain in OpenSSL that don't involve "just open a file and read it in," but they're vastly more complicated, which I guess is why Python ssl doesn't use them... and that explains why urllib3 doesn't use them, and that explains why requests doesn't use them.