refactor(tls): clarify & simplify tls configuration

This commit is contained in:
Brian Waldon
2014-02-03 20:46:27 -08:00
committed by Brandon Philips
parent 68305181f9
commit 63fa35c99f
6 changed files with 109 additions and 116 deletions

View File

@@ -16,28 +16,15 @@ func NewListener(addr string) (net.Listener, error) {
return l, nil
}
func NewTLSListener(config *tls.Config, addr, certFile, keyFile string) (net.Listener, error) {
func NewTLSListener(addr string, cfg *tls.Config) (net.Listener, error) {
if addr == "" {
addr = ":https"
}
if config == nil {
config = &tls.Config{}
}
config.NextProtos = []string{"http/1.1"}
var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
conn, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
return tls.NewListener(conn, config), nil
return tls.NewListener(conn, cfg), nil
}

View File

@@ -1,12 +0,0 @@
package server
import (
"crypto/tls"
)
// TLSConfig holds the TLS configuration.
type TLSConfig struct {
Scheme string // http or https
Server tls.Config // Used by the Raft or etcd Server transporter.
Client tls.Config // Used by the Raft peer client.
}

View File

@@ -15,62 +15,88 @@ type TLSInfo struct {
CAFile string `json:"CAFile"`
}
// Generates a TLS configuration from the given files.
func (info TLSInfo) Config() (TLSConfig, error) {
var t TLSConfig
t.Scheme = "http"
// If the user do not specify key file, cert file and CA file, the type will be HTTP
if info.KeyFile == "" && info.CertFile == "" && info.CAFile == "" {
return t, nil
func (info TLSInfo) Scheme() string {
if info.KeyFile != "" && info.CertFile != "" {
return "https"
} else {
return "http"
}
}
// Generates a tls.Config object for a server from the given files.
func (info TLSInfo) ServerConfig() (*tls.Config, error) {
// Both the key and cert must be present.
if info.KeyFile == "" || info.CertFile == "" {
return t, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
}
var cfg tls.Config
tlsCert, err := tls.LoadX509KeyPair(info.CertFile, info.KeyFile)
if err != nil {
return nil, err
}
cfg.Certificates = []tls.Certificate{tlsCert}
if info.CAFile != "" {
cfg.ClientAuth = tls.RequireAndVerifyClientCert
cp, err := newCertPool(info.CAFile)
if err != nil {
return nil, err
}
cfg.RootCAs = cp
cfg.ClientCAs = cp
} else {
cfg.ClientAuth = tls.NoClientCert
}
return &cfg, nil
}
// Generates a tls.Config object for a client from the given files.
func (info TLSInfo) ClientConfig() (*tls.Config, error) {
var cfg tls.Config
if info.KeyFile == "" || info.CertFile == "" {
return &cfg, nil
}
tlsCert, err := tls.LoadX509KeyPair(info.CertFile, info.KeyFile)
if err != nil {
return t, err
return nil, err
}
t.Scheme = "https"
t.Server.ClientAuth, t.Server.ClientCAs, err = newCertPool(info.CAFile)
if err != nil {
return t, err
cfg.Certificates = []tls.Certificate{tlsCert}
if info.CAFile != "" {
cp, err := newCertPool(info.CAFile)
if err != nil {
return nil, err
}
cfg.RootCAs = cp
}
// The client should trust the RootCA that the Server uses since
// everyone is a peer in the network.
t.Client.Certificates = []tls.Certificate{tlsCert}
t.Client.RootCAs = t.Server.ClientCAs
return t, nil
return &cfg, nil
}
// newCertPool creates x509 certPool and corresponding Auth Type.
// If the given CAfile is valid, add the cert into the pool and verify the clients'
// certs against the cert in the pool.
// If the given CAfile is empty, do not verify the clients' cert.
// If the given CAfile is not valid, fatal.
func newCertPool(CAFile string) (tls.ClientAuthType, *x509.CertPool, error) {
if CAFile == "" {
return tls.NoClientCert, nil, nil
}
// newCertPool creates x509 certPool with provided CA file
func newCertPool(CAFile string) (*x509.CertPool, error) {
pemByte, err := ioutil.ReadFile(CAFile)
if err != nil {
return 0, nil, err
return nil, err
}
block, pemByte := pem.Decode(pemByte)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return 0, nil, err
return nil, err
}
certPool := x509.NewCertPool()
certPool.AddCert(cert)
return tls.RequireAndVerifyClientCert, certPool, nil
return certPool, nil
}