mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-26 02:09:47 +08:00
fc2ff9155c
- Expose the list of Caddy instances through caddy.Instances() - Added arbitrary storage to caddy.Instance - The cache of loaded certificates is no longer global; now scoped per-instance, meaning upon reload (like SIGUSR1) the old cert cache will be discarded entirely, whereas before, aggressively reloading config that added and removed lots of sites would cause unnecessary build-up in the cache over time. - Key certificates in the cache by their SHA-256 hash instead of by their names. This means certificates will not be duplicated in memory (within each instance), making Caddy much more memory-efficient for large-scale deployments with thousands of sites sharing certs. - Perform name-to-certificate lookups scoped per caddytls.Config instead of a single global lookup. This prevents certificates from stepping on each other when they overlap in their names. - Do not allow TLS configurations keyed by the same hostname to be different; this now throws an error. - Updated relevant tests, with a stark awareness that more tests are needed. - Change the NewContext function signature to include an *Instance. - Strongly recommend (basically require) use of caddytls.NewConfig() to create a new *caddytls.Config, to ensure pointers to the instance certificate cache are initialized properly. - Update the TLS-SNI challenge solver (even though TLS-SNI is disabled currently on the CA side). Store temporary challenge cert in instance cache, but do so directly by the ACME challenge name, not the hash. Modified the getCertificate function to check the cache directly for a name match if one isn't found otherwise. This will allow any caddytls.Config to be able to help solve a TLS-SNI challenge, with one extra side-effect that might actually be kind of interesting (and useless): clients could send a certificate's hash as the SNI and Caddy would be able to serve that certificate for the handshake. - Do not attempt to match a "default" (random) certificate when SNI is present but unrecognized; return no certificate so a TLS alert happens instead. - Store an Instance in the list of instances even while the instance is still starting up (this allows access to the cert cache for performing renewals at startup, etc). Will be removed from list again if instance startup fails. - Laid groundwork for ACMEv2 and Let's Encrypt wildcard support. Server type plugins will need to be updated slightly to accommodate minor adjustments to their API (like passing in an Instance). This commit includes the changes for the HTTP server. Certain Caddyfile configurations might error out with this change, if they configured different TLS settings for the same hostname. This change trades some complexity for other complexity, but ultimately this new complexity is more correct and robust than earlier logic. Fixes #1991 Fixes #1994 Fixes #1303
652 lines
20 KiB
Go
652 lines
20 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
|
|
|
|
// The map of hostname to certificate hash. This is used to complete
|
|
// handshakes and serve the right certificate given the SNI.
|
|
Certificates map[string]string
|
|
|
|
certCache *certificateCache // pointer to the Instance's certificate store
|
|
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
|
|
|
|
// The url to call to check if an on-demand tls certificate should
|
|
// be issued. If a request to the URL fails or returns a non 2xx
|
|
// status on-demand issuances must fail.
|
|
AskURL *url.URL
|
|
}
|
|
|
|
// NewConfig returns a new Config with a pointer to the instance's
|
|
// certificate cache. You will usually need to set Other fields on
|
|
// the returned Config for successful practical use.
|
|
func NewConfig(inst *caddy.Instance) *Config {
|
|
inst.StorageMu.RLock()
|
|
certCache, ok := inst.Storage[CertCacheInstStorageKey].(*certificateCache)
|
|
inst.StorageMu.RUnlock()
|
|
if !ok || certCache == nil {
|
|
certCache = &certificateCache{cache: make(map[string]Certificate)}
|
|
inst.StorageMu.Lock()
|
|
inst.Storage[CertCacheInstStorageKey] = certCache
|
|
inst.StorageMu.Unlock()
|
|
}
|
|
cfg := new(Config)
|
|
cfg.Certificates = make(map[string]string)
|
|
cfg.certCache = certCache
|
|
return cfg
|
|
}
|
|
|
|
// 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. This is used
|
|
// to create a single TLS configuration for a listener (a group
|
|
// of sites).
|
|
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 this caddytls.Config into a tls.Config
|
|
if err := cfg.buildStandardTLSConfig(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// if an existing config with this hostname was already
|
|
// configured, then they must be identical (or at least
|
|
// compatible), otherwise that is a configuration error
|
|
if otherConfig, ok := configMap[cfg.Hostname]; ok {
|
|
if err := assertConfigsCompatible(cfg, otherConfig); err != nil {
|
|
return nil, fmt.Errorf("incompabile TLS configurations for the same SNI "+
|
|
"name (%s) on the same listener: %v",
|
|
cfg.Hostname, err)
|
|
}
|
|
}
|
|
|
|
// key this config by its hostname (overwrites
|
|
// configs with the same hostname pattern; should
|
|
// be OK since we already asserted they are roughly
|
|
// the same); 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
|
|
}
|
|
|
|
// assertConfigsCompatible returns an error if the two Configs
|
|
// do not have the same (or roughly compatible) configurations.
|
|
// If one of the tlsConfig pointers on either Config is nil,
|
|
// an error will be returned. If both are nil, no error.
|
|
func assertConfigsCompatible(cfg1, cfg2 *Config) error {
|
|
c1, c2 := cfg1.tlsConfig, cfg2.tlsConfig
|
|
|
|
if (c1 == nil && c2 != nil) || (c1 != nil && c2 == nil) {
|
|
return fmt.Errorf("one config is not made")
|
|
}
|
|
if c1 == nil && c2 == nil {
|
|
return nil
|
|
}
|
|
|
|
if len(c1.CipherSuites) != len(c2.CipherSuites) {
|
|
return fmt.Errorf("different number of allowed cipher suites")
|
|
}
|
|
for i, ciph := range c1.CipherSuites {
|
|
if c2.CipherSuites[i] != ciph {
|
|
return fmt.Errorf("different cipher suites or different order")
|
|
}
|
|
}
|
|
|
|
if len(c1.CurvePreferences) != len(c2.CurvePreferences) {
|
|
return fmt.Errorf("different number of allowed cipher suites")
|
|
}
|
|
for i, curve := range c1.CurvePreferences {
|
|
if c2.CurvePreferences[i] != curve {
|
|
return fmt.Errorf("different curve preferences or different order")
|
|
}
|
|
}
|
|
|
|
if len(c1.NextProtos) != len(c2.NextProtos) {
|
|
return fmt.Errorf("different number of ALPN (NextProtos) values")
|
|
}
|
|
for i, proto := range c1.NextProtos {
|
|
if c2.NextProtos[i] != proto {
|
|
return fmt.Errorf("different ALPN (NextProtos) values or different order")
|
|
}
|
|
}
|
|
|
|
if c1.PreferServerCipherSuites != c2.PreferServerCipherSuites {
|
|
return fmt.Errorf("one prefers server cipher suites, the other does not")
|
|
}
|
|
if c1.MinVersion != c2.MinVersion {
|
|
return fmt.Errorf("minimum TLS version mismatch")
|
|
}
|
|
if c1.MaxVersion != c2.MaxVersion {
|
|
return fmt.Errorf("maximum TLS version mismatch")
|
|
}
|
|
if c1.ClientAuth != c2.ClientAuth {
|
|
return fmt.Errorf("client authentication policy mismatch")
|
|
}
|
|
|
|
return 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"
|
|
|
|
// CertCacheInstStorageKey is the name of the key for
|
|
// accessing the certificate storage on the *caddy.Instance.
|
|
CertCacheInstStorageKey = "tls_cert_cache"
|
|
)
|