Bhargava
Bhargava

Reputation: 189

Verifying peer in SSL using python

I was trying to find out how I can go about verifying a self-signed certificate by a server in python. I could not find much data in google. I also want to make sure that the server url

Thanks in advance for any insights.

Upvotes: 9

Views: 8058

Answers (4)

rustyMagnet
rustyMagnet

Reputation: 4085

You asked "Verifying peer in SSL using python".

I tend to use a local "Trust Store" - a directory full or .crt, .pem, or .der files, To verify the Server is trustworthy based on that local directory of certificates:

#!/usr/bin/env python3
from socket import socket
import ssl

hostname = 'google.com'
port = 443
with socket() as sock:
    sock.setblocking(True)
    sock.connect((hostname, port))
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    context.verify_flags = 0x80000  # will verify if either the Root CA or Int CA is present for the server
    context.load_verify_locations(cafile=None,
                                  cadata=None,
                                  capath="ca_files/")
    with context.wrap_socket(sock=sock,
                             server_hostname=hostname,
                             do_handshake_on_connect=False) as ssl_sock:
        ssl_sock.do_handshake()
        print(hostname, ssl_sock.getpeername(), ssl_sock.version())
        print(ssl_sock)

As @abbott said - BEFORE you run that script - you need the symbolic links for capath to work. This is super simple if you have OpenSSL installed:

$ export CERTS=/path/to/ca_files
$ openssl/bin/c_rehash ${CERTS}

If you don't run c_rehash it won't work. For more info man c_rehash.

Upvotes: 1

abbot
abbot

Reputation: 27870

From the comments to my first reply I see that there is a general misunderstanding what does 'verify a certificate mean'. I will try to write a brief explanation here to eliminate some of the illusions.

Certificate verification is about checking a signature on the certificate metadata (i.e. subject, validity period, extensions and such) against some cryptographic signature.

If all you have for the validation is a self-signed certificate you cannot distinguish it from another self-signed certificate with exactly the same metadata, but the different key, unless you know the key certificate's key in advance. And don't forget that you establish all this verification procedure to remove the requirement to have this pre-shared knowledge. With regular certificate verification you cannot completely remove the requirement to have some pre-shared knowlege, which is a set of third-party certificates, also known as 'CA certificates'. Since this knowledge is pre-shared, those certificates may be self-signed, but remember that you have received information about validity of those certificates not from the verification process, but from some outer knowledge.

When you have a set of trusted 'CA certificates' distributed between peers, you can use those to sign other certificates and check signatures against that pre-shared knowledge of trusted CAs.

But if you have no additional knowledge about a self-signed certificate except the certificate itself you can make no assumptions about trust to this particular certificate, because it can be issued by some evil hacker as well as by you trustworthy server.

Please, acquire some knowledge about Man in the middle attack, Public key infrastructure and Public key cryptography in general before implementing any kind of certificate verification processes.

Please understand that blind verification of a self-signed certificate will not protect you even from a clever hacker in your own network, not even considering internet security in general.

Edit: question author clarified that he was actually looking for how to verify a verisign (or other CA) signature on a certificate using M2Crypto bindings. Here are two examples:

from M2Crypto import X509, SSL

# manual validation of a signature on a certificate using a given CA cert:
ca = X509.load_cert('/path/to/ca_cert.pem')
cert = X509.load_cert('certificate_to_validate.pem')
print "Verification results:", cert.verify(ca.get_pubkey())

# adding a given CA cert to the SSL Context for verification
ctx = SSL.Context()
# load a certificate from file
ctx.load_verify_locations(cafile='/path/to/ca_cert.pem') 
# or use all certificate in a CA directory
ctx.load_verify_locations(capath='/path/to/ca/dir') 
# or you can specify both options at the same time.

If you are going to use a directory with many CA certificates (which is often more convenient) you must rename each certificate to <hash>.0 where <hash> is the hash of the certificate subject (obtained with openssl x509 -noout -hash -in cert.pem).

Upvotes: 12

Denis Otkidach
Denis Otkidach

Reputation: 33210

I assume you use some OpenSSL binding. I see 2 ways to solve your problem.

  1. You can add your certificate to openssl directory (run openssl version -d to see it for your system). This will affect all programs using openssl on your machine.
  2. Load certificate and add it run-time (the code sketch below is for PyOpenSSL, but it should be similar for other bindings):

.

x509 = OpenSSL.crypto.load_certificate(...)
ctx = OpenSSL.SSL.Context(...)
store = ctx.get_cert_store()
store.add_cert(x509)
ctx.set_verify(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, ...)

Upvotes: 2

abbot
abbot

Reputation: 27870

It is impossible to verify a self-signed certificate because of its very nature: it is self-signed.

You have to sign a certificate by some other trusted third party's certificate to be able to verify anything, and after this you can add that third party's certificate to the list of your trusted CAs and then you will be able to verify certificates signed by that certificate/CA.

If you want recommendations about how to do this in Python, you should provide the name of the SSL library you are using, since there is a choice of SSL libraries for Python.

Upvotes: 0

Related Questions