Python

certist_example.py

#!/usr/bin/env python3

import hashlib
import socket
import ssl

import requests
from requests_toolbelt.adapters.fingerprint import FingerprintAdapter


def pin_via_sockets(domain):
    # find certificate's hash according to the public internet
    expected_cert = requests.get(f'https://api.cert.ist/{domain}').json()
    expected_hashcode = expected_cert.get('certificate').get('hashes').get('sha256')

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(100)
    context = ssl.create_default_context()
    with context.wrap_socket(sock, server_hostname=domain) as ssl_socket:
        ssl_socket.connect((domain, 443))
        cert_binary = ssl_socket.getpeercert(True)
    hashcode = hashlib.sha256(cert_binary).hexdigest()
    is_it = hashcode == expected_hashcode
    if not is_it:
        print(expected_cert)
        print("exp", expected_hashcode)
        print("act", hashcode)
    return is_it


def pin_via_requests_toolbelt(domain):
    # find certificate's hash according to the public internet
    expected_cert = requests.get(f'https://api.cert.ist/{domain}').json()
    expected_hashcode = expected_cert.get('certificate').get('hashes').get('sha256')[:-1]

    sess = requests.Session()
    # let mount a session adapter to validate the certificate during connection
    sess.mount(f'https://{domain}', FingerprintAdapter(expected_hashcode))
    try:
        # if sha256 hash of certificate received here doesn't match the one provided to
        # the FingerprintAdapter then this line will raise a `requests.exceptions.SSLError`
        reply = sess.get(f'https://{domain}')
        reply.raise_for_status()
        return True
    except:
        return False


print('api.cert.ist', pin_via_requests_toolbelt('api.cert.ist'))
print('cert.ist', pin_via_requests_toolbelt('cert.ist'))
print('example.com', pin_via_requests_toolbelt('example.com'))

print('api.cert.ist', pin_via_sockets('api.cert.ist'))
print('cert.ist', pin_via_sockets('cert.ist'))
print('example.com', pin_via_sockets('example.com'))

Output

## Assuming your traffic is not resigned the result will look like this
api.cert.ist True
cert.ist True
example.com True
api.cert.ist True
cert.ist True
example.com True