cmd/certdump: use certlib.Fetcher.
This commit is contained in:
@@ -2,19 +2,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -220,122 +216,6 @@ func displayCert(cert *x509.Certificate) {
|
||||
}
|
||||
}
|
||||
|
||||
func displayAllCerts(in []byte, leafOnly bool) {
|
||||
certs, err := certlib.ParseCertificatesPEM(in)
|
||||
if err != nil {
|
||||
certs, _, err = certlib.ParseCertificatesDER(in, "")
|
||||
if err != nil {
|
||||
_, _ = lib.Warn(err, "failed to parse certificates")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(certs) == 0 {
|
||||
_, _ = lib.Warnx("no certificates found")
|
||||
return
|
||||
}
|
||||
|
||||
if leafOnly {
|
||||
displayCert(certs[0])
|
||||
return
|
||||
}
|
||||
|
||||
for i := range certs {
|
||||
displayCert(certs[i])
|
||||
}
|
||||
}
|
||||
|
||||
func displayAllCertsWeb(uri string, leafOnly bool) {
|
||||
ci := getConnInfo(uri)
|
||||
d := &tls.Dialer{Config: permissiveConfig()}
|
||||
nc, err := d.DialContext(context.Background(), "tcp", ci.Addr)
|
||||
if err != nil {
|
||||
_, _ = lib.Warn(err, "couldn't connect to %s", ci.Addr)
|
||||
return
|
||||
}
|
||||
|
||||
conn, ok := nc.(*tls.Conn)
|
||||
if !ok {
|
||||
_, _ = lib.Warnx("invalid TLS connection (not a *tls.Conn)")
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
state := conn.ConnectionState()
|
||||
if err = conn.Close(); err != nil {
|
||||
_, _ = lib.Warn(err, "couldn't close TLS connection")
|
||||
}
|
||||
|
||||
d = &tls.Dialer{Config: verifyConfig(ci.Host)}
|
||||
nc, err = d.DialContext(context.Background(), "tcp", ci.Addr)
|
||||
if err == nil {
|
||||
conn, ok = nc.(*tls.Conn)
|
||||
if !ok {
|
||||
_, _ = lib.Warnx("invalid TLS connection (not a *tls.Conn)")
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.VerifyHostname(ci.Host)
|
||||
if err == nil {
|
||||
state = conn.ConnectionState()
|
||||
}
|
||||
conn.Close()
|
||||
} else {
|
||||
_, _ = lib.Warn(err, "TLS verification error with server name %s", ci.Host)
|
||||
}
|
||||
|
||||
if len(state.PeerCertificates) == 0 {
|
||||
_, _ = lib.Warnx("no certificates found")
|
||||
return
|
||||
}
|
||||
|
||||
if leafOnly {
|
||||
displayCert(state.PeerCertificates[0])
|
||||
return
|
||||
}
|
||||
|
||||
if len(state.VerifiedChains) == 0 {
|
||||
_, _ = lib.Warnx("no verified chains found; using peer chain")
|
||||
for i := range state.PeerCertificates {
|
||||
displayCert(state.PeerCertificates[i])
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintln(os.Stdout, "TLS chain verified successfully.")
|
||||
for i := range state.VerifiedChains {
|
||||
fmt.Fprintf(os.Stdout, "--- Verified certificate chain %d ---%s", i+1, "\n")
|
||||
for j := range state.VerifiedChains[i] {
|
||||
displayCert(state.VerifiedChains[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func shouldReadStdin(argc int, argv []string) bool {
|
||||
if argc == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if argc == 1 && argv[0] == "-" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func readStdin(leafOnly bool) {
|
||||
certs, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
_, _ = lib.Warn(err, "couldn't read certificates from standard input")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// This is needed for getting certs from JSON/jq.
|
||||
certs = bytes.TrimSpace(certs)
|
||||
certs = bytes.ReplaceAll(certs, []byte(`\n`), []byte{0xa})
|
||||
certs = bytes.Trim(certs, `"`)
|
||||
displayAllCerts(certs, leafOnly)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var leafOnly bool
|
||||
flag.BoolVar(&showHash, "d", false, "show hashes of raw DER contents")
|
||||
@@ -343,23 +223,26 @@ func main() {
|
||||
flag.BoolVar(&leafOnly, "l", false, "only show the leaf certificate")
|
||||
flag.Parse()
|
||||
|
||||
if shouldReadStdin(flag.NArg(), flag.Args()) {
|
||||
readStdin(leafOnly)
|
||||
return
|
||||
opts := &certlib.FetcherOpts{
|
||||
SkipVerify: true,
|
||||
Roots: nil,
|
||||
}
|
||||
|
||||
for _, filename := range flag.Args() {
|
||||
fmt.Fprintf(os.Stdout, "--%s ---%s", filename, "\n")
|
||||
if strings.HasPrefix(filename, "https://") {
|
||||
displayAllCertsWeb(filename, leafOnly)
|
||||
} else {
|
||||
in, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
_, _ = lib.Warn(err, "couldn't read certificate")
|
||||
continue
|
||||
}
|
||||
certs, err := certlib.GetCertificateChain(filename, opts)
|
||||
if err != nil {
|
||||
_, _ = lib.Warn(err, "couldn't read certificate")
|
||||
continue
|
||||
}
|
||||
|
||||
displayAllCerts(in, leafOnly)
|
||||
if leafOnly {
|
||||
displayCert(certs[0])
|
||||
continue
|
||||
}
|
||||
|
||||
for i := range certs {
|
||||
displayCert(certs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/kr/text"
|
||||
@@ -142,48 +140,3 @@ func dumpHex(in []byte) string {
|
||||
|
||||
return strings.Trim(s, ":")
|
||||
}
|
||||
|
||||
// permissiveConfig returns a maximally-accepting TLS configuration;
|
||||
// the purpose is to look at the cert, not verify the security properties
|
||||
// of the connection.
|
||||
func permissiveConfig() *tls.Config {
|
||||
return &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
} // #nosec G402
|
||||
}
|
||||
|
||||
// verifyConfig returns a config that will verify the connection.
|
||||
func verifyConfig(hostname string) *tls.Config {
|
||||
return &tls.Config{
|
||||
ServerName: hostname,
|
||||
} // #nosec G402
|
||||
}
|
||||
|
||||
type connInfo struct {
|
||||
// The original URI provided.
|
||||
URI string
|
||||
|
||||
// The hostname of the server.
|
||||
Host string
|
||||
|
||||
// The port to connect on.
|
||||
Port string
|
||||
|
||||
// The address to connect to.
|
||||
Addr string
|
||||
}
|
||||
|
||||
func getConnInfo(uri string) *connInfo {
|
||||
ci := &connInfo{URI: uri}
|
||||
ci.Host = uri[len("https://"):]
|
||||
|
||||
host, port, err := net.SplitHostPort(ci.Host)
|
||||
if err != nil {
|
||||
ci.Port = "443"
|
||||
} else {
|
||||
ci.Host = host
|
||||
ci.Port = port
|
||||
}
|
||||
ci.Addr = net.JoinHostPort(ci.Host, ci.Port)
|
||||
return ci
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user