@marcel91200 / caddy Mirror · read-only / commits / 61641828
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 11:45 UTC

caddyhttp: Support TLS key logging for debugging (#4808)

* Add SSL key logging. * Resolve merge conflict with master * Add Caddyfile support; various fixes * Also commit go.mod and go.sum, oops * Appease linter * Minor tweaks * Add doc comment Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

David Manouchehri committed Sep 16, 2022 at 16:05 UTC 616418281b49ed1052ee395b674d8df97c820b11
3 files changed +87 -40
caddyconfig/httpcaddyfile/builtins.go
+35 -32
@@ -53,8 +53,7 @@ func init() {
53
54 // parseBind parses the bind directive. Syntax:
55 //
56 -// bind <addresses...>
57 -//
56 +// bind <addresses...>
57 func parseBind(h Helper) ([]ConfigValue, error) {
58 var lnHosts []string
59 for h.Next() {
@@ -65,28 +64,28 @@ func parseBind(h Helper) ([]ConfigValue, error) {
64
65 // parseTLS parses the tls directive. Syntax:
66 //
68 -// tls [<email>|internal]|[<cert_file> <key_file>] {
69 -// protocols <min> [<max>]
70 -// ciphers <cipher_suites...>
71 -// curves <curves...>
72 -// client_auth {
73 -// mode [request|require|verify_if_given|require_and_verify]
74 -// trusted_ca_cert <base64_der>
75 -// trusted_ca_cert_file <filename>
76 -// trusted_leaf_cert <base64_der>
77 -// trusted_leaf_cert_file <filename>
78 -// }
79 -// alpn <values...>
80 -// load <paths...>
81 -// ca <acme_ca_endpoint>
82 -// ca_root <pem_file>
83 -// dns <provider_name> [...]
84 -// on_demand
85 -// eab <key_id> <mac_key>
86 -// issuer <module_name> [...]
87 -// get_certificate <module_name> [...]
88 -// }
89 -//
67 +// tls [<email>|internal]|[<cert_file> <key_file>] {
68 +// protocols <min> [<max>]
69 +// ciphers <cipher_suites...>
70 +// curves <curves...>
71 +// client_auth {
72 +// mode [request|require|verify_if_given|require_and_verify]
73 +// trusted_ca_cert <base64_der>
74 +// trusted_ca_cert_file <filename>
75 +// trusted_leaf_cert <base64_der>
76 +// trusted_leaf_cert_file <filename>
77 +// }
78 +// alpn <values...>
79 +// load <paths...>
80 +// ca <acme_ca_endpoint>
81 +// ca_root <pem_file>
82 +// dns <provider_name> [...]
83 +// on_demand
84 +// eab <key_id> <mac_key>
85 +// issuer <module_name> [...]
86 +// get_certificate <module_name> [...]
87 +// insecure_secrets_log <log_file>
88 +// }
89 func parseTLS(h Helper) ([]ConfigValue, error) {
90 cp := new(caddytls.ConnectionPolicy)
91 var fileLoader caddytls.FileLoader
@@ -396,6 +395,12 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
395 }
396 onDemand = true
397
398 + case "insecure_secrets_log":
399 + if !h.NextArg() {
400 + return nil, h.ArgErr()
401 + }
402 + cp.InsecureSecretsLog = h.Val()
403 +
404 default:
405 return nil, h.Errf("unknown subdirective: %s", h.Val())
406 }
@@ -516,8 +521,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
521
522 // parseRoot parses the root directive. Syntax:
523 //
519 -// root [<matcher>] <path>
520 -//
524 +// root [<matcher>] <path>
525 func parseRoot(h Helper) (caddyhttp.MiddlewareHandler, error) {
526 var root string
527 for h.Next() {
@@ -695,12 +699,11 @@ func parseHandleErrors(h Helper) ([]ConfigValue, error) {
699
700 // parseLog parses the log directive. Syntax:
701 //
698 -// log {
699 -// output <writer_module> ...
700 -// format <encoder_module> ...
701 -// level <level>
702 -// }
703 -//
702 +// log {
703 +// output <writer_module> ...
704 +// format <encoder_module> ...
705 +// level <level>
706 +// }
707 func parseLog(h Helper) ([]ConfigValue, error) {
708 return parseLogHelper(h, nil)
709 }
caddyconfig/httpcaddyfile/options.go
+7 -7
@@ -421,13 +421,13 @@ func parseOCSPStaplingOptions(d *caddyfile.Dispenser, _ any) (any, error) {
421
422 // parseLogOptions parses the global log option. Syntax:
423 //
424 -// log [name] {
425 -// output <writer_module> ...
426 -// format <encoder_module> ...
427 -// level <level>
428 -// include <namespaces...>
429 -// exclude <namespaces...>
430 -// }
424 +// log [name] {
425 +// output <writer_module> ...
426 +// format <encoder_module> ...
427 +// level <level>
428 +// include <namespaces...>
429 +// exclude <namespaces...>
430 +// }
431 //
432 // When the name argument is unspecified, this directive modifies the default
433 // logger.
modules/caddytls/connpolicy.go
+45 -1
@@ -20,11 +20,14 @@ import (
20 "encoding/base64"
21 "encoding/json"
22 "fmt"
23 + "io"
24 "os"
25 + "path/filepath"
26 "strings"
27
28 "github.com/caddyserver/caddy/v2"
29 "github.com/mholt/acmez"
30 + "go.uber.org/zap"
31 )
32
33 func init() {
@@ -156,6 +159,16 @@ type ConnectionPolicy struct {
159 // is no policy configured for the empty SNI value.
160 DefaultSNI string `json:"default_sni,omitempty"`
161
162 + // Also known as "SSLKEYLOGFILE", TLS secrets will be written to
163 + // this file in NSS key log format which can then be parsed by
164 + // Wireshark and other tools. This is INSECURE as it allows other
165 + // programs or tools to decrypt TLS connections. However, this
166 + // capability can be useful for debugging and troubleshooting.
167 + // **ENABLING THIS LOG COMPROMISES SECURITY!**
168 + //
169 + // This feature is EXPERIMENTAL and subject to change or removal.
170 + InsecureSecretsLog string `json:"insecure_secrets_log,omitempty"`
171 +
172 // TLSConfig is the fully-formed, standard lib TLS config
173 // used to serve TLS connections. Provision all
174 // ConnectionPolicies to populate this. It is exported only
@@ -280,6 +293,30 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
293 }
294 }
295
296 + if p.InsecureSecretsLog != "" {
297 + filename, err := caddy.NewReplacer().ReplaceOrErr(p.InsecureSecretsLog, true, true)
298 + if err != nil {
299 + return err
300 + }
301 + filename, err = filepath.Abs(filename)
302 + if err != nil {
303 + return err
304 + }
305 + logFile, _, err := secretsLogPool.LoadOrNew(filename, func() (caddy.Destructor, error) {
306 + w, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
307 + return destructableWriter{w}, err
308 + })
309 + if err != nil {
310 + return err
311 + }
312 + ctx.OnCancel(func() { _, _ = secretsLogPool.Delete(filename) })
313 +
314 + cfg.KeyLogWriter = logFile.(io.Writer)
315 +
316 + tlsApp.logger.Warn("TLS SECURITY COMPROMISED: secrets logging is enabled!",
317 + zap.String("log_filename", filename))
318 + }
319 +
320 setDefaultTLSParams(cfg)
321
322 p.TLSConfig = cfg
@@ -297,7 +334,8 @@ func (p ConnectionPolicy) SettingsEmpty() bool {
334 p.ProtocolMin == "" &&
335 p.ProtocolMax == "" &&
336 p.ClientAuthentication == nil &&
300 - p.DefaultSNI == ""
337 + p.DefaultSNI == "" &&
338 + p.InsecureSecretsLog == ""
339 }
340
341 // ClientAuthentication configures TLS client auth.
@@ -542,3 +580,9 @@ type ClientCertificateVerifier interface {
580 }
581
582 var defaultALPN = []string{"h2", "http/1.1"}
583 +
584 +type destructableWriter struct{ *os.File }
585 +
586 +func (d destructableWriter) Destruct() error { return d.Close() }
587 +
588 +var secretsLogPool = caddy.NewUsagePool()