Allow fetching certificates from servers.
This commit is contained in:
parent
e8045e0b1f
commit
b9deec27f0
|
@ -6,6 +6,7 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"flag"
|
"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() {
|
func main() {
|
||||||
var leafOnly bool
|
var leafOnly bool
|
||||||
flag.StringVar(&dateFormat, "s", oneTrueDateFormat, "date `format` in Go time format")
|
flag.StringVar(&dateFormat, "s", oneTrueDateFormat, "date `format` in Go time format")
|
||||||
|
@ -242,6 +292,9 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
for _, filename := range flag.Args() {
|
for _, filename := range flag.Args() {
|
||||||
fmt.Printf("--%s ---\n", filename)
|
fmt.Printf("--%s ---\n", filename)
|
||||||
|
if strings.HasPrefix(filename, "https://") {
|
||||||
|
displayAllCertsWeb(filename, leafOnly)
|
||||||
|
} else {
|
||||||
in, err := ioutil.ReadFile(filename)
|
in, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Warn(err, "couldn't read certificate")
|
Warn(err, "couldn't read certificate")
|
||||||
|
@ -251,4 +304,5 @@ func main() {
|
||||||
displayAllCerts(in, leafOnly)
|
displayAllCerts(in, leafOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -158,3 +160,48 @@ func dumpHex(in []byte) string {
|
||||||
|
|
||||||
return strings.Trim(s, ":")
|
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