analitics

Pages

Thursday, January 8, 2026

Python Qt6 : Check certificate of url.

Today, I will show this python script to check the certificate of url.
import sys
import ssl
import socket
from datetime import datetime

from cryptography import x509
from cryptography.hazmat.backends import default_backend

from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QLabel,
    QLineEdit, QPushButton, QTextEdit
)

def fetch_certificate_raw(hostname):
    """
    Connects to the server and retrieves the certificate in DER format.
    Also returns a validation status message.
    """

    # Create a default SSL context (validates certificates)
    context = ssl.create_default_context()

    try:
        # First attempt: strict validation
        with socket.create_connection((hostname, 443), timeout=5) as sock:
            with context.wrap_socket(sock, server_hostname=hostname) as ssock:
                der_cert = ssock.getpeercert(binary_form=True)
                return der_cert, "Certificate is VALID"

    except ssl.SSLError as e:
        # Certificate is invalid → try to retrieve it anyway
        try:
            unverified_context = ssl._create_unverified_context()
            with socket.create_connection((hostname, 443), timeout=5) as sock:
                with unverified_context.wrap_socket(sock, server_hostname=hostname) as ssock:
                    der_cert = ssock.getpeercert(binary_form=True)
                    return der_cert, f"Certificate is INVALID: {str(e)}"
        except Exception:
            return None, f"Could not retrieve certificate: {str(e)}"

    except Exception as e:
        return None, f"Connection error: {str(e)}"

def parse_certificate(der_cert):
    """
    Converts a DER-encoded certificate into a cryptography.x509 object.
    """
    return x509.load_der_x509_certificate(der_cert, default_backend())

class CertViewer(QWidget):
    """
    Main GUI window for the HTTPS certificate viewer.
    """
    def __init__(self):
        super().__init__()

        self.setWindowTitle("HTTPS Certificate Checker")
        self.setGeometry(200, 200, 700, 600)

        layout = QVBoxLayout()

        # Input label + text field
        layout.addWidget(QLabel("Enter URL (example: example.com):"))
        self.input = QLineEdit()
        layout.addWidget(self.input)

        # Button to trigger certificate check
        self.button = QPushButton("Check Certificate")
        self.button.clicked.connect(self.check_certificate)
        layout.addWidget(self.button)

        # Output text box
        self.output = QTextEdit()
        self.output.setReadOnly(True)
        layout.addWidget(self.output)

        self.setLayout(layout)

    def check_certificate(self):
        """
        Triggered when the user presses the button.
        Retrieves and displays certificate information.
        """

        hostname = self.input.text().strip()

        # Clean URL (remove http://, https://, and paths)
        for prefix in ("https://", "http://"):
            if hostname.startswith(prefix):
                hostname = hostname[len(prefix):]

        hostname = hostname.split("/")[0]

        # Fetch certificate
        der_cert, status = fetch_certificate_raw(hostname)

        if der_cert is None:
            self.output.setText(status)
            return

        # Parse certificate
        cert = parse_certificate(der_cert)

        # Build output text
        text = f"=== CERTIFICATE STATUS ===\n{status}\n\n"
        text += "=== CERTIFICATE DETAILS ===\n\n"

        text += f"Subject:\n{cert.subject}\n\n"
        text += f"Issuer:\n{cert.issuer}\n\n"
        text += f"Serial Number: {cert.serial_number}\n\n"
        text += f"Version: {cert.version}\n\n"
        text += f"Valid From: {cert.not_valid_before}\n"
        text += f"Valid To:   {cert.not_valid_after}\n\n"

        # Check expiration
        if cert.not_valid_after < datetime.utcnow():
            text += f"⚠ Certificate EXPIRED on: {cert.not_valid_after}\n\n"

        # Subject Alternative Names (SAN)
        try:
            san = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
            text += f"Subject Alternative Names:\n{san.value}\n\n"
        except Exception:
            text += "Subject Alternative Names: (none)\n\n"

        self.output.setText(text)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = CertViewer()
    viewer.show()
    sys.exit(app.exec())