views:

275

answers:

2

I need to build an encrypted connection between two peers, and I need to authenticate both. Both peers already share a fingerprint (SHA256 hash) of the other peer public key. I'm not using X509 or OpenPGP keys/certs as they are too big and bulky for my needs and they don't fit in the security model.

I'm trying to build a connection with M2Crypto (nice library) by abusing its x509 model:

  • given the rsa private key, create a selfsigned almost-empty cert.

  • connect to the other peer offering my cert

  • verify the other peer cert public key fingerprint;

Is the following code secure? is it correct? is there a way do do it better (maybe with other libraries)? My doubts are about OpenSSL not actually using the certificate public key for authentication as I'm not requesting any verification of the certificates.

I just need to use encrypted streams authed by der-encoded rsa keys, any Free Software solution for python is welcome. I'd like M2Crypto more because I know it better and have already some code using it in the same project.

Here is my code (just the client peer, server should be similar):

other_fingerprints = [] #list of fingerprints, (binary data)
mysocket = ... #any socket object

CERTFILE, KEYFILE = "testcert","testkey" # private key wrapped in the cert

from M2Crypto import *
ctx = SSL.Context('sslv3')
ctx.set_verify(SSL.verify_none, depth=1)
ctx.load_cert(CERTFILE, KEYFILE)
c = SSL.Connection(ctx, mysocket)
c.connect_ssl()
peercert = c.get_peer_cert()
keyobj = peercert.get_pubkey()
keydata = keyobj.as_der()
md = EVP.MessageDigest('sha256')
md.update(keydata)
h = md.digest()
if h not in other_fingerprints:
    raise(IOError) #other party not auth'ed
# from now on the connection is secure, right?
c.send("Hello secret world!")
print c.recv(4096)
c.close()

Thank you all in advance for your answers and advice.

A: 

The answer is in the question: use proper x509 certificates, and validate/verify symmetrically. "Is this secure?" - no, because you have to ask.

Your solution may work, but the fact you are asking for advice on "Is this secure?" tells me that you should probably use stuff straight from the box.

Ali A
I'm quite confident about the theory, what I'm not sure about is the code inside me2crypto (and openssl). My only worry is about openssl using or not the public key in certs during the handshake. If I could distribute the certs I would not have even asked. There is no "proper" way to use X509 in this context. M2Crypto has a function to do custom checks, SSL.Context.set_verify(,,callback()) but I don't find any documentation.
Kiwi
A: 

It seems your approach should work, but there is already a builtin fingerprint checker you might be able to use. See here: http://stackoverflow.com/questions/2150048/what-to-put-for-a-commonname-when-making-an-openssl-key#2150499

Heikki Toivonen
Thank you. It's everything I need to know!Anyway I'm thinking about using SSL.Checker for elegance, but I don't know if a X509 "fingerprint" is already the digest of the DER key or it is the digest of the full cert (including key and fields) ? As I may generate certificates from the bare key, I fear subtle changes in OpenSSL could generate different fingerprints and break things.If it is so, what about doing my own Checker class, or inherit it? is it considered elegant or quite an hack?
Kiwi
In SSL.Checker that fingerprint means taking the hash of the whole certificate in DER format. I believe this is the same as what openssl x509 -fingerprint does. If you compute the fingerprint in a different way, you are of course free to write your own checker routine.
Heikki Toivonen