Last active
October 10, 2023 13:20
-
-
Save rswift/2b40bda6955bb2a5aabc8f73b82fb5af to your computer and use it in GitHub Desktop.
Trivial script to explore only using built-in Python 3 modules to establish a connection to a host that issues certs signed by a CA that isn't well known...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Trivial script to explore only using built-in Python 3 modules to establish a connection to | |
# a host that issues certs signed by a CA that isn't well known... | |
# | |
# It does require that the root cert is available, so primarily an enterprise that has an | |
# internal or private CA and signs server certs with that... | |
# | |
import urllib.request | |
import ssl | |
import socket | |
# | |
# Google kindly provide a handy site for such testing | |
# | |
hostname = "untrusted-root.badssl.com" | |
port = 443 | |
method = "GET" | |
data = None | |
##headers = {"Content-Type": "text/html; charset=UTF-8"} | |
cert_on_filesystem = False | |
# | |
# Using the untrusted-root test host, grab the cert using openssl and then simply copy it in | |
# or use your favourite utility to make the string from the openssl output. to get the cert, use: | |
# | |
# openssl s_client -showcerts -servername untrusted-root.badssl.com -connect untrusted-root.badssl.com:443 | |
# | |
# and obviously make sure you take the correct cert in the chain, in this case the CN to use was | |
# | |
# CN=BadSSL Untrusted Root Certificate Authority | |
# | |
# also note that this cert may change (although it is valid until 2036), so check in case of errors | |
# | |
CA_ROOT_PEM = "-----BEGIN CERTIFICATE-----\n" \ | |
"MIIGfjCCBGagAwIBAgIJAJeg/PrX5Sj9MA0GCSqGSIb3DQEBCwUAMIGBMQswCQYD" \ | |
"VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j" \ | |
"aXNjbzEPMA0GA1UECgwGQmFkU1NMMTQwMgYDVQQDDCtCYWRTU0wgVW50cnVzdGVk" \ | |
"IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE2MDcwNzA2MzEzNVoXDTM2" \ | |
"MDcwMjA2MzEzNVowgYExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh" \ | |
"MRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wxNDAyBgNV" \ | |
"BAMMK0JhZFNTTCBVbnRydXN0ZWQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw" \ | |
"ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKQtPMhEH073gis/HISWAi" \ | |
"bOEpCtOsatA3JmeVbaWal8O/5ZO5GAn9dFVsGn0CXAHR6eUKYDAFJLa/3AhjBvWa" \ | |
"tnQLoXaYlCvBjodjLEaFi8ckcJHrAYG9qZqioRQ16Yr8wUTkbgZf+er/Z55zi1yn" \ | |
"CnhWth7kekvrwVDGP1rApeLqbhYCSLeZf5W/zsjLlvJni9OrU7U3a9msvz8mcCOX" \ | |
"fJX9e3VbkD/uonIbK2SvmAGMaOj/1k0dASkZtMws0Bk7m1pTQL+qXDM/h3BQZJa5" \ | |
"DwTcATaa/Qnk6YHbj/MaS5nzCSmR0Xmvs/3CulQYiZJ3kypns1KdqlGuwkfiCCgD" \ | |
"yWJy7NE9qdj6xxLdqzne2DCyuPrjFPS0mmYimpykgbPnirEPBF1LW3GJc9yfhVXE" \ | |
"Cc8OY8lWzxazDNNbeSRDpAGbBeGSQXGjAbliFJxwLyGzZ+cG+G8lc+zSvWjQu4Xp" \ | |
"GJ+dOREhQhl+9U8oyPX34gfKo63muSgo539hGylqgQyzj+SX8OgK1FXXb2LS1gxt" \ | |
"VIR5Qc4MmiEG2LKwPwfU8Yi+t5TYjGh8gaFv6NnksoX4hU42gP5KvjYggDpR+NSN" \ | |
"CGQSWHfZASAYDpxjrOo+rk4xnO+sbuuMk7gORsrl+jgRT8F2VqoR9Z3CEdQxcCjR" \ | |
"5FsfTymZCk3GfIbWKkaeLQIDAQABo4H2MIHzMB0GA1UdDgQWBBRvx4NzSbWnY/91" \ | |
"3m1u/u37l6MsADCBtgYDVR0jBIGuMIGrgBRvx4NzSbWnY/913m1u/u37l6MsAKGB" \ | |
"h6SBhDCBgTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV" \ | |
"BAcMDVNhbiBGcmFuY2lzY28xDzANBgNVBAoMBkJhZFNTTDE0MDIGA1UEAwwrQmFk" \ | |
"U1NMIFVudHJ1c3RlZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eYIJAJeg/PrX" \ | |
"5Sj9MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IC" \ | |
"AQBQU9U8+jTRT6H9AIFm6y50tXTg/ySxRNmeP1Ey9Zf4jUE6yr3Q8xBv9gTFLiY1" \ | |
"qW2qfkDSmXVdBkl/OU3+xb5QOG5hW7wVolWQyKREV5EvUZXZxoH7LVEMdkCsRJDK" \ | |
"wYEKnEErFls5WPXY3bOglBOQqAIiuLQ0f77a2HXULDdQTn5SueW/vrA4RJEKuWxU" \ | |
"iD9XPnVZ9tPtky2Du7wcL9qhgTddpS/NgAuLO4PXh2TQ0EMCll5reZ5AEr0NSLDF" \ | |
"c/koDv/EZqB7VYhcPzr1bhQgbv1dl9NZU0dWKIMkRE/T7vZ97I3aPZqIapC2ulrf" \ | |
"KrlqjXidwrGFg8xbiGYQHPx3tHPZxoM5WG2voI6G3s1/iD+B4V6lUEvivd3f6tq7" \ | |
"d1V/3q1sL5DNv7TvaKGsq8g5un0TAkqaewJQ5fXLigF/yYu5a24/GUD783MdAPFv" \ | |
"gWz8F81evOyRfpf9CAqIswMF+T6Dwv3aw5L9hSniMrblkg+ai0K22JfoBcGOzMtB" \ | |
"Ke/Ps2Za56dTRoY/a4r62hrcGxufXd0mTdPaJLw3sJeHYjLxVAYWQq4QKJQWDgTS" \ | |
"dAEWyN2WXaBFPx5c8KIW95Eu8ShWE00VVC3oA4emoZ2nrzBXLrUScifY6VaYYkkR" \ | |
"2O2tSqU8Ri3XRdgpNPDWp8ZL49KhYGYo3R/k98gnMHiY5g==\n" \ | |
"-----END CERTIFICATE-----" | |
try: | |
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) | |
ssl_context.verify_mode = ssl.CERT_REQUIRED | |
# https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_verify_locations | |
if cert_on_filesystem: | |
ssl_context.load_verify_locations(cafile="/tmp/pca.pem") | |
else: | |
ssl_context.load_verify_locations(cadata=CA_ROOT_PEM) | |
# https://docs.python.org/3/library/ssl.html#ssl.SSLContext.cert_store_stats | |
ca_stats = ssl_context.cert_store_stats() | |
if 'x509_ca' in ca_stats: | |
print("{} CA entr{} in use".format(ca_stats['x509_ca'], 'y' if ca_stats['x509_ca'] == 1 else 'ies')) | |
except Exception as ssl_error: | |
print(ssl_error) | |
import sys | |
sys.exit() | |
with socket.create_connection((hostname, port)) as sock: | |
try: | |
# https://docs.python.org/3/library/ssl.html#ssl.SSLContext.wrap_socket | |
with ssl_context.wrap_socket(sock, server_hostname=hostname) as secure_socket: | |
print("Secure connection to {} using {}".format(secure_socket.server_hostname, secure_socket.version())) | |
# https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert | |
peer_cert = secure_socket.getpeercert() | |
# not pretty, but i'm on a train, it's late and i can't be arsed putting much effort in - knock yourself out though... | |
common_name = "***UNKNOWN***" | |
for x in peer_cert['subject']: | |
if x[0][0] == "commonName": | |
common_name = x[0][1] | |
issuer = "***UNKNOWN***" | |
for x in peer_cert['issuer']: | |
if x[0][0] == "commonName": | |
issuer = x[0][1] | |
not_before = "***UNKNOWN***" | |
if 'notBefore' in peer_cert: | |
not_before = peer_cert['notBefore'] | |
not_after = "***UNKNOWN***" | |
if 'notAfter' in peer_cert: | |
not_after = peer_cert['notAfter'] | |
print("Their certificate was issued to \"{}\", is valid from {} till {} and was signed by \"{}\"".format(common_name, not_before, not_after, issuer)) | |
except ssl.SSLCertVerificationError as cert_error: | |
print("Got a cert error: {}".format(cert_error.verify_message)) | |
except Exception as ssl_error: | |
print(ssl_error) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment