diff --git a/command/server/listener.go b/command/server/listener.go index 5d8a88780dc7..af601457d9d2 100644 --- a/command/server/listener.go +++ b/command/server/listener.go @@ -7,6 +7,7 @@ import ( _ "crypto/sha512" "crypto/tls" "crypto/x509" + "errors" "fmt" "io" "io/ioutil" @@ -145,18 +146,28 @@ PASSPHRASECORRECT: // https://tools.ietf.org/html/rfc7540#appendix-A // // Since the CLI (net/http) automatically uses HTTP/2 with TLS 1.2, - // we check here if all specified cipher suites are blacklisted. + // we check here if all or some specified cipher suites are blacklisted. badCiphersCount := 0 + badCiphers := []string{} for _, cipher := range ciphers { if isBadCipher(cipher) { badCiphersCount++ + + // Get the name of the current cipher. + cipherStr, err := tlsutil.GetCipherName(cipher) + if err != nil { + return nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_cipher_suites': {{err}}", err) + } + badCiphers = append(badCiphers, cipherStr) } } if badCiphersCount == len(ciphers) { - ui.Warn(`WARNING! All cipher suites defined by 'tls_cipher_suites' are blacklisted by the -HTTP/2 specification. HTTP/2 communication with TLS 1.2 will not work as intended -and Vault will be unavailable via the CLI. -Please see https://tools.ietf.org/html/rfc7540#appendix-A for further information.`) + return nil, nil, nil, errors.New("all defined cipher suites by 'tls_cipher_suites' are blacklisted by the HTTP/2 specification") + } else if badCiphersCount > 0 { + ui.Warn(fmt.Sprintf(`WARNING! The following cipher suites defined by 'tls_cipher_suites' are +blacklisted by the HTTP/2 specification: +%v +Please see https://tools.ietf.org/html/rfc7540#appendix-A for further information.`, badCiphers)) } tlsConf.CipherSuites = ciphers } diff --git a/helper/tlsutil/tlsutil.go b/helper/tlsutil/tlsutil.go index 08b3ebd0c832..d7f3f2990166 100644 --- a/helper/tlsutil/tlsutil.go +++ b/helper/tlsutil/tlsutil.go @@ -14,34 +14,36 @@ var TLSLookup = map[string]uint16{ "tls12": tls.VersionTLS12, } +// cipherMap maps the cipher suite names to the internal cipher suite code. +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_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, + "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, + "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_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + "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": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, +} + // ParseCiphers parse ciphersuites from the comma-separated string into recognized slice func ParseCiphers(cipherStr string) ([]uint16, error) { suites := []uint16{} ciphers := strutil.ParseStringSlice(cipherStr, ",") - 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_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - "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, - "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_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - "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": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - } for _, cipher := range ciphers { if v, ok := cipherMap[cipher]; ok { suites = append(suites, v) @@ -52,3 +54,14 @@ func ParseCiphers(cipherStr string) ([]uint16, error) { return suites, nil } + +// GetCipherName returns the name of a given cipher suite code or an error if the +// given cipher is unsupported. +func GetCipherName(cipher uint16) (string, error) { + for cipherStr, cipherCode := range cipherMap { + if cipherCode == cipher { + return cipherStr, nil + } + } + return "", fmt.Errorf("unsupported cipher %d", cipher) +} diff --git a/helper/tlsutil/tlsutil_test.go b/helper/tlsutil/tlsutil_test.go index 79aac9ba61e5..046760a57941 100644 --- a/helper/tlsutil/tlsutil_test.go +++ b/helper/tlsutil/tlsutil_test.go @@ -28,3 +28,21 @@ func TestParseCiphers(t *testing.T) { t.Fatal("cipher order is not preserved") } } + +func TestGetCipherName(t *testing.T) { + testOkCipherStr := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + testOkCipher := tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + cipherStr, err := GetCipherName(testOkCipher) + if err != nil { + t.Fatal(err) + } + if cipherStr != testOkCipherStr { + t.Fatalf("cipher string should be %s but is %s", testOkCipherStr, cipherStr) + } + + var testBadCipher uint16 = 0xC022 + cipherStr, err = GetCipherName(testBadCipher) + if err == nil { + t.Fatal("should fail on unsupported cipher 0xC022") + } +}