mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 02:27:19 -04:00 
			
		
		
		
	I am not a lawyer, but according to the appendix of the license, these boilerplate notices should be included with every source file.
		
			
				
	
	
		
			547 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2015 Light Code Labs, LLC
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package caddytls
 | |
| 
 | |
| import (
 | |
| 	"crypto/tls"
 | |
| 	"crypto/x509"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/codahale/aesnicheck"
 | |
| 	"github.com/mholt/caddy"
 | |
| 	"github.com/xenolf/lego/acme"
 | |
| )
 | |
| 
 | |
| // Config describes how TLS should be configured and used.
 | |
| type Config struct {
 | |
| 	// The hostname or class of hostnames this config is
 | |
| 	// designated for; can contain wildcard characters
 | |
| 	// according to RFC 6125 §6.4.3 - this field MUST
 | |
| 	// be set in order for things to work as expected
 | |
| 	Hostname string
 | |
| 
 | |
| 	// Whether TLS is enabled
 | |
| 	Enabled bool
 | |
| 
 | |
| 	// Minimum and maximum protocol versions to allow
 | |
| 	ProtocolMinVersion uint16
 | |
| 	ProtocolMaxVersion uint16
 | |
| 
 | |
| 	// The list of cipher suites; first should be
 | |
| 	// TLS_FALLBACK_SCSV to prevent degrade attacks
 | |
| 	Ciphers []uint16
 | |
| 
 | |
| 	// Whether to prefer server cipher suites
 | |
| 	PreferServerCipherSuites bool
 | |
| 
 | |
| 	// The list of preferred curves
 | |
| 	CurvePreferences []tls.CurveID
 | |
| 
 | |
| 	// Client authentication policy
 | |
| 	ClientAuth tls.ClientAuthType
 | |
| 
 | |
| 	// List of client CA certificates to allow, if
 | |
| 	// client authentication is enabled
 | |
| 	ClientCerts []string
 | |
| 
 | |
| 	// Manual means user provides own certs and keys
 | |
| 	Manual bool
 | |
| 
 | |
| 	// Managed means config qualifies for implicit,
 | |
| 	// automatic, managed TLS; as opposed to the user
 | |
| 	// providing and managing the certificate manually
 | |
| 	Managed bool
 | |
| 
 | |
| 	// OnDemand means the class of hostnames this
 | |
| 	// config applies to may obtain and manage
 | |
| 	// certificates at handshake-time (as opposed
 | |
| 	// to pre-loaded at startup); OnDemand certs
 | |
| 	// will be managed the same way as preloaded
 | |
| 	// ones, however, if an OnDemand cert fails to
 | |
| 	// renew, it is removed from the in-memory
 | |
| 	// cache; if this is true, Managed must
 | |
| 	// necessarily be true
 | |
| 	OnDemand bool
 | |
| 
 | |
| 	// SelfSigned means that this hostname is
 | |
| 	// served with a self-signed certificate
 | |
| 	// that we generated in memory for convenience
 | |
| 	SelfSigned bool
 | |
| 
 | |
| 	// The endpoint of the directory for the ACME
 | |
| 	// CA we are to use
 | |
| 	CAUrl string
 | |
| 
 | |
| 	// The host (ONLY the host, not port) to listen
 | |
| 	// on if necessary to start a listener to solve
 | |
| 	// an ACME challenge
 | |
| 	ListenHost string
 | |
| 
 | |
| 	// The alternate port (ONLY port, not host)
 | |
| 	// to use for the ACME HTTP challenge; this
 | |
| 	// port will be used if we proxy challenges
 | |
| 	// coming in on port 80 to this alternate port
 | |
| 	AltHTTPPort string
 | |
| 
 | |
| 	// The alternate port (ONLY port, not host)
 | |
| 	// to use for the ACME TLS-SNI challenge.
 | |
| 	// The system must forward the standard port
 | |
| 	// for the TLS-SNI challenge to this port.
 | |
| 	AltTLSSNIPort string
 | |
| 
 | |
| 	// The string identifier of the DNS provider
 | |
| 	// to use when solving the ACME DNS challenge
 | |
| 	DNSProvider string
 | |
| 
 | |
| 	// The email address to use when creating or
 | |
| 	// using an ACME account (fun fact: if this
 | |
| 	// is set to "off" then this config will not
 | |
| 	// qualify for managed TLS)
 | |
| 	ACMEEmail string
 | |
| 
 | |
| 	// The type of key to use when generating
 | |
| 	// certificates
 | |
| 	KeyType acme.KeyType
 | |
| 
 | |
| 	// The storage creator; use StorageFor() to get a guaranteed
 | |
| 	// non-nil Storage instance. Note, Caddy may call this frequently
 | |
| 	// so implementors are encouraged to cache any heavy instantiations.
 | |
| 	StorageProvider string
 | |
| 
 | |
| 	// The state needed to operate on-demand TLS
 | |
| 	OnDemandState OnDemandState
 | |
| 
 | |
| 	// Add the must staple TLS extension to the CSR generated by lego/acme
 | |
| 	MustStaple bool
 | |
| 
 | |
| 	// The list of protocols to choose from for Application Layer
 | |
| 	// Protocol Negotiation (ALPN).
 | |
| 	ALPN []string
 | |
| 
 | |
| 	tlsConfig *tls.Config // the final tls.Config created with buildStandardTLSConfig()
 | |
| }
 | |
| 
 | |
| // OnDemandState contains some state relevant for providing
 | |
| // on-demand TLS.
 | |
| type OnDemandState struct {
 | |
| 	// The number of certificates that have been issued on-demand
 | |
| 	// by this config. It is only safe to modify this count atomically.
 | |
| 	// If it reaches MaxObtain, on-demand issuances must fail.
 | |
| 	ObtainedCount int32
 | |
| 
 | |
| 	// Set from max_certs in tls config, it specifies the
 | |
| 	// maximum number of certificates that can be issued.
 | |
| 	MaxObtain int32
 | |
| }
 | |
| 
 | |
| // ObtainCert obtains a certificate for name using c, as long
 | |
| // as a certificate does not already exist in storage for that
 | |
| // name. The name must qualify and c must be flagged as Managed.
 | |
| // This function is a no-op if storage already has a certificate
 | |
| // for name.
 | |
| //
 | |
| // It only obtains and stores certificates (and their keys),
 | |
| // it does not load them into memory. If allowPrompts is true,
 | |
| // the user may be shown a prompt.
 | |
| func (c *Config) ObtainCert(name string, allowPrompts bool) error {
 | |
| 	if !c.Managed || !HostQualifies(name) {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	storage, err := c.StorageFor(c.CAUrl)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	siteExists, err := storage.SiteExists(name)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if siteExists {
 | |
| 		return nil
 | |
| 	}
 | |
| 	if c.ACMEEmail == "" {
 | |
| 		c.ACMEEmail = getEmail(storage, allowPrompts)
 | |
| 	}
 | |
| 
 | |
| 	client, err := newACMEClient(c, allowPrompts)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return client.Obtain(name)
 | |
| }
 | |
| 
 | |
| // RenewCert renews the certificate for name using c. It stows the
 | |
| // renewed certificate and its assets in storage if successful.
 | |
| func (c *Config) RenewCert(name string, allowPrompts bool) error {
 | |
| 	client, err := newACMEClient(c, allowPrompts)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return client.Renew(name)
 | |
| }
 | |
| 
 | |
| // StorageFor obtains a TLS Storage instance for the given CA URL which should
 | |
| // be unique for every different ACME CA. If a StorageCreator is set on this
 | |
| // Config, it will be used. Otherwise the default file storage implementation
 | |
| // is used. When the error is nil, this is guaranteed to return a non-nil
 | |
| // Storage instance.
 | |
| func (c *Config) StorageFor(caURL string) (Storage, error) {
 | |
| 	// Validate CA URL
 | |
| 	if caURL == "" {
 | |
| 		caURL = DefaultCAUrl
 | |
| 	}
 | |
| 	if caURL == "" {
 | |
| 		return nil, fmt.Errorf("cannot create storage without CA URL")
 | |
| 	}
 | |
| 	caURL = strings.ToLower(caURL)
 | |
| 
 | |
| 	// scheme required or host will be parsed as path (as of Go 1.6)
 | |
| 	if !strings.Contains(caURL, "://") {
 | |
| 		caURL = "https://" + caURL
 | |
| 	}
 | |
| 
 | |
| 	u, err := url.Parse(caURL)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("%s: unable to parse CA URL: %v", caURL, err)
 | |
| 	}
 | |
| 
 | |
| 	if u.Host == "" {
 | |
| 		return nil, fmt.Errorf("%s: no host in CA URL", caURL)
 | |
| 	}
 | |
| 
 | |
| 	// Create the storage based on the URL
 | |
| 	var s Storage
 | |
| 	if c.StorageProvider == "" {
 | |
| 		c.StorageProvider = "file"
 | |
| 	}
 | |
| 
 | |
| 	creator, ok := storageProviders[c.StorageProvider]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("%s: Unknown storage: %v", caURL, c.StorageProvider)
 | |
| 	}
 | |
| 
 | |
| 	s, err = creator(u)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("%s: unable to create custom storage '%v': %v", caURL, c.StorageProvider, err)
 | |
| 	}
 | |
| 
 | |
| 	return s, nil
 | |
| }
 | |
| 
 | |
| // buildStandardTLSConfig converts cfg (*caddytls.Config) to a *tls.Config
 | |
| // and stores it in cfg so it can be used in servers. If TLS is disabled,
 | |
| // no tls.Config is created.
 | |
| func (c *Config) buildStandardTLSConfig() error {
 | |
| 	if !c.Enabled {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	config := new(tls.Config)
 | |
| 
 | |
| 	ciphersAdded := make(map[uint16]struct{})
 | |
| 	curvesAdded := make(map[tls.CurveID]struct{})
 | |
| 
 | |
| 	// add cipher suites
 | |
| 	for _, ciph := range c.Ciphers {
 | |
| 		if _, ok := ciphersAdded[ciph]; !ok {
 | |
| 			ciphersAdded[ciph] = struct{}{}
 | |
| 			config.CipherSuites = append(config.CipherSuites, ciph)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	config.PreferServerCipherSuites = c.PreferServerCipherSuites
 | |
| 
 | |
| 	// add curve preferences
 | |
| 	for _, curv := range c.CurvePreferences {
 | |
| 		if _, ok := curvesAdded[curv]; !ok {
 | |
| 			curvesAdded[curv] = struct{}{}
 | |
| 			config.CurvePreferences = append(config.CurvePreferences, curv)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	config.MinVersion = c.ProtocolMinVersion
 | |
| 	config.MaxVersion = c.ProtocolMaxVersion
 | |
| 	config.ClientAuth = c.ClientAuth
 | |
| 	config.NextProtos = c.ALPN
 | |
| 	config.GetCertificate = c.GetCertificate
 | |
| 
 | |
| 	// set up client authentication if enabled
 | |
| 	if config.ClientAuth != tls.NoClientCert {
 | |
| 		pool := x509.NewCertPool()
 | |
| 		clientCertsAdded := make(map[string]struct{})
 | |
| 
 | |
| 		for _, caFile := range c.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 err
 | |
| 			}
 | |
| 
 | |
| 			if !pool.AppendCertsFromPEM(caCrt) {
 | |
| 				return fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		config.ClientCAs = pool
 | |
| 	}
 | |
| 
 | |
| 	// default cipher suites
 | |
| 	if len(config.CipherSuites) == 0 {
 | |
| 		config.CipherSuites = getPreferredDefaultCiphers()
 | |
| 	}
 | |
| 
 | |
| 	// for security, ensure TLS_FALLBACK_SCSV is always included first
 | |
| 	if len(config.CipherSuites) == 0 || config.CipherSuites[0] != tls.TLS_FALLBACK_SCSV {
 | |
| 		config.CipherSuites = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.CipherSuites...)
 | |
| 	}
 | |
| 
 | |
| 	// store the resulting new tls.Config
 | |
| 	c.tlsConfig = config
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // MakeTLSConfig makes a tls.Config from configs. The returned
 | |
| // tls.Config is programmed to load the matching caddytls.Config
 | |
| // based on the hostname in SNI, but that's all.
 | |
| func MakeTLSConfig(configs []*Config) (*tls.Config, error) {
 | |
| 	if len(configs) == 0 {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 
 | |
| 	configMap := make(configGroup)
 | |
| 
 | |
| 	for i, cfg := range configs {
 | |
| 		if cfg == nil {
 | |
| 			// avoid nil pointer dereference below this loop
 | |
| 			configs[i] = new(Config)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// can't serve TLS and non-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)
 | |
| 		}
 | |
| 
 | |
| 		// convert each caddytls.Config into a tls.Config
 | |
| 		if err := cfg.buildStandardTLSConfig(); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		// Key this config by its hostname (overwriting
 | |
| 		// configs with the same hostname pattern); during
 | |
| 		// TLS handshakes, configs are loaded based on
 | |
| 		// the hostname pattern, according to client's SNI.
 | |
| 		configMap[cfg.Hostname] = cfg
 | |
| 	}
 | |
| 
 | |
| 	// Is TLS disabled? By now, we know that all
 | |
| 	// configs agree whether it is or not, so we
 | |
| 	// can just look at the first one. If so,
 | |
| 	// we're done here.
 | |
| 	if len(configs) == 0 || !configs[0].Enabled {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 
 | |
| 	return &tls.Config{
 | |
| 		GetConfigForClient: configMap.GetConfigForClient,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // ConfigGetter gets a Config keyed by key.
 | |
| type ConfigGetter func(c *caddy.Controller) *Config
 | |
| 
 | |
| var configGetters = make(map[string]ConfigGetter)
 | |
| 
 | |
| // RegisterConfigGetter registers fn as the way to get a
 | |
| // Config for server type serverType.
 | |
| func RegisterConfigGetter(serverType string, fn ConfigGetter) {
 | |
| 	configGetters[serverType] = fn
 | |
| }
 | |
| 
 | |
| // SetDefaultTLSParams sets the default TLS cipher suites, protocol versions,
 | |
| // and server preferences of a server.Config if they were not previously set
 | |
| // (it does not overwrite; only fills in missing values).
 | |
| func SetDefaultTLSParams(config *Config) {
 | |
| 	// If no ciphers provided, use default list
 | |
| 	if len(config.Ciphers) == 0 {
 | |
| 		config.Ciphers = getPreferredDefaultCiphers()
 | |
| 	}
 | |
| 
 | |
| 	// Not a cipher suite, but still important for mitigating protocol downgrade attacks
 | |
| 	// (prepend since having it at end breaks http2 due to non-h2-approved suites before it)
 | |
| 	config.Ciphers = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.Ciphers...)
 | |
| 
 | |
| 	// If no curves provided, use default list
 | |
| 	if len(config.CurvePreferences) == 0 {
 | |
| 		config.CurvePreferences = defaultCurves
 | |
| 	}
 | |
| 
 | |
| 	// Set default protocol min and max versions - must balance compatibility and security
 | |
| 	if config.ProtocolMinVersion == 0 {
 | |
| 		config.ProtocolMinVersion = tls.VersionTLS11
 | |
| 	}
 | |
| 	if config.ProtocolMaxVersion == 0 {
 | |
| 		config.ProtocolMaxVersion = tls.VersionTLS12
 | |
| 	}
 | |
| 
 | |
| 	// Prefer server cipher suites
 | |
| 	config.PreferServerCipherSuites = true
 | |
| }
 | |
| 
 | |
| // Map of supported key types
 | |
| var supportedKeyTypes = map[string]acme.KeyType{
 | |
| 	"P384":    acme.EC384,
 | |
| 	"P256":    acme.EC256,
 | |
| 	"RSA8192": acme.RSA8192,
 | |
| 	"RSA4096": acme.RSA4096,
 | |
| 	"RSA2048": acme.RSA2048,
 | |
| }
 | |
| 
 | |
| // 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,
 | |
| }
 | |
| 
 | |
| // Map of supported ciphers, used only for parsing config.
 | |
| //
 | |
| // Note that, at time of writing, HTTP/2 blacklists 276 cipher suites,
 | |
| // including all but four of the suites below (the four GCM suites).
 | |
| // See https://http2.github.io/http2-spec/#BadCipherSuites
 | |
| //
 | |
| // TLS_FALLBACK_SCSV is not in this list because we manually ensure
 | |
| // it is always added (even though it is not technically a cipher suite).
 | |
| //
 | |
| // This map, like any map, is NOT ORDERED. Do not range over this map.
 | |
| var supportedCiphersMap = 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,
 | |
| }
 | |
| 
 | |
| // List of all the ciphers we want to use by default
 | |
| var defaultCiphers = []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,
 | |
| 	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
 | |
| 	tls.TLS_RSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_RSA_WITH_AES_128_CBC_SHA,
 | |
| }
 | |
| 
 | |
| // List of ciphers we should prefer if native AESNI support is missing
 | |
| var defaultCiphersNonAESNI = []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,
 | |
| 	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
 | |
| 	tls.TLS_RSA_WITH_AES_256_CBC_SHA,
 | |
| 	tls.TLS_RSA_WITH_AES_128_CBC_SHA,
 | |
| }
 | |
| 
 | |
| // getPreferredDefaultCiphers returns an appropriate cipher suite to use, depending on
 | |
| // the hardware support available for AES-NI.
 | |
| //
 | |
| // See https://github.com/mholt/caddy/issues/1674
 | |
| func getPreferredDefaultCiphers() []uint16 {
 | |
| 	if aesnicheck.HasAESNI() {
 | |
| 		return defaultCiphers
 | |
| 	}
 | |
| 
 | |
| 	// Return a cipher suite that prefers ChaCha20
 | |
| 	return defaultCiphersNonAESNI
 | |
| }
 | |
| 
 | |
| // Map of supported curves
 | |
| // https://golang.org/pkg/crypto/tls/#CurveID
 | |
| var supportedCurvesMap = map[string]tls.CurveID{
 | |
| 	"X25519": tls.X25519,
 | |
| 	"P256":   tls.CurveP256,
 | |
| 	"P384":   tls.CurveP384,
 | |
| 	"P521":   tls.CurveP521,
 | |
| }
 | |
| 
 | |
| // List of all the curves we want to use by default
 | |
| //
 | |
| // 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,
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// HTTPChallengePort is the officially designated port for
 | |
| 	// the HTTP challenge according to the ACME spec.
 | |
| 	HTTPChallengePort = "80"
 | |
| 
 | |
| 	// TLSSNIChallengePort is the officially designated port for
 | |
| 	// the TLS-SNI challenge according to the ACME spec.
 | |
| 	TLSSNIChallengePort = "443"
 | |
| 
 | |
| 	// DefaultHTTPAlternatePort is the port on which the ACME
 | |
| 	// client will open a listener and solve the HTTP challenge.
 | |
| 	// If this alternate port is used instead of the default
 | |
| 	// port, then whatever is listening on the default port must
 | |
| 	// be capable of proxying or forwarding the request to this
 | |
| 	// alternate port.
 | |
| 	DefaultHTTPAlternatePort = "5033"
 | |
| )
 |