Table of Contents
- About
- Why tlsctl?
- Installation
- Quick start
- Basic usage
- Advanced usage
- Output formats
- Exit codes
- Status indicators
- Quiet mode
- Disabling color
- Revocation checking
- Certificate fields
- Testing with badssl.com
- Shell completion
- License
About
tlsctl is a fast, zero-config command-line tool for inspecting TLS certificates from remote endpoints or local PEM files. Get instant visibility into certificate chains, expiry status, revocation state, and more — all from your terminal.
$ tlsctl client github.com
github.com (secure, expires in 52 days) ✓
Subject: CN=github.com
Issuer: CN=Sectigo Public Server Authentication CA DV E36,O=Sectigo Limited,C=GB
Validity: 2026-01-06 → 2026-04-05
SANs: github.com, www.github.com
Chain: github.com → Sectigo Public Server Authentication CA DV E36 → Sectigo Public Server Authentication Root E46 (3 certificates)
Why tlsctl?
- Instant insights — One command shows certificate status, chain, SANs, and expiry at a glance
- Multiple output formats — Human-readable, JSON, YAML, verbose text, or raw PEM
- Revocation checking — Built-in CRL and OCSP support to detect revoked certificates
- PEM file parsing — Inspect local certificate files with the same rich output
- Custom CA support — Validate against private CAs with
--cacert - STARTTLS — Upgrade plaintext connections for SMTP, IMAP, POP3, and LDAP with
--starttls - SNI override — Set a custom server name with
--servernamefor IP-based targets with virtual hosts - Proxy aware — Connect through HTTP proxies with
--proxyor environment variables - Cross-platform — Pre-built binaries for Linux, macOS, and Windows (amd64 & arm64)
- Lightweight — Single static binary, no runtime dependencies
Installation
Pre-built binaries (recommended)
Download the latest release for your platform from the GitHub Releases page.
| Platform | Architecture | Archive |
|---|---|---|
| Linux | amd64 | tlsctl_1.0.0_linux_amd64.tar.gz |
| Linux | arm64 | tlsctl_1.0.0_linux_arm64.tar.gz |
| macOS | amd64 | tlsctl_1.0.0_darwin_amd64.tar.gz |
| macOS | arm64 | tlsctl_1.0.0_darwin_arm64.tar.gz |
| Windows | amd64 | tlsctl_1.0.0_windows_amd64.zip |
| Windows | arm64 | tlsctl_1.0.0_windows_arm64.zip |
# Example: install on Linux amd64 curl -sL https://github.com/catay/tlsctl/releases/latest/download/tlsctl_1.0.0_linux_amd64.tar.gz | tar xz sudo mv tlsctl /usr/local/bin/
Build from source
Requires Go 1.25 or later.
git clone https://github.com/catay/tlsctl.git cd tlsctl make build # or: go build -o tlsctl .
Docker
# Build the image docker build -t tlsctl . # Run docker run --rm tlsctl client github.com # Inspect a local PEM file (mount it into the container) docker run --rm -v /path/to/cert.pem:/cert.pem:ro tlsctl pem /cert.pem
Quick start
# Inspect any TLS endpoint (port 443 is the default) tlsctl client example.com # Inspect multiple endpoints from a file (one per line) tlsctl client --file hosts.txt # Probe supported TLS versions tlsctl client --tls-versions example.com # Use a custom port tlsctl client example.com:8443 # Inspect a local PEM file tlsctl pem cert.pem
Basic usage
Inspecting valid certificates
$ tlsctl client badssl.com
*.badssl.com (secure, expires in 66 days) ✓
Subject: CN=*.badssl.com
Issuer: CN=R13,O=Let's Encrypt,C=US
Validity: 2026-01-20 → 2026-04-20
SANs: *.badssl.com, badssl.com
Chain: *.badssl.com → R13 (2 certificates)
Detecting expired certificates
$ tlsctl client expired.badssl.com
*.badssl.com (insecure, certificate expired, expires in -3958 days) ✗
Subject: CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard
Issuer: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
Validity: 2015-04-09 → 2015-04-12
SANs: *.badssl.com, badssl.com
Chain: *.badssl.com → COMODO RSA Domain Validation Secure Server CA → COMODO RSA Certification Authority (3 certificates)
Detecting hostname mismatches
$ tlsctl client wrong.host.badssl.com
*.badssl.com (insecure, hostname mismatch, expires in 66 days) ✗
Subject: CN=*.badssl.com
Issuer: CN=R13,O=Let's Encrypt,C=US
Validity: 2026-01-20 → 2026-04-20
SANs: *.badssl.com, badssl.com
Chain: *.badssl.com → R13 (2 certificates)
Detecting self-signed certificates
$ tlsctl client self-signed.badssl.com
*.badssl.com (insecure, unknown authority, expires in 727 days) ✗
Subject: CN=*.badssl.com,O=BadSSL,L=San Francisco,ST=California,C=US
Issuer: CN=*.badssl.com,O=BadSSL,L=San Francisco,ST=California,C=US
Validity: 2026-02-10 → 2028-02-10
SANs: *.badssl.com, badssl.com
Detecting untrusted root CAs
$ tlsctl client untrusted-root.badssl.com
*.badssl.com (insecure, unknown authority, expires in 727 days) ✗
Subject: CN=*.badssl.com,O=BadSSL,L=San Francisco,ST=California,C=US
Issuer: CN=BadSSL Untrusted Root Certificate Authority,O=BadSSL,L=San Francisco,ST=California,C=US
Validity: 2026-02-10 → 2028-02-10
SANs: *.badssl.com, badssl.com
Chain: *.badssl.com → BadSSL Untrusted Root Certificate Authority (2 certificates)
Detecting incomplete certificate chains
$ tlsctl client incomplete-chain.badssl.com
*.badssl.com (insecure, unknown authority, expires in 66 days) ✗
Subject: CN=*.badssl.com
Issuer: CN=R13,O=Let's Encrypt,C=US
Validity: 2026-01-20 → 2026-04-20
SANs: *.badssl.com, badssl.com
Revocation checking with CRL
$ tlsctl client --revocation crl revoked.badssl.com
revoked.badssl.com (secure, expires in 52 days) ✓
Subject: CN=revoked.badssl.com
Issuer: CN=E7,O=Let's Encrypt,C=US
Validity: 2026-01-06 → 2026-04-06
SANs: revoked.badssl.com
Revocation: REVOKED (CRL)
Chain: revoked.badssl.com → E7 (2 certificates)
Revocation checking with OCSP
$ tlsctl client --revocation ocsp google.com
*.google.com (secure, expires in 59 days) ✓
Subject: CN=*.google.com
Issuer: CN=WR2,O=Google Trust Services,C=US
Validity: 2026-01-19 → 2026-04-13
SANs: *.google.com, *.appengine.google.com, *.bdn.dev, *.origin-test.bdn.dev, *.cloud.google.com (+132 more)
Revocation: not revoked (OCSP)
Chain: *.google.com → WR2 → GTS Root R1 (3 certificates)
Verbose text output
Use -o text for the full certificate details:
$ tlsctl client -o text badssl.com
[LEAF]
Version: 3
Serial Number: 06:17:1e:8f:ca:26:0a:2a:33:19:4f:1b:e5:a7:75:e1:c5:ed
Signature Algorithm: SHA256-RSA
Issuer: CN=R13,O=Let's Encrypt,C=US
Subject: CN=*.badssl.com
Not Before: 2026-01-20T20:02:51Z
Not After: 2026-04-20T20:02:50Z
Public Key Algorithm: RSA
Key Usage: Digital Signature, Key Encipherment
Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication
Basic Constraints: CA:FALSE
Subject Key ID: 2F:70:81:3B:C8:46:E1:26:35:CD:23:DB:C7:65:DA:30:CE:90:E7:44
Authority Key ID: E7:AB:9F:0F:2C:33:A0:53:D3:5E:4F:78:C8:B2:84:0E:3B:D6:92:33
Subject Alt Names: *.badssl.com, badssl.com
CA Issuers: http://r13.i.lencr.org/
CRL Distribution: http://r13.c.lencr.org/110.crl
[INTERMEDIATE]
Version: 3
Serial Number: 5a:00:f2:12:d8:d4:b4:80:f3:92:41:57:ea:29:83:05
Signature Algorithm: SHA256-RSA
Issuer: CN=ISRG Root X1,O=Internet Security Research Group,C=US
Subject: CN=R13,O=Let's Encrypt,C=US
Not Before: 2024-03-13T00:00:00Z
Not After: 2027-03-12T23:59:59Z
Public Key Algorithm: RSA
Key Usage: Digital Signature, Certificate Sign, CRL Sign
Extended Key Usage: TLS Web Client Authentication, TLS Web Server Authentication
Basic Constraints: CA:TRUE, pathlen:0
Subject Key ID: E7:AB:9F:0F:2C:33:A0:53:D3:5E:4F:78:C8:B2:84:0E:3B:D6:92:33
Authority Key ID: 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E
CA Issuers: http://x1.i.lencr.org/
CRL Distribution: http://x1.c.lencr.org/
JSON output
Use -o json for machine-readable structured output:
$ tlsctl client -o json badssl.com
{
"certificates": [
{
"type": "leaf",
"version": 3,
"serial_number": "06:17:1e:8f:ca:26:0a:2a:33:19:4f:1b:e5:a7:75:e1:c5:ed",
"signature_algorithm": "SHA256-RSA",
"issuer": "CN=R13,O=Let's Encrypt,C=US",
"subject": "CN=*.badssl.com",
"common_name": "*.badssl.com",
"not_before": "2026-01-20T20:02:51Z",
"not_after": "2026-04-20T20:02:50Z",
"public_key_algorithm": "RSA",
"key_usage": ["Digital Signature", "Key Encipherment"],
"extended_key_usage": ["TLS Web Server Authentication", "TLS Web Client Authentication"],
"subject_alternative_names": ["*.badssl.com", "badssl.com"],
"fingerprint": {
"sha1": "71:03:e9:e6:7c:f1:0e:e0:a7:29:28:fe:85:49:a6:4f:e5:66:e0:48",
"sha256": "b4:5a:53:24:32:d9:8f:62:b6:ea:f1:47:32:06:10:f1:..."
}
}
],
"verified": true
}YAML output
Use -o yaml for YAML-formatted output:
$ tlsctl client -o yaml badssl.com
certificates: - type: leaf version: 3 serial_number: 06:17:1e:8f:ca:26:0a:2a:33:19:4f:1b:e5:a7:75:e1:c5:ed signature_algorithm: SHA256-RSA issuer: CN=R13,O=Let's Encrypt,C=US subject: CN=*.badssl.com common_name: '*.badssl.com' not_before: "2026-01-20T20:02:51Z" not_after: "2026-04-20T20:02:50Z" public_key_algorithm: RSA key_usage: - Digital Signature - Key Encipherment subject_alternative_names: - '*.badssl.com' - badssl.com verified: true
Raw PEM output
Use -o raw to extract the PEM-encoded certificates:
# Save the certificate chain to a file tlsctl client -o raw badssl.com > chain.pem # Pipe to openssl for further inspection tlsctl client -o raw badssl.com | openssl x509 -noout -text
Skip certificate verification
Use -k or --insecure to skip TLS certificate verification entirely:
tlsctl client -k self-signed.example.com tlsctl client --insecure internal.example.com
Custom CA certificate
Use --cacert to validate certificates against a private CA:
tlsctl client --cacert /path/to/internal-ca.pem internal.example.com tlsctl pem --cacert /path/to/ca.pem server-cert.pem
Proxy support
Connect through an HTTP proxy with --proxy (or -x):
tlsctl client --proxy http://proxy.corp.example.com:8080 example.com tlsctl client -x http://proxy:3128 example.com
The --proxy flag falls back to HTTPS_PROXY / HTTP_PROXY environment variables if not set.
SNI override
Use --servername to override the TLS Server Name Indication (SNI) value. This is useful when connecting to an IP address that hosts multiple virtual hosts:
tlsctl client --servername example.com 93.184.216.34:443
STARTTLS support
Use --starttls to negotiate a plaintext-to-TLS upgrade before inspecting the certificate. Supported protocols: smtp, imap, pop3, ldap.
When --starttls is used without an explicit port, the default port for the protocol is used automatically:
| Protocol | Default port |
|---|---|
smtp |
587 |
imap |
143 |
pop3 |
110 |
ldap |
389 |
# SMTP STARTTLS (connects to port 587 by default) tlsctl client --starttls smtp mail.example.com # SMTP on a custom port tlsctl client --starttls smtp mail.example.com:25 # IMAP STARTTLS tlsctl client --starttls imap mail.example.com # POP3 STARTTLS tlsctl client --starttls pop3 mail.example.com # LDAP STARTTLS tlsctl client --starttls ldap ldap.example.com
Parsing PEM files
# Parse a single certificate tlsctl pem cert.pem # Parse a certificate chain (multiple certs in one file) tlsctl pem chain.pem # Verbose output tlsctl pem -o text cert.pem # JSON output tlsctl pem -o json cert.pem # YAML output tlsctl pem -o yaml cert.pem # CRL revocation check on a PEM file tlsctl pem --revocation crl cert.pem
Advanced usage
The JSON output (-o json) pairs well with jq for extracting specific fields:
# Get the SHA-256 fingerprint of the leaf certificate tlsctl client -o json example.com | jq -r '.certificates[] | select(.type == "leaf") | .fingerprint.sha256' # List all Subject Alternative Names (SANs) tlsctl client -o json example.com | jq -r '.certificates[] | select(.type == "leaf") | .subject_alternative_names[]' # Show expiry date for each certificate in the chain tlsctl client -o json example.com | jq -r '.certificates[] | "\(.type): \(.common_name) expires \(.not_after)"' # Check if the certificate is verified tlsctl client -o json example.com | jq '.verified' # Extract the issuer and subject of the leaf certificate tlsctl client -o json example.com | jq '.certificates[] | select(.type == "leaf") | {subject, issuer}' # Get serial numbers of all certificates in the chain tlsctl client -o json example.com | jq -r '.certificates[] | "\(.type): \(.serial_number)"' # Count the number of SANs on the leaf certificate tlsctl client -o json example.com | jq '.certificates[] | select(.type == "leaf") | .subject_alternative_names | length' # Check multiple hosts and report their expiry dates tlsctl client -o json google.com github.com | jq -r '.[] | .certificates[] | select(.type == "leaf") | "\(.common_name) expires \(.not_after)"'
Output formats
| Format | Flag | Description |
|---|---|---|
| Default | (none) | Brief human-readable summary with color-coded status |
| Text | -o text |
Verbose output with all certificate fields |
| JSON | -o json |
Full structured JSON, ideal for scripting and automation |
| YAML | -o yaml |
Full structured YAML |
| Raw | -o raw |
PEM-encoded certificates |
Exit codes
0ok1runtime error (e.g., connection or parsing failure)2insecure or invalid (unverified, expired, or revoked)3revocation error (revocation check failed)4expiring soon (certificate expires within 30 days, configurable via--expiry-warning)
Status indicators
The default output uses color-coded status indicators:
| Indicator | Color | Meaning |
|---|---|---|
✓ secure |
Green | Certificate is valid and verified |
⚠ secure |
Yellow | Certificate is verified but expires within the warning threshold (default: 30 days, configurable via --expiry-warning) |
✗ insecure |
Red | Certificate verification failed (with reason) |
Quiet mode
Use -q or --quiet to suppress all informational and warning output. Only error messages are displayed. Exit codes are preserved, making this ideal for scripting and monitoring:
tlsctl client -q example.com echo $? # 0 = ok, 2 = insecure, 4 = expiring soon, etc.
Disabling color
Use --no-color to strip ANSI color codes from output, useful for piping to other tools or log ingestion:
tlsctl client --no-color example.com
tlsctl client --no-color example.com | tee cert.logRevocation checking
Both client and pem subcommands support certificate revocation checking via the --revocation flag.
| Flag | Default | Description |
|---|---|---|
--revocation |
off |
Revocation check mode: off, crl, or ocsp |
--revocation-timeout |
5s |
Timeout for revocation requests |
--revocation-soft-fail |
true |
Treat unreachable revocation endpoints as non-fatal |
# CRL-based revocation check tlsctl client --revocation crl example.com # OCSP-based revocation check tlsctl client --revocation ocsp example.com # Custom timeout for slow networks tlsctl client --revocation ocsp --revocation-timeout 10s example.com
Certificate fields
The tool extracts and displays the following X.509 certificate fields:
| Field | Description |
|---|---|
| Type | Leaf, intermediate, or root |
| Version | X.509 certificate version |
| Serial Number | Hex-formatted serial number |
| Signature Algorithm | e.g., SHA256-RSA, ECDSA-SHA256 |
| Issuer / Subject | Distinguished name (DN) |
| Validity | Not Before / Not After in RFC 3339 format |
| Public Key Algorithm | e.g., RSA, ECDSA |
| Key Usage | Digital Signature, Key Encipherment, Certificate Sign, etc. |
| Extended Key Usage | TLS Web Server Authentication, Client Authentication, etc. |
| Basic Constraints | CA flag and path length |
| Subject / Authority Key ID | Hex-formatted key identifiers |
| Subject Alt Names | DNS names |
| Email / IP Addresses | Additional identifiers |
| OCSP / CA Issuers / CRL | Revocation and issuer endpoints |
| Revocation Status | CRL or OCSP result (when --revocation is enabled) |
| Fingerprint | SHA-1 and SHA-256 fingerprints |
Testing with badssl.com
badssl.com provides various endpoints for testing TLS certificate scenarios. Here are some useful ones to try with tlsctl:
# Valid certificate tlsctl client badssl.com # Expired certificate tlsctl client expired.badssl.com # Wrong hostname tlsctl client wrong.host.badssl.com # Self-signed certificate tlsctl client self-signed.badssl.com # Untrusted root CA tlsctl client untrusted-root.badssl.com # Incomplete certificate chain tlsctl client incomplete-chain.badssl.com # Revoked certificate (check via CRL) tlsctl client --revocation crl revoked.badssl.com # ECC certificate tlsctl client ecc256.badssl.com
Shell completion
Generate autocompletion scripts for your shell:
# Bash tlsctl completion bash > /etc/bash_completion.d/tlsctl # Zsh tlsctl completion zsh > "${fpath[1]}/_tlsctl" # Fish tlsctl completion fish > ~/.config/fish/completions/tlsctl.fish
