cmd: add tlsinfo.

This commit is contained in:
2025-11-14 15:21:38 -08:00
parent 31baa10b3b
commit e375963243
2 changed files with 98 additions and 0 deletions

34
cmd/tlsinfo/README.txt Normal file
View File

@@ -0,0 +1,34 @@
tlsinfo: show TLS version, cipher, and peer certificates
---------------------------------------------------------
Description
tlsinfo connects to a TLS server and prints the negotiated TLS version and
cipher suite, followed by details for each certificate in the servers
presented chain (as provided by the server).
Usage
tlsinfo <hostname:port>
Output
The program prints the negotiated protocol and cipher, then one section per
certificate in the order received from the server. Example fields:
TLS Version: TLS 1.3
Cipher Suite: TLS_AES_128_GCM_SHA256
Certificate 1
Subject: CN=example.com, O=Example Corp, C=US
Issuer: CN=Example Root CA, O=Example Corp, C=US
DNS Names: [example.com www.example.com]
Not Before: 2025-01-01 00:00:00 +0000 UTC
Not After: 2026-01-01 23:59:59 +0000 UTC
Examples
# Inspect a public HTTPS endpoint
tlsinfo example.com:443
Notes
- Verification is intentionally disabled (InsecureSkipVerify=true). The tool
does not validate the server certificate or hostname; it is for inspection
only.
- The SNI/ServerName is inferred from <hostname> when applicable.
- You must specify a port (e.g., 443 for HTTPS).
- The entire certificate chain is printed exactly as presented by the server.

64
cmd/tlsinfo/main.go Normal file
View File

@@ -0,0 +1,64 @@
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"os"
)
func main() {
if len(os.Args) != 2 {
fmt.Printf("Usage: %s hostname:port>\n", os.Args[0])
os.Exit(1)
}
hostPort := os.Args[1]
conn, err := tls.Dial("tcp", hostPort, &tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
fmt.Printf("Failed to connect to the TLS server: %v\n", err)
os.Exit(1)
}
defer conn.Close()
state := conn.ConnectionState()
printConnectionDetails(state)
}
func printConnectionDetails(state tls.ConnectionState) {
version := tlsVersion(state.Version)
cipherSuite := tls.CipherSuiteName(state.CipherSuite)
fmt.Printf("TLS Version: %s\n", version)
fmt.Printf("Cipher Suite: %s\n", cipherSuite)
printPeerCertificates(state.PeerCertificates)
}
func tlsVersion(version uint16) string {
switch version {
case tls.VersionTLS13:
return "TLS 1.3"
case tls.VersionTLS12:
return "TLS 1.2"
case tls.VersionTLS11:
return "TLS 1.1"
case tls.VersionTLS10:
return "TLS 1.0"
default:
return "Unknown"
}
}
func printPeerCertificates(certificates []*x509.Certificate) {
for i, cert := range certificates {
fmt.Printf("Certificate %d\n", i+1)
fmt.Printf("\tSubject: %s\n", cert.Subject)
fmt.Printf("\tIssuer: %s\n", cert.Issuer)
fmt.Printf("\tDNS Names: %v\n", cert.DNSNames)
fmt.Printf("\tNot Before: %s\n:", cert.NotBefore)
fmt.Printf("\tNot After: %s\n", cert.NotAfter)
}
}