Python client - SSL lib - certificate verify failed
Asked Answered
N

2

12

I'm trying to do a small secure HTTPS client for learning purposes and see how all the mechanics of SSL works on a higher level for now, so i'm trying to convert a simple socket into a ssl via ssl.wrap_socket.

I probably got the whole concept backwards but, here's what i'm doing:

s.connect((host, port))
if port == 443:
    f = open('cacerts.txt', 'r')
    calist = f.read()
    f.close()
    ca = ssl.get_server_certificate((host, port), ssl_version=ssl.PROTOCOL_SSLv3|ssl.PROTOCOL_TLSv1)
    if not ca in calist:
        f = open('cacerts.txt', 'a')
        f.write(ca)
        f.close()
    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3|ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED, ca_certs="cacerts.txt")
    s.do_handshake()

And when i call do_handshake() i get this:

Traceback (most recent call last):
  File "SSL_test.py", line 84, in Requester
    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3|ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED, ca_certs="cacerts.txt")
  File "C:\Python26\lib\ssl.py", line 338, in wrap_socket
    suppress_ragged_eofs=suppress_ragged_eofs)
  File "C:\Python26\lib\ssl.py", line 120, in __init__
    self.do_handshake()
  File "C:\Python26\lib\ssl.py", line 279, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [Errno 1] _ssl.c:490: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

I've searched around for a while and tried for find something that would be close to what i do, but everyone points to either PyOpenSSL or Twisted and i'd prefer if i could stay out of those libraries, mainly because later on i'm planing on bringing this into a sharp production environment where i'm only allowed to use the built in libraries of Python2.6.

Any help would be greatful!

Newscast answered 21/9, 2011 at 9:3 Comment(3)
Note that i've also tried without SSLv3 since i know the server is running TLSv1 all the way, same result and exactly the same error message.Newscast
Is this a issue due to (perhaps) self signed certificates or? Because i'm trying this against google.se and also my bank nordea.se which, should have valid certificates?Newscast
Tried with cert_reqs=ssl.CERT_NONE and that worked so i'm assuming i'm on the right track. But then i'd have to manually check the certificate that the peer (in this case, the server) is sending me in the handshake?Newscast
M
10

The problem here is that you can't validate a certificate with itself (that is what you are trying to do) unless it is self-signed, and has a CA bit set. You should add a real CA certificate of the web site to the cacerts.txt file. Another alternative (something like "connect anyway" in a web browser) is to drop the cert_reqs to ssl.CERT_NONE after you get such exception, and understand that there could possibly be a man in the middle. This is not the ssl module issue, this is how SSL/X.509 work.

Mutineer answered 21/9, 2011 at 15:53 Comment(4)
Lets say i'm connecting to my Bank, and i need to be safe from MITM attacks, can this be done with ssl WITHOUT having any contact with the CA distributer, in this case, "VeriSign, Inc."? Can this be resolved in any way by me sending my CA name? used the openSSL verification tool and it gave me: "No client certificate CA names sent"..Newscast
I understand there are restrictions in how the SSL/X.509 protocol works, and i THINK that i still need to have a CA verification "sign" to approve the PEM that the server gives me (or at least that's how i understood the whole protocol). But i'm wondering if there's any way of approving the server anyways without loosing security :)Newscast
You should read about how MITM protection in SSL/X.509 work (wikipedia MITM article is a good start). Short answer: no, you can't do this with SSL without a CA certificate obtained in some other way.Mutineer
I already guessed it wasn't possible, just thought i'd make damn sure there wasn't a workaround of sorts :) Thank you!Newscast
V
1

If you are just learning, you can also use Anonymous Diffie-Hellman, that is a server doesn't have a certificate at all, and your client doesn't care to validate it.

Below is a simple (and insecure) test.

Test server, courtesy of openssl package:

openssl s_server  -nocert -cipher "ALL:aNULL:eNULL"

Test client in Python:

...
ssl.wrap_socket(..., ciphers="ALL:aNULL:eNULL")
...

--

If you want to play with certificates, openssl package can generate what you want, but it's a bit tricky to get it right. Good GUI tool is TinyCA, it's written in perl and uses openssl commands, but offers you a decent framework to create own CAs, sign own certificates, etc.

If you're in a hurry, just install apache, start it up, your distro (linux or wamp) will most likely create a self-signed certificate to get you started. Configure apache to the point where you can connect to https://localhost with a browser. Then use that server to connect to, I think you will get by if you add server's self-signed CA to your clients CA list/file.

Vomitory answered 3/12, 2013 at 10:2 Comment(1)
Custom ciphers are required here because openssl is secure by default, here I allow all possible ka/mac/enc combinations. A smaller subset could do the job, but DEFAULT won't work.Vomitory

© 2022 - 2024 — McMap. All rights reserved.