smallstep-certificates/authority/config/tls_options.go

180 lines
6.5 KiB
Go

package config
import (
"crypto/tls"
"fmt"
"github.com/pkg/errors"
)
var (
// DefaultTLSMinVersion default minimum version of TLS.
DefaultTLSMinVersion = TLSVersion(1.2)
// DefaultTLSMaxVersion default maximum version of TLS.
DefaultTLSMaxVersion = TLSVersion(1.3)
// DefaultTLSRenegotiation default TLS connection renegotiation policy.
DefaultTLSRenegotiation = false // Never regnegotiate.
// DefaultTLSCipherSuites specifies default step ciphersuite(s).
// These are TLS 1.0 - 1.2 cipher suites.
DefaultTLSCipherSuites = CipherSuites{
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
}
// ApprovedTLSCipherSuites smallstep approved ciphersuites.
ApprovedTLSCipherSuites = CipherSuites{
// AEADs w/ ECDHE
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
// CBC w/ ECDHE
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
}
// DefaultTLSOptions represents the default TLS version as well as the cipher
// suites used in the TLS certificates.
DefaultTLSOptions = TLSOptions{
CipherSuites: DefaultTLSCipherSuites,
MinVersion: DefaultTLSMinVersion,
MaxVersion: DefaultTLSMaxVersion,
Renegotiation: DefaultTLSRenegotiation,
}
)
// TLSVersion represents a TLS version number.
type TLSVersion float64
// Validate implements models.Validator and checks that a cipher suite is
// valid.
func (v TLSVersion) Validate() error {
if _, ok := tlsVersions[v]; ok {
return nil
}
return errors.Errorf("%f is not a valid tls version", v)
}
// Value returns the Go constant for the TLSVersion.
func (v TLSVersion) Value() uint16 {
return tlsVersions[v]
}
// String returns the Go constant for the TLSVersion.
func (v TLSVersion) String() string {
k := v.Value()
switch k {
case tls.VersionTLS10:
return "1.0"
case tls.VersionTLS11:
return "1.1"
case tls.VersionTLS12:
return "1.2"
case tls.VersionTLS13:
return "1.3"
default:
return fmt.Sprintf("unexpected value: %f", v)
}
}
// tlsVersions has the list of supported tls version.
var tlsVersions = map[TLSVersion]uint16{
// Defaults to TLS 1.3
0: tls.VersionTLS13,
// Options
1.0: tls.VersionTLS10,
1.1: tls.VersionTLS11,
1.2: tls.VersionTLS12,
1.3: tls.VersionTLS13,
}
// CipherSuites represents an array of string codes representing the cipher
// suites.
type CipherSuites []string
// Validate implements models.Validator and checks that a cipher suite is
// valid.
func (c CipherSuites) Validate() error {
for _, s := range c {
if _, ok := cipherSuites[s]; !ok {
return errors.Errorf("%s is not a valid cipher suite", s)
}
}
return nil
}
// Value returns an []uint16 for the cipher suites.
func (c CipherSuites) Value() []uint16 {
values := make([]uint16, len(c))
for i, s := range c {
values[i] = cipherSuites[s]
}
return values
}
// cipherSuites has the list of supported cipher suites.
var cipherSuites = map[string]uint16{
// TLS 1.0 - 1.2 cipher suites.
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, // lgtm[go/insecure-tls]
"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, // lgtm[go/insecure-tls]
"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, // lgtm[go/insecure-tls]
"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, // lgtm[go/insecure-tls]
"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, // lgtm[go/insecure-tls]
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // lgtm[go/insecure-tls]
"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_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 1.3 cipher sutes.
"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,
// Legacy names.
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
}
// TLSOptions represents the TLS options that can be specified on *tls.Config
// types to configure HTTPS servers and clients.
type TLSOptions struct {
CipherSuites CipherSuites `json:"cipherSuites"`
MinVersion TLSVersion `json:"minVersion"`
MaxVersion TLSVersion `json:"maxVersion"`
Renegotiation bool `json:"renegotiation"`
}
// TLSConfig returns the tls.Config equivalent of the TLSOptions.
func (t *TLSOptions) TLSConfig() *tls.Config {
var rs tls.RenegotiationSupport
if t.Renegotiation {
rs = tls.RenegotiateFreelyAsClient
} else {
rs = tls.RenegotiateNever
}
//nolint:gosec // default MinVersion 1.2, if defined but empty 1.3 is used
return &tls.Config{
CipherSuites: t.CipherSuites.Value(),
MinVersion: t.MinVersion.Value(),
MaxVersion: t.MaxVersion.Value(),
Renegotiation: rs,
}
}