@marcel91200 / caddy Mirror · read-only / commits / 34399332
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

Implement session ticket keys; default STEK module with rotation

Matthew Holt committed May 29, 2019 at 23:11 UTC 34399332354b5cbc742200ef11aa33f199ba6755
6 files changed +453 -99
cmd/caddy2/main.go
+1
@@ -13,6 +13,7 @@ import (
13 _ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/reverseproxy"
14 _ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/rewrite"
15 _ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
16 + _ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls/standardstek"
17 )
18
19 func main() {
modules/caddytls/connpolicy.go
+13 -1
@@ -133,9 +133,21 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy2.Context) error {
133 },
134 MinVersion: tls.VersionTLS12,
135 MaxVersion: tls.VersionTLS13,
136 - // TODO: Session ticket key rotation (use Storage)
136 }
137
138 + // session tickets support
139 + cfg.SessionTicketsDisabled = tlsApp.SessionTickets.Disabled
140 +
141 + // session ticket key rotation
142 + tlsApp.SessionTickets.register(cfg)
143 + ctx.OnCancel(func() {
144 + // do cleanup when the context is cancelled because,
145 + // though unlikely, it is possible that a context
146 + // needing a TLS server config could exist for less
147 + // than the lifetime of the whole app
148 + tlsApp.SessionTickets.unregister(cfg)
149 + })
150 +
151 // add all the cipher suites in order, without duplicates
152 cipherSuitesAdded := make(map[uint16]struct{})
153 for _, csName := range p.CipherSuites {
modules/caddytls/sessiontickets.go new
+214
@@ -0,0 +1,214 @@
1 +package caddytls
2 +
3 +import (
4 + "crypto/rand"
5 + "crypto/tls"
6 + "encoding/json"
7 + "fmt"
8 + "io"
9 + "sync"
10 + "time"
11 +
12 + "bitbucket.org/lightcodelabs/caddy2"
13 +)
14 +
15 +// SessionTicketService configures and manages TLS session tickets.
16 +type SessionTicketService struct {
17 + KeySource json.RawMessage `json:"key_source,omitempty"`
18 + RotationInterval caddy2.Duration `json:"rotation_interval,omitempty"`
19 + MaxKeys int `json:"max_keys,omitempty"`
20 + DisableRotation bool `json:"disable_rotation,omitempty"`
21 + Disabled bool `json:"disabled,omitempty"`
22 +
23 + keySource STEKProvider
24 + configs map[*tls.Config]struct{}
25 + stopChan chan struct{}
26 + currentKeys [][32]byte
27 + mu *sync.Mutex
28 +}
29 +
30 +func (s *SessionTicketService) provision(ctx caddy2.Context) error {
31 + s.configs = make(map[*tls.Config]struct{})
32 + s.mu = new(sync.Mutex)
33 +
34 + // establish sane defaults
35 + if s.RotationInterval == 0 {
36 + s.RotationInterval = caddy2.Duration(defaultSTEKRotationInterval)
37 + }
38 + if s.MaxKeys <= 0 {
39 + s.MaxKeys = defaultMaxSTEKs
40 + }
41 + if s.KeySource == nil {
42 + s.KeySource = json.RawMessage(`{"provider":"standard"}`)
43 + }
44 +
45 + // load the STEK module, which will provide keys
46 + val, err := ctx.LoadModuleInline("provider", "tls.stek", s.KeySource)
47 + if err != nil {
48 + return fmt.Errorf("loading TLS session ticket ephemeral keys provider module: %s", err)
49 + }
50 + s.keySource = val.(STEKProvider)
51 + s.KeySource = nil // allow GC to deallocate - TODO: Does this help?
52 +
53 + // if session tickets or just rotation are
54 + // disabled, no need to start service
55 + if s.Disabled || s.DisableRotation {
56 + return nil
57 + }
58 +
59 + // start the STEK module; this ensures we have
60 + // a starting key before any config needs one
61 + return s.start()
62 +}
63 +
64 +// start loads the starting STEKs and spawns a goroutine
65 +// which loops to rotate the STEKs, which continues until
66 +// stop() is called. If start() was already called, this
67 +// is a no-op.
68 +func (s *SessionTicketService) start() error {
69 + if s.stopChan != nil {
70 + return nil
71 + }
72 + s.stopChan = make(chan struct{})
73 +
74 + // initializing the key source gives us our
75 + // initial key(s) to start with; if successful,
76 + // we need to be sure to call Next() so that
77 + // the key source can know when it is done
78 + initialKeys, err := s.keySource.Initialize(s)
79 + if err != nil {
80 + return fmt.Errorf("setting STEK module configuration: %v", err)
81 + }
82 +
83 + s.mu.Lock()
84 + s.currentKeys = initialKeys
85 + s.mu.Unlock()
86 +
87 + // keep the keys rotated
88 + go s.stayUpdated()
89 +
90 + return nil
91 +}
92 +
93 +// stayUpdated is a blocking function which rotates
94 +// the keys whenever new ones are sent. It reads
95 +// from keysChan until s.stop() is called.
96 +func (s *SessionTicketService) stayUpdated() {
97 + // this call is essential when Initialize()
98 + // returns without error, because the stop
99 + // channel is the only way the key source
100 + // will know when to clean up
101 + keysChan := s.keySource.Next(s.stopChan)
102 +
103 + for {
104 + select {
105 + case newKeys := <-keysChan:
106 + s.mu.Lock()
107 + s.currentKeys = newKeys
108 + configs := s.configs
109 + s.mu.Unlock()
110 + for cfg := range configs {
111 + cfg.SetSessionTicketKeys(newKeys)
112 + }
113 + case <-s.stopChan:
114 + return
115 + }
116 + }
117 +}
118 +
119 +// stop terminates the key rotation goroutine.
120 +func (s *SessionTicketService) stop() {
121 + if s.stopChan != nil {
122 + close(s.stopChan)
123 + }
124 +}
125 +
126 +// register sets the session ticket keys on cfg
127 +// and keeps them updated. Any values registered
128 +// must be unregistered, or they will not be
129 +// garbage-collected. s.start() must have been
130 +// called first. If session tickets are disabled
131 +// or if ticket key rotation is disabled, this
132 +// function is a no-op.
133 +func (s *SessionTicketService) register(cfg *tls.Config) {
134 + if s.Disabled || s.DisableRotation {
135 + return
136 + }
137 + s.mu.Lock()
138 + cfg.SetSessionTicketKeys(s.currentKeys)
139 + s.configs[cfg] = struct{}{}
140 + s.mu.Unlock()
141 +}
142 +
143 +// unregister stops session key management on cfg and
144 +// removes the internal stored reference to cfg. If
145 +// session tickets are disabled or if ticket key rotation
146 +// is disabled, this function is a no-op.
147 +func (s *SessionTicketService) unregister(cfg *tls.Config) {
148 + if s.Disabled || s.DisableRotation {
149 + return
150 + }
151 + s.mu.Lock()
152 + delete(s.configs, cfg)
153 + s.mu.Unlock()
154 +}
155 +
156 +// RotateSTEKs rotates the keys in keys by producing a new key and eliding
157 +// the oldest one. The new slice of keys is returned.
158 +func (s SessionTicketService) RotateSTEKs(keys [][32]byte) ([][32]byte, error) {
159 + // produce a new key
160 + newKey, err := s.generateSTEK()
161 + if err != nil {
162 + return nil, fmt.Errorf("generating STEK: %v", err)
163 + }
164 +
165 + // we need to prepend this new key to the list of
166 + // keys so that it is preferred, but we need to be
167 + // careful that we do not grow the slice larger
168 + // than MaxKeys, otherwise we'll be storing one
169 + // more key in memory than we expect; so be sure
170 + // that the slice does not grow beyond the limit
171 + // even for a brief period of time, since there's
172 + // no guarantee when that extra allocation will
173 + // be overwritten; this is why we first trim the
174 + // length to one less the max, THEN prepend the
175 + // new key
176 + if len(keys) >= s.MaxKeys {
177 + keys[len(keys)-1] = [32]byte{} // zero-out memory of oldest key
178 + keys = keys[:s.MaxKeys-1] // trim length of slice
179 + }
180 + keys = append([][32]byte{newKey}, keys...) // prepend new key
181 +
182 + return keys, nil
183 +}
184 +
185 +// generateSTEK generates key material suitable for use as a
186 +// session ticket ephemeral key.
187 +func (s *SessionTicketService) generateSTEK() ([32]byte, error) {
188 + var newTicketKey [32]byte
189 + _, err := io.ReadFull(rand.Reader, newTicketKey[:])
190 + return newTicketKey, err
191 +}
192 +
193 +// STEKProvider is a type that can provide session ticket ephemeral
194 +// keys (STEKs).
195 +type STEKProvider interface {
196 + // Initialize provides the STEK configuration to the STEK
197 + // module so that it can obtain and manage keys accordingly.
198 + // It returns the initial key(s) to use. Implementations can
199 + // rely on Next() being called if Initialize() returns
200 + // without error, so that it may know when it is done.
201 + Initialize(config *SessionTicketService) ([][32]byte, error)
202 +
203 + // Next returns the channel through which the next session
204 + // ticket keys will be transmitted until doneChan is closed.
205 + // Keys should be sent on keysChan as they are updated.
206 + // When doneChan is closed, any resources allocated in
207 + // Initialize() must be cleaned up.
208 + Next(doneChan <-chan struct{}) (keysChan <-chan [][32]byte)
209 +}
210 +
211 +const (
212 + defaultSTEKRotationInterval = 12 * time.Hour
213 + defaultMaxSTEKs = 4
214 +)
modules/caddytls/standardstek/stek.go new
+112
@@ -0,0 +1,112 @@
1 +package standardstek
2 +
3 +import (
4 + "log"
5 + "sync"
6 + "time"
7 +
8 + "bitbucket.org/lightcodelabs/caddy2"
9 + "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
10 +)
11 +
12 +func init() {
13 + caddy2.RegisterModule(caddy2.Module{
14 + Name: "tls.stek.standard",
15 + New: func() interface{} { return new(standardSTEKProvider) },
16 + })
17 +}
18 +
19 +type standardSTEKProvider struct {
20 + stekConfig *caddytls.SessionTicketService
21 + timer *time.Timer
22 +}
23 +
24 +// Initialize sets the configuration for s and returns the starting keys.
25 +func (s *standardSTEKProvider) Initialize(config *caddytls.SessionTicketService) ([][32]byte, error) {
26 + // keep a reference to the config, we'll need when rotating keys
27 + s.stekConfig = config
28 +
29 + itvl := time.Duration(s.stekConfig.RotationInterval)
30 +
31 + mutex.Lock()
32 + defer mutex.Unlock()
33 +
34 + // if this is our first rotation or we are overdue
35 + // for one, perform a rotation immediately; otherwise,
36 + // we assume that the keys are non-empty and fresh
37 + since := time.Since(lastRotation)
38 + if lastRotation.IsZero() || since > itvl {
39 + var err error
40 + keys, err = s.stekConfig.RotateSTEKs(keys)
41 + if err != nil {
42 + return nil, err
43 + }
44 + since = 0 // since this is overdue or is the first rotation, use full interval
45 + lastRotation = time.Now()
46 + }
47 +
48 + // create timer for the remaining time on the interval;
49 + // this timer is cleaned up only when Next() returns
50 + s.timer = time.NewTimer(itvl - since)
51 +
52 + return keys, nil
53 +}
54 +
55 +// Next returns a channel which transmits the latest session ticket keys.
56 +func (s *standardSTEKProvider) Next(doneChan <-chan struct{}) <-chan [][32]byte {
57 + keysChan := make(chan [][32]byte)
58 + go s.rotate(doneChan, keysChan)
59 + return keysChan
60 +}
61 +
62 +// rotate rotates keys on a regular basis, sending each updated set of
63 +// keys down keysChan, until doneChan is closed.
64 +func (s *standardSTEKProvider) rotate(doneChan <-chan struct{}, keysChan chan<- [][32]byte) {
65 + for {
66 + select {
67 + case now := <-s.timer.C:
68 + // copy the slice header to avoid races
69 + mutex.RLock()
70 + keysCopy := keys
71 + mutex.RUnlock()
72 +
73 + // generate a new key, rotating old ones
74 + var err error
75 + keysCopy, err = s.stekConfig.RotateSTEKs(keysCopy)
76 + if err != nil {
77 + // TODO: improve this handling
78 + log.Printf("[ERROR] Generating STEK: %v", err)
79 + continue
80 + }
81 +
82 + // replace keys slice with updated value and
83 + // record the timestamp of rotation
84 + mutex.Lock()
85 + keys = keysCopy
86 + lastRotation = now
87 + mutex.Unlock()
88 +
89 + // send the updated keys to the service
90 + keysChan <- keysCopy
91 +
92 + // timer channel is already drained, so reset directly (see godoc)
93 + s.timer.Reset(time.Duration(s.stekConfig.RotationInterval))
94 +
95 + case <-doneChan:
96 + // again, see godocs for why timer is stopped this way
97 + if !s.timer.Stop() {
98 + <-s.timer.C
99 + }
100 + return
101 + }
102 + }
103 +}
104 +
105 +var (
106 + lastRotation time.Time
107 + keys [][32]byte
108 + mutex sync.RWMutex // protects keys and lastRotation
109 +)
110 +
111 +// Interface guard
112 +var _ caddytls.STEKProvider = (*standardSTEKProvider)(nil)
modules/caddytls/tls.go
+11 -98
@@ -2,14 +2,12 @@ package caddytls
2
3 import (
4 "crypto/tls"
5 - "crypto/x509"
5 "encoding/json"
6 "fmt"
7 "net/http"
8
9 "bitbucket.org/lightcodelabs/caddy2"
10 "github.com/go-acme/lego/challenge"
12 - "github.com/klauspost/cpuid"
11 "github.com/mholt/certmagic"
12 )
13
@@ -22,8 +20,9 @@ func init() {
20
21 // TLS represents a process-wide TLS configuration.
22 type TLS struct {
25 - Certificates map[string]json.RawMessage `json:"certificates"`
26 - Automation AutomationConfig `json:"automation"`
23 + Certificates map[string]json.RawMessage `json:"certificates,omitempty"`
24 + Automation AutomationConfig `json:"automation,omitempty"`
25 + SessionTickets SessionTicketService `json:"session_tickets,omitempty"`
26
27 certificateLoaders []CertificateLoader
28 certCache *certmagic.Cache
@@ -44,6 +43,7 @@ func (t *TLS) Provision(ctx caddy2.Context) error {
43 },
44 })
45
46 + // automation/management policies
47 for i, ap := range t.Automation.Policies {
48 val, err := ctx.LoadModuleInline("module", "tls.management", ap.Management)
49 if err != nil {
@@ -65,6 +65,12 @@ func (t *TLS) Provision(ctx caddy2.Context) error {
65 t.certificateLoaders = append(t.certificateLoaders, val.(CertificateLoader))
66 }
67
68 + // session ticket ephemeral keys (STEK) service and provider
69 + err := t.SessionTickets.provision(ctx)
70 + if err != nil {
71 + return fmt.Errorf("provisioning session tickets configuration: %v", err)
72 + }
73 +
74 return nil
75 }
76
@@ -110,6 +116,7 @@ func (t *TLS) Stop() error {
116 // TODO: ensure locks are cleaned up too... maybe in certmagic though
117 t.certCache.Stop()
118 }
119 + t.SessionTickets.stop()
120 return nil
121 }
122
@@ -230,98 +237,4 @@ type ManagerMaker interface {
237 newManager(interactive bool) (certmagic.Manager, error)
238 }
239
233 -// supportedCipherSuites is the unordered map of cipher suite
234 -// string names to their definition in crypto/tls.
235 -// TODO: might not be needed much longer, see:
236 -// https://github.com/golang/go/issues/30325
237 -var supportedCipherSuites = map[string]uint16{
238 - "ECDHE_ECDSA_AES256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
239 - "ECDHE_RSA_AES256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
240 - "ECDHE_ECDSA_AES128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
241 - "ECDHE_RSA_AES128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
242 - "ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
243 - "ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
244 - "ECDHE_RSA_AES256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
245 - "ECDHE_RSA_AES128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
246 - "ECDHE_ECDSA_AES256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
247 - "ECDHE_ECDSA_AES128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
248 - "RSA_AES256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
249 - "RSA_AES128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
250 - "ECDHE_RSA_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
251 - "RSA_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
252 -}
253 -
254 -// defaultCipherSuites is the ordered list of all the cipher
255 -// suites we want to support by default, assuming AES-NI
256 -// (hardware acceleration for AES).
257 -var defaultCipherSuitesWithAESNI = []uint16{
258 - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
259 - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
260 - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
261 - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
262 - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
263 - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
264 -}
265 -
266 -// defaultCipherSuites is the ordered list of all the cipher
267 -// suites we want to support by default, assuming lack of
268 -// AES-NI (NO hardware acceleration for AES).
269 -var defaultCipherSuitesWithoutAESNI = []uint16{
270 - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
271 - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
272 - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
273 - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
274 - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
275 - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
276 -}
277 -
278 -// getOptimalDefaultCipherSuites returns an appropriate cipher
279 -// suite to use depending on the hardware support for AES.
280 -//
281 -// See https://github.com/mholt/caddy/issues/1674
282 -func getOptimalDefaultCipherSuites() []uint16 {
283 - if cpuid.CPU.AesNi() {
284 - return defaultCipherSuitesWithAESNI
285 - }
286 - return defaultCipherSuitesWithoutAESNI
287 -}
288 -
289 -// supportedCurves is the unordered map of supported curves.
290 -// https://golang.org/pkg/crypto/tls/#CurveID
291 -var supportedCurves = map[string]tls.CurveID{
292 - "X25519": tls.X25519,
293 - "P256": tls.CurveP256,
294 - "P384": tls.CurveP384,
295 - "P521": tls.CurveP521,
296 -}
297 -
298 -// defaultCurves is the list of only the curves we want to use
299 -// by default, in descending order of preference.
300 -//
301 -// This list should only include curves which are fast by design
302 -// (e.g. X25519) and those for which an optimized assembly
303 -// implementation exists (e.g. P256). The latter ones can be
304 -// found here:
305 -// https://github.com/golang/go/tree/master/src/crypto/elliptic
306 -var defaultCurves = []tls.CurveID{
307 - tls.X25519,
308 - tls.CurveP256,
309 -}
310 -
311 -// supportedProtocols is a map of supported protocols.
312 -// HTTP/2 only supports TLS 1.2 and higher.
313 -var supportedProtocols = map[string]uint16{
314 - "tls1.0": tls.VersionTLS10,
315 - "tls1.1": tls.VersionTLS11,
316 - "tls1.2": tls.VersionTLS12,
317 - "tls1.3": tls.VersionTLS13,
318 -}
319 -
320 -// publicKeyAlgorithms is the map of supported public key algorithms.
321 -var publicKeyAlgorithms = map[string]x509.PublicKeyAlgorithm{
322 - "rsa": x509.RSA,
323 - "dsa": x509.DSA,
324 - "ecdsa": x509.ECDSA,
325 -}
326 -
240 const automateKey = "automate"
modules/caddytls/values.go new
+102
@@ -0,0 +1,102 @@
1 +package caddytls
2 +
3 +import (
4 + "crypto/tls"
5 + "crypto/x509"
6 +
7 + "github.com/klauspost/cpuid"
8 +)
9 +
10 +// supportedCipherSuites is the unordered map of cipher suite
11 +// string names to their definition in crypto/tls.
12 +// TODO: might not be needed much longer, see:
13 +// https://github.com/golang/go/issues/30325
14 +var supportedCipherSuites = map[string]uint16{
15 + "ECDHE_ECDSA_AES256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
16 + "ECDHE_RSA_AES256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
17 + "ECDHE_ECDSA_AES128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
18 + "ECDHE_RSA_AES128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
19 + "ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
20 + "ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
21 + "ECDHE_RSA_AES256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
22 + "ECDHE_RSA_AES128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
23 + "ECDHE_ECDSA_AES256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
24 + "ECDHE_ECDSA_AES128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
25 + "RSA_AES256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
26 + "RSA_AES128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
27 + "ECDHE_RSA_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
28 + "RSA_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
29 +}
30 +
31 +// defaultCipherSuites is the ordered list of all the cipher
32 +// suites we want to support by default, assuming AES-NI
33 +// (hardware acceleration for AES).
34 +var defaultCipherSuitesWithAESNI = []uint16{
35 + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
36 + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
37 + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
38 + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
39 + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
40 + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
41 +}
42 +
43 +// defaultCipherSuites is the ordered list of all the cipher
44 +// suites we want to support by default, assuming lack of
45 +// AES-NI (NO hardware acceleration for AES).
46 +var defaultCipherSuitesWithoutAESNI = []uint16{
47 + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
48 + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
49 + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
50 + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
51 + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
52 + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
53 +}
54 +
55 +// getOptimalDefaultCipherSuites returns an appropriate cipher
56 +// suite to use depending on the hardware support for AES.
57 +//
58 +// See https://github.com/mholt/caddy/issues/1674
59 +func getOptimalDefaultCipherSuites() []uint16 {
60 + if cpuid.CPU.AesNi() {
61 + return defaultCipherSuitesWithAESNI
62 + }
63 + return defaultCipherSuitesWithoutAESNI
64 +}
65 +
66 +// supportedCurves is the unordered map of supported curves.
67 +// https://golang.org/pkg/crypto/tls/#CurveID
68 +var supportedCurves = map[string]tls.CurveID{
69 + "X25519": tls.X25519,
70 + "P256": tls.CurveP256,
71 + "P384": tls.CurveP384,
72 + "P521": tls.CurveP521,
73 +}
74 +
75 +// defaultCurves is the list of only the curves we want to use
76 +// by default, in descending order of preference.
77 +//
78 +// This list should only include curves which are fast by design
79 +// (e.g. X25519) and those for which an optimized assembly
80 +// implementation exists (e.g. P256). The latter ones can be
81 +// found here:
82 +// https://github.com/golang/go/tree/master/src/crypto/elliptic
83 +var defaultCurves = []tls.CurveID{
84 + tls.X25519,
85 + tls.CurveP256,
86 +}
87 +
88 +// supportedProtocols is a map of supported protocols.
89 +// HTTP/2 only supports TLS 1.2 and higher.
90 +var supportedProtocols = map[string]uint16{
91 + "tls1.0": tls.VersionTLS10,
92 + "tls1.1": tls.VersionTLS11,
93 + "tls1.2": tls.VersionTLS12,
94 + "tls1.3": tls.VersionTLS13,
95 +}
96 +
97 +// publicKeyAlgorithms is the map of supported public key algorithms.
98 +var publicKeyAlgorithms = map[string]x509.PublicKeyAlgorithm{
99 + "rsa": x509.RSA,
100 + "dsa": x509.DSA,
101 + "ecdsa": x509.ECDSA,
102 +}