SSL Client Authentication with Python and pycurl

Posted Thursday, April 14th at 7:51a.m. under Work, Python


If you are using Python to make requests over SSL then most likely you'll have run into the limitations of urllib2 if you are using a web service that requires client authentication. I found some recipes that "kind of" solved the problem but didn't bother to check server certificates, which kind of defeats the point if you are using two-way SSL to prevent man-in-the-middle attacks.

It was frustrating since most simple things are relatively simple to do in Python. In cURL, two-way SSL verification can be as easy as:

curl -cacert CA.crt -E client.pem https://myservice.com:443/secure/page

Obviously here we are doing verification with a Certificate Authority we created ourselves. When I vented to a colleague about the difficulty of implementing similar functionality in Python, he wondered why I hadn't bothered using pycurl. pycurl is a C-binding and the documentation is not the greatest, nor do the examples explain how to do simple SSL never mind two-way. But after digging around the source, here is one recipe that works:

import pycurl

class Response(object):
    """ utility class to collect the response """
    def __init__(self):
        self.chunks = []
    def callback(self, chunk):
        self.chunks.append(chunk)
    def content(self):
        return ''.join(self.chunks)

res = Response()

curl = pycurl.Curl()
curl.setopt(curl.URL, "https://yourservice/path")
curl.setopt(curl.WRITEFUNCTION, res.callback)
curl.setopt(curl.CAINFO, "/path/to/CA.crt")
curl.setopt(curl.SSLCERT, "/path/to/client.pem")
curl.perform()

print res.content()

And that's it. One other option you might use when testing your SSL implementation with curl is the -k flag, which skips host verification of the server. The option to set in pycurl to do the same is:

curl.setopt(curl.SSL_VERIFYHOST, 0)

Hopefully this saved you digging around the pycurl mailing list and source code like I had to.

Posted by David McLaughlin on Thursday, April 14th