Skip to content

Instantly share code, notes, and snippets.

@zerolagtime
Created May 15, 2024 01:40
Show Gist options
  • Save zerolagtime/164c8899e04cdfee592a370ad446c15d to your computer and use it in GitHub Desktop.
Save zerolagtime/164c8899e04cdfee592a370ad446c15d to your computer and use it in GitHub Desktop.
Python to analyze a servers X.509 certificate chain - requires packages and libopenssl.do
Fetching certificate chain for: untrusted-root.badssl.com
0: Subject: <Name(C=US,ST=California,L=San Francisco,O=BadSSL,CN=*.badssl.com)>
0: Issuer: <Name(C=US,ST=California,L=San Francisco,O=BadSSL,CN=BadSSL Untrusted Root Certificate Authority)>
0: Serial Number: 16983658469221716870
0: Validity: From 2024-02-21 21:28:32+00:00 to 2026-02-20 21:28:32+00:00
{idx}: Extensions:
0.0: basicConstraints: <BasicConstraints(ca=False, path_length=None)>
0.1: subjectAltName: <SubjectAlternativeName(<GeneralNames([<DNSName(value='*.badssl.com')>, <DNSName(value='badssl.com')>])>)>
1: Subject: <Name(C=US,ST=California,L=San Francisco,O=BadSSL,CN=BadSSL Untrusted Root Certificate Authority)>
1: Issuer: <Name(C=US,ST=California,L=San Francisco,O=BadSSL,CN=BadSSL Untrusted Root Certificate Authority)>
1: Serial Number: 10926010850294966525
1: Validity: From 2016-07-07 06:31:35+00:00 to 2036-07-02 06:31:35+00:00
{idx}: Extensions:
1.0: subjectKeyIdentifier: <SubjectKeyIdentifier(digest=b'o\xc7\x83sI\xb5\xa7c\xffu\xdemn\xfe\xed\xfb\x97\xa3,\x00')>
1.1: authorityKeyIdentifier: <AuthorityKeyIdentifier(key_identifier=b'o\xc7\x83sI\xb5\xa7c\xffu\xdemn\xfe\xed\xfb\x97\xa3,\x00', authority_cert_issuer=[<DirectoryName(value=<Name(C=US,ST=California,L=San Francisco,O=BadSSL,CN=BadSSL Untrusted Root Certificate Authority)>)>], authority_cert_serial_number=10926010850294966525)>
1.2: basicConstraints: <BasicConstraints(ca=True, path_length=None)>
1.3: keyUsage: <KeyUsage(digital_signature=False, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, key_cert_sign=True, crl_sign=True, encipher_only=False, decipher_only=False)>
import socket
import sys
import OpenSSL
from OpenSSL import SSL
from cryptography import x509
from cryptography.hazmat.backends import default_backend
def get_certificate_chain(hostname, port=443):
# Create a context with SSL method
context = SSL.Context(SSL.SSLv23_METHOD)
# Create a socket and wrap it in an SSL connection
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection = SSL.Connection(context, sock)
connection.set_tlsext_host_name(hostname.encode())
connection.connect((hostname, port))
connection.do_handshake()
# Get the certificate chain
chain = connection.get_peer_cert_chain()
connection.close()
return chain
def parse_certificates(chain):
for idx,openssl_cert in enumerate(chain):
# Convert OpenSSL certificate to DER format
der_cert = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, openssl_cert)
# Load DER formatted certificate using cryptography
cert = x509.load_der_x509_certificate(der_cert, default_backend())
# Extract various details from the certificate
print(f"{idx}: Subject: {cert.subject}")
print(f"{idx}: Issuer: {cert.issuer}")
print(f"{idx}: Serial Number: {cert.serial_number}")
print(f"{idx}: Validity: From {cert.not_valid_before_utc} to {cert.not_valid_after_utc}")
print("{idx}: Extensions:")
for subidx, ext in enumerate(cert.extensions):
print(f"{idx}.{subidx}: {ext.oid._name if ext.oid._name else ext.oid.dotted_string}: {ext.value}")
print()
def main():
hostname = sys.argv[1] if len(sys.argv)>1 and sys.argv[1] \
else "example.com"
print(f"Fetching certificate chain for: {hostname}")
chain = get_certificate_chain(hostname)
parse_certificates(chain)
if __name__ == '__main__':
main()
cffi==1.16.0
cryptography==42.0.7
pycparser==2.22
pyOpenSSL==24.1.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment