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()