From 68e5822176582be4d5f3e51621d8d4d498e7d338 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 28 Aug 2017 17:05:34 -0700 Subject: [PATCH] cmd/stealchain-server: Initial commit. --- cmd/stealchain-server/README | 17 +++++++ cmd/stealchain-server/main.go | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 cmd/stealchain-server/README create mode 100644 cmd/stealchain-server/main.go diff --git a/cmd/stealchain-server/README b/cmd/stealchain-server/README new file mode 100644 index 0000000..e689ee1 --- /dev/null +++ b/cmd/stealchain-server/README @@ -0,0 +1,17 @@ +stealchain-server + +This is a utility to extract the verified X.509 chain from a TLS +connection initiated by another client. It listens on a port, and +for each connection, it will dump the certificates that the peer +actually sent (and not the verified chain that is built from this). + +It was written to assist in debugging issues with certificate chains. + +There are a few knobs: + +-listen specifies the address to listen on. + +-ca allows the trusted CA roots to be specified via a PEM bundle of +root certificates. + +-verify requires that the client present a valid certificate chain. diff --git a/cmd/stealchain-server/main.go b/cmd/stealchain-server/main.go new file mode 100644 index 0000000..5b4a4fb --- /dev/null +++ b/cmd/stealchain-server/main.go @@ -0,0 +1,83 @@ +package main + +import ( + "crypto/rand" + "crypto/tls" + "crypto/x509" + "encoding/hex" + "encoding/pem" + "flag" + "fmt" + "io/ioutil" + "net" + "os" + + "github.com/kisom/goutils/die" +) + +func main() { + cfg := &tls.Config{} + + var sysRoot, listenAddr string + var verify bool + flag.StringVar(&sysRoot, "ca", "", "provide an alternate CA bundle") + flag.StringVar(&listenAddr, "listen", ":443", "address to listen on") + flag.BoolVar(&verify, "verify", false, "verify client certificates") + flag.Parse() + + if verify { + cfg.ClientAuth = tls.RequireAndVerifyClientCert + } + if sysRoot != "" { + pemList, err := ioutil.ReadFile(sysRoot) + die.If(err) + + roots := x509.NewCertPool() + if !roots.AppendCertsFromPEM(pemList) { + fmt.Printf("[!] no valid roots found") + roots = nil + } + + cfg.RootCAs = roots + } + + l, err := net.Listen("tcp", listenAddr) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + for { + conn, err := l.Accept() + if err != nil { + fmt.Println(err.Error()) + } + + raddr := conn.RemoteAddr() + tconn := tls.Server(conn, cfg) + cs := tconn.ConnectionState() + if len(cs.PeerCertificates) == 0 { + fmt.Printf("[+] %v: no chain presented\n", raddr) + continue + } + + var chain []byte + for _, cert := range cs.PeerCertificates { + p := &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.Raw, + } + chain = append(chain, pem.EncodeToMemory(p)...) + } + + var nonce [16]byte + _, err = rand.Read(nonce[:]) + if err != nil { + panic(err) + } + fname := fmt.Sprintf("%v-%v.pem", raddr, hex.EncodeToString(nonce[:])) + err = ioutil.WriteFile(fname, chain, 0644) + die.If(err) + fmt.Printf("%v: [+] wrote %v.\n", raddr, fname) + } +}