2015-03-13 16:37:32 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2015-07-23 20:51:45 +00:00
|
|
|
// We must import sha512 so that it registers with the runtime so that
|
|
|
|
// certificates that use it can be parsed.
|
|
|
|
_ "crypto/sha512"
|
2015-03-13 16:56:08 +00:00
|
|
|
"crypto/tls"
|
2015-03-13 16:37:32 +00:00
|
|
|
"fmt"
|
2016-06-02 16:40:25 +00:00
|
|
|
"io"
|
2015-03-13 16:37:32 +00:00
|
|
|
"net"
|
2016-03-10 02:40:46 +00:00
|
|
|
"sync"
|
2016-07-12 23:32:47 +00:00
|
|
|
|
2017-06-22 19:29:53 +00:00
|
|
|
"github.com/hashicorp/vault/helper/parseutil"
|
2016-07-12 23:32:47 +00:00
|
|
|
"github.com/hashicorp/vault/helper/tlsutil"
|
2016-09-30 04:06:40 +00:00
|
|
|
"github.com/hashicorp/vault/vault"
|
2015-03-13 16:37:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ListenerFactory is the factory function to create a listener.
|
2017-06-22 19:29:53 +00:00
|
|
|
type ListenerFactory func(map[string]interface{}, io.Writer) (net.Listener, map[string]string, vault.ReloadFunc, error)
|
2015-03-13 16:37:32 +00:00
|
|
|
|
|
|
|
// BuiltinListeners is the list of built-in listener types.
|
|
|
|
var BuiltinListeners = map[string]ListenerFactory{
|
2017-06-22 19:29:53 +00:00
|
|
|
"tcp": tcpListenerFactory,
|
2015-03-13 16:37:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewListener creates a new listener of the given type with the given
|
|
|
|
// configuration. The type is looked up in the BuiltinListeners map.
|
2017-06-22 19:29:53 +00:00
|
|
|
func NewListener(t string, config map[string]interface{}, logger io.Writer) (net.Listener, map[string]string, vault.ReloadFunc, error) {
|
2015-03-13 16:37:32 +00:00
|
|
|
f, ok := BuiltinListeners[t]
|
|
|
|
if !ok {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("unknown listener type: %s", t)
|
2015-03-13 16:37:32 +00:00
|
|
|
}
|
|
|
|
|
2016-06-02 16:40:25 +00:00
|
|
|
return f(config, logger)
|
2015-03-13 16:37:32 +00:00
|
|
|
}
|
2015-03-13 16:56:08 +00:00
|
|
|
|
|
|
|
func listenerWrapTLS(
|
2015-04-04 19:06:41 +00:00
|
|
|
ln net.Listener,
|
|
|
|
props map[string]string,
|
2017-06-22 19:29:53 +00:00
|
|
|
config map[string]interface{}) (net.Listener, map[string]string, vault.ReloadFunc, error) {
|
2015-04-04 19:06:41 +00:00
|
|
|
props["tls"] = "disabled"
|
|
|
|
|
2015-11-25 19:37:57 +00:00
|
|
|
if v, ok := config["tls_disable"]; ok {
|
2017-06-22 19:29:53 +00:00
|
|
|
disabled, err := parseutil.ParseBool(v)
|
2015-11-25 19:37:57 +00:00
|
|
|
if err != nil {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("invalid value for 'tls_disable': %v", err)
|
2015-11-25 19:37:57 +00:00
|
|
|
}
|
|
|
|
if disabled {
|
2016-03-10 02:40:46 +00:00
|
|
|
return ln, props, nil, nil
|
2015-11-25 19:37:57 +00:00
|
|
|
}
|
2015-03-13 16:56:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 02:40:46 +00:00
|
|
|
_, ok := config["tls_cert_file"]
|
2015-03-13 16:56:08 +00:00
|
|
|
if !ok {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("'tls_cert_file' must be set")
|
2015-03-13 16:56:08 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 02:40:46 +00:00
|
|
|
_, ok = config["tls_key_file"]
|
2015-03-13 16:56:08 +00:00
|
|
|
if !ok {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("'tls_key_file' must be set")
|
2015-03-13 16:56:08 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 19:29:53 +00:00
|
|
|
addrRaw, ok := config["address"]
|
|
|
|
if !ok {
|
|
|
|
return nil, nil, nil, fmt.Errorf("'address' must be set")
|
|
|
|
}
|
|
|
|
addr := addrRaw.(string)
|
2016-03-10 02:40:46 +00:00
|
|
|
cg := &certificateGetter{
|
2017-06-22 19:29:53 +00:00
|
|
|
id: addr,
|
2016-03-10 02:40:46 +00:00
|
|
|
}
|
|
|
|
|
2016-03-11 22:28:03 +00:00
|
|
|
if err := cg.reload(config); err != nil {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("error loading TLS cert: %s", err)
|
2015-03-13 16:56:08 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 19:29:53 +00:00
|
|
|
var tlsvers string
|
|
|
|
tlsversRaw, ok := config["tls_min_version"]
|
2015-07-23 03:19:41 +00:00
|
|
|
if !ok {
|
|
|
|
tlsvers = "tls12"
|
2017-06-22 19:29:53 +00:00
|
|
|
} else {
|
|
|
|
tlsvers = tlsversRaw.(string)
|
2015-07-23 03:19:41 +00:00
|
|
|
}
|
2015-07-23 20:51:45 +00:00
|
|
|
|
2015-03-13 16:56:08 +00:00
|
|
|
tlsConf := &tls.Config{}
|
2016-03-10 02:40:46 +00:00
|
|
|
tlsConf.GetCertificate = cg.getCertificate
|
2016-07-20 17:57:49 +00:00
|
|
|
tlsConf.NextProtos = []string{"h2", "http/1.1"}
|
2016-07-12 23:32:47 +00:00
|
|
|
tlsConf.MinVersion, ok = tlsutil.TLSLookup[tlsvers]
|
2015-07-23 03:19:41 +00:00
|
|
|
if !ok {
|
2016-03-10 02:40:46 +00:00
|
|
|
return nil, nil, nil, fmt.Errorf("'tls_min_version' value %s not supported, please specify one of [tls10,tls11,tls12]", tlsvers)
|
2015-07-23 03:19:41 +00:00
|
|
|
}
|
2015-05-20 23:01:40 +00:00
|
|
|
tlsConf.ClientAuth = tls.RequestClientCert
|
2015-03-13 16:56:08 +00:00
|
|
|
|
2017-01-23 18:48:35 +00:00
|
|
|
if v, ok := config["tls_cipher_suites"]; ok {
|
2017-06-22 19:29:53 +00:00
|
|
|
ciphers, err := tlsutil.ParseCiphers(v.(string))
|
2017-01-23 18:48:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, fmt.Errorf("invalid value for 'tls_cipher_suites': %v", err)
|
|
|
|
}
|
|
|
|
tlsConf.CipherSuites = ciphers
|
|
|
|
}
|
|
|
|
if v, ok := config["tls_prefer_server_cipher_suites"]; ok {
|
2017-06-22 19:29:53 +00:00
|
|
|
preferServer, err := parseutil.ParseBool(v)
|
2017-01-23 18:48:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, fmt.Errorf("invalid value for 'tls_prefer_server_cipher_suites': %v", err)
|
|
|
|
}
|
|
|
|
tlsConf.PreferServerCipherSuites = preferServer
|
|
|
|
}
|
2017-03-08 15:21:31 +00:00
|
|
|
if v, ok := config["tls_require_and_verify_client_cert"]; ok {
|
2017-06-22 19:29:53 +00:00
|
|
|
requireClient, err := parseutil.ParseBool(v)
|
2017-03-08 15:21:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, fmt.Errorf("invalid value for 'tls_require_and_verify_client_cert': %v", err)
|
|
|
|
}
|
|
|
|
if requireClient {
|
|
|
|
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
|
|
|
|
}
|
|
|
|
}
|
2017-01-23 18:48:35 +00:00
|
|
|
|
2015-03-13 16:56:08 +00:00
|
|
|
ln = tls.NewListener(ln, tlsConf)
|
2015-04-04 19:06:41 +00:00
|
|
|
props["tls"] = "enabled"
|
2016-03-11 22:28:03 +00:00
|
|
|
return ln, props, cg.reload, nil
|
2016-03-10 02:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type certificateGetter struct {
|
|
|
|
sync.RWMutex
|
|
|
|
|
2016-03-11 21:46:56 +00:00
|
|
|
cert *tls.Certificate
|
|
|
|
|
|
|
|
id string
|
2016-03-10 02:40:46 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 19:29:53 +00:00
|
|
|
func (cg *certificateGetter) reload(config map[string]interface{}) error {
|
|
|
|
if config["address"].(string) != cg.id {
|
2016-03-11 21:46:56 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-06-22 19:29:53 +00:00
|
|
|
cert, err := tls.LoadX509KeyPair(config["tls_cert_file"].(string), config["tls_key_file"].(string))
|
2016-03-10 02:40:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cg.Lock()
|
|
|
|
defer cg.Unlock()
|
|
|
|
|
|
|
|
cg.cert = &cert
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *certificateGetter) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
|
|
cg.RLock()
|
|
|
|
defer cg.RUnlock()
|
|
|
|
|
|
|
|
if cg.cert == nil {
|
|
|
|
return nil, fmt.Errorf("nil certificate")
|
|
|
|
}
|
|
|
|
|
|
|
|
return cg.cert, nil
|
2015-03-13 16:56:08 +00:00
|
|
|
}
|