1
1
mirror of https://git.sr.ht/~emersion/tlstunnel synced 2024-11-19 15:53:50 +01:00

Add client_auth directive

This commit is contained in:
Tom Lebreux 2024-05-01 23:02:39 -04:00 committed by Simon Ser
parent c888547e5b
commit c3623f6b38
3 changed files with 58 additions and 3 deletions

@ -39,7 +39,8 @@ type frontendConfig struct {
} `scfg:"listen"` } `scfg:"listen"`
Backend *backendConfig `scfg:"backend"` Backend *backendConfig `scfg:"backend"`
TLS struct { TLS struct {
Load *[2]string `scfg:"load"` Load *[2]string `scfg:"load"`
ClientAuth *[2]string `scfg:"client_auth"`
} `scfg:"tls"` } `scfg:"tls"`
Protocol []string `scfg:"protocol"` Protocol []string `scfg:"protocol"`
} }
@ -129,6 +130,25 @@ func parseFrontend(srv *Server, cfg *frontendConfig) error {
srv.UnmanagedCerts = append(srv.UnmanagedCerts, cert) srv.UnmanagedCerts = append(srv.UnmanagedCerts, cert)
unmanaged = true unmanaged = true
} }
if cfg.TLS.ClientAuth != nil {
clientAuth, err := parseClientAuth(cfg.TLS.ClientAuth[0])
if err != nil {
return fmt.Errorf(`directive "tls.client_auth": %w`, err)
}
clientCAs, err := os.ReadFile(cfg.TLS.ClientAuth[1])
if err != nil {
return fmt.Errorf(`directive "tls.client_auth": %w`, err)
}
pool := x509.NewCertPool()
if ok := pool.AppendCertsFromPEM(clientCAs); !ok {
return fmt.Errorf("failed to append to client pool")
}
frontend.ClientAuth = clientAuth
frontend.ClientCAs = pool
}
frontend.Protocols = cfg.Protocol frontend.Protocols = cfg.Protocol
@ -292,3 +312,20 @@ func parseTLSOnDemand(srv *Server, cfg *tlsOnDemandConfig) error {
return nil return nil
} }
func parseClientAuth(clientAuth string) (tls.ClientAuthType, error) {
var auth tls.ClientAuthType
switch clientAuth {
case "request":
auth = tls.RequestClientCert
case "require":
auth = tls.RequireAnyClientCert
case "verify":
auth = tls.RequireAnyClientCert
case "require_and_verify":
auth = tls.RequireAndVerifyClientCert
default:
return auth, fmt.Errorf("unknown client auth %s", clientAuth)
}
return auth, nil
}

@ -3,6 +3,7 @@ package tlstunnel
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -312,6 +313,10 @@ func (ln *Listener) handle(conn net.Conn) error {
} }
tlsConfig.NextProtos = append(tlsConfig.NextProtos, fe.Protocols...) tlsConfig.NextProtos = append(tlsConfig.NextProtos, fe.Protocols...)
if fe.ClientAuth != tls.NoClientCert {
tlsConfig.ClientAuth = fe.ClientAuth
tlsConfig.ClientCAs = fe.ClientCAs
}
return tlsConfig, nil return tlsConfig, nil
} }
tlsConn := tls.Server(conn, tlsConfig) tlsConn := tls.Server(conn, tlsConfig)
@ -362,8 +367,10 @@ func (ln *Listener) matchFrontend(serverName string) (*Frontend, error) {
} }
type Frontend struct { type Frontend struct {
Backend Backend Backend Backend
Protocols []string Protocols []string
ClientAuth tls.ClientAuthType
ClientCAs *x509.CertPool
} }
func (fe *Frontend) handle(downstream net.Conn, tlsState *tls.ConnectionState) error { func (fe *Frontend) handle(downstream net.Conn, tlsState *tls.ConnectionState) error {

@ -93,6 +93,17 @@ The following directives are supported:
This disables automatic TLS. This disables automatic TLS.
*client_auth* <type> <cert>
Configures client authentication.
The available verification types are the following:
request, require, verify, require_and_verify. They are
defined here:
https://pkg.go.dev/crypto/tls#ClientAuthType.
The certificate must be a PEM file and is used as a CA to validate
client certificates.
*protocol* <name>... *protocol* <name>...
List of supported application-layer protocols. List of supported application-layer protocols.