func GetSupportedCipherName(cipher uint16) (string, error) {
	for k, v := range SupportedCiphersMap {
		if v == cipher {
			return k, nil
		}
	}
	return "", fmt.Errorf("name: unsupported cipher")
}
GetSupportedCipherName returns the cipher name
package caskettls
import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"time"
	"github.com/go-acme/lego/v4/certcrypto"
	"github.com/go-acme/lego/v4/challenge/tlsalpn01"
	"github.com/klauspost/cpuid"
	"github.com/tmpim/casket"
	"github.com/tmpim/certmagic"
)
type Config struct {
	Hostname string
	Enabled bool
	ProtocolMinVersion uint16
	ProtocolMaxVersion uint16
	Ciphers []uint16
	PreferServerCipherSuites bool
	CurvePreferences []tls.CurveID
	ClientAuth tls.ClientAuthType
	ClientCerts []string
	InsecureDisableSNIMatching bool
	Manual bool
	Managed bool
	Manager *certmagic.Config
	SelfSigned bool
	ACMEEmail string
	ALPN []string
	tlsConfig *tls.Config
}
func NewConfig(inst *casket.Instance) (*Config, error) {
	inst.StorageMu.RLock()
	certCache, ok := inst.Storage[CertCacheInstStorageKey].(*certmagic.Cache)
	inst.StorageMu.RUnlock()
	if !ok || certCache == nil {
		if err := makeClusteringPlugin(); err != nil {
			return nil, err
		}
		certCache = certmagic.NewCache(certmagic.CacheOptions{
			GetConfigForCert: func(cert certmagic.Certificate) (certmagic.Config, error) {
				inst.StorageMu.RLock()
				cfgMap, ok := inst.Storage[configMapKey].(map[string]*Config)
				inst.StorageMu.RUnlock()
				if ok {
					for hostname, cfg := range cfgMap {
						if cfg.Manager != nil && hostname == cert.Names[0] {
							return *cfg.Manager, nil
						}
					}
				}
				return certmagic.Default, nil
			},
		})
		storageCleaningTicker := time.NewTicker(12 * time.Hour)
		done := make(chan bool)
		go func() {
			for {
				select {
				case <-done:
					storageCleaningTicker.Stop()
					return
				case <-storageCleaningTicker.C:
					certmagic.CleanStorage(certmagic.Default.Storage, certmagic.CleanStorageOptions{
						OCSPStaples: true,
					})
				}
			}
		}()
		inst.OnShutdown = append(inst.OnShutdown, func() error {
			certCache.Stop()
			done <- true
			close(done)
			return nil
		})
		inst.StorageMu.Lock()
		inst.Storage[CertCacheInstStorageKey] = certCache
		inst.StorageMu.Unlock()
	}
	return &Config{
		Manager: certmagic.New(certCache, certmagic.Config{}),
	}, nil
}
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{})
	for _, ciph := range c.Ciphers {
		if _, ok := ciphersAdded[ciph]; !ok {
			ciphersAdded[ciph] = struct{}{}
			config.CipherSuites = append(config.CipherSuites, ciph)
		}
	}
	config.PreferServerCipherSuites = c.PreferServerCipherSuites
	for _, curv := range c.CurvePreferences {
		if _, ok := curvesAdded[curv]; !ok {
			curvesAdded[curv] = struct{}{}
			config.CurvePreferences = append(config.CurvePreferences, curv)
		}
	}
	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
	if config.ClientAuth != tls.NoClientCert {
		pool := x509.NewCertPool()
		clientCertsAdded := make(map[string]struct{})
		for _, caFile := range c.ClientCerts {
			if _, ok := clientCertsAdded[caFile]; ok {
				continue
			}
			clientCertsAdded[caFile] = struct{}{}
			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
	}
	if len(config.CipherSuites) == 0 {
		config.CipherSuites = getPreferredDefaultCiphers()
	}
	if len(config.CipherSuites) == 0 || config.CipherSuites[0] != tls.TLS_FALLBACK_SCSV {
		config.CipherSuites = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.CipherSuites...)
	}
	c.tlsConfig = config
	return nil
}
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 {
			configs[i] = new(Config)
			continue
		}
		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)
		}
		if err := cfg.buildStandardTLSConfig(); err != nil {
			return nil, err
		}
		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)
			}
		}
		if cfg.Hostname == "0.0.0.0" || cfg.Hostname == "::" {
			configMap[""] = cfg
		} else {
			configMap[cfg.Hostname] = cfg
		}
	}
	if len(configs) == 0 || !configs[0].Enabled {
		return nil, nil
	}
	return &tls.Config{
		GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
			return nil, fmt.Errorf("all certificates configured via GetConfigForClient")
		},
		GetConfigForClient: configMap.GetConfigForClient,
	}, nil
}
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 err := assertClientCertsCompatible(cfg1, cfg2); err != nil {
		return err
	}
	return nil
}
type ConfigGetter func(c *casket.Controller) *Config
var configGetters = make(map[string]ConfigGetter)
func RegisterConfigGetter(serverType string, fn ConfigGetter) {
	configGetters[serverType] = fn
}
func SetDefaultTLSParams(config *Config) {
	if len(config.Ciphers) == 0 {
		config.Ciphers = getPreferredDefaultCiphers()
	}
	config.Ciphers = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.Ciphers...)
	if len(config.CurvePreferences) == 0 {
		config.CurvePreferences = defaultCurves
	}
	if config.ProtocolMinVersion == 0 {
		config.ProtocolMinVersion = tls.VersionTLS12
	}
	if config.ProtocolMaxVersion == 0 {
		config.ProtocolMaxVersion = tls.VersionTLS13
	}
	config.PreferServerCipherSuites = true
}
var supportedKeyTypes = map[string]certcrypto.KeyType{
	"P384":    certcrypto.EC384,
	"P256":    certcrypto.EC256,
	"RSA4096": certcrypto.RSA4096,
	"RSA2048": certcrypto.RSA2048,
}
var SupportedProtocols = map[string]uint16{
	"tls1.0": tls.VersionTLS10,
	"tls1.1": tls.VersionTLS11,
	"tls1.2": tls.VersionTLS12,
	"tls1.3": tls.VersionTLS13,
}
func GetSupportedProtocolName(protocol uint16) (string, error) {
	for k, v := range SupportedProtocols {
		if v == protocol {
			return k, nil
		}
	}
	return "", fmt.Errorf("name: unsupported protocol")
}
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,
}