1

I am trying to create a socket connection using python.

Here is my python code...

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.settimeout(config['timeout'])
self.socket.connect((config['host'], config['port']))

self.ssl = ssl.wrap_socket(
    self.socket,
    certfile=config['certificate'],
    keyfile=config['key']
)

It didn't work as remote server's certificate seems to be self-signed or missing from trust store. I am new to python and could not figure out how to disable verify_peer in python so connection could work.

I have working code in php...

$context = stream_context_create([
    'ssl' => [
        'verify_peer' => false,
        'local_cert' => $config['certificate'],
        'local_pk' => $config['key']
    ]
]);

$socket = stream_socket_client(
    'ssl://secure.test.com:700',
    $errno, $errstr, $config['timeout'],
    STREAM_CLIENT_CONNECT, $context
);

Setting 'verify_peer' => false helps to establish the connection. How can i do something like that in python?

openssl debug

openssl s_client -connect secure.test.com:700

verify error:num=20:unable to get local issuer certificate
verify return:1

verify error:num=21:unable to verify the first certificate
verify return:1

Please help and suggest. Thanks

seoppc
  • 2,766
  • 7
  • 44
  • 76
  • *"Setting `verify_peer => false` helps to establish the connection. How can i do something like that in python?"* - Very bad idea; see [The most dangerous code in the world: validating SSL certificates in non-browser software](http://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html). – jww Jul 14 '17 at 19:08
  • *"It didn't work as remote server's certificate seems to be self-signed or missing from trust store..."* - Which is it? The use case affects the answer. Please post the URL you are using to connect to the server, and post the output of `openssl s_client -connect : -tls1 -servername | openssl x509 -text -noout`. Do so by adding it to your question by clicking *Edit* (and don't post it as a comment). Otherwise, we can't reproduce it and there's not enough information to help troubleshoot it. – jww Jul 14 '17 at 19:11
  • @jww Thanks for your help. I've edited the question with more details. I am getting this error: `verify error:num=20:unable to get local issuer certificate` already tried to re-acquire the current certificate via a Linux command `openssl s_client -connect secure.test.com:700:` – seoppc Jul 14 '17 at 22:05
  • `secure.test.com:700` times out for me. Port 700 appears to be unavailable from the outside world, but port 443 is accessible and has a server on it. The Issuer's CommonName is `CN=Network Solutions OV Server CA 2`. You need to install [Network Solution's CA Root](http://www.networksolutions.com/support/where-can-i-locate-the-network-solutions-nsprotect-root-and-intermediate-certificate-files/) in your local trust store (the one Python uses). You won't need `verify_peer => false` because the path from the server to the CA will validate. – jww Jul 14 '17 at 22:11
  • @jww How to import ca root in local trust store so python can use it. I am new to python. Sorry. – seoppc Jul 14 '17 at 22:21
  • See [18.2. ssl — TLS/SSL wrapper for socket objects](https://docs.python.org/3/library/ssl.html) in the manual. – jww Jul 14 '17 at 22:32
  • @jww can you please suggest, how to import ca root in local trust store so python can use it. This would solve the issue. Thanks once again for your help. – seoppc Jul 14 '17 at 22:35

1 Answers1

0

Disabling certificate validation can simply be done by adding cert_reqs = ssl.CERT_NONE. But, just disabling certificate validation is a very bad idea since you know open to man-in-the-middle attacks.

Therefore you should check that the certificate is the expected one. With self-signed certificates (and others too) you can check for example that the received certificate matches the expected certificate fingerprint, like in the following code:

import socket
import ssl
import hashlib

dst = ('www.paypal.com',443)
fp_expected = '0722d46c216327bab8075f5db57ebed64d80e6699204c249c3f6ea9cc281c15b'

# connect to the target with TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(dst)

# upgrade the socket to SSL without checking the certificate
s = ssl.wrap_socket(s,cert_reqs = ssl.CERT_NONE)

# get certificate, compute fingerprint and check against expected value
cert_bin = s.getpeercert(True)
fp = hashlib.sha256()
fp.update(cert_bin)
assert(fp.hexdigest() == fp_expected)
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Thanks for explanation. I am stuck with this error. `verify error:num=20:unable to get local issuer certificate` and `verify error:num=21:unable to verify the first certificate` when i run `openssl s_client -connect secure.test.com:700 -key client.key -cert client.crt` so i thought to disable certificate checking. – seoppc Jul 14 '17 at 21:52
  • @seoppc: the code above can be used to verify at least that the server certificate is the expected if it is self-signed or somehow broken. But it there should be proper certificate + chain then maybe you are doing it wrong from start: it could for example be that the server requires you to use SNI extension to get the right certificate and chain which a simple wrap_socket will not achieve. Note that I cannot test this with s_client since secure.test.com:700 is not accessible from my location, i.e. already the TCP connect fails. – Steffen Ullrich Jul 15 '17 at 05:04