|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +"""A simple Python program to show the use of the pyOpenSSL |
| 4 | +library. We connect to a HTTPS server and retrieve its home page. (Of |
| 5 | +course, for this specific task, pyCurl would be a better solution but |
| 6 | +the goal is to demonstrate pyOpenSSL.)""" |
| 7 | + |
| 8 | +PORT = 443 # Hardwired |
| 9 | +PATH = "/" # Hardwired |
| 10 | + |
| 11 | +# https://www.pyopenssl.org/ |
| 12 | +# https://pyopenssl.readthedocs.io/ |
| 13 | +import OpenSSL |
| 14 | + |
| 15 | +import socket |
| 16 | +import sys |
| 17 | + |
| 18 | +if len(sys.argv) != 2: |
| 19 | + raise Exception("Usage: %s hostname" % sys.argv[0]) |
| 20 | +host = sys.argv[1] |
| 21 | + |
| 22 | +addrinfo = socket.getaddrinfo(host, PORT, 0) |
| 23 | + |
| 24 | +# We should loop over the IP addresses instead of taking only the first one… |
| 25 | +sock = socket.socket(addrinfo[0][0], socket.SOCK_STREAM) |
| 26 | +addr = addrinfo[0][4] |
| 27 | +print("Connecting to %s ..." % str(addr)) |
| 28 | + |
| 29 | +context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) |
| 30 | + |
| 31 | +# Use the OS' default CAs |
| 32 | +context.set_default_verify_paths() |
| 33 | + |
| 34 | +# Ask for a certificate check. Warning, this does not check the host |
| 35 | +# name, just the path from the CA, the expiration, may be the CRLs… |
| 36 | +context.set_verify(OpenSSL.SSL.VERIFY_PEER | OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT | \ |
| 37 | + OpenSSL.SSL.VERIFY_CLIENT_ONCE, |
| 38 | + lambda conn, cert, errno, depth, preverify_ok: preverify_ok) |
| 39 | + |
| 40 | +session = OpenSSL.SSL.Connection(context, sock) |
| 41 | +session.set_tlsext_host_name(host.encode()) # Server Name Indication (SNI) |
| 42 | + |
| 43 | +# TCP |
| 44 | +session.connect((addr)) |
| 45 | + |
| 46 | +# TLS |
| 47 | +session.do_handshake() |
| 48 | +cert = session.get_peer_certificate() |
| 49 | +print("Connected, its certificate is for \"%s\", delivered by \"%s\"" % \ |
| 50 | + (cert.get_subject().commonName, |
| 51 | + cert.get_issuer().commonName)) |
| 52 | + |
| 53 | +# HTTP |
| 54 | +request = """GET %s HTTP/1.1 |
| 55 | +Host: %s |
| 56 | +Connection: close |
| 57 | +
|
| 58 | +""" % (PATH, host) |
| 59 | +session.write(request.replace("\n","\r\n")) |
| 60 | + |
| 61 | +# A real program must loop to read all the data |
| 62 | +data = session.read(4096) |
| 63 | +print("Got %i bytes, the first ones are: \"%s...\"" % (len(data), |
| 64 | + data[:256].decode())) |
| 65 | + |
| 66 | +session.close() |
| 67 | +sock.close() |
0 commit comments