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
|
||||
|
||||
import (
|
||||
"github.com/mholt/caddy/middleware"
|
||||
"crypto/tls"
|
||||
"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) {
|
||||
c.TLS.Enabled = true
|
||||
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."+
|
||||
" Make sure you are specifying https://%s in your config (if you haven't already)."+
|
||||
" 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() {
|
||||
|
@ -25,6 +53,69 @@ func TLS(c *Controller) (middleware.Middleware, error) {
|
|||
return nil, c.ArgErr()
|
||||
}
|
||||
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
|
||||
|
|
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,
|
||||
// if at all. A certificate and key are both required.
|
||||
// Ciphers, Protocols and CacheSize are optional
|
||||
type TLSConfig struct {
|
||||
Enabled bool
|
||||
Certificate 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()
|
||||
|
||||
// Add a session cache LRU algorithm with default capacity (64)
|
||||
config.ClientSessionCache = tls.NewLRUClientSessionCache(0)
|
||||
// Here we change some crypto/tls defaults based on caddyfile
|
||||
// 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)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue