use go 1.12

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-03-12 15:47:56 +08:00
parent b59c244ca2
commit 4144404b0b
1110 changed files with 161100 additions and 14519 deletions

541
vendor/github.com/mholt/caddy/caddytls/config.go generated vendored Normal file
View File

@@ -0,0 +1,541 @@
// 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"
"os"
"sync/atomic"
"github.com/xenolf/lego/challenge/tlsalpn01"
"github.com/klauspost/cpuid"
"github.com/mholt/caddy"
"github.com/mholt/certmagic"
"github.com/xenolf/lego/certcrypto"
)
// 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,
// must be normalized, and if an IP address, must
// be normalized
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 this config should be managed
// by the CertMagic Config (Manager field)
Managed bool
// Manager is how certificates are managed
Manager *certmagic.Config
// SelfSigned means that this hostname is
// served with a self-signed certificate
// that we generated in memory for convenience
SelfSigned bool
// 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 list of protocols to choose from for Application Layer
// Protocol Negotiation (ALPN).
ALPN []string
// The final tls.Config created with
// buildStandardTLSConfig()
tlsConfig *tls.Config
}
// 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, error) {
inst.StorageMu.RLock()
certCache, ok := inst.Storage[CertCacheInstStorageKey].(*certmagic.Cache)
inst.StorageMu.RUnlock()
if !ok || certCache == nil {
// set up the clustering plugin, if there is one (and there should always
// be one since this tls plugin requires it) -- this should be done exactly
// once, but we can't do it during init while plugins are still registering,
// so do it as soon as we run a setup)
if atomic.CompareAndSwapInt32(&clusterPluginSetup, 0, 1) {
clusterPluginName := os.Getenv("CADDY_CLUSTERING")
if clusterPluginName == "" {
clusterPluginName = "file" // name of default storage plugin
}
clusterFn, ok := clusterProviders[clusterPluginName]
if ok {
storage, err := clusterFn()
if err != nil {
return nil, fmt.Errorf("constructing cluster plugin %s: %v", clusterPluginName, err)
}
certmagic.DefaultStorage = storage
} else {
return nil, fmt.Errorf("unrecognized cluster plugin (was it included in the Caddy build?): %s", clusterPluginName)
}
}
certCache = certmagic.NewCache(certmagic.DefaultStorage)
inst.OnShutdown = append(inst.OnShutdown, func() error {
certCache.Stop()
return nil
})
inst.StorageMu.Lock()
inst.Storage[CertCacheInstStorageKey] = certCache
inst.StorageMu.Unlock()
}
return &Config{
Manager: certmagic.NewWithCache(certCache, certmagic.Config{}),
}, 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)
}
}
// ensure ALPN includes the ACME TLS-ALPN protocol
var alpnFound bool
for _, a := range c.ALPN {
if a == tlsalpn01.ACMETLS1Protocol {
alpnFound = true
break
}
}
if !alpnFound {
c.ALPN = append(c.ALPN, tlsalpn01.ACMETLS1Protocol)
}
config.MinVersion = c.ProtocolMinVersion
config.MaxVersion = c.ProtocolMaxVersion
config.ClientAuth = c.ClientAuth
config.NextProtos = c.ALPN
config.GetCertificate = c.Manager.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("incompatible 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 ServerName (SNI) value
if cfg.Hostname == "0.0.0.0" || cfg.Hostname == "::" {
configMap[""] = cfg
} else {
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{
// A tls.Config must have Certificates or GetCertificate
// set, in order to be accepted by tls.Listen and quic.Listen.
// TODO: remove this once the standard library allows a tls.Config with
// only GetConfigForClient set. https://github.com/mholt/caddy/pull/2404
GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
return nil, fmt.Errorf("all certificates configured via GetConfigForClient")
},
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")
}
if c1.ClientAuth != tls.NoClientCert && c2.ClientAuth != tls.NoClientCert && c1.ClientCAs != c2.ClientCAs {
// Two hosts defined on the same listener are not compatible if they
// have ClientAuth enabled, because there's no guarantee beyond the
// hostname which config will be used (because SNI only has server name).
// To prevent clients from bypassing authentication, require that
// ClientAuth be configured in an unambiguous manner.
return fmt.Errorf("multiple hosts requiring client authentication ambiguously configured")
}
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.VersionTLS12
}
if config.ProtocolMaxVersion == 0 {
config.ProtocolMaxVersion = tls.VersionTLS13
}
// Prefer server cipher suites
config.PreferServerCipherSuites = true
}
// Map of supported key types
var supportedKeyTypes = map[string]certcrypto.KeyType{
"P384": certcrypto.EC384,
"P256": certcrypto.EC256,
"RSA8192": certcrypto.RSA8192,
"RSA4096": certcrypto.RSA4096,
"RSA2048": certcrypto.RSA2048,
}
// SupportedProtocols is a map of supported protocols.
// HTTP/2 only supports TLS 1.2 and higher.
// If updating this map, also update tlsProtocolStringToMap in caddyhttp/fastcgi/fastcgi.go
var SupportedProtocols = map[string]uint16{
"tls1.0": tls.VersionTLS10,
"tls1.1": tls.VersionTLS11,
"tls1.2": tls.VersionTLS12,
"tls1.3": tls.VersionTLS13,
}
// GetSupportedProtocolName returns the protocol name
func GetSupportedProtocolName(protocol uint16) (string, error) {
for k, v := range SupportedProtocols {
if v == protocol {
return k, nil
}
}
return "", fmt.Errorf("name: unsupported protocol")
}
// SupportedCiphersMap has 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,
}
// GetSupportedCipherName returns the cipher name
func GetSupportedCipherName(cipher uint16) (string, error) {
for k, v := range SupportedCiphersMap {
if v == cipher {
return k, nil
}
}
return "", fmt.Errorf("name: unsupported cipher")
}
// 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,
}
// 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,
}
// 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 cpuid.CPU.AesNi() {
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,
}
var clusterPluginSetup int32 // access atomically
// CertCacheInstStorageKey is the name of the key for
// accessing the certificate storage on the *caddy.Instance.
const CertCacheInstStorageKey = "tls_cert_cache"

113
vendor/github.com/mholt/caddy/caddytls/crypto.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
// 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/rand"
"crypto/tls"
"io"
"sync"
"time"
)
// RotateSessionTicketKeys rotates the TLS session ticket keys
// on cfg every TicketRotateInterval. It spawns a new goroutine so
// this function does NOT block. It returns a channel you should
// close when you are ready to stop the key rotation, like when the
// server using cfg is no longer running.
//
// TODO: See about moving this into CertMagic and using its Storage
func RotateSessionTicketKeys(cfg *tls.Config) chan struct{} {
ch := make(chan struct{})
ticker := time.NewTicker(TicketRotateInterval)
go runTLSTicketKeyRotation(cfg, ticker, ch)
return ch
}
// Functions that may be swapped out for testing
var (
runTLSTicketKeyRotation = standaloneTLSTicketKeyRotation
setSessionTicketKeysTestHook = func(keys [][32]byte) [][32]byte { return keys }
setSessionTicketKeysTestHookMu sync.Mutex
)
// standaloneTLSTicketKeyRotation governs over the array of TLS ticket keys used to de/crypt TLS tickets.
// It periodically sets a new ticket key as the first one, used to encrypt (and decrypt),
// pushing any old ticket keys to the back, where they are considered for decryption only.
//
// Lack of entropy for the very first ticket key results in the feature being disabled (as does Go),
// later lack of entropy temporarily disables ticket key rotation.
// Old ticket keys are still phased out, though.
//
// Stops the ticker when returning.
func standaloneTLSTicketKeyRotation(c *tls.Config, ticker *time.Ticker, exitChan chan struct{}) {
defer ticker.Stop()
// The entire page should be marked as sticky, but Go cannot do that
// without resorting to syscall#Mlock. And, we don't have madvise (for NODUMP), too. ☹
keys := make([][32]byte, 1, NumTickets)
rng := c.Rand
if rng == nil {
rng = rand.Reader
}
if _, err := io.ReadFull(rng, keys[0][:]); err != nil {
c.SessionTicketsDisabled = true // bail if we don't have the entropy for the first one
return
}
setSessionTicketKeysTestHookMu.Lock()
setSessionTicketKeysHook := setSessionTicketKeysTestHook
setSessionTicketKeysTestHookMu.Unlock()
c.SetSessionTicketKeys(setSessionTicketKeysHook(keys))
for {
select {
case _, isOpen := <-exitChan:
if !isOpen {
return
}
case <-ticker.C:
rng = c.Rand // could've changed since the start
if rng == nil {
rng = rand.Reader
}
var newTicketKey [32]byte
_, err := io.ReadFull(rng, newTicketKey[:])
if len(keys) < NumTickets {
keys = append(keys, keys[0]) // manipulates the internal length
}
for idx := len(keys) - 1; idx >= 1; idx-- {
keys[idx] = keys[idx-1] // yes, this makes copies
}
if err == nil {
keys[0] = newTicketKey
}
// pushes the last key out, doesn't matter that we don't have a new one
c.SetSessionTicketKeys(setSessionTicketKeysHook(keys))
}
}
}
const (
// NumTickets is how many tickets to hold and consider
// to decrypt TLS sessions.
NumTickets = 4
// TicketRotateInterval is how often to generate
// new ticket for TLS PFS encryption
TicketRotateInterval = 10 * time.Hour
)

152
vendor/github.com/mholt/caddy/caddytls/handshake.go generated vendored Normal file
View File

@@ -0,0 +1,152 @@
// 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"
"fmt"
"log"
"net"
"strings"
"github.com/mholt/caddy/telemetry"
"github.com/mholt/certmagic"
)
// configGroup is a type that keys configs by their hostname
// (hostnames can have wildcard characters; use the getConfig
// method to get a config by matching its hostname).
type configGroup map[string]*Config
// getConfig gets the config by the first key match for hello.
// In other words, "sub.foo.bar" will get the config for "*.foo.bar"
// if that is the closest match. If no match is found, the first
// (random) config will be loaded, which will defer any TLS alerts
// to the certificate validation (this may or may not be ideal;
// let's talk about it if this becomes problematic).
//
// This function follows nearly the same logic to lookup
// a hostname as the getCertificate function uses.
func (cg configGroup) getConfig(hello *tls.ClientHelloInfo) *Config {
name := certmagic.NormalizedName(hello.ServerName)
if name == "" {
name = certmagic.NormalizedName(certmagic.DefaultServerName)
}
// if SNI is empty, prefer matching IP address (it is
// more specific than a "catch-all" configuration)
if name == "" && hello.Conn != nil {
addr := hello.Conn.LocalAddr().String()
ip, _, err := net.SplitHostPort(addr)
if err == nil {
addr = ip
}
if config, ok := cg[addr]; ok {
return config
}
}
// otherwise, try an exact match
if config, ok := cg[name]; ok {
return config
}
// then try replacing labels in the name with
// wildcards until we get a match
labels := strings.Split(name, ".")
for i := range labels {
labels[i] = "*"
candidate := strings.Join(labels, ".")
if config, ok := cg[candidate]; ok {
return config
}
}
// try a config that matches all names - this
// is needed to match configs defined without
// a specific host, like ":443", when SNI is
// a non-empty value
if config, ok := cg[""]; ok {
return config
}
// failover with a random config: this is necessary
// because we might be needing to solve a TLS-ALPN
// ACME challenge for a name that we don't have a
// TLS configuration for; any config will do for
// this purpose
for _, config := range cg {
return config
}
log.Printf("[ERROR] No TLS configuration available for ClientHello with ServerName: %s", hello.ServerName)
return nil
}
// GetConfigForClient gets a TLS configuration satisfying clientHello.
// In getting the configuration, it abides the rules and settings
// defined in the Config that matches clientHello.ServerName. If no
// tls.Config is set on the matching Config, a nil value is returned.
//
// This method is safe for use as a tls.Config.GetConfigForClient callback.
func (cg configGroup) GetConfigForClient(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
config := cg.getConfig(clientHello)
if config != nil {
return config.tlsConfig, nil
}
return nil, nil
}
// ClientHelloInfo is our own version of the standard lib's
// tls.ClientHelloInfo. As of May 2018, any fields populated
// by the Go standard library are not guaranteed to have their
// values in the original order as on the wire.
type ClientHelloInfo struct {
Version uint16 `json:"version,omitempty"`
CipherSuites []uint16 `json:"cipher_suites,omitempty"`
Extensions []uint16 `json:"extensions,omitempty"`
CompressionMethods []byte `json:"compression,omitempty"`
Curves []tls.CurveID `json:"curves,omitempty"`
Points []uint8 `json:"points,omitempty"`
// Whether a couple of fields are unknown; if not, the key will encode
// differently to reflect that, as opposed to being known empty values.
// (some fields may be unknown depending on what package is being used;
// i.e. the Go standard lib doesn't expose some things)
// (very important to NOT encode these to JSON)
ExtensionsUnknown bool `json:"-"`
CompressionMethodsUnknown bool `json:"-"`
}
// Key returns a standardized string form of the data in info,
// useful for identifying duplicates.
func (info ClientHelloInfo) Key() string {
extensions, compressionMethods := "?", "?"
if !info.ExtensionsUnknown {
extensions = fmt.Sprintf("%x", info.Extensions)
}
if !info.CompressionMethodsUnknown {
compressionMethods = fmt.Sprintf("%x", info.CompressionMethods)
}
return telemetry.FastHash([]byte(fmt.Sprintf("%x-%x-%s-%s-%x-%x",
info.Version, info.CipherSuites, extensions,
compressionMethods, info.Curves, info.Points)))
}
// ClientHelloTelemetry determines whether to report
// TLS ClientHellos to telemetry. Disable if doing
// it from a different package.
var ClientHelloTelemetry = true

103
vendor/github.com/mholt/caddy/caddytls/selfsigned.go generated vendored Normal file
View File

@@ -0,0 +1,103 @@
package caddytls
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"math/big"
"net"
"strings"
"time"
"github.com/xenolf/lego/certcrypto"
)
// newSelfSignedCertificate returns a new self-signed certificate.
func newSelfSignedCertificate(ssconfig selfSignedConfig) (tls.Certificate, error) {
// start by generating private key
var privKey interface{}
var err error
switch ssconfig.KeyType {
case "", certcrypto.EC256:
privKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
case certcrypto.EC384:
privKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
case certcrypto.RSA2048:
privKey, err = rsa.GenerateKey(rand.Reader, 2048)
case certcrypto.RSA4096:
privKey, err = rsa.GenerateKey(rand.Reader, 4096)
case certcrypto.RSA8192:
privKey, err = rsa.GenerateKey(rand.Reader, 8192)
default:
return tls.Certificate{}, fmt.Errorf("cannot generate private key; unknown key type %v", ssconfig.KeyType)
}
if err != nil {
return tls.Certificate{}, fmt.Errorf("failed to generate private key: %v", err)
}
// create certificate structure with proper values
notBefore := time.Now()
notAfter := ssconfig.Expire
if notAfter.IsZero() || notAfter.Before(notBefore) {
notAfter = notBefore.Add(24 * time.Hour * 7)
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return tls.Certificate{}, fmt.Errorf("failed to generate serial number: %v", err)
}
cert := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{Organization: []string{"Caddy Self-Signed"}},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
if len(ssconfig.SAN) == 0 {
ssconfig.SAN = []string{""}
}
for _, san := range ssconfig.SAN {
if ip := net.ParseIP(san); ip != nil {
cert.IPAddresses = append(cert.IPAddresses, ip)
} else {
cert.DNSNames = append(cert.DNSNames, strings.ToLower(san))
}
}
// generate the associated public key
publicKey := func(privKey interface{}) interface{} {
switch k := privKey.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return fmt.Errorf("unknown key type")
}
}
derBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, publicKey(privKey), privKey)
if err != nil {
return tls.Certificate{}, fmt.Errorf("could not create certificate: %v", err)
}
chain := [][]byte{derBytes}
return tls.Certificate{
Certificate: chain,
PrivateKey: privKey,
Leaf: cert,
}, nil
}
// selfSignedConfig configures a self-signed certificate.
type selfSignedConfig struct {
SAN []string
KeyType certcrypto.KeyType
Expire time.Time
}

451
vendor/github.com/mholt/caddy/caddytls/setup.go generated vendored Normal file
View File

@@ -0,0 +1,451 @@
// 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 (
"bytes"
"crypto/tls"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"github.com/mholt/caddy"
"github.com/mholt/caddy/telemetry"
"github.com/mholt/certmagic"
)
func init() {
// opt-in TLS 1.3 for Go1.12
// TODO: remove this line when Go1.13 is released.
os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
caddy.RegisterPlugin("tls", caddy.Plugin{Action: setupTLS})
// ensure the default Storage implementation is plugged in
RegisterClusterPlugin("file", constructDefaultClusterPlugin)
}
// setupTLS sets up the TLS configuration and installs certificates that
// are specified by the user in the config file. All the automatic HTTPS
// stuff comes later outside of this function.
func setupTLS(c *caddy.Controller) error {
// set up the clustering plugin, if there is one (and there should always
// be one since this tls plugin requires it) -- this should be done exactly
// once, but we can't do it during init while plugins are still registering,
// so do it as soon as we run a setup)
if atomic.CompareAndSwapInt32(&clusterPluginSetup, 0, 1) {
clusterPluginName := os.Getenv("CADDY_CLUSTERING")
if clusterPluginName == "" {
clusterPluginName = "file" // name of default storage plugin
}
clusterFn, ok := clusterProviders[clusterPluginName]
if ok {
storage, err := clusterFn()
if err != nil {
return fmt.Errorf("constructing cluster plugin %s: %v", clusterPluginName, err)
}
certmagic.DefaultStorage = storage
} else {
return fmt.Errorf("unrecognized cluster plugin (was it included in the Caddy build?): %s", clusterPluginName)
}
}
configGetter, ok := configGetters[c.ServerType()]
if !ok {
return fmt.Errorf("no caddytls.ConfigGetter for %s server type; must call RegisterConfigGetter", c.ServerType())
}
config := configGetter(c)
if config == nil {
return fmt.Errorf("no caddytls.Config to set up for %s", c.Key)
}
config.Enabled = true
// we use certmagic events to collect metrics for telemetry
config.Manager.OnEvent = func(event string, data interface{}) {
switch event {
case "tls_handshake_started":
clientHello := data.(*tls.ClientHelloInfo)
if ClientHelloTelemetry && len(clientHello.SupportedVersions) > 0 {
// If no other plugin (such as the HTTP server type) is implementing ClientHello telemetry, we do it.
// NOTE: The values in the Go standard lib's ClientHelloInfo aren't guaranteed to be in order.
info := ClientHelloInfo{
Version: clientHello.SupportedVersions[0], // report the highest
CipherSuites: clientHello.CipherSuites,
ExtensionsUnknown: true, // no extension info... :(
CompressionMethodsUnknown: true, // no compression methods... :(
Curves: clientHello.SupportedCurves,
Points: clientHello.SupportedPoints,
// We also have, but do not yet use: SignatureSchemes, ServerName, and SupportedProtos (ALPN)
// because the standard lib parses some extensions, but our MITM detector generally doesn't.
}
go telemetry.SetNested("tls_client_hello", info.Key(), info)
}
case "tls_handshake_completed":
// TODO: This is a "best guess" for now - at this point, we only gave a
// certificate to the client; we need something listener-level to be sure
go telemetry.Increment("tls_handshake_count")
case "acme_cert_obtained":
go telemetry.Increment("tls_acme_certs_obtained")
case "acme_cert_renewed":
name := data.(string)
caddy.EmitEvent(caddy.CertRenewEvent, name)
go telemetry.Increment("tls_acme_certs_renewed")
case "acme_cert_revoked":
telemetry.Increment("acme_certs_revoked")
case "cached_managed_cert":
telemetry.Increment("tls_managed_cert_count")
case "cached_unmanaged_cert":
telemetry.Increment("tls_unmanaged_cert_count")
}
}
for c.Next() {
var certificateFile, keyFile, loadDir, maxCerts, askURL string
var onDemand bool
args := c.RemainingArgs()
switch len(args) {
case 1:
// even if the email is one of the special values below,
// it is still necessary for future analysis that we store
// that value in the ACMEEmail field.
config.ACMEEmail = args[0]
switch args[0] {
// user can force-disable managed TLS this way
case "off":
config.Enabled = false
return nil
// user might want a temporary, in-memory, self-signed cert
case "self_signed":
config.SelfSigned = true
default:
config.Manager.Email = args[0]
}
case 2:
certificateFile = args[0]
keyFile = args[1]
config.Manual = true
}
// Optional block with extra parameters
var hadBlock bool
for c.NextBlock() {
hadBlock = true
switch c.Val() {
case "ca":
arg := c.RemainingArgs()
if len(arg) != 1 {
return c.ArgErr()
}
config.Manager.CA = arg[0]
case "key_type":
arg := c.RemainingArgs()
value, ok := supportedKeyTypes[strings.ToUpper(arg[0])]
if !ok {
return c.Errf("Wrong key type name or key type not supported: '%s'", c.Val())
}
config.Manager.KeyType = value
case "protocols":
args := c.RemainingArgs()
if len(args) == 1 {
value, ok := SupportedProtocols[strings.ToLower(args[0])]
if !ok {
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
}
config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value
} else {
value, ok := SupportedProtocols[strings.ToLower(args[0])]
if !ok {
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
}
config.ProtocolMinVersion = value
value, ok = SupportedProtocols[strings.ToLower(args[1])]
if !ok {
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
}
config.ProtocolMaxVersion = value
if config.ProtocolMinVersion > config.ProtocolMaxVersion {
return c.Errf("Minimum protocol version cannot be higher than maximum (reverse the order)")
}
}
case "ciphers":
for c.NextArg() {
value, ok := SupportedCiphersMap[strings.ToUpper(c.Val())]
if !ok {
return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val())
}
config.Ciphers = append(config.Ciphers, value)
}
case "curves":
for c.NextArg() {
value, ok := supportedCurvesMap[strings.ToUpper(c.Val())]
if !ok {
return c.Errf("Wrong curve name or curve not supported: '%s'", c.Val())
}
config.CurvePreferences = append(config.CurvePreferences, value)
}
case "clients":
clientCertList := c.RemainingArgs()
if len(clientCertList) == 0 {
return c.ArgErr()
}
listStart, mustProvideCA := 1, true
switch clientCertList[0] {
case "request":
config.ClientAuth = tls.RequestClientCert
mustProvideCA = false
case "require":
config.ClientAuth = tls.RequireAnyClientCert
mustProvideCA = false
case "verify_if_given":
config.ClientAuth = tls.VerifyClientCertIfGiven
default:
config.ClientAuth = tls.RequireAndVerifyClientCert
listStart = 0
}
if mustProvideCA && len(clientCertList) <= listStart {
return c.ArgErr()
}
config.ClientCerts = clientCertList[listStart:]
case "load":
c.Args(&loadDir)
config.Manual = true
case "max_certs":
c.Args(&maxCerts)
onDemand = true
case "ask":
c.Args(&askURL)
onDemand = true
case "dns":
args := c.RemainingArgs()
if len(args) != 1 {
return c.ArgErr()
}
// TODO: we can get rid of DNS provider plugins with this one line
// of code; however, currently (Dec. 2018) this adds about 20 MB
// of bloat to the Caddy binary, doubling its size to ~40 MB...!
// dnsProv, err := dns.NewDNSChallengeProviderByName(args[0])
// if err != nil {
// return c.Errf("Configuring DNS provider '%s': %v", args[0], err)
// }
dnsProvName := args[0]
dnsProvConstructor, ok := dnsProviders[dnsProvName]
if !ok {
return c.Errf("Unknown DNS provider by name '%s'", dnsProvName)
}
dnsProv, err := dnsProvConstructor()
if err != nil {
return c.Errf("Setting up DNS provider '%s': %v", dnsProvName, err)
}
config.Manager.DNSProvider = dnsProv
case "alpn":
args := c.RemainingArgs()
if len(args) == 0 {
return c.ArgErr()
}
for _, arg := range args {
config.ALPN = append(config.ALPN, arg)
}
case "must_staple":
config.Manager.MustStaple = true
case "wildcard":
if !certmagic.HostQualifies(config.Hostname) {
return c.Errf("Hostname '%s' does not qualify for managed TLS, so cannot manage wildcard certificate for it", config.Hostname)
}
if strings.Contains(config.Hostname, "*") {
return c.Errf("Cannot convert domain name '%s' to a valid wildcard: already has a wildcard label", config.Hostname)
}
parts := strings.Split(config.Hostname, ".")
if len(parts) < 3 {
return c.Errf("Cannot convert domain name '%s' to a valid wildcard: too few labels", config.Hostname)
}
parts[0] = "*"
config.Hostname = strings.Join(parts, ".")
default:
return c.Errf("Unknown subdirective '%s'", c.Val())
}
}
// tls requires at least one argument if a block is not opened
if len(args) == 0 && !hadBlock {
return c.ArgErr()
}
// configure on-demand TLS, if enabled
if onDemand {
config.Manager.OnDemand = new(certmagic.OnDemandConfig)
if maxCerts != "" {
maxCertsNum, err := strconv.Atoi(maxCerts)
if err != nil || maxCertsNum < 1 {
return c.Err("max_certs must be a positive integer")
}
config.Manager.OnDemand.MaxObtain = int32(maxCertsNum)
}
if askURL != "" {
parsedURL, err := url.Parse(askURL)
if err != nil {
return c.Err("ask must be a valid url")
}
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
return c.Err("ask URL must use http or https")
}
config.Manager.OnDemand.AskURL = parsedURL
}
}
// don't try to load certificates unless we're supposed to
if !config.Enabled || !config.Manual {
continue
}
// load a single certificate and key, if specified
if certificateFile != "" && keyFile != "" {
err := config.Manager.CacheUnmanagedCertificatePEMFile(certificateFile, keyFile)
if err != nil {
return c.Errf("Unable to load certificate and key files for '%s': %v", c.Key, err)
}
log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile)
}
// load a directory of certificates, if specified
if loadDir != "" {
err := loadCertsInDir(config, c, loadDir)
if err != nil {
return err
}
}
}
SetDefaultTLSParams(config)
// generate self-signed cert if needed
if config.SelfSigned {
ssCert, err := newSelfSignedCertificate(selfSignedConfig{
SAN: []string{config.Hostname},
KeyType: config.Manager.KeyType,
})
if err != nil {
return fmt.Errorf("self-signed certificate generation: %v", err)
}
err = config.Manager.CacheUnmanagedTLSCertificate(ssCert)
if err != nil {
return fmt.Errorf("self-signed: %v", err)
}
telemetry.Increment("tls_self_signed_count")
}
return nil
}
// loadCertsInDir loads all the certificates/keys in dir, as long as
// the file ends with .pem. This method of loading certificates is
// modeled after haproxy, which expects the certificate and key to
// be bundled into the same file:
// https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.1-crt
//
// This function may write to the log as it walks the directory tree.
func loadCertsInDir(cfg *Config, c *caddy.Controller, dir string) error {
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Printf("[WARNING] Unable to traverse into %s; skipping", path)
return nil
}
if info.IsDir() {
return nil
}
if strings.HasSuffix(strings.ToLower(info.Name()), ".pem") {
certBuilder, keyBuilder := new(bytes.Buffer), new(bytes.Buffer)
var foundKey bool // use only the first key in the file
bundle, err := ioutil.ReadFile(path)
if err != nil {
return err
}
for {
// Decode next block so we can see what type it is
var derBlock *pem.Block
derBlock, bundle = pem.Decode(bundle)
if derBlock == nil {
break
}
if derBlock.Type == "CERTIFICATE" {
// Re-encode certificate as PEM, appending to certificate chain
pem.Encode(certBuilder, derBlock)
} else if derBlock.Type == "EC PARAMETERS" {
// EC keys generated from openssl can be composed of two blocks:
// parameters and key (parameter block should come first)
if !foundKey {
// Encode parameters
pem.Encode(keyBuilder, derBlock)
// Key must immediately follow
derBlock, bundle = pem.Decode(bundle)
if derBlock == nil || derBlock.Type != "EC PRIVATE KEY" {
return c.Errf("%s: expected elliptic private key to immediately follow EC parameters", path)
}
pem.Encode(keyBuilder, derBlock)
foundKey = true
}
} else if derBlock.Type == "PRIVATE KEY" || strings.HasSuffix(derBlock.Type, " PRIVATE KEY") {
// RSA key
if !foundKey {
pem.Encode(keyBuilder, derBlock)
foundKey = true
}
} else {
return c.Errf("%s: unrecognized PEM block type: %s", path, derBlock.Type)
}
}
certPEMBytes, keyPEMBytes := certBuilder.Bytes(), keyBuilder.Bytes()
if len(certPEMBytes) == 0 {
return c.Errf("%s: failed to parse PEM data", path)
}
if len(keyPEMBytes) == 0 {
return c.Errf("%s: no private key block found", path)
}
err = cfg.Manager.CacheUnmanagedCertificatePEMBytes(certPEMBytes, keyPEMBytes)
if err != nil {
return c.Errf("%s: failed to load cert and key for '%s': %v", path, c.Key, err)
}
log.Printf("[INFO] Successfully loaded TLS assets from %s", path)
}
return nil
})
}
func constructDefaultClusterPlugin() (certmagic.Storage, error) {
return &certmagic.FileStorage{Path: caddy.AssetsPath()}, nil
}

126
vendor/github.com/mholt/caddy/caddytls/tls.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
// 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 facilitates the management of TLS assets and integrates
// Let's Encrypt functionality into Caddy with first-class support for
// creating and renewing certificates automatically. It also implements
// the tls directive. It's mostly powered by the CertMagic package.
//
// This package is meant to be used by Caddy server types. To use the
// tls directive, a server type must import this package and call
// RegisterConfigGetter(). The server type must make and keep track of
// the caddytls.Config structs that this package produces. It must also
// add tls to its list of directives. When it comes time to make the
// server instances, the server type can call MakeTLSConfig() to convert
// a []caddytls.Config to a single tls.Config for use in tls.NewListener().
// It is also recommended to call RotateSessionTicketKeys() when
// starting a new listener.
package caddytls
import (
"github.com/mholt/caddy"
"github.com/mholt/certmagic"
"github.com/xenolf/lego/challenge"
)
// ConfigHolder is any type that has a Config; it presumably is
// connected to a hostname and port on which it is serving.
type ConfigHolder interface {
TLSConfig() *Config
Host() string
Port() string
}
// QualifiesForManagedTLS returns true if c qualifies for
// for managed TLS (but not on-demand TLS specifically).
// It does NOT check to see if a cert and key already exist
// for the config. If the return value is true, you should
// be OK to set c.TLSConfig().Managed to true; then you should
// check that value in the future instead, because the process
// of setting up the config may make it look like it doesn't
// qualify even though it originally did.
func QualifiesForManagedTLS(c ConfigHolder) bool {
if c == nil {
return false
}
tlsConfig := c.TLSConfig()
if tlsConfig == nil || tlsConfig.Manager == nil {
return false
}
onDemand := tlsConfig.Manager.OnDemand != nil
return (!tlsConfig.Manual || onDemand) && // user might provide own cert and key
// if self-signed, we've already generated one to use
!tlsConfig.SelfSigned &&
// user can force-disable managed TLS
c.Port() != "80" &&
tlsConfig.ACMEEmail != "off" &&
// we get can't certs for some kinds of hostnames, but
// on-demand TLS allows empty hostnames at startup
(certmagic.HostQualifies(c.Host()) || onDemand)
}
// Revoke revokes the certificate fro host via the ACME protocol.
// It assumes the certificate was obtained from certmagic.CA.
func Revoke(domainName string) error {
return certmagic.NewDefault().RevokeCert(domainName, true)
}
// KnownACMECAs is a list of ACME directory endpoints of
// known, public, and trusted ACME-compatible certificate
// authorities.
var KnownACMECAs = []string{
"https://acme-v02.api.letsencrypt.org/directory",
}
// ChallengeProvider defines an own type that should be used in Caddy plugins
// over challenge.Provider. Using challenge.Provider causes version mismatches
// with vendored dependencies (see https://github.com/mattfarina/golang-broken-vendor)
//
// challenge.Provider is an interface that allows the implementation of custom
// challenge providers. For more details, see:
// https://godoc.org/github.com/xenolf/lego/acme#ChallengeProvider
type ChallengeProvider challenge.Provider
// DNSProviderConstructor is a function that takes credentials and
// returns a type that can solve the ACME DNS challenges.
type DNSProviderConstructor func(credentials ...string) (ChallengeProvider, error)
// dnsProviders is the list of DNS providers that have been plugged in.
var dnsProviders = make(map[string]DNSProviderConstructor)
// RegisterDNSProvider registers provider by name for solving the ACME DNS challenge.
func RegisterDNSProvider(name string, provider DNSProviderConstructor) {
dnsProviders[name] = provider
caddy.RegisterPlugin("tls.dns."+name, caddy.Plugin{})
}
// ClusterPluginConstructor is a function type that is used to
// instantiate a new implementation of both certmagic.Storage
// and certmagic.Locker, which are required for successful
// use in cluster environments.
type ClusterPluginConstructor func() (certmagic.Storage, error)
// clusterProviders is the list of storage providers
var clusterProviders = make(map[string]ClusterPluginConstructor)
// RegisterClusterPlugin registers provider by name for facilitating
// cluster-wide operations like storage and synchronization.
func RegisterClusterPlugin(name string, provider ClusterPluginConstructor) {
clusterProviders[name] = provider
caddy.RegisterPlugin("tls.cluster."+name, caddy.Plugin{})
}