How to open ssl socket using certificate stored in string variables in python

Question:

In Python, ssl.wrap_socket can read certificates from files, ssl.wrap_socket require the certificate as a file path.

How can I start an SSL connection using a certificate read from string variables?

My host environment does not allow write to files, and tempfile module is not functional
I’m using Python 2.7.
I store the certificate inside MySQL and read as a string.

Edit:
I gave up, this is basically require implement ssl by pure python code, this is beyond my current knowledge.

Asked By: kaala

||

Answers:

You can treat strings like files with StringIO.

Answered By: Sean W.

Looking at the source, ssl.wrap_socket calls directly into the native code (openssl) function SSL_CTX_use_cert_chain_file which requires a path to a file, so what you are trying to do is not possible.

For reference:

In ssl/init.py we see:

def wrap_socket(sock, keyfile=None, certfile=None,
                server_side=False, cert_reqs=CERT_NONE,
                ssl_version=PROTOCOL_SSLv23, ca_certs=None,
                do_handshake_on_connect=True):

    return SSLSocket(sock, keyfile=keyfile, certfile=certfile,
                   server_side=server_side, cert_reqs=cert_reqs,
                   ssl_version=ssl_version, ca_certs=ca_certs,
                   do_handshake_on_connect=do_handshake_on_connect)

Points us to the SSLSocket constructor (which is in the same file) and we see the following happen:

self._sslobj = _ssl2.sslwrap(self._sock, server_side,
                                     keyfile, certfile,
                                     cert_reqs, ssl_version, ca_certs)

_ssl2 is implemented in C (_ssl2.c)

Looking at the sslwrap function, we see it’s creating a new object:

    return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
                                       server_side, verification_mode,
                                       protocol, cacerts_file);

Looking at the constructor for that object, we eventually see:

            ret = SSL_CTX_use_certificate_chain_file(self->ctx,
                                                     cert_file);

That function is defined in openssl, so now we need to switch to that codebase.

In ssl/ssl_rsa.c we eventually find in the function:

BIO_read_filename(in,file) 

If you dig far enough into the BIO code (part of openssl) you’ll eventually come to a normal fopen():

fp=fopen(ptr,p);

So it looks like as it’s currently written. It must be in a file openable by C’s fopen().

Also, since python’s ssl library so quickly jumps into C, I don’t see a immediately obvious place to monkeypatch in a workaround either.

Answered By: cnelson

Quick look though the ssl module source confirms what you want is not supported by the API:
http://code.google.com/codesearch#2T6lfGELm_A/trunk/Modules/_ssl.c&q=sslwrap&type=cs

Which is not to say it is impossible, you could create a named pipe, feed one end from Python and give the filename to the ssl module.

For simpler, less secure use, dump cert from memory to mkstemp()’d file.

You could even mount FUSE volume and intercept file callback.

Finally, use ctypes to hack at ssl context at runtime and load cert/ket from a buffer following the C recipe Read certificate files from memory instead of a file using OpenSSL Things like these have been done before, but it’s not for the faintest of heart.

It looks like you are trying to get out of e.g. app engine “jail,” perhaps it is just not possible?

If you are not picky on ssl implementation, you can use M2Crypto, TLS Lite, pyOpenSSL or something else. The earlier is pure python, you can definitely hack it to use in-memory certificates/keys.

Answered By: Dima Tisnek

From Python 3.4, you can use SSLContext#load_verify_locations:

context = ssl.SSLContext()
context.load_verify_locations(cadata=cert)  # Where cert is str.

From https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_verify_locations

Answered By: judepereira

Python 3.4 added support for a cdata parameter to load certificates from a string. From https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_verify_locations:

"The cadata object, if present, is either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates. Like with capath extra lines around PEM-encoded certificates are ignored but at least one certificate must be present".

Answered By: zalmane
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.