cndump: The Minimalist Certificate Scanner That Does One Thing Fast
Hook
While security teams struggle with bloated certificate scanning tools that take minutes to process hundreds of endpoints, a 300-line Go utility does it in seconds by deliberately ignoring 90% of what certificates contain.
Context
SSL/TLS certificates contain a wealth of information: subject alternative names, validity periods, issuer chains, key algorithms, and more. But sometimes you just need one piece: the Common Name field that identifies what the certificate claims to protect. Traditional tools like OpenSSL's s_client command are incredibly powerful but painfully slow when you need to check certificates across dozens or hundreds of hosts. You end up writing bash loops that take forever, or reaching for heavyweight scanning frameworks like nmap or zgrab2 that bring along capabilities you don't need.
cndump emerged from this specific friction point in security reconnaissance and infrastructure auditing workflows. When you're documenting network topology, verifying certificate deployments after a migration, or doing initial reconnaissance on a list of IP addresses, you don't always need a comprehensive certificate dump. You need speed, you need simplicity, and you need something that plays nicely with Unix pipes. cndump trades feature completeness for execution speed and compositional simplicity—a classic Unix philosophy applied to modern TLS certificate inspection.
Technical Insight
At its core, cndump is an exercise in effective Go concurrency for I/O-bound operations. The tool reads a list of targets (IP addresses, hostnames, or URLs) and fans them out to a worker pool of goroutines that each establish TLS connections, extract the CN field, and write results to stdout. The architecture is deliberately simple: input reader → work queue → worker pool → output writer.
The concurrency model uses Go's standard patterns: a buffered channel acts as the work queue, a configurable number of goroutines pull from that queue, and a sync.WaitGroup coordinates shutdown. Here's what the core extraction logic looks like in typical usage:
// Simplified conceptual example of cndump's approach
func extractCN(target string, results chan<- string) {
conn, err := tls.Dial("tcp", target+":443", &tls.Config{
InsecureSkipVerify: true, // For reconnaissance
})
if err != nil {
results <- fmt.Sprintf("%s,ERROR", target)
return
}
defer conn.Close()
certs := conn.ConnectionState().PeerCertificates
if len(certs) > 0 {
cn := certs[0].Subject.CommonName
results <- fmt.Sprintf("%s,%s", target, cn)
}
}
The InsecureSkipVerify setting is key here—cndump isn't validating certificates, it's documenting them. This design decision allows it to extract CNs from expired, self-signed, or otherwise invalid certificates that a strict TLS client would reject. For reconnaissance and documentation workflows, this is exactly what you want.
The tool shines in pipeline composition. Feed it a list of targets and redirect the output to CSV for immediate spreadsheet import:
# Generate a quick certificate inventory
cat hosts.txt | cndump > cert-inventory.csv
# Combine with other tools to find certificate mismatches
cat ips.txt | cndump | grep -v "expected-domain.com" | \
mail -s "Certificate Mismatch Alert" security@company.com
# Parallel processing with xargs for massive lists
cat large-hostlist.txt | xargs -P 50 -n 100 cndump
The worker pool size is typically configurable via a flag (commonly -workers or similar), letting you tune concurrency based on your network conditions and rate limiting concerns. With 50-100 workers, you can scan hundreds of hosts in seconds rather than minutes. The goroutine-per-connection model keeps memory overhead low since Go's runtime efficiently multiplexes thousands of goroutines onto OS threads.
One architectural choice worth noting: cndump outputs results as they arrive rather than buffering and sorting. This streaming approach means you get immediate feedback and can begin processing results before the entire scan completes—critical when checking thousands of endpoints. The tradeoff is that output ordering is non-deterministic, but that's acceptable for most certificate reconnaissance workflows where you'll be post-processing the CSV anyway.
The tool's simplicity also makes it trivially modifiable. Need to extract the issuer instead of CN? That's a one-line change from Subject.CommonName to Issuer.CommonName. Want to add timeout configuration? Wrap the Dial call with context.WithTimeout. The codebase is small enough that you can fork it and customize for your specific needs in minutes rather than navigating a complex framework.
Gotcha
cndump's single-minded focus on Common Names becomes a significant limitation the moment you need anything else from certificates. Modern certificates increasingly rely on Subject Alternative Names (SANs) rather than CN fields—many certificates have empty CNs or use generic values, putting all the meaningful information in SAN extensions. cndump ignores these completely, which means you might extract "*.cloudflare.com" as the CN while missing the hundred specific domains listed in SANs.
The tool also provides minimal error differentiation. When a host fails, you typically get a generic error marker in the output, but you won't know if it was a connection timeout, a TLS handshake failure, a certificate parsing error, or a DNS resolution problem. For one-off reconnaissance this is fine, but if you're debugging why certain hosts aren't responding, you'll find yourself falling back to openssl s_client anyway. There's no support for custom TLS configurations like client certificates, specific cipher suites, or SNI (Server Name Indication) overrides—capabilities you'd need in more complex enterprise environments where certificate inspection isn't straightforward. The tool assumes port 443 unless you specify otherwise in the input, which works for standard HTTPS but requires explicit port notation for other TLS services.
Verdict
Use if: You need to quickly extract certificate Common Names from dozens or hundreds of hosts for network documentation, infrastructure audits, or security reconnaissance. You're working in Unix-style pipelines and value speed and simplicity over comprehensive certificate analysis. You're scanning publicly-facing services where standard TLS configurations apply, and you're comfortable with non-deterministic output ordering. You might want to fork and modify the tool for custom certificate field extraction since the codebase is small and approachable.
Skip if: You need to inspect Subject Alternative Names (which most modern certificates rely on), extract expiration dates, analyze certificate chains, or capture comprehensive certificate metadata. You require detailed error reporting to distinguish between connection failures, handshake problems, and certificate issues. You're working with services that need client certificates, custom CA bundles, or non-standard TLS configurations. Consider openssl s_client for comprehensive single-host analysis, tlsx from ProjectDiscovery for modern multi-field certificate extraction with JSON output, or zgrab2 for full-featured network reconnaissance that includes rich certificate capture.