docs/utils/tls_config.go

130 lines
3.6 KiB
Go

package utils
import (
"crypto/rand"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
)
// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set)
var clientCipherSuites = []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
}
// Server TLS cipher suites
var serverCipherSuites = append(clientCipherSuites, []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
}...)
func poolFromFile(filename string) (*x509.CertPool, error) {
pemBytes, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
if ok := pool.AppendCertsFromPEM(pemBytes); !ok {
return nil, fmt.Errorf(
"Unable to parse certificates from %s", filename)
}
if len(pool.Subjects()) == 0 {
return nil, fmt.Errorf(
"No certificates parsed from %s", filename)
}
return pool, nil
}
// ServerTLSOpts generates a tls configuration for servers using the
// provided parameters.
type ServerTLSOpts struct {
ServerCertFile string
ServerKeyFile string
ClientCAFile string
}
// ConfigureServerTLS specifies a set of ciphersuites, the server cert and key,
// and optionally client authentication. Note that a tls configuration is
// constructed that either requires and verifies client authentication or
// doesn't deal with client certs at all. Nothing in the middle.
//
// Also note that if the client CA file contains invalid data, behavior is not
// guaranteed. Currently (as of Go 1.5.1) only the valid certificates up to
// the bad data will be parsed and added the client CA pool.
func ConfigureServerTLS(opts *ServerTLSOpts) (*tls.Config, error) {
keypair, err := tls.LoadX509KeyPair(
opts.ServerCertFile, opts.ServerKeyFile)
if err != nil {
return nil, err
}
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
PreferServerCipherSuites: true,
CipherSuites: serverCipherSuites,
Certificates: []tls.Certificate{keypair},
Rand: rand.Reader,
}
if opts.ClientCAFile != "" {
pool, err := poolFromFile(opts.ClientCAFile)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
return tlsConfig, nil
}
// ClientTLSOpts is a struct that contains options to pass to
// ConfigureClientTLS
type ClientTLSOpts struct {
RootCAFile string
ServerName string
InsecureSkipVerify bool
ClientCertFile string
ClientKeyFile string
}
// ConfigureClientTLS generates a tls configuration for clients using the
// provided parameters.
///
// Note that if the root CA file contains invalid data, behavior is not
// guaranteed. Currently (as of Go 1.5.1) only the valid certificates up to
// the bad data will be parsed and added the root CA pool.
func ConfigureClientTLS(opts *ClientTLSOpts) (*tls.Config, error) {
tlsConfig := &tls.Config{
InsecureSkipVerify: opts.InsecureSkipVerify,
MinVersion: tls.VersionTLS12,
CipherSuites: clientCipherSuites,
ServerName: opts.ServerName,
}
if opts.RootCAFile != "" {
pool, err := poolFromFile(opts.RootCAFile)
if err != nil {
return nil, err
}
tlsConfig.RootCAs = pool
}
if opts.ClientCertFile != "" || opts.ClientKeyFile != "" {
keypair, err := tls.LoadX509KeyPair(
opts.ClientCertFile, opts.ClientKeyFile)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{keypair}
}
return tlsConfig, nil
}