From ca34a3e1aa21c767322f9275c2281df96a3eb402 Mon Sep 17 00:00:00 2001 From: David Somers Date: Sun, 18 Mar 2018 00:27:10 +0100 Subject: [PATCH] httpserver: Placeholders for tls_protocol and tls_cipher (#2062) Also add SSL_PROTOCOL and SSL_CIPHER env vars for fastcgi. * Implement placeholders for ssl_protocol and ssl_cipher * gofmt * goimports * Housekeeping and implement as {tls_protocol} and {tls_cipher} --- caddyhttp/fastcgi/fastcgi.go | 24 ++++++++++++++++++++++++ caddyhttp/httpserver/replacer.go | 21 +++++++++++++++++++++ caddytls/config.go | 5 +++-- caddytls/setup.go | 8 ++++---- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/caddyhttp/fastcgi/fastcgi.go b/caddyhttp/fastcgi/fastcgi.go index 28ea55f9f..54eb4e36c 100644 --- a/caddyhttp/fastcgi/fastcgi.go +++ b/caddyhttp/fastcgi/fastcgi.go @@ -33,8 +33,11 @@ import ( "sync/atomic" "time" + "crypto/tls" + "github.com/mholt/caddy" "github.com/mholt/caddy/caddyhttp/httpserver" + "github.com/mholt/caddy/caddytls" ) // Handler is a middleware type that can handle requests as a FastCGI client. @@ -323,6 +326,19 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string] // Some web apps rely on knowing HTTPS or not if r.TLS != nil { env["HTTPS"] = "on" + // and pass the protocol details in a manner compatible with apache's mod_ssl + // (which is why they have a SSL_ prefix and not TLS_). + v, ok := tlsProtocolStringToMap[r.TLS.Version] + if ok { + env["SSL_PROTOCOL"] = v + } + // and pass the cipher suite in a manner compatible with apache's mod_ssl + for k, v := range caddytls.SupportedCiphersMap { + if v == r.TLS.CipherSuite { + env["SSL_CIPHER"] = k + break + } + } } // Add env variables from config (with support for placeholders in values) @@ -465,3 +481,11 @@ type LogError string func (l LogError) Error() string { return string(l) } + +// Map of supported protocols to Apache ssl_mod format +// Note that these are slightly different from SupportedProtocols in caddytls/config.go's +var tlsProtocolStringToMap = map[uint16]string{ + tls.VersionTLS10: "TLSv1", + tls.VersionTLS11: "TLSv1.1", + tls.VersionTLS12: "TLSv1.2", +} diff --git a/caddyhttp/httpserver/replacer.go b/caddyhttp/httpserver/replacer.go index 211c09466..f8c4f8d17 100644 --- a/caddyhttp/httpserver/replacer.go +++ b/caddyhttp/httpserver/replacer.go @@ -29,6 +29,7 @@ import ( "time" "github.com/mholt/caddy" + "github.com/mholt/caddy/caddytls" ) // requestReplacer is a strings.Replacer which is used to @@ -375,6 +376,26 @@ func (r *replacer) getSubstitution(key string) string { } elapsedDuration := time.Since(r.responseRecorder.start) return strconv.FormatInt(convertToMilliseconds(elapsedDuration), 10) + case "{tls_protocol}": + if r.request.TLS != nil { + for k, v := range caddytls.SupportedProtocols { + if v == r.request.TLS.Version { + return k + } + } + return "tls" // this should never happen, but guard in case + } + return r.emptyValue // because not using a secure channel + case "{tls_cipher}": + if r.request.TLS != nil { + for k, v := range caddytls.SupportedCiphersMap { + if v == r.request.TLS.CipherSuite { + return k + } + } + return "UNKNOWN" // this should never happen, but guard in case + } + return r.emptyValue } return r.emptyValue diff --git a/caddytls/config.go b/caddytls/config.go index 43956a253..56dc94bcf 100644 --- a/caddytls/config.go +++ b/caddytls/config.go @@ -532,7 +532,8 @@ var supportedKeyTypes = map[string]acme.KeyType{ // Map of supported protocols. // HTTP/2 only supports TLS 1.2 and higher. -var supportedProtocols = map[string]uint16{ +// If updating this map, also update tlsProtocolStringToMap in caddyhttp/fastcgi/fastcgi.go +var SupportedProtocols = map[string]uint16{ "tls1.0": tls.VersionTLS10, "tls1.1": tls.VersionTLS11, "tls1.2": tls.VersionTLS12, @@ -548,7 +549,7 @@ var supportedProtocols = map[string]uint16{ // it is always added (even though it is not technically a cipher suite). // // This map, like any map, is NOT ORDERED. Do not range over this map. -var supportedCiphersMap = map[string]uint16{ +var SupportedCiphersMap = map[string]uint16{ "ECDHE-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "ECDHE-RSA-AES256-GCM-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, diff --git a/caddytls/setup.go b/caddytls/setup.go index 63c2a9e6d..1b8c79bee 100644 --- a/caddytls/setup.go +++ b/caddytls/setup.go @@ -106,19 +106,19 @@ func setupTLS(c *caddy.Controller) error { case "protocols": args := c.RemainingArgs() if len(args) == 1 { - value, ok := supportedProtocols[strings.ToLower(args[0])] + value, ok := SupportedProtocols[strings.ToLower(args[0])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0]) } config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value } else { - value, ok := supportedProtocols[strings.ToLower(args[0])] + value, ok := SupportedProtocols[strings.ToLower(args[0])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0]) } config.ProtocolMinVersion = value - value, ok = supportedProtocols[strings.ToLower(args[1])] + value, ok = SupportedProtocols[strings.ToLower(args[1])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1]) } @@ -129,7 +129,7 @@ func setupTLS(c *caddy.Controller) error { } case "ciphers": for c.NextArg() { - value, ok := supportedCiphersMap[strings.ToUpper(c.Val())] + value, ok := SupportedCiphersMap[strings.ToUpper(c.Val())] if !ok { return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val()) }