mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Merge pull request #78 from guilhermebr/master
tls: Optional block for ciphers, protocols and cache options
This commit is contained in:
commit
9c039474b3
4 changed files with 222 additions and 7 deletions
|
@ -1,10 +1,38 @@
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mholt/caddy/middleware"
|
"crypto/tls"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mholt/caddy/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Map of supported protocols
|
||||||
|
// SSLv3 will be not supported in next release
|
||||||
|
var supportedProtocols = map[string]uint16{
|
||||||
|
"ssl3.0": tls.VersionSSL30,
|
||||||
|
"tls1.0": tls.VersionTLS10,
|
||||||
|
"tls1.1": tls.VersionTLS11,
|
||||||
|
"tls1.2": tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of supported ciphers
|
||||||
|
// For security reasons caddy will not support RC4 ciphers
|
||||||
|
var supportedCiphers = map[string]uint16{
|
||||||
|
"ECDHE-RSA-AES128-GCM-SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"ECDHE-RSA-AES128-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"ECDHE-RSA-AES256-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"ECDHE-ECDSA-AES256-CBC-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"ECDHE-ECDSA-AES128-CBC-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"RSA-AES128-CBC-SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"RSA-AES256-CBC-SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"ECDHE-RSA-3DES-EDE-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
"RSA-3DES-EDE-CBC-SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
}
|
||||||
|
|
||||||
func TLS(c *Controller) (middleware.Middleware, error) {
|
func TLS(c *Controller) (middleware.Middleware, error) {
|
||||||
c.TLS.Enabled = true
|
c.TLS.Enabled = true
|
||||||
if c.Port == "http" {
|
if c.Port == "http" {
|
||||||
|
@ -12,7 +40,7 @@ func TLS(c *Controller) (middleware.Middleware, error) {
|
||||||
log.Printf("Warning: TLS was disabled on host http://%s."+
|
log.Printf("Warning: TLS was disabled on host http://%s."+
|
||||||
" Make sure you are specifying https://%s in your config (if you haven't already)."+
|
" Make sure you are specifying https://%s in your config (if you haven't already)."+
|
||||||
" If you meant to serve tls on port 80,"+
|
" If you meant to serve tls on port 80,"+
|
||||||
" specify port 80 in your config (http://%s:80).", c.Host, c.Host, c.Host)
|
" specify port 80 in your config (https://%s:80).", c.Host, c.Host, c.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
for c.Next() {
|
for c.Next() {
|
||||||
|
@ -25,6 +53,69 @@ func TLS(c *Controller) (middleware.Middleware, error) {
|
||||||
return nil, c.ArgErr()
|
return nil, c.ArgErr()
|
||||||
}
|
}
|
||||||
c.TLS.Key = c.Val()
|
c.TLS.Key = c.Val()
|
||||||
|
|
||||||
|
// Optional block
|
||||||
|
for c.NextBlock() {
|
||||||
|
switch c.Val() {
|
||||||
|
case "protocols":
|
||||||
|
args := c.RemainingArgs()
|
||||||
|
if len(args) != 2 {
|
||||||
|
return nil, c.ArgErr()
|
||||||
|
}
|
||||||
|
value, ok := supportedProtocols[strings.ToLower(args[0])]
|
||||||
|
if !ok {
|
||||||
|
return nil, c.Errf("Wrong protocol name or protocol not supported '%s'", c.Val())
|
||||||
|
|
||||||
|
}
|
||||||
|
c.TLS.ProtocolMinVersion = value
|
||||||
|
value, ok = supportedProtocols[strings.ToLower(args[1])]
|
||||||
|
if !ok {
|
||||||
|
return nil, c.Errf("Wrong protocol name or protocol not supported '%s'", c.Val())
|
||||||
|
}
|
||||||
|
c.TLS.ProtocolMaxVersion = value
|
||||||
|
case "ciphers":
|
||||||
|
for c.NextArg() {
|
||||||
|
value, ok := supportedCiphers[strings.ToUpper(c.Val())]
|
||||||
|
if !ok {
|
||||||
|
return nil, c.Errf("Wrong cipher name or cipher not supported '%s'", c.Val())
|
||||||
|
}
|
||||||
|
c.TLS.Ciphers = append(c.TLS.Ciphers, value)
|
||||||
|
}
|
||||||
|
case "cache":
|
||||||
|
if !c.NextArg() {
|
||||||
|
return nil, c.ArgErr()
|
||||||
|
}
|
||||||
|
size, err := strconv.Atoi(c.Val())
|
||||||
|
if err != nil {
|
||||||
|
return nil, c.Errf("Cache parameter should be an number '%s': %v", c.Val(), err)
|
||||||
|
}
|
||||||
|
c.TLS.CacheSize = size
|
||||||
|
default:
|
||||||
|
return nil, c.Errf("Unknown keyword '%s'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no Ciphers provided, use all caddy supportedCiphers
|
||||||
|
if len(c.TLS.Ciphers) == 0 {
|
||||||
|
for _, v := range supportedCiphers {
|
||||||
|
c.TLS.Ciphers = append(c.TLS.Ciphers, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no ProtocolMin provided, set default MinVersion to TLSv1.1 for security reasons
|
||||||
|
if c.TLS.ProtocolMinVersion == 0 {
|
||||||
|
c.TLS.ProtocolMinVersion = tls.VersionTLS11
|
||||||
|
}
|
||||||
|
|
||||||
|
//If no ProtocolMax provided, use crypto/tls default MaxVersion(tls1.2)
|
||||||
|
if c.TLS.ProtocolMaxVersion == 0 {
|
||||||
|
c.TLS.ProtocolMaxVersion = tls.VersionTLS12
|
||||||
|
}
|
||||||
|
|
||||||
|
//If no cachesize provided, set default to 64
|
||||||
|
if c.TLS.CacheSize == 0 {
|
||||||
|
c.TLS.CacheSize = 64
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
109
config/setup/tls_test.go
Normal file
109
config/setup/tls_test.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTLSParseNoOptional(t *testing.T) {
|
||||||
|
c := newTestController(`tls cert.crt cert.key`)
|
||||||
|
|
||||||
|
_, err := TLS(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no errors, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.TLS.Ciphers) != len(supportedCiphers) {
|
||||||
|
t.Errorf("Expected %v Ciphers, got %v", len(supportedCiphers), len(c.TLS.Ciphers))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.ProtocolMinVersion != tls.VersionTLS11 {
|
||||||
|
t.Errorf("Expected 'tls1.1 (0x0302)' as ProtocolMinVersion, got %#v", c.TLS.ProtocolMinVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.ProtocolMaxVersion != tls.VersionTLS12 {
|
||||||
|
t.Errorf("Expected 'tls1.2 (0x0303)' as ProtocolMaxVersion, got %v", c.TLS.ProtocolMaxVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.CacheSize != 64 {
|
||||||
|
t.Errorf("Expected CacheSize 64, got %v", c.TLS.CacheSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTLSParseIncompleteParams(t *testing.T) {
|
||||||
|
c := newTestController(`tls`)
|
||||||
|
|
||||||
|
_, err := TLS(c)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected errors, but no error returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
c = newTestController(`tls cert.key`)
|
||||||
|
|
||||||
|
_, err = TLS(c)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected errors, but no error returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTLSParseWithOptionalParams(t *testing.T) {
|
||||||
|
params := `tls cert.crt cert.key {
|
||||||
|
protocols ssl3.0 tls1.2
|
||||||
|
ciphers RSA-3DES-EDE-CBC-SHA RSA-AES256-CBC-SHA ECDHE-RSA-AES128-GCM-SHA256
|
||||||
|
cache 128
|
||||||
|
}`
|
||||||
|
c := newTestController(params)
|
||||||
|
|
||||||
|
_, err := TLS(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no errors, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.ProtocolMinVersion != tls.VersionSSL30 {
|
||||||
|
t.Errorf("Expected 'ssl3.0 (0x0300)' as ProtocolMinVersion, got %#v", c.TLS.ProtocolMinVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.ProtocolMaxVersion != tls.VersionTLS12 {
|
||||||
|
t.Errorf("Expected 'tls1.2 (0x0302)' as ProtocolMaxVersion, got %#v", c.TLS.ProtocolMaxVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.TLS.Ciphers) != 3 {
|
||||||
|
t.Errorf("Expected 3 Ciphers, got %v", len(c.TLS.Ciphers))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLS.CacheSize != 128 {
|
||||||
|
t.Errorf("Expected CacheSize 128, got %v", c.TLS.CacheSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTLSParseWithWrongOptionalParams(t *testing.T) {
|
||||||
|
params := `tls cert.crt cert.key {
|
||||||
|
cache a
|
||||||
|
}`
|
||||||
|
c := newTestController(params)
|
||||||
|
_, err := TLS(c)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected errors, but no error returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test protocols wrong params
|
||||||
|
params = `tls cert.crt cert.key {
|
||||||
|
protocols ssl tls
|
||||||
|
}`
|
||||||
|
c = newTestController(params)
|
||||||
|
_, err = TLS(c)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected errors, but no error returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test ciphers wrong params
|
||||||
|
params = `tls cert.crt cert.key {
|
||||||
|
ciphers not-valid-cipher
|
||||||
|
}`
|
||||||
|
c = newTestController(params)
|
||||||
|
_, err = TLS(c)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected errors, but no error returned")
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,8 +55,13 @@ func (c Config) Address() string {
|
||||||
|
|
||||||
// TLSConfig describes how TLS should be configured and used,
|
// TLSConfig describes how TLS should be configured and used,
|
||||||
// if at all. A certificate and key are both required.
|
// if at all. A certificate and key are both required.
|
||||||
|
// Ciphers, Protocols and CacheSize are optional
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Certificate string
|
Certificate string
|
||||||
Key string
|
Key string
|
||||||
|
Ciphers []uint16
|
||||||
|
ProtocolMinVersion uint16
|
||||||
|
ProtocolMaxVersion uint16
|
||||||
|
CacheSize int
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,8 +132,18 @@ func ListenAndServeTLSWithSNI(srv *http.Server, tlsConfigs []TLSConfig) error {
|
||||||
}
|
}
|
||||||
config.BuildNameToCertificate()
|
config.BuildNameToCertificate()
|
||||||
|
|
||||||
// Add a session cache LRU algorithm with default capacity (64)
|
// Here we change some crypto/tls defaults based on caddyfile
|
||||||
config.ClientSessionCache = tls.NewLRUClientSessionCache(0)
|
// If no config provided, we set defaults focused in security
|
||||||
|
|
||||||
|
// Add a session cache LRU algorithm
|
||||||
|
config.ClientSessionCache = tls.NewLRUClientSessionCache(tlsConfigs[0].CacheSize)
|
||||||
|
|
||||||
|
config.MinVersion = tlsConfigs[0].ProtocolMinVersion
|
||||||
|
config.MaxVersion = tlsConfigs[0].ProtocolMaxVersion
|
||||||
|
config.CipherSuites = tlsConfigs[0].Ciphers
|
||||||
|
|
||||||
|
// Server ciphers have priority over client ciphers
|
||||||
|
config.PreferServerCipherSuites = true
|
||||||
|
|
||||||
conn, err := net.Listen("tcp", addr)
|
conn, err := net.Listen("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue