wiki:GSIHTTPSConnector

The scenario is we need a httplib.HTTPSConnection which uses the client certs to connect to the server. This way we can have authenticated TLS, as opposed to WS-Security (which is too hard). httplib lets you give cert files, but it doesn't authenticate the server (against a CA for instance). M2Crypto gives you the server authing, but once again requires cert files!

My solution, ctypes to patch in the missing methods, as openssl does allow you to pass in X509 and RSA object for a connection context. I should note that in the next version of M2Crypto these methods are available directly, but that release could be months away.

I've got an implementation which works with a ZSI client, in the  http://git.hpc.jcu.edu.au pycat git repo.

import M2Crypto
import sys

context = M2Crypto.SSL.Context('sslv23')
context.load_verify_locations(cafile='/opt/CA/cacert.pem')
context.set_verify(M2Crypto.SSL.verify_peer, -1)

cert = M2Crypto.X509.load_cert('/tmp/x509up_u1000')
key=M2Crypto.RSA.load_key('/tmp/x509up_u1000')

context.set_allow_unknown_ca(False)

#Magic
import ctypes, ctypes.util
libname = ctypes.util.find_library('ssl')
dll = ctypes.CDLL(libname)

fun = dll['SSL_CTX_use_certificate']
fun.argtypes = (ctypes.c_voidp,ctypes.c_voidp,)
ret = fun(ctypes.c_void_p(int(context.ctx)), ctypes.c_void_p(int(cert._ptr())))
if ret != 1:
    print "Couldn't import cert"
    sys.exit(1)

fun = dll['SSL_CTX_use_RSAPrivateKey']
fun.argtypes = (ctypes.c_voidp,ctypes.c_voidp,)
ret = fun(ctypes.c_void_p(int(context.ctx)), ctypes.c_void_p(int(key.rsa)))
if ret != 1:
    print "Couldn't import key"
    sys.exit(1)

check = dll['SSL_CTX_check_private_key']
check.argtypes = (ctypes.c_voidp,)
ret = check(ctypes.c_voidp(int(context.ctx)))
if ret != 1:
    print "Key/cert pair is not valid"
    sys.exit(1)

# Old, crap way of doing this
#context.load_cert('/tmp/x509up_u1000')
con = M2Crypto.httpslib.HTTPSConnection('goldman', 443, 
ssl_context=context)
con.connect()
con.request('GET','/~nigel/test.php')
print con.getresponse().read()
con.close()