After the Heartbleed vulnerability forced widespread certificate reissuance, manually checking each server's SSL certificate through browser interfaces becomes tedious and unreliable. We need an automated way to:
- Fetch certificate serial numbers
- Verify installation status
- Check for proper renewal
The most robust solution uses OpenSSL's s_client command with these key parameters:
echo "" | openssl s_client -showcerts -status -verify 0 \
-connect example.com:443 2>&1 | \
grep -E "Verify return|subject=/serial"
This one-liner provides:
- Certificate validation (-verify 0)
- Clean output through grep filtering
- Forced termination (echo "")
curl with Certificate Inspection
curl -vI --ssl-reqd https://example.com \
| grep -E "SSL connection|certificate"
nmap for Bulk Scanning
nmap --script ssl-cert -p 443 server1.example.com server2.example.com
For production environments, consider this bash script that checks multiple domains:
#!/bin/bash
domains=("example.com" "api.example.com" "staging.example.com")
for domain in "${domains[@]}"; do
echo "Checking $domain..."
echo | openssl s_client -connect $domain:443 2>&1 | \
openssl x509 -noout -dates -serial
done
For ongoing monitoring, tools like certspotter or Facebook's certificate transparency monitoring can alert you about new certificates issued for your domains.
After critical vulnerabilities like Heartbleed surface, system administrators face the tedious task of reissuing and verifying SSL certificates across multiple servers. Manual verification through browser interfaces becomes impractical at scale. Here's why command line tools are essential:
- Batch processing for multiple domains/servers
- Integration with monitoring systems
- Historical tracking of certificate changes
- Automated expiration alerts
The most reliable tool for certificate inspection is OpenSSL, available on virtually all Unix-like systems. Here's an enhanced version of the basic certificate fetching command:
#!/bin/bash
DOMAIN="example.com"
PORT=443
echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:$PORT 2>&1 | \
openssl x509 -noout -serial -subject -dates -issuer
This script outputs:
- Certificate serial number
- Subject details
- Validity period
- Issuer information
For complete chain verification, add these OpenSSL options:
openssl s_client -showcerts -verify 5 -connect $DOMAIN:$PORT < /dev/null
Key parameters:
-showcerts
: Displays entire chain-verify 5
: Sets chain verification depth-CAfile
: Specify custom CA bundle
For large-scale environments, consider these specialized tools:
1. SSLScan:
sslscan --show-certificate example.com
2. TestSSL.sh:
testssl.sh --csvfile report.csv example.com
3. Python Implementation:
import ssl
import socket
context = ssl.create_default_context()
with socket.create_connection(("example.com", 443)) as sock:
with context.wrap_socket(sock, server_hostname="example.com") as ssock:
cert = ssock.getpeercert()
print(cert['serialNumber'])
This Bash function checks expiration dates:
check_cert_expiry() {
local domain=$1
local port=${2:-443}
local expiry_date=$(echo | openssl s_client -servername $domain -connect $domain:$port 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
local remaining_days=$(( ($(date -d "$expiry_date" +%s) - $(date +%s)) / 86400 ))
echo "$domain: $remaining_days days remaining"
}
For non-standard setups:
- SNI certificates: Use
-servername
parameter - Self-signed certs: Add
-verify_return_error
- SMTP/IMAP: Adjust port numbers accordingly
- Client certificates: Use
-cert
and-key
options