Allow fetching certificates from servers.
This commit is contained in:
parent
e8045e0b1f
commit
b9deec27f0
|
@ -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,6 +292,9 @@ func main() {
|
|||
} else {
|
||||
for _, filename := range flag.Args() {
|
||||
fmt.Printf("--%s ---\n", filename)
|
||||
if strings.HasPrefix(filename, "https://") {
|
||||
displayAllCertsWeb(filename, leafOnly)
|
||||
} else {
|
||||
in, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
Warn(err, "couldn't read certificate")
|
||||
|
@ -252,3 +305,4 @@ func main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue