116 lines
4.1 KiB
Go
116 lines
4.1 KiB
Go
package tls
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
validVersions = map[string]uint16{
|
|
"1.3": tls.VersionTLS13,
|
|
"1.2": tls.VersionTLS12,
|
|
// Deprecated.
|
|
"1.1": tls.VersionTLS11,
|
|
// Deprecated.
|
|
"1.0": tls.VersionTLS10,
|
|
}
|
|
|
|
// https://golang.org/pkg/crypto/tls/#pkg-constants
|
|
validCiphers10to12 = map[string]uint16{
|
|
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
|
|
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
"TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
|
"TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
|
"TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
|
|
"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
|
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
|
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
|
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
|
}
|
|
|
|
validCiphers13 = map[string]uint16{
|
|
"TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256,
|
|
"TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384,
|
|
"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
|
|
}
|
|
)
|
|
|
|
func baseTLSConfig(minVersion, ciphers string) (*tls.Config, error) {
|
|
version, err := validatedMinVersion(minVersion)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cipherSuites, err := validatedCiphers(ciphers, version)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &tls.Config{
|
|
MinVersion: version,
|
|
CipherSuites: cipherSuites,
|
|
}, nil
|
|
}
|
|
|
|
func validatedMinVersion(version string) (uint16, error) {
|
|
if val, ok := validVersions[strings.TrimSpace(version)]; ok {
|
|
return val, nil
|
|
}
|
|
valid := keysFromMap(validVersions)
|
|
sort.Strings(valid)
|
|
return 0, fmt.Errorf("unsupported minimal TLS version %s, must be one of: %s", version, strings.Join(valid, ", "))
|
|
}
|
|
|
|
func validatedCiphers(ciphers string, version uint16) ([]uint16, error) {
|
|
split := strings.Split(ciphers, ",")
|
|
if version == tls.VersionTLS13 {
|
|
return validatedCipherSet(split, validCiphers13)
|
|
}
|
|
return validatedCipherSet(split, union(validCiphers10to12, validCiphers13))
|
|
}
|
|
|
|
func validatedCipherSet(ciphers []string, validCiphers map[string]uint16) ([]uint16, error) {
|
|
tlsCiphers := make([]uint16, 0, len(ciphers))
|
|
for _, cipher := range ciphers {
|
|
c, ok := validCiphers[strings.TrimSpace(cipher)]
|
|
if !ok {
|
|
valid := keysFromMap(validCiphers)
|
|
sort.Strings(valid)
|
|
return nil, fmt.Errorf("unsupported cipher %s, must be one or more of: %s", cipher, strings.Join(valid, "\n"))
|
|
}
|
|
tlsCiphers = append(tlsCiphers, c)
|
|
}
|
|
return tlsCiphers, nil
|
|
}
|
|
|
|
func union(cipherSets ...map[string]uint16) map[string]uint16 {
|
|
result := make(map[string]uint16)
|
|
for _, set := range cipherSets {
|
|
for k, v := range set {
|
|
result[k] = v
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func keysFromMap(input map[string]uint16) []string {
|
|
keys := make([]string, 0, len(input))
|
|
for key := range input {
|
|
keys = append(keys, key)
|
|
}
|
|
return keys
|
|
}
|