120 lines
3.9 KiB
Go
120 lines
3.9 KiB
Go
package proxy
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func buildTLSConfig(config TLSConfig) *tls.Config {
|
|
tlsConfig := &tls.Config{}
|
|
if versions := parseTLSVersions(config.Protocols); versions != nil {
|
|
tlsConfig.MinVersion = versions.min
|
|
tlsConfig.MaxVersion = versions.max
|
|
}
|
|
if suites := parseCipherSuites(config.Ciphers); len(suites) > 0 {
|
|
tlsConfig.CipherSuites = suites
|
|
}
|
|
return tlsConfig
|
|
}
|
|
|
|
type tlsVersionBounds struct {
|
|
min uint16
|
|
max uint16
|
|
}
|
|
|
|
func parseTLSVersions(value string) *tlsVersionBounds {
|
|
if strings.TrimSpace(value) == "" {
|
|
return nil
|
|
}
|
|
|
|
bounds := tlsVersionBounds{}
|
|
for _, token := range splitTLSList(value) {
|
|
version, ok := parseTLSVersionToken(token)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if bounds.min == 0 || version < bounds.min {
|
|
bounds.min = version
|
|
}
|
|
if version > bounds.max {
|
|
bounds.max = version
|
|
}
|
|
}
|
|
|
|
if bounds.min == 0 || bounds.max == 0 {
|
|
return nil
|
|
}
|
|
|
|
return &bounds
|
|
}
|
|
|
|
func parseTLSVersionToken(token string) (uint16, bool) {
|
|
switch strings.ToLower(strings.TrimSpace(token)) {
|
|
case "tls1.0", "tlsv1.0", "tls1", "tlsv1", "1.0", "tls10":
|
|
return tls.VersionTLS10, true
|
|
case "tls1.1", "tlsv1.1", "1.1", "tls11":
|
|
return tls.VersionTLS11, true
|
|
case "tls1.2", "tlsv1.2", "1.2", "tls12":
|
|
return tls.VersionTLS12, true
|
|
case "tls1.3", "tlsv1.3", "1.3", "tls13":
|
|
return tls.VersionTLS13, true
|
|
}
|
|
|
|
if raw, errorValue := strconv.ParseUint(strings.TrimSpace(token), 10, 16); errorValue == nil {
|
|
switch uint16(raw) {
|
|
case tls.VersionTLS10, tls.VersionTLS11, tls.VersionTLS12, tls.VersionTLS13:
|
|
return uint16(raw), true
|
|
}
|
|
}
|
|
|
|
return 0, false
|
|
}
|
|
|
|
func parseCipherSuites(value string) []uint16 {
|
|
if strings.TrimSpace(value) == "" {
|
|
return nil
|
|
}
|
|
|
|
var suites []uint16
|
|
for _, token := range splitTLSList(value) {
|
|
if suite, ok := tlsCipherSuiteNames[strings.ToUpper(strings.TrimSpace(token))]; ok {
|
|
suites = append(suites, suite)
|
|
}
|
|
}
|
|
return suites
|
|
}
|
|
|
|
func splitTLSList(value string) []string {
|
|
return strings.FieldsFunc(value, func(r rune) bool {
|
|
switch r {
|
|
case ':', ',', ' ', ';':
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
})
|
|
}
|
|
|
|
var tlsCipherSuiteNames = map[string]uint16{
|
|
"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_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_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_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
"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,
|
|
"ECDHE-RSA-AES128-GCM-SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
"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-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
"AES128-GCM-SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
|
"AES256-GCM-SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
|
"ECDHE-RSA-CHACHA20-POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
"ECDHE-ECDSA-CHACHA20-POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
"CHACHA20-POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
}
|