Allow fetching certificates from servers.

This commit is contained in:
Kyle Isom 2016-10-14 09:50:22 -07:00
parent e8045e0b1f
commit b9deec27f0
2 changed files with 107 additions and 6 deletions

View File

@ -6,6 +6,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"flag"
@ -221,6 +222,55 @@ func displayAllCerts(in []byte, leafOnly bool) {
}
}
func displayAllCertsWeb(uri string, leafOnly bool) {
ci := getConnInfo(uri)
conn, err := tls.Dial("tcp", ci.Addr, permissiveConfig())
if err != nil {
Warn(err, "couldn't connect to %s", ci.Addr)
return
}
defer conn.Close()
state := conn.ConnectionState()
conn.Close()
conn, err = tls.Dial("tcp", ci.Addr, verifyConfig(ci.Host))
if err == nil {
err = conn.VerifyHostname(ci.Host)
if err == nil {
state = conn.ConnectionState()
}
} else {
Warn(err, "TLS verification error with server name %s", ci.Host)
}
conn.Close()
if len(state.PeerCertificates) == 0 {
Warnx("no certificates found")
return
}
if leafOnly {
displayCert(state.PeerCertificates[0])
return
}
if len(state.VerifiedChains) == 0 {
Warnx("no verified chains found; using peer chain")
for i := range state.PeerCertificates {
displayCert(state.PeerCertificates[i])
}
} else {
fmt.Println("TLS chain verified successfully.")
for i := range state.VerifiedChains {
fmt.Printf("--- Verified certificate chain %d ---\n", i+1)
for j := range state.VerifiedChains[i] {
displayCert(state.VerifiedChains[i][j])
}
}
}
}
func main() {
var leafOnly bool
flag.StringVar(&dateFormat, "s", oneTrueDateFormat, "date `format` in Go time format")
@ -242,13 +292,17 @@ func main() {
} else {
for _, filename := range flag.Args() {
fmt.Printf("--%s ---\n", filename)
in, err := ioutil.ReadFile(filename)
if err != nil {
Warn(err, "couldn't read certificate")
continue
}
if strings.HasPrefix(filename, "https://") {
displayAllCertsWeb(filename, leafOnly)
} else {
in, err := ioutil.ReadFile(filename)
if err != nil {
Warn(err, "couldn't read certificate")
continue
}
displayAllCerts(in, leafOnly)
displayAllCerts(in, leafOnly)
}
}
}
}

View File

@ -1,9 +1,11 @@
package main
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net"
"os"
"strings"
@ -158,3 +160,48 @@ 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,
}
}
// verifyConfig returns a config that will verify the connection.
func verifyConfig(hostname string) *tls.Config {
return &tls.Config{
ServerName: hostname,
}
}
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
}