diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go index 28ea20001..faa275b03 100644 --- a/cmd/commandfuncs.go +++ b/cmd/commandfuncs.go @@ -697,7 +697,7 @@ func cmdFmt(fl Flags) (int, error) { output := caddyfile.Format(input) if fl.Bool("overwrite") { - if err := os.WriteFile(configFile, output, 0o600); err != nil { + if err := os.WriteFile(configFile, output, 0o600); err != nil { //nolint:gosec // path traversal is not really a thing here, this is either "Caddyfile" or admin-controlled return caddy.ExitCodeFailedStartup, fmt.Errorf("overwriting formatted file: %v", err) } return caddy.ExitCodeSuccess, nil diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go index 6b6dc3636..c9258da48 100644 --- a/modules/caddytls/connpolicy.go +++ b/modules/caddytls/connpolicy.go @@ -885,24 +885,29 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro // if a custom verification function already exists, wrap it clientauth.existingVerifyPeerCert = cfg.VerifyPeerCertificate - cfg.VerifyPeerCertificate = clientauth.verifyPeerCertificate + cfg.VerifyConnection = clientauth.verifyConnection return nil } -// verifyPeerCertificate is for use as a tls.Config.VerifyPeerCertificate -// callback to do custom client certificate verification. It is intended -// for installation only by clientauth.ConfigureTLSConfig(). -func (clientauth *ClientAuthentication) verifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { +// verifyConnection is for use as a tls.Config.VerifyConnection callback +// to do custom client certificate verification. It is intended for +// installation only by clientauth.ConfigureTLSConfig(). +// +// Unlike VerifyPeerCertificate, VerifyConnection is called on every +// connection including resumed sessions, preventing session-resumption bypass. +func (clientauth *ClientAuthentication) verifyConnection(cs tls.ConnectionState) error { // first use any pre-existing custom verification function if clientauth.existingVerifyPeerCert != nil { - err := clientauth.existingVerifyPeerCert(rawCerts, verifiedChains) - if err != nil { + rawCerts := make([][]byte, len(cs.PeerCertificates)) + for i, cert := range cs.PeerCertificates { + rawCerts[i] = cert.Raw + } + if err := clientauth.existingVerifyPeerCert(rawCerts, cs.VerifiedChains); err != nil { return err } } for _, verifier := range clientauth.verifiers { - err := verifier.VerifyClientCertificate(rawCerts, verifiedChains) - if err != nil { + if err := verifier.VerifyClientCertificate(nil, cs.VerifiedChains); err != nil { return err } } diff --git a/modules/caddytls/folderloader.go b/modules/caddytls/folderloader.go index 2df6f4cee..b86d3b6ae 100644 --- a/modules/caddytls/folderloader.go +++ b/modules/caddytls/folderloader.go @@ -19,6 +19,7 @@ import ( "crypto/tls" "encoding/pem" "fmt" + "io/fs" "os" "path/filepath" "strings" @@ -62,18 +63,27 @@ func (fl FolderLoader) Provision(ctx caddy.Context) error { func (fl FolderLoader) LoadCertificates() ([]Certificate, error) { var certs []Certificate for _, dir := range fl { - err := filepath.Walk(dir, func(fpath string, info os.FileInfo, err error) error { + root, err := os.OpenRoot(dir) + if err != nil { + return nil, fmt.Errorf("unable to open root directory %s: %w", dir, err) + } + err = filepath.WalkDir(dir, func(fpath string, d fs.DirEntry, err error) error { if err != nil { return fmt.Errorf("unable to traverse into path: %s", fpath) } - if info.IsDir() { + if d.IsDir() { return nil } - if !strings.HasSuffix(strings.ToLower(info.Name()), ".pem") { + if !strings.HasSuffix(strings.ToLower(d.Name()), ".pem") { return nil } - bundle, err := os.ReadFile(fpath) + rel, err := filepath.Rel(dir, fpath) + if err != nil { + return fmt.Errorf("unable to get relative path for %s: %w", fpath, err) + } + + bundle, err := root.ReadFile(rel) if err != nil { return err } @@ -83,11 +93,11 @@ func (fl FolderLoader) LoadCertificates() ([]Certificate, error) { } certs = append(certs, Certificate{Certificate: cert}) - return nil }) + _ = root.Close() if err != nil { - return nil, err + return nil, fmt.Errorf("walking certificates directory %s: %w", dir, err) } } return certs, nil