mirror of
https://github.com/caddyserver/caddy.git
synced 2025-03-21 12:59:26 +01:00
- Server types no longer need to store their own contexts; they are stored on the caddy.Instance, which means each context will be properly GC'ed when the instance is stopped. Server types should use type assertions to convert from caddy.Context to their concrete context type when they need to use it. - Pass the entire context into httpserver.GetConfig instead of only the Key field. - caddy.NewTestController now requires a server type string so it can create a controller with the proper concrete context associated with that server type. Tests still need more attention so that we can test the proper creation of startup functions, etc.
298 lines
8.7 KiB
Go
298 lines
8.7 KiB
Go
package caddytls
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/mholt/caddy"
|
|
"github.com/xenolf/lego/acme"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
// Write test certificates to disk before tests, and clean up
|
|
// when we're done.
|
|
err := ioutil.WriteFile(certFile, testCert, 0644)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
err = ioutil.WriteFile(keyFile, testKey, 0644)
|
|
if err != nil {
|
|
os.Remove(certFile)
|
|
log.Fatal(err)
|
|
}
|
|
|
|
result := m.Run()
|
|
|
|
os.Remove(certFile)
|
|
os.Remove(keyFile)
|
|
os.Exit(result)
|
|
}
|
|
|
|
func TestSetupParseBasic(t *testing.T) {
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", `tls `+certFile+` `+keyFile+``)
|
|
|
|
err := setupTLS(c)
|
|
if err != nil {
|
|
t.Errorf("Expected no errors, got: %v", err)
|
|
}
|
|
|
|
// Basic checks
|
|
if !cfg.Manual {
|
|
t.Error("Expected TLS Manual=true, but was false")
|
|
}
|
|
if !cfg.Enabled {
|
|
t.Error("Expected TLS Enabled=true, but was false")
|
|
}
|
|
|
|
// Security defaults
|
|
if cfg.ProtocolMinVersion != tls.VersionTLS11 {
|
|
t.Errorf("Expected 'tls1.1 (0x0302)' as ProtocolMinVersion, got %#v", cfg.ProtocolMinVersion)
|
|
}
|
|
if cfg.ProtocolMaxVersion != tls.VersionTLS12 {
|
|
t.Errorf("Expected 'tls1.2 (0x0303)' as ProtocolMaxVersion, got %v", cfg.ProtocolMaxVersion)
|
|
}
|
|
|
|
// Cipher checks
|
|
expectedCiphers := []uint16{
|
|
tls.TLS_FALLBACK_SCSV,
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
|
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
}
|
|
|
|
// Ensure count is correct (plus one for TLS_FALLBACK_SCSV)
|
|
if len(cfg.Ciphers) != len(expectedCiphers) {
|
|
t.Errorf("Expected %v Ciphers (including TLS_FALLBACK_SCSV), got %v",
|
|
len(expectedCiphers), len(cfg.Ciphers))
|
|
}
|
|
|
|
// Ensure ordering is correct
|
|
for i, actual := range cfg.Ciphers {
|
|
if actual != expectedCiphers[i] {
|
|
t.Errorf("Expected cipher in position %d to be %0x, got %0x", i, expectedCiphers[i], actual)
|
|
}
|
|
}
|
|
|
|
if !cfg.PreferServerCipherSuites {
|
|
t.Error("Expected PreferServerCipherSuites = true, but was false")
|
|
}
|
|
}
|
|
|
|
func TestSetupParseIncompleteParams(t *testing.T) {
|
|
// Using tls without args is an error because it's unnecessary.
|
|
c := caddy.NewTestController("http", `tls`)
|
|
err := setupTLS(c)
|
|
if err == nil {
|
|
t.Error("Expected an error, but didn't get one")
|
|
}
|
|
}
|
|
|
|
func TestSetupParseWithOptionalParams(t *testing.T) {
|
|
params := `tls ` + certFile + ` ` + keyFile + ` {
|
|
protocols tls1.0 tls1.2
|
|
ciphers RSA-AES256-CBC-SHA ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384
|
|
}`
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", params)
|
|
|
|
err := setupTLS(c)
|
|
if err != nil {
|
|
t.Errorf("Expected no errors, got: %v", err)
|
|
}
|
|
|
|
if cfg.ProtocolMinVersion != tls.VersionTLS10 {
|
|
t.Errorf("Expected 'tls1.0 (0x0301)' as ProtocolMinVersion, got %#v", cfg.ProtocolMinVersion)
|
|
}
|
|
|
|
if cfg.ProtocolMaxVersion != tls.VersionTLS12 {
|
|
t.Errorf("Expected 'tls1.2 (0x0303)' as ProtocolMaxVersion, got %#v", cfg.ProtocolMaxVersion)
|
|
}
|
|
|
|
if len(cfg.Ciphers)-1 != 3 {
|
|
t.Errorf("Expected 3 Ciphers (not including TLS_FALLBACK_SCSV), got %v", len(cfg.Ciphers)-1)
|
|
}
|
|
}
|
|
|
|
func TestSetupDefaultWithOptionalParams(t *testing.T) {
|
|
params := `tls {
|
|
ciphers RSA-3DES-EDE-CBC-SHA
|
|
}`
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", params)
|
|
|
|
err := setupTLS(c)
|
|
if err != nil {
|
|
t.Errorf("Expected no errors, got: %v", err)
|
|
}
|
|
if len(cfg.Ciphers)-1 != 1 {
|
|
t.Errorf("Expected 1 ciphers (not including TLS_FALLBACK_SCSV), got %v", len(cfg.Ciphers)-1)
|
|
}
|
|
}
|
|
|
|
func TestSetupParseWithWrongOptionalParams(t *testing.T) {
|
|
// Test protocols wrong params
|
|
params := `tls ` + certFile + ` ` + keyFile + ` {
|
|
protocols ssl tls
|
|
}`
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", params)
|
|
err := setupTLS(c)
|
|
if err == nil {
|
|
t.Errorf("Expected errors, but no error returned")
|
|
}
|
|
|
|
// Test ciphers wrong params
|
|
params = `tls ` + certFile + ` ` + keyFile + ` {
|
|
ciphers not-valid-cipher
|
|
}`
|
|
cfg = new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c = caddy.NewTestController("http", params)
|
|
err = setupTLS(c)
|
|
if err == nil {
|
|
t.Errorf("Expected errors, but no error returned")
|
|
}
|
|
|
|
// Test key_type wrong params
|
|
params = `tls {
|
|
key_type ab123
|
|
}`
|
|
cfg = new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c = caddy.NewTestController("http", params)
|
|
err = setupTLS(c)
|
|
if err == nil {
|
|
t.Errorf("Expected errors, but no error returned")
|
|
}
|
|
}
|
|
|
|
func TestSetupParseWithClientAuth(t *testing.T) {
|
|
// Test missing client cert file
|
|
params := `tls ` + certFile + ` ` + keyFile + ` {
|
|
clients
|
|
}`
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", params)
|
|
err := setupTLS(c)
|
|
if err == nil {
|
|
t.Errorf("Expected an error, but no error returned")
|
|
}
|
|
|
|
noCAs, twoCAs := []string{}, []string{"client_ca.crt", "client2_ca.crt"}
|
|
for caseNumber, caseData := range []struct {
|
|
params string
|
|
clientAuthType tls.ClientAuthType
|
|
expectedErr bool
|
|
expectedCAs []string
|
|
}{
|
|
{"", tls.NoClientCert, false, noCAs},
|
|
{`tls ` + certFile + ` ` + keyFile + ` {
|
|
clients client_ca.crt client2_ca.crt
|
|
}`, tls.RequireAndVerifyClientCert, false, twoCAs},
|
|
// now come modifier
|
|
{`tls ` + certFile + ` ` + keyFile + ` {
|
|
clients request
|
|
}`, tls.RequestClientCert, false, noCAs},
|
|
{`tls ` + certFile + ` ` + keyFile + ` {
|
|
clients require
|
|
}`, tls.RequireAnyClientCert, false, noCAs},
|
|
{`tls ` + certFile + ` ` + keyFile + ` {
|
|
clients verify_if_given client_ca.crt client2_ca.crt
|
|
}`, tls.VerifyClientCertIfGiven, false, twoCAs},
|
|
{`tls ` + certFile + ` ` + keyFile + ` {
|
|
clients verify_if_given
|
|
}`, tls.VerifyClientCertIfGiven, true, noCAs},
|
|
} {
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", caseData.params)
|
|
err := setupTLS(c)
|
|
if caseData.expectedErr {
|
|
if err == nil {
|
|
t.Errorf("In case %d: Expected an error, got: %v", caseNumber, err)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("In case %d: Expected no errors, got: %v", caseNumber, err)
|
|
}
|
|
|
|
if caseData.clientAuthType != cfg.ClientAuth {
|
|
t.Errorf("In case %d: Expected TLS client auth type %v, got: %v",
|
|
caseNumber, caseData.clientAuthType, cfg.ClientAuth)
|
|
}
|
|
|
|
if count := len(cfg.ClientCerts); count < len(caseData.expectedCAs) {
|
|
t.Fatalf("In case %d: Expected %d client certs, had %d", caseNumber, len(caseData.expectedCAs), count)
|
|
}
|
|
|
|
for idx, expected := range caseData.expectedCAs {
|
|
if actual := cfg.ClientCerts[idx]; actual != expected {
|
|
t.Errorf("In case %d: Expected %dth client cert file to be '%s', but was '%s'",
|
|
caseNumber, idx, expected, actual)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSetupParseWithKeyType(t *testing.T) {
|
|
params := `tls {
|
|
key_type p384
|
|
}`
|
|
cfg := new(Config)
|
|
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
|
c := caddy.NewTestController("http", params)
|
|
|
|
err := setupTLS(c)
|
|
if err != nil {
|
|
t.Errorf("Expected no errors, got: %v", err)
|
|
}
|
|
|
|
if cfg.KeyType != acme.EC384 {
|
|
t.Errorf("Expected 'P384' as KeyType, got %#v", cfg.KeyType)
|
|
}
|
|
}
|
|
|
|
const (
|
|
certFile = "test_cert.pem"
|
|
keyFile = "test_key.pem"
|
|
)
|
|
|
|
var testCert = []byte(`-----BEGIN CERTIFICATE-----
|
|
MIIBkjCCATmgAwIBAgIJANfFCBcABL6LMAkGByqGSM49BAEwFDESMBAGA1UEAxMJ
|
|
bG9jYWxob3N0MB4XDTE2MDIxMDIyMjAyNFoXDTE4MDIwOTIyMjAyNFowFDESMBAG
|
|
A1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEs22MtnG7
|
|
9K1mvIyjEO9GLx7BFD0tBbGnwQ0VPsuCxC6IeVuXbQDLSiVQvFZ6lUszTlczNxVk
|
|
pEfqrM6xAupB7qN1MHMwHQYDVR0OBBYEFHxYDvAxUwL4XrjPev6qZ/BiLDs5MEQG
|
|
A1UdIwQ9MDuAFHxYDvAxUwL4XrjPev6qZ/BiLDs5oRikFjAUMRIwEAYDVQQDEwls
|
|
b2NhbGhvc3SCCQDXxQgXAAS+izAMBgNVHRMEBTADAQH/MAkGByqGSM49BAEDSAAw
|
|
RQIgRvBqbyJM2JCJqhA1FmcoZjeMocmhxQHTt1c+1N2wFUgCIQDtvrivbBPA688N
|
|
Qh3sMeAKNKPsx5NxYdoWuu9KWcKz9A==
|
|
-----END CERTIFICATE-----
|
|
`)
|
|
|
|
var testKey = []byte(`-----BEGIN EC PARAMETERS-----
|
|
BggqhkjOPQMBBw==
|
|
-----END EC PARAMETERS-----
|
|
-----BEGIN EC PRIVATE KEY-----
|
|
MHcCAQEEIGLtRmwzYVcrH3J0BnzYbGPdWVF10i9p6mxkA4+b2fURoAoGCCqGSM49
|
|
AwEHoUQDQgAEs22MtnG79K1mvIyjEO9GLx7BFD0tBbGnwQ0VPsuCxC6IeVuXbQDL
|
|
SiVQvFZ6lUszTlczNxVkpEfqrM6xAupB7g==
|
|
-----END EC PRIVATE KEY-----
|
|
`)
|