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
+}