Last active
April 4, 2025 11:37
-
-
Save recalde/6253986f2ae304dc3a8d19ad33a48139 to your computer and use it in GitHub Desktop.
Certificate Check
This file contains hidden or 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
import ssl | |
import socket | |
import requests | |
from urllib.parse import urljoin | |
from cryptography import x509 | |
from cryptography.hazmat.backends import default_backend | |
from bs4 import BeautifulSoup | |
import hashlib | |
def fetch_ssl_chain(domain, port=443): | |
certs = [] | |
context = ssl.create_default_context() | |
context.check_hostname = False | |
context.verify_mode = ssl.CERT_NONE # Accept self-signed certs | |
with socket.create_connection((domain, port)) as sock: | |
with context.wrap_socket(sock, server_hostname=domain) as ssock: | |
# Get the peer certificate in DER form | |
der_cert = ssock.getpeercert(binary_form=True) | |
pem_cert = ssl.DER_cert_to_PEM_cert(der_cert) | |
cert = x509.load_pem_x509_certificate(pem_cert.encode(), default_backend()) | |
certs.append(cert) | |
# Python 3.11+ can access full chain with get_verified_chain() | |
if hasattr(ssock, "get_verified_chain"): | |
try: | |
chain = ssock.get_verified_chain() | |
for chain_cert in chain: | |
der = chain_cert.public_bytes(encoding=ssl.Encoding.DER) | |
pem = ssl.DER_cert_to_PEM_cert(der) | |
xcert = x509.load_pem_x509_certificate(pem.encode(), default_backend()) | |
certs.append(xcert) | |
except Exception: | |
pass | |
return certs | |
def list_remote_cert_files(base_url): | |
response = requests.get(base_url) | |
soup = BeautifulSoup(response.text, "html.parser") | |
cert_files = [] | |
for link in soup.find_all("a"): | |
href = link.get("href") | |
if href and (href.endswith(".crt") or href.endswith(".pem")): | |
cert_files.append(urljoin(base_url, href)) | |
return cert_files | |
def load_remote_cert(cert_url): | |
response = requests.get(cert_url) | |
content = response.content | |
try: | |
return x509.load_pem_x509_certificate(content, default_backend()) | |
except Exception: | |
try: | |
return x509.load_der_x509_certificate(content, default_backend()) | |
except Exception as e: | |
print(f"Failed to parse cert from {cert_url}: {e}") | |
return None | |
def cert_fingerprint(cert): | |
return cert.fingerprint(hashlib.sha256()) | |
def main(): | |
domain = "example.com" # <-- your target domain | |
cert_dir_url = "http://example.com/certs/" # <-- your cert directory URL | |
print(f"Fetching SSL certificate chain for {domain}...") | |
domain_certs = fetch_ssl_chain(domain) | |
domain_fingerprints = {cert_fingerprint(c) for c in domain_certs} | |
print(f"\nChecking remote certs at {cert_dir_url}...\n") | |
cert_files = list_remote_cert_files(cert_dir_url) | |
for cert_url in cert_files: | |
cert = load_remote_cert(cert_url) | |
if cert is None: | |
continue | |
remote_fp = cert_fingerprint(cert) | |
match = remote_fp in domain_fingerprints | |
print(f"{cert_url} => Match: {match}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment