mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-23 09:06:29 +01:00
tls: Per-site TLS configs using GetClientConfig, including http2 switch (#1389)
* Remove manual TLS clone method * WiP tls * Use GetClientConfig for tls.Config * gofmt -s -w * GetConfig * Handshake * Removed comment * Disable HTTP2 on demand * Remove junk * Remove http2 enable (no-op)
This commit is contained in:
parent
977a3c3226
commit
286d8d1e89
8 changed files with 190 additions and 206 deletions
|
@ -31,6 +31,7 @@ type Server struct {
|
|||
connTimeout time.Duration // max time to wait for a connection before force stop
|
||||
tlsGovChan chan struct{} // close to stop the TLS maintenance goroutine
|
||||
vhosts *vhostTrie
|
||||
tlsConfig caddytls.ConfigGroup
|
||||
}
|
||||
|
||||
// ensure it satisfies the interface
|
||||
|
@ -72,16 +73,31 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) {
|
|||
}
|
||||
|
||||
// Set up TLS configuration
|
||||
var tlsConfigs []*caddytls.Config
|
||||
tlsConfigs := make(caddytls.ConfigGroup)
|
||||
var allConfigs []*caddytls.Config
|
||||
|
||||
for _, site := range group {
|
||||
tlsConfigs = append(tlsConfigs, site.TLS)
|
||||
|
||||
if err := site.TLS.Build(tlsConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfigs[site.TLS.Hostname] = site.TLS
|
||||
allConfigs = append(allConfigs, site.TLS)
|
||||
}
|
||||
var err error
|
||||
s.Server.TLSConfig, err = caddytls.MakeTLSConfig(tlsConfigs)
|
||||
if err != nil {
|
||||
|
||||
// Check if configs are valid
|
||||
if err := caddytls.CheckConfigs(allConfigs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.tlsConfig = tlsConfigs
|
||||
|
||||
s.Server.TLSConfig = &tls.Config{
|
||||
GetConfigForClient: s.tlsConfig.GetConfigForClient,
|
||||
GetCertificate: s.tlsConfig.GetCertificate,
|
||||
}
|
||||
|
||||
// As of Go 1.7, HTTP/2 is enabled only if NextProtos includes the string "h2"
|
||||
if HTTP2 && s.Server.TLSConfig != nil && len(s.Server.TLSConfig.NextProtos) == 0 {
|
||||
s.Server.TLSConfig.NextProtos = []string{"h2"}
|
||||
|
|
|
@ -442,7 +442,7 @@ func newConnHijackerTransport(base http.RoundTripper) *connHijackerTransport {
|
|||
if b, _ := base.(*http.Transport); b != nil {
|
||||
tlsClientConfig := b.TLSClientConfig
|
||||
if tlsClientConfig.NextProtos != nil {
|
||||
tlsClientConfig = cloneTLSClientConfig(tlsClientConfig)
|
||||
tlsClientConfig = tlsClientConfig.Clone()
|
||||
tlsClientConfig.NextProtos = nil
|
||||
}
|
||||
|
||||
|
@ -566,37 +566,6 @@ func (tlsHandshakeTimeoutError) Timeout() bool { return true }
|
|||
func (tlsHandshakeTimeoutError) Temporary() bool { return true }
|
||||
func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
|
||||
|
||||
// cloneTLSClientConfig is like cloneTLSConfig but omits
|
||||
// the fields SessionTicketsDisabled and SessionTicketKey.
|
||||
// This makes it safe to call cloneTLSClientConfig on a config
|
||||
// in active use by a server.
|
||||
func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return &tls.Config{
|
||||
Rand: cfg.Rand,
|
||||
Time: cfg.Time,
|
||||
Certificates: cfg.Certificates,
|
||||
NameToCertificate: cfg.NameToCertificate,
|
||||
GetCertificate: cfg.GetCertificate,
|
||||
RootCAs: cfg.RootCAs,
|
||||
NextProtos: cfg.NextProtos,
|
||||
ServerName: cfg.ServerName,
|
||||
ClientAuth: cfg.ClientAuth,
|
||||
ClientCAs: cfg.ClientCAs,
|
||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||
CipherSuites: cfg.CipherSuites,
|
||||
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
|
||||
ClientSessionCache: cfg.ClientSessionCache,
|
||||
MinVersion: cfg.MinVersion,
|
||||
MaxVersion: cfg.MaxVersion,
|
||||
CurvePreferences: cfg.CurvePreferences,
|
||||
DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
|
||||
Renegotiation: cfg.Renegotiation,
|
||||
}
|
||||
}
|
||||
|
||||
func requestIsWebsocket(req *http.Request) bool {
|
||||
return strings.ToLower(req.Header.Get("Upgrade")) == "websocket" && strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade")
|
||||
}
|
||||
|
|
|
@ -108,6 +108,12 @@ type Config struct {
|
|||
|
||||
// Add the must staple TLS extension to the CSR generated by lego/acme
|
||||
MustStaple bool
|
||||
|
||||
// Disables HTTP2 completely
|
||||
DisableHTTP2 bool
|
||||
|
||||
// Holds final tls.Config
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
// OnDemandState contains some state relevant for providing
|
||||
|
@ -217,88 +223,70 @@ func (c *Config) StorageFor(caURL string) (Storage, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
// MakeTLSConfig reduces configs into a single tls.Config.
|
||||
// If TLS is to be disabled, a nil tls.Config will be returned.
|
||||
func MakeTLSConfig(configs []*Config) (*tls.Config, error) {
|
||||
if len(configs) == 0 {
|
||||
return nil, nil
|
||||
func (cfg *Config) Build(group ConfigGroup) error {
|
||||
config, err := cfg.build()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.tlsConfig = config
|
||||
cfg.tlsConfig.GetCertificate = group.GetCertificate
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) build() (*tls.Config, error) {
|
||||
config := new(tls.Config)
|
||||
|
||||
ciphersAdded := make(map[uint16]struct{})
|
||||
curvesAdded := make(map[tls.CurveID]struct{})
|
||||
configMap := make(configGroup)
|
||||
|
||||
for i, cfg := range configs {
|
||||
if cfg == nil {
|
||||
// avoid nil pointer dereference below
|
||||
configs[i] = new(Config)
|
||||
continue
|
||||
}
|
||||
|
||||
// Key this config by its hostname; this
|
||||
// overwrites configs with the same hostname
|
||||
configMap[cfg.Hostname] = cfg
|
||||
|
||||
// Can't serve TLS and not-TLS on same port
|
||||
if i > 0 && cfg.Enabled != configs[i-1].Enabled {
|
||||
thisConfProto, lastConfProto := "not TLS", "not TLS"
|
||||
if cfg.Enabled {
|
||||
thisConfProto = "TLS"
|
||||
}
|
||||
if configs[i-1].Enabled {
|
||||
lastConfProto = "TLS"
|
||||
}
|
||||
return nil, fmt.Errorf("cannot multiplex %s (%s) and %s (%s) on same listener",
|
||||
configs[i-1].Hostname, lastConfProto, cfg.Hostname, thisConfProto)
|
||||
}
|
||||
|
||||
if !cfg.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
// Union cipher suites
|
||||
for _, ciph := range cfg.Ciphers {
|
||||
if _, ok := ciphersAdded[ciph]; !ok {
|
||||
ciphersAdded[ciph] = struct{}{}
|
||||
config.CipherSuites = append(config.CipherSuites, ciph)
|
||||
}
|
||||
}
|
||||
|
||||
// Can't resolve conflicting PreferServerCipherSuites settings
|
||||
if i > 0 && cfg.PreferServerCipherSuites != configs[i-1].PreferServerCipherSuites {
|
||||
return nil, fmt.Errorf("cannot both PreferServerCipherSuites and not prefer them")
|
||||
}
|
||||
config.PreferServerCipherSuites = cfg.PreferServerCipherSuites
|
||||
|
||||
// Union curves
|
||||
for _, curv := range cfg.CurvePreferences {
|
||||
if _, ok := curvesAdded[curv]; !ok {
|
||||
curvesAdded[curv] = struct{}{}
|
||||
config.CurvePreferences = append(config.CurvePreferences, curv)
|
||||
}
|
||||
}
|
||||
|
||||
// Go with the widest range of protocol versions
|
||||
if config.MinVersion == 0 || cfg.ProtocolMinVersion < config.MinVersion {
|
||||
config.MinVersion = cfg.ProtocolMinVersion
|
||||
}
|
||||
if cfg.ProtocolMaxVersion > config.MaxVersion {
|
||||
config.MaxVersion = cfg.ProtocolMaxVersion
|
||||
}
|
||||
|
||||
// Go with the strictest ClientAuth type
|
||||
if cfg.ClientAuth > config.ClientAuth {
|
||||
config.ClientAuth = cfg.ClientAuth
|
||||
// Add cipher suites
|
||||
for _, ciph := range cfg.Ciphers {
|
||||
if _, ok := ciphersAdded[ciph]; !ok {
|
||||
ciphersAdded[ciph] = struct{}{}
|
||||
config.CipherSuites = append(config.CipherSuites, ciph)
|
||||
}
|
||||
}
|
||||
|
||||
// Is TLS disabled? If so, we're done here.
|
||||
// By now, we know that all configs agree
|
||||
// whether it is or not, so we can just look
|
||||
// at the first one.
|
||||
if len(configs) == 0 || !configs[0].Enabled {
|
||||
return nil, nil
|
||||
config.PreferServerCipherSuites = cfg.PreferServerCipherSuites
|
||||
|
||||
// Union curves
|
||||
for _, curv := range cfg.CurvePreferences {
|
||||
if _, ok := curvesAdded[curv]; !ok {
|
||||
curvesAdded[curv] = struct{}{}
|
||||
config.CurvePreferences = append(config.CurvePreferences, curv)
|
||||
}
|
||||
}
|
||||
|
||||
config.MinVersion = cfg.ProtocolMinVersion
|
||||
config.MaxVersion = cfg.ProtocolMaxVersion
|
||||
config.ClientAuth = cfg.ClientAuth
|
||||
|
||||
// Set up client authentication if enabled
|
||||
if config.ClientAuth != tls.NoClientCert {
|
||||
pool := x509.NewCertPool()
|
||||
clientCertsAdded := make(map[string]struct{})
|
||||
|
||||
for _, caFile := range cfg.ClientCerts {
|
||||
// don't add cert to pool more than once
|
||||
if _, ok := clientCertsAdded[caFile]; ok {
|
||||
continue
|
||||
}
|
||||
clientCertsAdded[caFile] = struct{}{}
|
||||
|
||||
// Any client with a certificate from this CA will be allowed to connect
|
||||
caCrt, err := ioutil.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(caCrt) {
|
||||
return nil, fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile)
|
||||
}
|
||||
}
|
||||
|
||||
config.ClientCAs = pool
|
||||
}
|
||||
|
||||
// Default cipher suites
|
||||
|
@ -311,43 +299,44 @@ func MakeTLSConfig(configs []*Config) (*tls.Config, error) {
|
|||
config.CipherSuites = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.CipherSuites...)
|
||||
}
|
||||
|
||||
// Default curves
|
||||
if len(config.CurvePreferences) == 0 {
|
||||
config.CurvePreferences = defaultCurves
|
||||
if cfg.DisableHTTP2 {
|
||||
config.NextProtos = []string{}
|
||||
} else {
|
||||
config.NextProtos = []string{"h2"}
|
||||
}
|
||||
|
||||
// Set up client authentication if enabled
|
||||
if config.ClientAuth != tls.NoClientCert {
|
||||
pool := x509.NewCertPool()
|
||||
clientCertsAdded := make(map[string]struct{})
|
||||
for _, cfg := range configs {
|
||||
for _, caFile := range cfg.ClientCerts {
|
||||
// don't add cert to pool more than once
|
||||
if _, ok := clientCertsAdded[caFile]; ok {
|
||||
continue
|
||||
}
|
||||
clientCertsAdded[caFile] = struct{}{}
|
||||
|
||||
// Any client with a certificate from this CA will be allowed to connect
|
||||
caCrt, err := ioutil.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(caCrt) {
|
||||
return nil, fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
config.ClientCAs = pool
|
||||
}
|
||||
|
||||
// Associate the GetCertificate callback, or almost nothing we just did will work
|
||||
config.GetCertificate = configMap.GetCertificate
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// CheckConfigs checks if multiple TLS configs does not collide with each other
|
||||
func CheckConfigs(configs []*Config) error {
|
||||
if len(configs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, cfg := range configs {
|
||||
|
||||
// Can't serve TLS and not-TLS on same port
|
||||
if i > 0 && cfg.Enabled != configs[i-1].Enabled {
|
||||
thisConfProto, lastConfProto := "not TLS", "not TLS"
|
||||
if cfg.Enabled {
|
||||
thisConfProto = "TLS"
|
||||
}
|
||||
if configs[i-1].Enabled {
|
||||
lastConfProto = "TLS"
|
||||
}
|
||||
return fmt.Errorf("cannot multiplex %s (%s) and %s (%s) on same listener",
|
||||
configs[i-1].Hostname, lastConfProto, cfg.Hostname, thisConfProto)
|
||||
}
|
||||
|
||||
if !cfg.Enabled {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigGetter gets a Config keyed by key.
|
||||
type ConfigGetter func(c *caddy.Controller) *Config
|
||||
|
||||
|
|
|
@ -10,14 +10,12 @@ import (
|
|||
|
||||
func TestMakeTLSConfigProtocolVersions(t *testing.T) {
|
||||
// same min and max protocol versions
|
||||
configs := []*Config{
|
||||
{
|
||||
Enabled: true,
|
||||
ProtocolMinVersion: tls.VersionTLS12,
|
||||
ProtocolMaxVersion: tls.VersionTLS12,
|
||||
},
|
||||
config := Config{
|
||||
Enabled: true,
|
||||
ProtocolMinVersion: tls.VersionTLS12,
|
||||
ProtocolMaxVersion: tls.VersionTLS12,
|
||||
}
|
||||
result, err := MakeTLSConfig(configs)
|
||||
result, err := config.build()
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect an error, but got %v", err)
|
||||
}
|
||||
|
@ -31,28 +29,14 @@ func TestMakeTLSConfigProtocolVersions(t *testing.T) {
|
|||
|
||||
func TestMakeTLSConfigPreferServerCipherSuites(t *testing.T) {
|
||||
// prefer server cipher suites
|
||||
configs := []*Config{{Enabled: true, PreferServerCipherSuites: true}}
|
||||
result, err := MakeTLSConfig(configs)
|
||||
config := Config{Enabled: true, PreferServerCipherSuites: true}
|
||||
result, err := config.build()
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect an error, but got %v", err)
|
||||
}
|
||||
if got, want := result.PreferServerCipherSuites, true; got != want {
|
||||
t.Errorf("Expected PreferServerCipherSuites==%v but got %v", want, got)
|
||||
}
|
||||
|
||||
// make sure we don't get an error if there's a conflict
|
||||
// when both of the configs have TLS disabled
|
||||
configs = []*Config{
|
||||
{Enabled: false, PreferServerCipherSuites: false},
|
||||
{Enabled: false, PreferServerCipherSuites: true},
|
||||
}
|
||||
result, err = MakeTLSConfig(configs)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect an error when TLS is disabled, but got '%v'", err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Errorf("Expected nil result because TLS disabled, got: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeTLSConfigTLSEnabledDisabled(t *testing.T) {
|
||||
|
@ -61,20 +45,10 @@ func TestMakeTLSConfigTLSEnabledDisabled(t *testing.T) {
|
|||
{Enabled: true},
|
||||
{Enabled: false},
|
||||
}
|
||||
_, err := MakeTLSConfig(configs)
|
||||
err := CheckConfigs(configs)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error, but got %v", err)
|
||||
}
|
||||
|
||||
// verify that when disabled, a nil pair is returned
|
||||
configs = []*Config{{}, {}}
|
||||
result, err := MakeTLSConfig(configs)
|
||||
if err != nil {
|
||||
t.Errorf("Did not expect an error, but got %v", err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Errorf("Expected a nil *tls.Config result, got %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeTLSConfigCipherSuites(t *testing.T) {
|
||||
|
@ -83,25 +57,22 @@ func TestMakeTLSConfigCipherSuites(t *testing.T) {
|
|||
configs := []*Config{
|
||||
{Enabled: true, Ciphers: []uint16{0xc02c, 0xc030}},
|
||||
{Enabled: true, Ciphers: []uint16{0xc012, 0xc030, 0xc00a}},
|
||||
}
|
||||
result, err := MakeTLSConfig(configs)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect an error, but got %v", err)
|
||||
}
|
||||
expected := []uint16{tls.TLS_FALLBACK_SCSV, 0xc02c, 0xc030, 0xc012, 0xc00a}
|
||||
if !reflect.DeepEqual(result.CipherSuites, expected) {
|
||||
t.Errorf("Expected ciphers %v but got %v", expected, result.CipherSuites)
|
||||
{Enabled: true, Ciphers: nil},
|
||||
}
|
||||
|
||||
// use default suites if none specified
|
||||
configs = []*Config{{Enabled: true}}
|
||||
result, err = MakeTLSConfig(configs)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect an error, but got %v", err)
|
||||
expectedCiphers := [][]uint16{
|
||||
{tls.TLS_FALLBACK_SCSV, 0xc02c, 0xc030},
|
||||
{tls.TLS_FALLBACK_SCSV, 0xc012, 0xc030, 0xc00a},
|
||||
append([]uint16{tls.TLS_FALLBACK_SCSV}, defaultCiphers...),
|
||||
}
|
||||
expected = append([]uint16{tls.TLS_FALLBACK_SCSV}, defaultCiphers...)
|
||||
if !reflect.DeepEqual(result.CipherSuites, expected) {
|
||||
t.Errorf("Expected default ciphers %v but got %v", expected, result.CipherSuites)
|
||||
|
||||
for i, config := range configs {
|
||||
cfg, _ := config.build()
|
||||
|
||||
if !reflect.DeepEqual(cfg.CipherSuites, expectedCiphers[i]) {
|
||||
t.Errorf("Expected ciphers %v but got %v", expectedCiphers[i], cfg.CipherSuites)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// (hostnames can have wildcard characters; use the getConfig
|
||||
// method to get a config by matching its hostname). Its
|
||||
// GetCertificate function can be used with tls.Config.
|
||||
type configGroup map[string]*Config
|
||||
type ConfigGroup map[string]*Config
|
||||
|
||||
// getConfig gets the config by the first key match for name.
|
||||
// In other words, "sub.foo.bar" will get the config for "*.foo.bar"
|
||||
|
@ -24,7 +24,7 @@ type configGroup map[string]*Config
|
|||
//
|
||||
// This function follows nearly the same logic to lookup
|
||||
// a hostname as the getCertificate function uses.
|
||||
func (cg configGroup) getConfig(name string) *Config {
|
||||
func (cg ConfigGroup) getConfig(name string) *Config {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
// exact match? great, let's use it
|
||||
|
@ -58,11 +58,27 @@ func (cg configGroup) getConfig(name string) *Config {
|
|||
// via ACME.
|
||||
//
|
||||
// This method is safe for use as a tls.Config.GetCertificate callback.
|
||||
func (cg configGroup) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
func (cg ConfigGroup) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
cert, err := cg.getCertDuringHandshake(strings.ToLower(clientHello.ServerName), true, true)
|
||||
return &cert.Certificate, err
|
||||
}
|
||||
|
||||
// GetConfigForClient gets a TLS configuration satisfying clientHello. In getting
|
||||
// the configuration, it abides the rules and settings defined in the
|
||||
// Config that matches clientHello.ServerName.
|
||||
//
|
||||
// This method is safe for use as a tls.Config.GetConfigForClient callback.
|
||||
func (cg ConfigGroup) GetConfigForClient(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
|
||||
config := cg.getConfig(clientHello.ServerName)
|
||||
|
||||
if config != nil {
|
||||
return config.tlsConfig, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// getCertDuringHandshake will get a certificate for name. It first tries
|
||||
// the in-memory cache. If no certificate for name is in the cache, the
|
||||
// config most closely corresponding to name will be loaded. If that config
|
||||
|
@ -74,7 +90,7 @@ func (cg configGroup) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Cer
|
|||
// certificate is available.
|
||||
//
|
||||
// This function is safe for concurrent use.
|
||||
func (cg configGroup) getCertDuringHandshake(name string, loadIfNecessary, obtainIfNecessary bool) (Certificate, error) {
|
||||
func (cg ConfigGroup) getCertDuringHandshake(name string, loadIfNecessary, obtainIfNecessary bool) (Certificate, error) {
|
||||
// First check our in-memory cache to see if we've already loaded it
|
||||
cert, matched, defaulted := getCertificate(name)
|
||||
if matched {
|
||||
|
@ -127,7 +143,7 @@ func (cg configGroup) getCertDuringHandshake(name string, loadIfNecessary, obtai
|
|||
// now according to mitigating factors we keep track of and preferences the
|
||||
// user has set. If a non-nil error is returned, do not issue a new certificate
|
||||
// for name.
|
||||
func (cg configGroup) checkLimitsForObtainingNewCerts(name string, cfg *Config) error {
|
||||
func (cg ConfigGroup) checkLimitsForObtainingNewCerts(name string, cfg *Config) error {
|
||||
// User can set hard limit for number of certs for the process to issue
|
||||
if cfg.OnDemandState.MaxObtain > 0 &&
|
||||
atomic.LoadInt32(&cfg.OnDemandState.ObtainedCount) >= cfg.OnDemandState.MaxObtain {
|
||||
|
@ -160,7 +176,7 @@ func (cg configGroup) checkLimitsForObtainingNewCerts(name string, cfg *Config)
|
|||
// name, it will wait and use what the other goroutine obtained.
|
||||
//
|
||||
// This function is safe for use by multiple concurrent goroutines.
|
||||
func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certificate, error) {
|
||||
func (cg ConfigGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certificate, error) {
|
||||
// We must protect this process from happening concurrently, so synchronize.
|
||||
obtainCertWaitChansMu.Lock()
|
||||
wait, ok := obtainCertWaitChans[name]
|
||||
|
@ -219,7 +235,7 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
|
|||
// validity.
|
||||
//
|
||||
// This function is safe for use by multiple concurrent goroutines.
|
||||
func (cg configGroup) handshakeMaintenance(name string, cert Certificate) (Certificate, error) {
|
||||
func (cg ConfigGroup) handshakeMaintenance(name string, cert Certificate) (Certificate, error) {
|
||||
// Check cert expiration
|
||||
timeLeft := cert.NotAfter.Sub(time.Now().UTC())
|
||||
if timeLeft < RenewDurationBefore {
|
||||
|
@ -252,7 +268,7 @@ func (cg configGroup) handshakeMaintenance(name string, cert Certificate) (Certi
|
|||
// usable. name should already be lower-cased before calling this function.
|
||||
//
|
||||
// This function is safe for use by multiple concurrent goroutines.
|
||||
func (cg configGroup) renewDynamicCertificate(name string, cfg *Config) (Certificate, error) {
|
||||
func (cg ConfigGroup) renewDynamicCertificate(name string, cfg *Config) (Certificate, error) {
|
||||
obtainCertWaitChansMu.Lock()
|
||||
wait, ok := obtainCertWaitChans[name]
|
||||
if ok {
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
func TestGetCertificate(t *testing.T) {
|
||||
defer func() { certCache = make(map[string]Certificate) }()
|
||||
|
||||
cg := make(configGroup)
|
||||
cg := make(ConfigGroup)
|
||||
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.com"}
|
||||
helloSub := &tls.ClientHelloInfo{ServerName: "sub.example.com"}
|
||||
|
|
|
@ -164,6 +164,20 @@ func setupTLS(c *caddy.Controller) error {
|
|||
return c.Errf("Unsupported Storage provider '%s'", args[0])
|
||||
}
|
||||
config.StorageProvider = args[0]
|
||||
|
||||
case "http2":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) != 1 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "off":
|
||||
config.DisableHTTP2 = true
|
||||
default:
|
||||
c.ArgErr()
|
||||
}
|
||||
|
||||
case "muststaple":
|
||||
config.MustStaple = true
|
||||
default:
|
||||
|
|
|
@ -91,6 +91,10 @@ func TestSetupParseBasic(t *testing.T) {
|
|||
t.Error("Expected PreferServerCipherSuites = true, but was false")
|
||||
}
|
||||
|
||||
if cfg.DisableHTTP2 {
|
||||
t.Error("Expected HTTP2 to be enabled by default")
|
||||
}
|
||||
|
||||
// Ensure curve count is correct
|
||||
if len(cfg.CurvePreferences) != len(defaultCurves) {
|
||||
t.Errorf("Expected %v Curves, got %v", len(defaultCurves), len(cfg.CurvePreferences))
|
||||
|
@ -118,6 +122,7 @@ func TestSetupParseWithOptionalParams(t *testing.T) {
|
|||
protocols tls1.0 tls1.2
|
||||
ciphers RSA-AES256-CBC-SHA ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384
|
||||
muststaple
|
||||
http2 off
|
||||
}`
|
||||
cfg := new(Config)
|
||||
RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
|
||||
|
@ -141,7 +146,11 @@ func TestSetupParseWithOptionalParams(t *testing.T) {
|
|||
}
|
||||
|
||||
if !cfg.MustStaple {
|
||||
t.Errorf("Expected must staple to be true")
|
||||
t.Error("Expected must staple to be true")
|
||||
}
|
||||
|
||||
if !cfg.DisableHTTP2 {
|
||||
t.Error("Expected HTTP2 to be disabled")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +193,7 @@ func TestSetupParseWithWrongOptionalParams(t *testing.T) {
|
|||
c = caddy.NewTestController("", params)
|
||||
err = setupTLS(c)
|
||||
if err == nil {
|
||||
t.Errorf("Expected errors, but no error returned")
|
||||
t.Error("Expected errors, but no error returned")
|
||||
}
|
||||
|
||||
// Test key_type wrong params
|
||||
|
@ -196,7 +205,7 @@ func TestSetupParseWithWrongOptionalParams(t *testing.T) {
|
|||
c = caddy.NewTestController("", params)
|
||||
err = setupTLS(c)
|
||||
if err == nil {
|
||||
t.Errorf("Expected errors, but no error returned")
|
||||
t.Error("Expected errors, but no error returned")
|
||||
}
|
||||
|
||||
// Test curves wrong params
|
||||
|
@ -208,7 +217,7 @@ func TestSetupParseWithWrongOptionalParams(t *testing.T) {
|
|||
c = caddy.NewTestController("", params)
|
||||
err = setupTLS(c)
|
||||
if err == nil {
|
||||
t.Errorf("Expected errors, but no error returned")
|
||||
t.Error("Expected errors, but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +231,7 @@ func TestSetupParseWithClientAuth(t *testing.T) {
|
|||
c := caddy.NewTestController("", params)
|
||||
err := setupTLS(c)
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but no error returned")
|
||||
t.Error("Expected an error, but no error returned")
|
||||
}
|
||||
|
||||
noCAs, twoCAs := []string{}, []string{"client_ca.crt", "client2_ca.crt"}
|
||||
|
|
Loading…
Reference in a new issue