From b8005dd868dde3de59f0f4c49ce5882792675864 Mon Sep 17 00:00:00 2001 From: Riccardo Gori Date: Fri, 24 Nov 2017 13:52:47 +0100 Subject: [PATCH] tunneld: Add option to authenticate client certificate --- cmd/tunneld/options.go | 3 +++ cmd/tunneld/tunneld.go | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/cmd/tunneld/options.go b/cmd/tunneld/options.go index fce0e90..81b41d6 100644 --- a/cmd/tunneld/options.go +++ b/cmd/tunneld/options.go @@ -41,6 +41,7 @@ type options struct { tunnelAddr string tlsCrt string tlsKey string + rootCA string clients string logTo string logLevel int @@ -53,6 +54,7 @@ func parseArgs() *options { tunnelAddr := flag.String("tunnelAddr", ":5223", "Public address listening for tunnel client") tlsCrt := flag.String("tlsCrt", "server.crt", "Path to a TLS certificate file") tlsKey := flag.String("tlsKey", "server.key", "Path to a TLS key file") + rootCA := flag.String("rootCA", "", "Path to the trusted certificate chian used for client certificate authentication. If empty do not authenticate clients.") clients := flag.String("clients", "", "Comma-separated list of tunnel client ids") logTo := flag.String("log", "stdout", "Write log messages to this file, file name or 'stdout', 'stderr', 'none'") logLevel := flag.Int("log-level", 1, "Level of messages to log, 0-3") @@ -65,6 +67,7 @@ func parseArgs() *options { tunnelAddr: *tunnelAddr, tlsCrt: *tlsCrt, tlsKey: *tlsKey, + rootCA: *rootCA, clients: *clients, logTo: *logTo, logLevel: *logLevel, diff --git a/cmd/tunneld/tunneld.go b/cmd/tunneld/tunneld.go index 4e1cc93..1e2b4a8 100644 --- a/cmd/tunneld/tunneld.go +++ b/cmd/tunneld/tunneld.go @@ -6,7 +6,9 @@ package main import ( "crypto/tls" + "crypto/x509" "fmt" + "io/ioutil" "net/http" "os" "strings" @@ -31,16 +33,15 @@ func main() { fatal("failed to init logger: %s", err) } - // load certs - cert, err := tls.LoadX509KeyPair(opts.tlsCrt, opts.tlsKey) + tlsconf, err := tlsConfig(opts) if err != nil { - fatal("failed to load certificate: %s", err) + fatal("failed to configure tls: %s", err) } // setup server server, err := tunnel.NewServer(&tunnel.ServerConfig{ Addr: opts.tunnelAddr, - TLSConfig: tlsConfig(cert), + TLSConfig: tlsconf, Logger: logger, }) if err != nil { @@ -101,16 +102,38 @@ func main() { server.Start() } -func tlsConfig(cert tls.Certificate) *tls.Config { +func tlsConfig(opts *options) (*tls.Config, error) { + // load certs + cert, err := tls.LoadX509KeyPair(opts.tlsCrt, opts.tlsKey) + if err != nil { + return nil, err + } + + // load root CA for client authentication + clientAuth := tls.RequireAnyClientCert + var roots *x509.CertPool + if opts.rootCA != "" { + roots = x509.NewCertPool() + rootPEM, err := ioutil.ReadFile(opts.rootCA) + if err != nil { + return nil, err + } + if ok := roots.AppendCertsFromPEM(rootPEM); !ok { + return nil, err + } + clientAuth = tls.RequireAndVerifyClientCert + } + return &tls.Config{ Certificates: []tls.Certificate{cert}, - ClientAuth: tls.RequireAnyClientCert, + ClientAuth: clientAuth, + ClientCAs: roots, SessionTicketsDisabled: true, MinVersion: tls.VersionTLS12, CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, PreferServerCipherSuites: true, NextProtos: []string{"h2"}, - } + }, nil } func fatal(format string, a ...interface{}) {