A powerful, developer-friendly Python tool to analyze TLS/SSL certificates for any domain.
- β¨ Check TLS Certificate β¨
- π Table of Contents
- π Features
- π οΈ Installation
- βοΈ Usage
- π₯οΈ REST API Usage
- OCSP Status Explained
- π Web Interface
- π Security
- β¨ Shell Completion
- ποΈ Project Structure
- β FAQ
- π οΈ Troubleshooting
- π©βπ» Development
- π€ Contributing
- π License
- π¦ Release & Publish
- Comprehensive Analysis: Fetches leaf & intermediate certificates using Authority Information Access (AIA).
- Chain Validation: Validates the certificate chain against the system's default trust store.
- Profile Detection: Detects certificate profiles like TLS Server, Code Signing, S/MIME, etc., based on Key Usage and Extended Key Usage extensions.
- Revocation Checks:
- OCSP: Performs Online Certificate Status Protocol (OCSP) checks.
- CRL: Checks Certificate Revocation Lists (CRL).
- DNS CAA Check: Displays DNS Certification Authority Authorization (CAA) records for the domain.
- Certificate Transparency: Queries
crt.shfor Certificate Transparency logs. - Flexible Output: Human-readable (color-coded), JSON, or CSV formats.
- Web UI: Interactive browser-based analysis via a built-in Flask server.
- REST API: Programmatic access for seamless integration into other tools.
- Dockerized: Ready to use with zero local setup via Docker Hub or GHCR.
- IPv6 Ready: The web server listens on all network interfaces (IPv4 & IPv6).
uv installs CLI tools in isolated
environments, with fast resolution and caching. This is the recommended way
to install check-tls.
uv tool install check-tlsTo upgrade later:
uv tool upgrade check-tlspipx also installs CLI tools in isolated environments.
pipx install check-tlspip install check-tlsPull the latest image from Docker Hub or GHCR:
# From Docker Hub
docker pull obeoneorg/check-tls:latest
# Or from GHCR.io
docker pull ghcr.io/obeone/check-tls:latestYou can run the tool in either CLI mode or as a web server.
To analyze a domain, pass it as a command to the container:
docker run --rm obeoneorg/check-tls:latest example.comTo output to a file on your host machine, mount a volume:
# Create a reports directory first: mkdir -p reports
docker run --rm -v "$(pwd)/reports:/app/reports" \
obeoneorg/check-tls:latest example.com -j /app/reports/report.jsonTo run the interactive web UI, use the --server flag and map the port:
docker run --rm -p 8000:8000 obeoneorg/check-tls:latest --serverThe web interface will be available at http://localhost:8000. The server listens on all interfaces, so you can also access it via http://<your-ip>:8000.
Example: Command-line output for analyzing a domain (including OCSP status)
Analyze a single domain:
check-tls example.comAnalyze a domain with a specific port:
# The port in the URL overrides the default or --connect-port
check-tls https://example.net:9000Analyze multiple domains and output to a JSON file:
check-tls google.com https://github.com:443 -j report.jsonThe CLI provides human-readable output by default. Use -j for JSON and -c for CSV. When analyzing multiple domains, a progress indicator will be displayed.
Key Options:
-j, --json FILE: Output JSON to a file (use "-" for stdout).-c, --csv FILE: Output CSV to a file (use "-" for stdout).-P, --connect-port PORT: Port for TLS analysis (default: 443). Overridden by port in domain/URL.-m, --mode [simple|full]: Analysis mode.simplechecks the leaf certificate only;fullfetches intermediates (default).-l, --loglevel LEVEL: Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL).-k, --insecure: Allow self-signed or invalid certificates.-s, --server: Launch the web UI.-p, --port PORT: Web server port for the UI (default: 8000).--no-transparency: Skip certificate transparency check.--no-crl-check: Skip CRL check.--no-ocsp-check: Disable OCSP revocation check.--no-caa-check: Disable DNS CAA check.
To launch the interactive web interface, use the --server flag:
check-tls --serverThen, open http://localhost:8000 in your browser. The server listens on all network interfaces (IPv4 & IPv6).
The tool provides a REST API for programmatic analysis. When launched with --server, the API is available.
- Endpoint:
/api/analyze - Method:
POST - Content-Type:
application/json
Request Body:
domains(array of strings, required): List of domains to analyze (e.g.,["example.com", "google.com:443"]).connect_port(integer, optional): Default port to connect to if not specified in the domain string. Defaults to 443.insecure(boolean, optional): Allow insecure (self-signed) certificates.no_transparency(boolean, optional): Skip certificate transparency check.no_crl_check(boolean, optional): Disable CRL check.no_ocsp_check(boolean,optional): Disable OCSP check.no_caa_check(boolean, optional): Disable CAA check.
curl -X POST http://localhost:8000/api/analyze \
-H "Content-Type: application/json" \
-d '{"domains": ["example.com", "google.com"], "insecure": true, "no_transparency": true}'[
{
"domain": "example.com:443",
"status": "completed",
"analysis_timestamp": "2025-04-26T08:30:00+00:00",
"connection_health": { ... },
"validation": { ... },
"certificates": [ ... ],
"crl_check": { ... },
"transparency": { ... },
"ocsp_check": { ... },
"caa_check": { ... }
}
]The tool provides the following OCSP statuses for the leaf certificate:
good: The certificate is valid according to its OCSP responder.revoked: The certificate has been revoked.unknown: The OCSP responder does not have status information for the certificate.error: An error occurred during the OCSP check (e.g., network issue, responder unavailable).no_ocsp_url: The certificate does not contain an OCSP URI.skipped: The OCSP check was disabled or not applicable.
Example: HTML-based interactive certificate analysis (including OCSP status)
- User-friendly web UI for interactive analysis.
- Supports all CLI options via the browser.
- Great for demos, teams, and non-CLI users!
- Includes a light/dark theme toggle.
Starting from version 1.8.0, check-tls includes built-in protection against Server-Side Request Forgery (SSRF) attacks. By default, the tool blocks connections to private and internal IP addresses to prevent malicious users from:
- Scanning internal network ports
- Accessing internal services
- Enumerating private infrastructure
Blocked IP Ranges:
- Private networks:
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 - Loopback:
127.0.0.0/8 - Link-local:
169.254.0.0/16 - And other reserved ranges (see
SECURITY.mdfor complete list)
For legitimate internal network analysis (e.g., in development or private infrastructure), you can disable SSRF protection using the ALLOW_INTERNAL_IPS environment variable:
# Allow analysis of internal IPs
export ALLOW_INTERNAL_IPS=true
check-tls 192.168.1.1
# Or inline for a single command
ALLOW_INTERNAL_IPS=true check-tls 10.0.0.50:8443
# For the web server
ALLOW_INTERNAL_IPS=true check-tls --server- Never set
ALLOW_INTERNAL_IPS=truein production environments - Only use this in trusted, isolated development/testing environments
- See
SECURITY.mdfor detailed security documentation and best practices
check-tls supports shell completion for bash, zsh, and fish. To enable it, add the appropriate command to your shell's configuration file (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish).
Bash:
eval "$(check-tls --print-completion bash)"Zsh:
eval "$(check-tls --print-completion zsh)"Fish:
check-tls --print-completion fish | sourceThe project follows the standard src layout for packaging.
check-tls/
βββ src/
β βββ check_tls/
β βββ __init__.py
β βββ main.py # CLI entry point
β βββ tls_checker.py # Core analysis logic
β βββ web_server.py # Flask web server and API
β βββ static/ # CSS/JS for web UI
β βββ templates/ # HTML templates for web UI
β βββ utils/ # Utility modules
β βββ __init__.py
β βββ cert_utils.py
β βββ crl_utils.py
β βββ crtsh_utils.py
β βββ dns_utils.py
β βββ ocsp_utils.py
βββ pyproject.toml # Project metadata and dependencies
βββ Dockerfile
βββ LICENSE
βββ README.md
Q: What's the difference between --port and --connect-port?
A: --port (or -p) specifies the port for the web server UI (--server mode). --connect-port (or -P) specifies the default port for the TLS connection to the target domain.
Q: What does "No CDP" or "No OCSP URL" mean?
A: This means the certificate does not contain a URL for its Certificate Revocation List (CRL) or an OCSP responder. This is common and not necessarily an error, but it prevents the tool from performing that specific revocation check.
Q: How do I analyze a server that uses a self-signed certificate?
A: Use the -k or --insecure flag. This tells the tool to connect without validating the certificate against a trusted authority, which is necessary for self-signed certs.
Q: Can I use this tool without Python installed?
A: Yes! The Docker image provides a self-contained environment with all dependencies. See the "With Docker" section for instructions.
Q: How do I get JSON or CSV output?
A: Use -j file.json or -c file.csv. Use - as the filename to print to standard output.
Q: Can I analyze internal/private IP addresses?
A: By default, check-tls blocks connections to private IP ranges (192.168.x.x, 10.x.x.x, etc.) for security reasons. To analyze internal hosts in development/testing environments, use: ALLOW_INTERNAL_IPS=true check-tls 192.168.1.1. Never use this in production! See the Security section for more details.
Q: Why am I getting "Blocked connection to private/internal IP" errors?
A: This is the built-in SSRF protection. If you need to analyze internal hosts (e.g., in a development environment), use the ALLOW_INTERNAL_IPS=true environment variable. See the Security section for details and warnings.
Problem: ssl.SSLCertVerificationError
- Cause: The certificate chain could not be validated against your system's trust store. This is expected for self-signed certificates or if an intermediate certificate is missing.
- Solution: If you trust the server, use the
-kor--insecureflag to bypass validation. For production systems, this error indicates a misconfiguration that should be fixed.
Problem: Connection Errors (Connection refused, timed out, gaierror)
- Cause: These are network-level issues.
Connection refused: The server is not listening on the specified port.timed out: The server is unreachable, or a firewall is blocking the connection.gaierrororName or service not known: The domain name could not be resolved by DNS.
- Solution: Verify the domain name and port. Check for firewall rules and ensure the server is running and accessible from your location.
Problem: ModuleNotFoundError or import errors.
- Solution: Ensure the package was installed correctly (e.g.,
pip install .). When running from source, usepython -m check_tls.main ....
Problem: Shell completion isn't working.
- Solution: Ensure you have sourced the completion script in your shell's configuration file (
.bashrc,.zshrc, etc.) and have restarted your shell. For Fish, the completion file must be placed in the correct directory.
Problem: Docker container exits immediately.
- Cause: You need to provide a command to the container.
- Solution: Specify a domain to analyze or a flag like
--server. For example:docker run --rm obeoneorg/check-tls:latest example.com.
- All source code is located in
src/check_tls/. - Imports should be relative to the package, e.g.,
from check_tls.utils import .... - For development, use an editable install:
pip install -e .. This allows you to test changes without reinstalling. - To run the application from source, use
python -m check_tls.main [OPTIONS]. - Run tests and linting before submitting a pull request.
Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
MIT License Β© GrΓ©goire Compagnon (obeone)
To publish a new version to PyPI, create a new release on GitHub. The GitHub Actions workflow will build and publish the package automatically if the release tag matches the version in pyproject.toml.
See .github/workflows/publish-to-pypi.yaml for details.