A fast, memory-safe command-line tool for inspecting X.509 certificates. Read-only alternative to openssl x509 with JSON output and colored terminal display.
Warning: This code is experimental and not ready for production. It is mostly AI generated and has not had human review.
# Build
cargo build --release
# Generate a test certificate (or use any .pem/.der file you have)
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -out test.pem \
-days 365 -nodes -subj "/CN=example.com"
# Inspect it
target/release/xcert show test.pemExample output:
Certificate:
Version: 3 (0x2)
Serial: 10:00
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = California, O = Test PKI, CN = Test Intermediate CA
Validity:
Not Before: Feb 24 22:17:10 2026 GMT
Not After: Feb 24 22:17:10 2101 GMT
Subject: C = US, ST = California, L = San Francisco, O = Example Corp, CN = www.example.com
Public Key:
Algorithm: RSA (2048 bit)
Exponent: 65537 (0x10001)
Extensions:
Basic Constraints: CA=false
Key Usage: [critical] Digital Signature, Key Encipherment
Extended Key Usage: TLS Web Server Authentication
Subject Alternative Name:
DNS: www.example.com
DNS: example.com
Email: admin@example.com
Authority Information Access:
OCSP: http://ocsp.example.com
Fingerprint (SHA-256): E8:74:48:2A:8B:AA:...
cargo install --path xcertOr build from source:
cargo build --release
# Binary at target/release/xcertxcert show cert.pem
xcert show --json cert.pem # JSON output
xcert show --all cert.pem # Include signature bytes
# Bulk: show all certs in a directory
xcert show /etc/ssl/certs/ --json
xcert show /etc/ssl/certs/ --recursexcert field subject cert.pem
# Output: C = US, ST = California, O = Example Corp, CN = www.example.com
xcert field serial cert.pem
# Output: 10:00
xcert field fingerprint cert.pem
# Output: E8:74:48:2A:8B:AA:E7:36:9D:5B:51:2A:60:12:34:29:...
xcert field dns-names cert.pem
# Output:
# www.example.com
# example.com
# *.example.com
xcert field fingerprint --digest sha384 cert.pem
xcert field curve ec-cert.pem # EC curve name (e.g. P-256)
xcert field san --json cert.pem
xcert field public-key cert.pem
# Bulk: extract field from all certs in a directory
xcert field serial /etc/ssl/certs/ --json
xcert field not-after /etc/ssl/certs/ --recurseAvailable fields:
| Field | Description |
|---|---|
subject |
Subject distinguished name |
issuer |
Issuer distinguished name |
serial |
Serial number (colon-separated hex) |
not-before |
Not Before date (ISO 8601) |
not-after |
Not After date (ISO 8601) |
fingerprint |
Certificate fingerprint (default: SHA-256; use --digest for sha384/sha512/sha1) |
public-key |
Subject public key in PEM format |
modulus |
RSA modulus in hex (RSA certificates only) |
exponent |
RSA public exponent (RSA certificates only) |
curve |
EC named curve, e.g. P-256, P-384, P-521 (EC certificates only) |
emails |
Email addresses from subject DN emailAddress attribute and SAN rfc822Name entries |
dns-names |
DNS names from the SAN extension |
ip-addrs |
IP addresses from the SAN extension (IPv4 and IPv6) |
san |
All Subject Alternative Name entries (DNS, Email, IP, URI, DirName) |
ocsp-url |
OCSP responder URL(s) from AIA extension |
key-usage |
Key Usage extension values |
ext-key-usage |
Extended Key Usage extension values |
extensions |
All extensions (use --ext to filter by name or OID) |
Returns exit code 0 for pass, 1 for fail.
xcert check expiry 30d cert.pem # Valid for 30+ days?
# (exit code 0 = yes, 1 = no)
xcert check host www.example.com cert.pem
# (exit code 0 = matches, 1 = no match)
xcert check email user@example.com cert.pem
xcert check ip 93.184.216.34 cert.pem
# Use in scripts:
if xcert check expiry 7d cert.pem; then
echo "Certificate is valid for at least 7 more days"
fi
# Bulk: check all certs in a directory
xcert check expiry 30d /etc/ssl/certs/
xcert check expiry 7d --failures-only /etc/ssl/certs/Check types:
| Check | Value | Description |
|---|---|---|
expiry |
Duration | Pass if cert is valid for at least this much longer |
host |
Hostname | Pass if hostname matches SAN DNS entries or subject CN (RFC 6125 wildcards supported) |
email |
Email address | Pass if email matches SAN rfc822Name entries or subject emailAddress attribute (case-insensitive) |
ip |
IP address | Pass if IP matches SAN IP entries (IPv4 or IPv6, normalized for comparison) |
Duration formats: 30d, 1w, 2h30m, 1w3d, or plain seconds (e.g., 2592000).
Units: s, m/min, h/hr, d/day, w/week, month, y/year.
xcert verify chain.pem
# Output: chain.pem: OK, www.example.com, 10:00
xcert verify --hostname example.com chain.pem
xcert verify --CAfile ca.pem chain.pem
xcert verify --untrusted intermediates.pem leaf.pem
xcert verify --json chain.pem
# Bulk: verify all certs in a directory
xcert verify --CAfile ca.pem /etc/ssl/certs/ --json
xcert verify --failures-only /etc/ssl/certs/Exit code 0 = valid, 2 = invalid.
Options:
| Option | Description |
|---|---|
--hostname <NAME> |
Verify hostname against the leaf certificate's SAN/CN |
--CAfile <FILE> |
PEM file containing trusted CA certificates (default: system trust store) |
--CApath <DIR> |
Directory of trusted CA certificates in PEM format |
--untrusted <FILE> |
PEM file with untrusted intermediate certificates for chain building |
--purpose <PURPOSE> |
Required Extended Key Usage: sslserver, sslclient, smimesign, codesign, any, or a custom OID |
--partial-chain |
Accept any certificate in the chain as a trust anchor |
--no-check-time |
Skip validity date checks |
--attime <EPOCH> |
Verify at a specific Unix timestamp instead of current time |
--verify-depth <N> |
Maximum chain depth (default: 32) |
--verify-email <EMAIL> |
Verify email address against the leaf certificate's SAN/subject |
--verify-ip <IP> |
Verify IP address against the leaf certificate's SAN |
--show-chain |
Display subject and issuer for each certificate in the verified chain |
--CRLfile <FILE> |
PEM file containing CRL(s) for revocation checking |
--crl-check |
Check CRL revocation for the leaf certificate (requires --CRLfile) |
--crl-check-all |
Check CRL revocation for all certificates in the chain (requires --CRLfile) |
xcert convert cert.pem cert.der # PEM to DER (format inferred from extension)
xcert convert cert.der cert.pem # DER to PEM
xcert convert cert.pem --to der # Explicit format (stdout)All commands support --json for machine-readable output. Bulk operations return:
{
"results": [
{"file": "path/to/cert.pem", "success": true, "data": {...}},
{"file": "path/to/bad.pem", "success": false, "error": "..."}
],
"summary": {"total": 10, "succeeded": 8, "failed": 2}
}Each result has success: true with a data field, or success: false with an error field.
The data field contains command-specific output (e.g., full certificate info for show, the extracted value for field, a {"check", "value", "passed"} object for check, or a {"valid", "errors"} object for verify).
The summary counts processing outcomes: succeeded is the number of files processed without errors, and failed is the number of files that could not be read or parsed. For check and verify, the pass/fail status of each individual check is in the per-result data, not in the summary.
- Auto-detection of PEM vs DER format
- Colored terminal output (dates, hex values, URLs, strings)
- Parallel directory processing via rayon
- Certificate chain verification against system or custom trust store
- CRL revocation checking (
--CRLfile,--crl-check,--crl-check-all) - RSA, ECDSA (P-256/P-384/P-521), Ed25519, Ed448 key types
- SHA-256/384/512/SHA-1 fingerprints
- Memory-safe Rust with
unsafeforbidden
cargo test279 tests covering parsing, verification, checks, conversions, and compatibility with external test vectors.
Three git submodules provide additional test vectors from external projects. Tests skip gracefully when submodules are not initialized.
# Initialize all submodules
git submodule update --init
# Run tests (submodule tests now included)
cargo test| Submodule | Source | What it tests |
|---|---|---|
testdata/zlint |
zmap/zlint | 2000+ real-world and edge-case certificates |
testdata/x509-limbo |
C2SP/x509-limbo | RFC 5280, WebPKI, and path-building verification vectors |
testdata/pyca-cryptography |
pyca/cryptography | Algorithm diversity (Ed25519, Ed448, RSA-PSS, DSA) and NIST PKITS suite |
cargo +nightly fuzz run parse_cert -- -max_total_time=60Four fuzz targets: parse_cert, parse_der, parse_pem, roundtrip.
unsafecode denied at workspace level- Clippy warns on
unwrap(),expect(),panic!() cargo auditfor dependency scanning
See PERF.md for benchmarks. xcert is 3.7x-4.5x faster than OpenSSL for common operations.