mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-14 06:46:27 +03:00
Implement session ticket keys; default STEK module with rotation
This commit is contained in:
parent
1b6b422c63
commit
3439933235
6 changed files with 453 additions and 99 deletions
|
@ -13,6 +13,7 @@ import (
|
||||||
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/reverseproxy"
|
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/reverseproxy"
|
||||||
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/rewrite"
|
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/rewrite"
|
||||||
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
|
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
|
||||||
|
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls/standardstek"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -133,9 +133,21 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy2.Context) error {
|
||||||
},
|
},
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
MaxVersion: tls.VersionTLS13,
|
MaxVersion: tls.VersionTLS13,
|
||||||
// TODO: Session ticket key rotation (use Storage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// session tickets support
|
||||||
|
cfg.SessionTicketsDisabled = tlsApp.SessionTickets.Disabled
|
||||||
|
|
||||||
|
// session ticket key rotation
|
||||||
|
tlsApp.SessionTickets.register(cfg)
|
||||||
|
ctx.OnCancel(func() {
|
||||||
|
// do cleanup when the context is cancelled because,
|
||||||
|
// though unlikely, it is possible that a context
|
||||||
|
// needing a TLS server config could exist for less
|
||||||
|
// than the lifetime of the whole app
|
||||||
|
tlsApp.SessionTickets.unregister(cfg)
|
||||||
|
})
|
||||||
|
|
||||||
// add all the cipher suites in order, without duplicates
|
// add all the cipher suites in order, without duplicates
|
||||||
cipherSuitesAdded := make(map[uint16]struct{})
|
cipherSuitesAdded := make(map[uint16]struct{})
|
||||||
for _, csName := range p.CipherSuites {
|
for _, csName := range p.CipherSuites {
|
||||||
|
|
214
modules/caddytls/sessiontickets.go
Normal file
214
modules/caddytls/sessiontickets.go
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
package caddytls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/lightcodelabs/caddy2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SessionTicketService configures and manages TLS session tickets.
|
||||||
|
type SessionTicketService struct {
|
||||||
|
KeySource json.RawMessage `json:"key_source,omitempty"`
|
||||||
|
RotationInterval caddy2.Duration `json:"rotation_interval,omitempty"`
|
||||||
|
MaxKeys int `json:"max_keys,omitempty"`
|
||||||
|
DisableRotation bool `json:"disable_rotation,omitempty"`
|
||||||
|
Disabled bool `json:"disabled,omitempty"`
|
||||||
|
|
||||||
|
keySource STEKProvider
|
||||||
|
configs map[*tls.Config]struct{}
|
||||||
|
stopChan chan struct{}
|
||||||
|
currentKeys [][32]byte
|
||||||
|
mu *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionTicketService) provision(ctx caddy2.Context) error {
|
||||||
|
s.configs = make(map[*tls.Config]struct{})
|
||||||
|
s.mu = new(sync.Mutex)
|
||||||
|
|
||||||
|
// establish sane defaults
|
||||||
|
if s.RotationInterval == 0 {
|
||||||
|
s.RotationInterval = caddy2.Duration(defaultSTEKRotationInterval)
|
||||||
|
}
|
||||||
|
if s.MaxKeys <= 0 {
|
||||||
|
s.MaxKeys = defaultMaxSTEKs
|
||||||
|
}
|
||||||
|
if s.KeySource == nil {
|
||||||
|
s.KeySource = json.RawMessage(`{"provider":"standard"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the STEK module, which will provide keys
|
||||||
|
val, err := ctx.LoadModuleInline("provider", "tls.stek", s.KeySource)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading TLS session ticket ephemeral keys provider module: %s", err)
|
||||||
|
}
|
||||||
|
s.keySource = val.(STEKProvider)
|
||||||
|
s.KeySource = nil // allow GC to deallocate - TODO: Does this help?
|
||||||
|
|
||||||
|
// if session tickets or just rotation are
|
||||||
|
// disabled, no need to start service
|
||||||
|
if s.Disabled || s.DisableRotation {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the STEK module; this ensures we have
|
||||||
|
// a starting key before any config needs one
|
||||||
|
return s.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// start loads the starting STEKs and spawns a goroutine
|
||||||
|
// which loops to rotate the STEKs, which continues until
|
||||||
|
// stop() is called. If start() was already called, this
|
||||||
|
// is a no-op.
|
||||||
|
func (s *SessionTicketService) start() error {
|
||||||
|
if s.stopChan != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.stopChan = make(chan struct{})
|
||||||
|
|
||||||
|
// initializing the key source gives us our
|
||||||
|
// initial key(s) to start with; if successful,
|
||||||
|
// we need to be sure to call Next() so that
|
||||||
|
// the key source can know when it is done
|
||||||
|
initialKeys, err := s.keySource.Initialize(s)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("setting STEK module configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
s.currentKeys = initialKeys
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
|
// keep the keys rotated
|
||||||
|
go s.stayUpdated()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// stayUpdated is a blocking function which rotates
|
||||||
|
// the keys whenever new ones are sent. It reads
|
||||||
|
// from keysChan until s.stop() is called.
|
||||||
|
func (s *SessionTicketService) stayUpdated() {
|
||||||
|
// this call is essential when Initialize()
|
||||||
|
// returns without error, because the stop
|
||||||
|
// channel is the only way the key source
|
||||||
|
// will know when to clean up
|
||||||
|
keysChan := s.keySource.Next(s.stopChan)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case newKeys := <-keysChan:
|
||||||
|
s.mu.Lock()
|
||||||
|
s.currentKeys = newKeys
|
||||||
|
configs := s.configs
|
||||||
|
s.mu.Unlock()
|
||||||
|
for cfg := range configs {
|
||||||
|
cfg.SetSessionTicketKeys(newKeys)
|
||||||
|
}
|
||||||
|
case <-s.stopChan:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop terminates the key rotation goroutine.
|
||||||
|
func (s *SessionTicketService) stop() {
|
||||||
|
if s.stopChan != nil {
|
||||||
|
close(s.stopChan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register sets the session ticket keys on cfg
|
||||||
|
// and keeps them updated. Any values registered
|
||||||
|
// must be unregistered, or they will not be
|
||||||
|
// garbage-collected. s.start() must have been
|
||||||
|
// called first. If session tickets are disabled
|
||||||
|
// or if ticket key rotation is disabled, this
|
||||||
|
// function is a no-op.
|
||||||
|
func (s *SessionTicketService) register(cfg *tls.Config) {
|
||||||
|
if s.Disabled || s.DisableRotation {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.mu.Lock()
|
||||||
|
cfg.SetSessionTicketKeys(s.currentKeys)
|
||||||
|
s.configs[cfg] = struct{}{}
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unregister stops session key management on cfg and
|
||||||
|
// removes the internal stored reference to cfg. If
|
||||||
|
// session tickets are disabled or if ticket key rotation
|
||||||
|
// is disabled, this function is a no-op.
|
||||||
|
func (s *SessionTicketService) unregister(cfg *tls.Config) {
|
||||||
|
if s.Disabled || s.DisableRotation {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.mu.Lock()
|
||||||
|
delete(s.configs, cfg)
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RotateSTEKs rotates the keys in keys by producing a new key and eliding
|
||||||
|
// the oldest one. The new slice of keys is returned.
|
||||||
|
func (s SessionTicketService) RotateSTEKs(keys [][32]byte) ([][32]byte, error) {
|
||||||
|
// produce a new key
|
||||||
|
newKey, err := s.generateSTEK()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("generating STEK: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to prepend this new key to the list of
|
||||||
|
// keys so that it is preferred, but we need to be
|
||||||
|
// careful that we do not grow the slice larger
|
||||||
|
// than MaxKeys, otherwise we'll be storing one
|
||||||
|
// more key in memory than we expect; so be sure
|
||||||
|
// that the slice does not grow beyond the limit
|
||||||
|
// even for a brief period of time, since there's
|
||||||
|
// no guarantee when that extra allocation will
|
||||||
|
// be overwritten; this is why we first trim the
|
||||||
|
// length to one less the max, THEN prepend the
|
||||||
|
// new key
|
||||||
|
if len(keys) >= s.MaxKeys {
|
||||||
|
keys[len(keys)-1] = [32]byte{} // zero-out memory of oldest key
|
||||||
|
keys = keys[:s.MaxKeys-1] // trim length of slice
|
||||||
|
}
|
||||||
|
keys = append([][32]byte{newKey}, keys...) // prepend new key
|
||||||
|
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateSTEK generates key material suitable for use as a
|
||||||
|
// session ticket ephemeral key.
|
||||||
|
func (s *SessionTicketService) generateSTEK() ([32]byte, error) {
|
||||||
|
var newTicketKey [32]byte
|
||||||
|
_, err := io.ReadFull(rand.Reader, newTicketKey[:])
|
||||||
|
return newTicketKey, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEKProvider is a type that can provide session ticket ephemeral
|
||||||
|
// keys (STEKs).
|
||||||
|
type STEKProvider interface {
|
||||||
|
// Initialize provides the STEK configuration to the STEK
|
||||||
|
// module so that it can obtain and manage keys accordingly.
|
||||||
|
// It returns the initial key(s) to use. Implementations can
|
||||||
|
// rely on Next() being called if Initialize() returns
|
||||||
|
// without error, so that it may know when it is done.
|
||||||
|
Initialize(config *SessionTicketService) ([][32]byte, error)
|
||||||
|
|
||||||
|
// Next returns the channel through which the next session
|
||||||
|
// ticket keys will be transmitted until doneChan is closed.
|
||||||
|
// Keys should be sent on keysChan as they are updated.
|
||||||
|
// When doneChan is closed, any resources allocated in
|
||||||
|
// Initialize() must be cleaned up.
|
||||||
|
Next(doneChan <-chan struct{}) (keysChan <-chan [][32]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultSTEKRotationInterval = 12 * time.Hour
|
||||||
|
defaultMaxSTEKs = 4
|
||||||
|
)
|
112
modules/caddytls/standardstek/stek.go
Normal file
112
modules/caddytls/standardstek/stek.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package standardstek
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/lightcodelabs/caddy2"
|
||||||
|
"bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy2.RegisterModule(caddy2.Module{
|
||||||
|
Name: "tls.stek.standard",
|
||||||
|
New: func() interface{} { return new(standardSTEKProvider) },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type standardSTEKProvider struct {
|
||||||
|
stekConfig *caddytls.SessionTicketService
|
||||||
|
timer *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize sets the configuration for s and returns the starting keys.
|
||||||
|
func (s *standardSTEKProvider) Initialize(config *caddytls.SessionTicketService) ([][32]byte, error) {
|
||||||
|
// keep a reference to the config, we'll need when rotating keys
|
||||||
|
s.stekConfig = config
|
||||||
|
|
||||||
|
itvl := time.Duration(s.stekConfig.RotationInterval)
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
|
||||||
|
// if this is our first rotation or we are overdue
|
||||||
|
// for one, perform a rotation immediately; otherwise,
|
||||||
|
// we assume that the keys are non-empty and fresh
|
||||||
|
since := time.Since(lastRotation)
|
||||||
|
if lastRotation.IsZero() || since > itvl {
|
||||||
|
var err error
|
||||||
|
keys, err = s.stekConfig.RotateSTEKs(keys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
since = 0 // since this is overdue or is the first rotation, use full interval
|
||||||
|
lastRotation = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// create timer for the remaining time on the interval;
|
||||||
|
// this timer is cleaned up only when Next() returns
|
||||||
|
s.timer = time.NewTimer(itvl - since)
|
||||||
|
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns a channel which transmits the latest session ticket keys.
|
||||||
|
func (s *standardSTEKProvider) Next(doneChan <-chan struct{}) <-chan [][32]byte {
|
||||||
|
keysChan := make(chan [][32]byte)
|
||||||
|
go s.rotate(doneChan, keysChan)
|
||||||
|
return keysChan
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate rotates keys on a regular basis, sending each updated set of
|
||||||
|
// keys down keysChan, until doneChan is closed.
|
||||||
|
func (s *standardSTEKProvider) rotate(doneChan <-chan struct{}, keysChan chan<- [][32]byte) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case now := <-s.timer.C:
|
||||||
|
// copy the slice header to avoid races
|
||||||
|
mutex.RLock()
|
||||||
|
keysCopy := keys
|
||||||
|
mutex.RUnlock()
|
||||||
|
|
||||||
|
// generate a new key, rotating old ones
|
||||||
|
var err error
|
||||||
|
keysCopy, err = s.stekConfig.RotateSTEKs(keysCopy)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: improve this handling
|
||||||
|
log.Printf("[ERROR] Generating STEK: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace keys slice with updated value and
|
||||||
|
// record the timestamp of rotation
|
||||||
|
mutex.Lock()
|
||||||
|
keys = keysCopy
|
||||||
|
lastRotation = now
|
||||||
|
mutex.Unlock()
|
||||||
|
|
||||||
|
// send the updated keys to the service
|
||||||
|
keysChan <- keysCopy
|
||||||
|
|
||||||
|
// timer channel is already drained, so reset directly (see godoc)
|
||||||
|
s.timer.Reset(time.Duration(s.stekConfig.RotationInterval))
|
||||||
|
|
||||||
|
case <-doneChan:
|
||||||
|
// again, see godocs for why timer is stopped this way
|
||||||
|
if !s.timer.Stop() {
|
||||||
|
<-s.timer.C
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastRotation time.Time
|
||||||
|
keys [][32]byte
|
||||||
|
mutex sync.RWMutex // protects keys and lastRotation
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface guard
|
||||||
|
var _ caddytls.STEKProvider = (*standardSTEKProvider)(nil)
|
|
@ -2,14 +2,12 @@ package caddytls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"bitbucket.org/lightcodelabs/caddy2"
|
"bitbucket.org/lightcodelabs/caddy2"
|
||||||
"github.com/go-acme/lego/challenge"
|
"github.com/go-acme/lego/challenge"
|
||||||
"github.com/klauspost/cpuid"
|
|
||||||
"github.com/mholt/certmagic"
|
"github.com/mholt/certmagic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,8 +20,9 @@ func init() {
|
||||||
|
|
||||||
// TLS represents a process-wide TLS configuration.
|
// TLS represents a process-wide TLS configuration.
|
||||||
type TLS struct {
|
type TLS struct {
|
||||||
Certificates map[string]json.RawMessage `json:"certificates"`
|
Certificates map[string]json.RawMessage `json:"certificates,omitempty"`
|
||||||
Automation AutomationConfig `json:"automation"`
|
Automation AutomationConfig `json:"automation,omitempty"`
|
||||||
|
SessionTickets SessionTicketService `json:"session_tickets,omitempty"`
|
||||||
|
|
||||||
certificateLoaders []CertificateLoader
|
certificateLoaders []CertificateLoader
|
||||||
certCache *certmagic.Cache
|
certCache *certmagic.Cache
|
||||||
|
@ -44,6 +43,7 @@ func (t *TLS) Provision(ctx caddy2.Context) error {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// automation/management policies
|
||||||
for i, ap := range t.Automation.Policies {
|
for i, ap := range t.Automation.Policies {
|
||||||
val, err := ctx.LoadModuleInline("module", "tls.management", ap.Management)
|
val, err := ctx.LoadModuleInline("module", "tls.management", ap.Management)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -65,6 +65,12 @@ func (t *TLS) Provision(ctx caddy2.Context) error {
|
||||||
t.certificateLoaders = append(t.certificateLoaders, val.(CertificateLoader))
|
t.certificateLoaders = append(t.certificateLoaders, val.(CertificateLoader))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// session ticket ephemeral keys (STEK) service and provider
|
||||||
|
err := t.SessionTickets.provision(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("provisioning session tickets configuration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +116,7 @@ func (t *TLS) Stop() error {
|
||||||
// TODO: ensure locks are cleaned up too... maybe in certmagic though
|
// TODO: ensure locks are cleaned up too... maybe in certmagic though
|
||||||
t.certCache.Stop()
|
t.certCache.Stop()
|
||||||
}
|
}
|
||||||
|
t.SessionTickets.stop()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,98 +237,4 @@ type ManagerMaker interface {
|
||||||
newManager(interactive bool) (certmagic.Manager, error)
|
newManager(interactive bool) (certmagic.Manager, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// supportedCipherSuites is the unordered map of cipher suite
|
|
||||||
// string names to their definition in crypto/tls.
|
|
||||||
// TODO: might not be needed much longer, see:
|
|
||||||
// https://github.com/golang/go/issues/30325
|
|
||||||
var supportedCipherSuites = 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,
|
|
||||||
"ECDHE_RSA_AES128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
|
||||||
"ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
|
||||||
"ECDHE_RSA_AES256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
||||||
"ECDHE_RSA_AES128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_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_AES256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
|
||||||
"RSA_AES128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_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,
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultCipherSuites is the ordered list of all the cipher
|
|
||||||
// suites we want to support by default, assuming AES-NI
|
|
||||||
// (hardware acceleration for AES).
|
|
||||||
var defaultCipherSuitesWithAESNI = []uint16{
|
|
||||||
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_ECDSA_WITH_CHACHA20_POLY1305,
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultCipherSuites is the ordered list of all the cipher
|
|
||||||
// suites we want to support by default, assuming lack of
|
|
||||||
// AES-NI (NO hardware acceleration for AES).
|
|
||||||
var defaultCipherSuitesWithoutAESNI = []uint16{
|
|
||||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
// getOptimalDefaultCipherSuites returns an appropriate cipher
|
|
||||||
// suite to use depending on the hardware support for AES.
|
|
||||||
//
|
|
||||||
// See https://github.com/mholt/caddy/issues/1674
|
|
||||||
func getOptimalDefaultCipherSuites() []uint16 {
|
|
||||||
if cpuid.CPU.AesNi() {
|
|
||||||
return defaultCipherSuitesWithAESNI
|
|
||||||
}
|
|
||||||
return defaultCipherSuitesWithoutAESNI
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedCurves is the unordered map of supported curves.
|
|
||||||
// https://golang.org/pkg/crypto/tls/#CurveID
|
|
||||||
var supportedCurves = map[string]tls.CurveID{
|
|
||||||
"X25519": tls.X25519,
|
|
||||||
"P256": tls.CurveP256,
|
|
||||||
"P384": tls.CurveP384,
|
|
||||||
"P521": tls.CurveP521,
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultCurves is the list of only the curves we want to use
|
|
||||||
// by default, in descending order of preference.
|
|
||||||
//
|
|
||||||
// This list should only include curves which are fast by design
|
|
||||||
// (e.g. X25519) and those for which an optimized assembly
|
|
||||||
// implementation exists (e.g. P256). The latter ones can be
|
|
||||||
// found here:
|
|
||||||
// https://github.com/golang/go/tree/master/src/crypto/elliptic
|
|
||||||
var defaultCurves = []tls.CurveID{
|
|
||||||
tls.X25519,
|
|
||||||
tls.CurveP256,
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedProtocols is a map of supported protocols.
|
|
||||||
// HTTP/2 only supports TLS 1.2 and higher.
|
|
||||||
var supportedProtocols = map[string]uint16{
|
|
||||||
"tls1.0": tls.VersionTLS10,
|
|
||||||
"tls1.1": tls.VersionTLS11,
|
|
||||||
"tls1.2": tls.VersionTLS12,
|
|
||||||
"tls1.3": tls.VersionTLS13,
|
|
||||||
}
|
|
||||||
|
|
||||||
// publicKeyAlgorithms is the map of supported public key algorithms.
|
|
||||||
var publicKeyAlgorithms = map[string]x509.PublicKeyAlgorithm{
|
|
||||||
"rsa": x509.RSA,
|
|
||||||
"dsa": x509.DSA,
|
|
||||||
"ecdsa": x509.ECDSA,
|
|
||||||
}
|
|
||||||
|
|
||||||
const automateKey = "automate"
|
const automateKey = "automate"
|
||||||
|
|
102
modules/caddytls/values.go
Normal file
102
modules/caddytls/values.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package caddytls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
|
||||||
|
"github.com/klauspost/cpuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// supportedCipherSuites is the unordered map of cipher suite
|
||||||
|
// string names to their definition in crypto/tls.
|
||||||
|
// TODO: might not be needed much longer, see:
|
||||||
|
// https://github.com/golang/go/issues/30325
|
||||||
|
var supportedCipherSuites = 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,
|
||||||
|
"ECDHE_RSA_AES128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||||
|
"ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||||
|
"ECDHE_RSA_AES256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"ECDHE_RSA_AES128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_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_AES256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"RSA_AES128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_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,
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultCipherSuites is the ordered list of all the cipher
|
||||||
|
// suites we want to support by default, assuming AES-NI
|
||||||
|
// (hardware acceleration for AES).
|
||||||
|
var defaultCipherSuitesWithAESNI = []uint16{
|
||||||
|
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_ECDSA_WITH_CHACHA20_POLY1305,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultCipherSuites is the ordered list of all the cipher
|
||||||
|
// suites we want to support by default, assuming lack of
|
||||||
|
// AES-NI (NO hardware acceleration for AES).
|
||||||
|
var defaultCipherSuitesWithoutAESNI = []uint16{
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
// getOptimalDefaultCipherSuites returns an appropriate cipher
|
||||||
|
// suite to use depending on the hardware support for AES.
|
||||||
|
//
|
||||||
|
// See https://github.com/mholt/caddy/issues/1674
|
||||||
|
func getOptimalDefaultCipherSuites() []uint16 {
|
||||||
|
if cpuid.CPU.AesNi() {
|
||||||
|
return defaultCipherSuitesWithAESNI
|
||||||
|
}
|
||||||
|
return defaultCipherSuitesWithoutAESNI
|
||||||
|
}
|
||||||
|
|
||||||
|
// supportedCurves is the unordered map of supported curves.
|
||||||
|
// https://golang.org/pkg/crypto/tls/#CurveID
|
||||||
|
var supportedCurves = map[string]tls.CurveID{
|
||||||
|
"X25519": tls.X25519,
|
||||||
|
"P256": tls.CurveP256,
|
||||||
|
"P384": tls.CurveP384,
|
||||||
|
"P521": tls.CurveP521,
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultCurves is the list of only the curves we want to use
|
||||||
|
// by default, in descending order of preference.
|
||||||
|
//
|
||||||
|
// This list should only include curves which are fast by design
|
||||||
|
// (e.g. X25519) and those for which an optimized assembly
|
||||||
|
// implementation exists (e.g. P256). The latter ones can be
|
||||||
|
// found here:
|
||||||
|
// https://github.com/golang/go/tree/master/src/crypto/elliptic
|
||||||
|
var defaultCurves = []tls.CurveID{
|
||||||
|
tls.X25519,
|
||||||
|
tls.CurveP256,
|
||||||
|
}
|
||||||
|
|
||||||
|
// supportedProtocols is a map of supported protocols.
|
||||||
|
// HTTP/2 only supports TLS 1.2 and higher.
|
||||||
|
var supportedProtocols = map[string]uint16{
|
||||||
|
"tls1.0": tls.VersionTLS10,
|
||||||
|
"tls1.1": tls.VersionTLS11,
|
||||||
|
"tls1.2": tls.VersionTLS12,
|
||||||
|
"tls1.3": tls.VersionTLS13,
|
||||||
|
}
|
||||||
|
|
||||||
|
// publicKeyAlgorithms is the map of supported public key algorithms.
|
||||||
|
var publicKeyAlgorithms = map[string]x509.PublicKeyAlgorithm{
|
||||||
|
"rsa": x509.RSA,
|
||||||
|
"dsa": x509.DSA,
|
||||||
|
"ecdsa": x509.ECDSA,
|
||||||
|
}
|
Loading…
Reference in a new issue