mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-15 18:50:41 -07:00
Require cipher suites to be specified in the configuration.
* Configuration requires a cipher suite * Removed default cipher suites * Added help to assist with TLS configuration and list available cipher suites.
This commit is contained in:
@@ -19,6 +19,7 @@ func main() {
|
||||
var showVersion bool
|
||||
var debugAndTrace bool
|
||||
var configFile string
|
||||
var showTlsHelp bool
|
||||
|
||||
// Parse flags
|
||||
flag.IntVar(&opts.Port, "port", 0, "Port to listen on.")
|
||||
@@ -52,6 +53,7 @@ func main() {
|
||||
flag.BoolVar(&showVersion, "v", false, "Print version information.")
|
||||
flag.IntVar(&opts.ProfPort, "profile", 0, "Profiling HTTP port")
|
||||
flag.StringVar(&opts.RoutesStr, "routes", "", "Routes to actively solicit a connection.")
|
||||
flag.BoolVar(&showTlsHelp, "help_tls", false, "TLS help.")
|
||||
|
||||
// Not public per se, will be replaced with dynamic system, but can be used to lower memory footprint when
|
||||
// lots of connections present.
|
||||
@@ -66,6 +68,10 @@ func main() {
|
||||
server.PrintServerAndExit()
|
||||
}
|
||||
|
||||
if showTlsHelp {
|
||||
server.PrintTlsHelpAndDie()
|
||||
}
|
||||
|
||||
// One flag can set multiple options.
|
||||
if debugAndTrace {
|
||||
opts.Trace, opts.Debug = true, true
|
||||
|
||||
@@ -7,6 +7,10 @@ net: apcera.me # net interface
|
||||
tls {
|
||||
cert_file: "./configs/certs/server.pem"
|
||||
key_file: "./configs/certs/key.pem"
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
authorization {
|
||||
|
||||
33
server/configs/tls_ciphers.conf
Normal file
33
server/configs/tls_ciphers.conf
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
# Simple TLS config file
|
||||
|
||||
port: 4443
|
||||
net: apcera.me # net interface
|
||||
|
||||
tls {
|
||||
cert_file: "./configs/certs/server.pem"
|
||||
key_file: "./configs/certs/key.pem"
|
||||
cipher_suites: [
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
# "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
# "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||
]
|
||||
}
|
||||
|
||||
authorization {
|
||||
user: derek
|
||||
password: buckley
|
||||
timeout: 1
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/gnatsd/conf"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Options block for gnatsd server.
|
||||
@@ -66,6 +67,7 @@ type tlsConfig struct {
|
||||
keyFile string
|
||||
caFile string
|
||||
verify bool
|
||||
ciphers []uint16
|
||||
}
|
||||
|
||||
// ProcessConfigFile processes a configuration file.
|
||||
@@ -199,6 +201,67 @@ func parseAuthorization(am map[string]interface{}) authorization {
|
||||
return auth
|
||||
}
|
||||
|
||||
// keep one place where we hold all of the available ciphers
|
||||
var cipherMap = map [string]uint16 {
|
||||
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
"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_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
"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,
|
||||
"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_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,
|
||||
// go 1.5 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
// go 1.5 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
|
||||
// For Usage...
|
||||
func PrintTlsHelpAndDie() {
|
||||
|
||||
var tlsUsage = `
|
||||
TLS configuration is specified in the tls section of a configuration file:
|
||||
|
||||
e.g.
|
||||
|
||||
tls {
|
||||
cert_file: "./certs/server-cert.pem"
|
||||
key_file: "./certs/server-key.pem"
|
||||
ca_file: "./certs/ca.pem"
|
||||
verify: true
|
||||
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
Available cipher suites include:
|
||||
`
|
||||
|
||||
fmt.Printf("%s\n", tlsUsage)
|
||||
for k, _ := range cipherMap {
|
||||
fmt.Printf(" %s\n", k);
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func parseCipher(cipherName string) (uint16, error) {
|
||||
|
||||
cipher, exists := cipherMap[cipherName];
|
||||
if !exists {
|
||||
return 0, fmt.Errorf("Unrecognized cipher %s", cipherName);
|
||||
}
|
||||
|
||||
return cipher, nil;
|
||||
}
|
||||
|
||||
// Helper function to parse TLS configs.
|
||||
func parseTLS(tlsm map[string]interface{}) (*tls.Config, error) {
|
||||
tc := tlsConfig{}
|
||||
@@ -228,11 +291,29 @@ func parseTLS(tlsm map[string]interface{}) (*tls.Config, error) {
|
||||
return nil, fmt.Errorf("error parsing tls config, expected 'verify' to be a boolean")
|
||||
}
|
||||
tc.verify = verify
|
||||
|
||||
case "cipher_suites":
|
||||
ra := mv.([]interface{})
|
||||
if len(ra) == 0 {
|
||||
return nil, fmt.Errorf("error parsing tls config, 'cipher_suites' cannot be empty.")
|
||||
}
|
||||
tc.ciphers = make([]uint16, 0, len(ra))
|
||||
for _, r := range ra {
|
||||
cipher, err := parseCipher(r.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tc.ciphers = append(tc.ciphers, cipher)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("error parsing tls config, unknown field [%q]", mk)
|
||||
}
|
||||
}
|
||||
|
||||
// specifing a cipher suite is required.
|
||||
if (tc.ciphers == nil) {
|
||||
return nil, fmt.Errorf("error parsing tls config, 'cipher_suites' not present.")
|
||||
}
|
||||
|
||||
// Now load in cert and private key
|
||||
cert, err := tls.LoadX509KeyPair(tc.certFile, tc.keyFile)
|
||||
if err != nil {
|
||||
@@ -242,21 +323,16 @@ func parseTLS(tlsm map[string]interface{}) (*tls.Config, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||
}
|
||||
|
||||
// Create TLSConfig
|
||||
// We will determine the cipher suites that we prefer.
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
PreferServerCipherSuites: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: []uint16{
|
||||
// The SHA384 versions are only in Go1.5
|
||||
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
// tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
},
|
||||
CipherSuites: tc.ciphers,
|
||||
}
|
||||
|
||||
// Require client certificates as needed
|
||||
if tc.verify == true {
|
||||
config.ClientAuth = tls.RequireAnyClientCert
|
||||
|
||||
@@ -100,13 +100,12 @@ func TestTLSConfigFile(t *testing.T) {
|
||||
golden, opts)
|
||||
}
|
||||
// Now check TLSConfig a bit more closely
|
||||
// CipherSuites
|
||||
// The default CipherSuites we recommend
|
||||
ciphers := []uint16{
|
||||
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
// tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
}
|
||||
if !reflect.DeepEqual(tlsConfig.CipherSuites, ciphers) {
|
||||
t.Fatalf("Got incorrect cipher suite list: [%+v]", tlsConfig.CipherSuites)
|
||||
@@ -125,6 +124,40 @@ func TestTLSConfigFile(t *testing.T) {
|
||||
if err := cert.VerifyHostname("localhost"); err != nil {
|
||||
t.Fatalf("Could not verify hostname in certificate: %v\n", err)
|
||||
}
|
||||
|
||||
// Now test adding cipher suites.
|
||||
opts, err = ProcessConfigFile("./configs/tls_ciphers.conf")
|
||||
if err != nil {
|
||||
t.Fatalf("Received an error reading config file: %v\n", err)
|
||||
}
|
||||
tlsConfig = opts.TLSConfig
|
||||
if tlsConfig == nil {
|
||||
t.Fatal("Expected opts.TLSConfig to be non-nil")
|
||||
}
|
||||
|
||||
// CipherSuites listed in the config - test all of them.
|
||||
ciphers = []uint16{
|
||||
tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
//tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
//tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tlsConfig.CipherSuites, ciphers) {
|
||||
t.Fatalf("Got incorrect cipher suite list: [%+v]", tlsConfig.CipherSuites)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMergeOverrides(t *testing.T) {
|
||||
|
||||
@@ -34,6 +34,7 @@ Cluster Options:
|
||||
Common Options:
|
||||
-h, --help Show this message
|
||||
-v, --version Show version
|
||||
--help_tls TLS help.
|
||||
`
|
||||
|
||||
// Usage will print out the flag options for the server.
|
||||
|
||||
@@ -17,6 +17,10 @@ cluster {
|
||||
# Optional certificate authority verifying connected routes
|
||||
# Required when we have self-signed CA, etc.
|
||||
ca_file: "./configs/certs/ca.pem"
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
# Routes are actively solicited and connected to from this server.
|
||||
|
||||
@@ -17,6 +17,10 @@ cluster {
|
||||
# Optional certificate authority verifying connected routes
|
||||
# Required when we have self-signed CA, etc.
|
||||
ca_file: "./configs/certs/ca.pem"
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
# Routes are actively solicited and connected to from this server.
|
||||
|
||||
@@ -9,6 +9,10 @@ tls {
|
||||
cert_file: "./configs/certs/server-cert.pem"
|
||||
# Server private key
|
||||
key_file: "./configs/certs/server-key.pem"
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
authorization {
|
||||
|
||||
@@ -13,4 +13,9 @@ tls {
|
||||
ca_file: "./configs/certs/ca.pem"
|
||||
# Require a client certificate
|
||||
verify: true
|
||||
|
||||
cipher_suites: [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user