summaryrefslogtreecommitdiffstats
path: root/rpc
diff options
context:
space:
mode:
authorEmmanuel Dreyfus <manu@netbsd.org>2015-07-30 13:54:51 +0200
committerKaleb KEITHLEY <kkeithle@redhat.com>2015-08-05 04:51:43 -0700
commit28fc199d5dc92a69eb2b899bbea23548dc14a39b (patch)
treee56099991bcf6579651cc7b021b26e52ce1ebd26 /rpc
parenta0919d638a889f03a5bd804cf4c3a63084680fce (diff)
SSL improvements: ECDH, DH, CRL, and accessible options
- Introduce ssl.dh-param option to specify a file containinf DH parameters. If it is provided, EDH ciphers are available. - Introduce ssl.ec-curve option to specify an elliptic curve name. If unspecified, ECDH ciphers are available using the prime256v1 curve. - Introduce ssl.crl-path option to specify the directory where the CRL hash file can be found. Setting to NULL disable CRL checking, just like the default. - Make all ssl.* options accessible through gluster volume set. - In default cipher list, exclude weak ciphers instead of listing the strong ones. - Enforce server cipher preference. - introduce RPC_SET_OPT macro to factor repetitive code in glusterd-volgen.c - Add ssl-ciphers.t test to check all the features touched by this change. Change-Id: I7bfd433df6bbf176f4a58e770e06bcdbe22a101a BUG: 1247152 Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org> Reviewed-on: http://review.gluster.org/11735 Tested-by: NetBSD Build System <jenkins@build.gluster.org> Reviewed-by: Kaushal M <kaushal@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Diffstat (limited to 'rpc')
-rw-r--r--rpc/rpc-transport/socket/src/socket.c260
1 files changed, 180 insertions, 80 deletions
diff --git a/rpc/rpc-transport/socket/src/socket.c b/rpc/rpc-transport/socket/src/socket.c
index d7b639c95ee..52b3e4bebd4 100644
--- a/rpc/rpc-transport/socket/src/socket.c
+++ b/rpc/rpc-transport/socket/src/socket.c
@@ -44,74 +44,13 @@
#define SSL_OWN_CERT_OPT "transport.socket.ssl-own-cert"
#define SSL_PRIVATE_KEY_OPT "transport.socket.ssl-private-key"
#define SSL_CA_LIST_OPT "transport.socket.ssl-ca-list"
+#define SSL_CERT_DEPTH_OPT "transport.socket.ssl-cert-depth"
+#define SSL_CIPHER_LIST_OPT "transport.socket.ssl-cipher-list"
+#define SSL_DH_PARAM_OPT "transport.socket.ssl-dh-param"
+#define SSL_EC_CURVE_OPT "transport.socket.ssl-ec-curve"
+#define SSL_CRL_PATH_OPT "transport.socket.ssl-crl-path"
#define OWN_THREAD_OPT "transport.socket.own-thread"
-/*
- * This list was derived by taking the cipher list "HIGH:!SSLv2" (the previous
- * default) and excluding CBC entries to mitigate the "POODLE" attack. It
- * should be re-evaluated in light of each future vulnerability, as those are
- * discovered.
- */
-static char *default_cipher_list =
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-RSA-AES256-SHA:"
- "ECDHE-ECDSA-AES256-SHA:"
- "DHE-DSS-AES256-GCM-SHA384:"
- "DHE-RSA-AES256-GCM-SHA384:"
- "DHE-RSA-AES256-SHA256:"
- "DHE-DSS-AES256-SHA256:"
- "DHE-RSA-AES256-SHA:"
- "DHE-DSS-AES256-SHA:"
- "DHE-RSA-CAMELLIA256-SHA:"
- "DHE-DSS-CAMELLIA256-SHA:"
- "AECDH-AES256-SHA:"
- "ADH-AES256-GCM-SHA384:"
- "ADH-AES256-SHA256:"
- "ADH-AES256-SHA:"
- "ADH-CAMELLIA256-SHA:"
- "ECDH-RSA-AES256-GCM-SHA384:"
- "ECDH-ECDSA-AES256-GCM-SHA384:"
- "ECDH-RSA-AES256-SHA384:"
- "ECDH-ECDSA-AES256-SHA384:"
- "ECDH-RSA-AES256-SHA:"
- "ECDH-ECDSA-AES256-SHA:"
- "AES256-GCM-SHA384:"
- "AES256-SHA256:"
- "AES256-SHA:"
- "CAMELLIA256-SHA:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-SHA256:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA:"
- "ECDHE-ECDSA-AES128-SHA:"
- "DHE-DSS-AES128-GCM-SHA256:"
- "DHE-RSA-AES128-GCM-SHA256:"
- "DHE-RSA-AES128-SHA256:"
- "DHE-DSS-AES128-SHA256:"
- "DHE-RSA-AES128-SHA:"
- "DHE-DSS-AES128-SHA:"
- "DHE-RSA-CAMELLIA128-SHA:"
- "DHE-DSS-CAMELLIA128-SHA:"
- "AECDH-AES128-SHA:"
- "ADH-AES128-GCM-SHA256:"
- "ADH-AES128-SHA256:"
- "ADH-AES128-SHA:"
- "ADH-CAMELLIA128-SHA:"
- "ECDH-RSA-AES128-GCM-SHA256:"
- "ECDH-ECDSA-AES128-GCM-SHA256:"
- "ECDH-RSA-AES128-SHA256:"
- "ECDH-ECDSA-AES128-SHA256:"
- "ECDH-RSA-AES128-SHA:"
- "ECDH-ECDSA-AES128-SHA:"
- "AES128-GCM-SHA256:"
- "AES128-SHA256:"
- "AES128-SHA:"
- "CAMELLIA128-SHA"; /* no colon for last entry */
-
/* TBD: do automake substitutions etc. (ick) to set these. */
#if !defined(DEFAULT_ETC_SSL)
# ifdef GF_LINUX_HOST_OS
@@ -127,6 +66,7 @@ static char *default_cipher_list =
# define DEFAULT_ETC_SSL "/etc/ssl"
# endif
#endif
+
#if !defined(DEFAULT_CERT_PATH)
#define DEFAULT_CERT_PATH DEFAULT_ETC_SSL "/glusterfs.pem"
#endif
@@ -136,6 +76,12 @@ static char *default_cipher_list =
#if !defined(DEFAULT_CA_PATH)
#define DEFAULT_CA_PATH DEFAULT_ETC_SSL "/glusterfs.ca"
#endif
+#if !defined(DEFAULT_VERIFY_DEPTH)
+#define DEFAULT_VERIFY_DEPTH 1
+#endif
+#define DEFAULT_CIPHER_LIST "EECDH:EDH:HIGH:!3DES:!RC4:!DES:!MD5:!aNULL:!eNULL"
+#define DEFAULT_DH_PARAM DEFAULT_ETC_SSL "/dhparam.pem"
+#define DEFAULT_EC_CURVE "prime256v1"
#define POLL_MASK_INPUT (POLLIN | POLLPRI)
#define POLL_MASK_OUTPUT (POLLOUT)
@@ -3774,9 +3720,11 @@ socket_init (rpc_transport_t *this)
uint32_t timeout = 0;
uint32_t backlog = 0;
int session_id = 0;
- int32_t cert_depth = 1;
- char *cipher_list = default_cipher_list;
- int ret;
+ int32_t cert_depth = DEFAULT_VERIFY_DEPTH;
+ char *cipher_list = DEFAULT_CIPHER_LIST;
+ char *dh_param = DEFAULT_DH_PARAM;
+ char *ec_curve = DEFAULT_EC_CURVE;
+ char *crl_path = NULL;
if (this->private) {
gf_log_callingfn (this->name, GF_LOG_ERROR,
@@ -3958,6 +3906,18 @@ socket_init (rpc_transport_t *this)
}
priv->ssl_ca_list = gf_strdup(priv->ssl_ca_list);
+ if (dict_get_str(this->options,SSL_CRL_PATH_OPT,&optstr) == 0) {
+ if (!priv->ssl_enabled) {
+ gf_log(this->name,GF_LOG_WARNING,
+ "%s specified without %s (ignored)",
+ SSL_CRL_PATH_OPT, SSL_ENABLED_OPT);
+ }
+ if (strcasecmp(optstr, "NULL") == 0)
+ crl_path = NULL;
+ else
+ crl_path = optstr;
+ }
+
gf_log(this->name, priv->ssl_enabled ? GF_LOG_INFO: GF_LOG_DEBUG,
"SSL support on the I/O path is %s",
priv->ssl_enabled ? "ENABLED" : "NOT enabled");
@@ -3982,16 +3942,26 @@ socket_init (rpc_transport_t *this)
"using %s polling thread",
priv->own_thread ? "private" : "system");
- if (!dict_get_int32 (this->options, "ssl-cert-depth", &cert_depth)) {
+ if (!dict_get_int32 (this->options, SSL_CERT_DEPTH_OPT, &cert_depth)) {
gf_log (this->name, GF_LOG_INFO,
"using certificate depth %d", cert_depth);
}
- if (!dict_get_str (this->options, "ssl-cipher-list", &cipher_list)) {
+ if (!dict_get_str (this->options, SSL_CIPHER_LIST_OPT, &cipher_list)) {
gf_log (this->name, GF_LOG_INFO,
"using cipher list %s", cipher_list);
}
+ if (!dict_get_str (this->options, SSL_DH_PARAM_OPT, &dh_param)) {
+ gf_log (this->name, GF_LOG_INFO,
+ "using DH parameters %s", dh_param);
+ }
+ if (!dict_get_str (this->options, SSL_EC_CURVE_OPT, &ec_curve)) {
+ gf_log (this->name, GF_LOG_INFO,
+ "using EC curve %s", ec_curve);
+ }
if (priv->ssl_enabled || priv->mgmt_ssl) {
+ BIO *bio = NULL;
+
/*
* The right time to check this is after all of our relevant
* fields have been set, but before we start issuing OpenSSL
@@ -4006,18 +3976,94 @@ socket_init (rpc_transport_t *this)
#if HAVE_TLSV1_2_METHOD
priv->ssl_meth = (SSL_METHOD *)TLSv1_2_method();
-#else /* old openssl */
-#warning TLSv1.2 is not available, using insecure TLSv1 support
- priv->ssl_meth = (SSL_METHOD *)TLSv1_method();
+#else
+/*
+ * Nobody should use an OpenSSL so old it does not support TLS 1.2.
+ * If that is really required, build with -DUSE_INSECURE_OPENSSL
+ */
+#ifndef USE_INSECURE_OPENSSL
+#error Old and insecure OpenSSL, use -DUSE_INSECURE_OPENSSL to use it anyway
+#endif
+ /* SSLv23_method uses highest available protocol */
+ priv->ssl_meth = (SSL_METHOD *)SSLv23_method();
#endif
priv->ssl_ctx = SSL_CTX_new(priv->ssl_meth);
+ SSL_CTX_set_options(priv->ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(priv->ssl_ctx, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(priv->ssl_ctx, SSL_OP_NO_TICKET);
+ SSL_CTX_set_options(priv->ssl_ctx, SSL_OP_NO_COMPRESSION);
+
+ if ((bio = BIO_new_file(dh_param, "r")) == NULL) {
+ gf_log(this->name,GF_LOG_ERROR,
+ "failed to open %s, "
+ "DH ciphers are disabled", dh_param);
+ }
+
+ if (bio != NULL) {
+#ifdef ERR_R_DH_LIB
+ DH *dh;
+ unsigned long err;
+
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (dh != NULL) {
+ SSL_CTX_set_options(priv->ssl_ctx,
+ SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_tmp_dh(priv->ssl_ctx, dh);
+ DH_free(dh);
+ } else {
+ err = ERR_get_error();
+ gf_log(this->name,GF_LOG_ERROR,
+ "failed to read DH param from %s: %s "
+ "DH ciphers are disabled.",
+ dh_param, ERR_error_string(err, NULL));
+ }
+#else /* ERR_R_DH_LIB */
+ BIO_free(bio);
+ gf_log(this->name, GF_LOG_ERROR,
+ "OpenSSL has no DH support");
+#endif /* ERR_R_DH_LIB */
+ }
+
+ if (ec_curve != NULL) {
+#ifdef ERR_R_ECDH_LIB
+ EC_KEY *ecdh = NULL;
+ int nid;
+ unsigned long err;
+
+ nid = OBJ_sn2nid(ec_curve);
+ if (nid != 0)
+ ecdh = EC_KEY_new_by_curve_name(nid);
+
+ if (ecdh != NULL) {
+ SSL_CTX_set_options(priv->ssl_ctx,
+ SSL_OP_SINGLE_ECDH_USE);
+ SSL_CTX_set_tmp_ecdh(priv->ssl_ctx, ecdh);
+ EC_KEY_free(ecdh);
+ } else {
+ err = ERR_get_error();
+ gf_log(this->name, GF_LOG_ERROR,
+ "failed to load EC curve %s: %s. "
+ "ECDH ciphers are disabled.",
+ ec_curve, ERR_error_string(err, NULL));
+ }
+#else /* ERR_R_ECDH_LIB */
+ gf_log(this->name, GF_LOG_ERROR,
+ "OpenSSL has no ECDH support");
+#endif /* ERR_R_ECDH_LIB */
+ }
+
+ /* This must be done after DH and ECDH setups */
if (SSL_CTX_set_cipher_list(priv->ssl_ctx, cipher_list) == 0) {
gf_log(this->name,GF_LOG_ERROR,
"failed to find any valid ciphers");
goto err;
}
+ SSL_CTX_set_options(priv->ssl_ctx,
+ SSL_OP_CIPHER_SERVER_PREFERENCE);
+
if (!SSL_CTX_use_certificate_chain_file(priv->ssl_ctx,
priv->ssl_own_cert)) {
gf_log(this->name,GF_LOG_ERROR,
@@ -4034,7 +4080,8 @@ socket_init (rpc_transport_t *this)
}
if (!SSL_CTX_load_verify_locations(priv->ssl_ctx,
- priv->ssl_ca_list,0)) {
+ priv->ssl_ca_list,
+ crl_path)) {
gf_log(this->name,GF_LOG_ERROR,
"could not load CA list");
goto err;
@@ -4044,6 +4091,19 @@ socket_init (rpc_transport_t *this)
SSL_CTX_set_verify_depth(ctx,cert_depth);
#endif
+ if (crl_path) {
+#ifdef X509_V_FLAG_CRL_CHECK_ALL
+ X509_STORE *x509store;
+
+ x509store = SSL_CTX_get_cert_store(priv->ssl_ctx);
+ X509_STORE_set_flags(x509store,
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+#else
+ gf_log(this->name,GF_LOG_ERROR,
+ "OpenSSL version does not support CRL");
+#endif
+ }
+
priv->ssl_session_id = ++session_id;
SSL_CTX_set_session_id_context(priv->ssl_ctx,
(void *)&priv->ssl_session_id,
@@ -4197,20 +4257,60 @@ struct volume_options options[] = {
{ .key = {SSL_CA_LIST_OPT},
.type = GF_OPTION_TYPE_STR
},
+ { .key = {SSL_CERT_DEPTH_OPT},
+ .type = GF_OPTION_TYPE_STR
+ },
+ { .key = {SSL_CIPHER_LIST_OPT},
+ .type = GF_OPTION_TYPE_STR
+ },
+ { .key = {SSL_DH_PARAM_OPT},
+ .type = GF_OPTION_TYPE_STR
+ },
+ { .key = {SSL_EC_CURVE_OPT},
+ .type = GF_OPTION_TYPE_STR
+ },
+ { .key = {SSL_CRL_PATH_OPT},
+ .type = GF_OPTION_TYPE_STR
+ },
{ .key = {OWN_THREAD_OPT},
.type = GF_OPTION_TYPE_BOOL
},
- { .key = {"ssl-cert-depth"},
- .type = GF_OPTION_TYPE_INT,
+ { .key = {"ssl-own-cert"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "SSL certificate. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-private-key"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "SSL private key. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-ca-list"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "SSL CA list. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-cert-depth"},
+ .type = GF_OPTION_TYPE_INT,
.description = "Maximum certificate-chain depth. If zero, the "
"peer's certificate itself must be in the local "
"certificate list. Otherwise, there may be up to N "
"signing certificates between the peer's and the "
"local list. Ignored if SSL is not enabled."
},
- { .key = {"ssl-cipher-list"},
- .type = GF_OPTION_TYPE_STR,
- .description = "Allowed SSL ciphers Ignored if SSL is not enabled."
+ { .key = {"ssl-cipher-list"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Allowed SSL ciphers. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-dh-param"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "DH parameters file. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-ec-curve"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "ECDH curve name. Ignored if SSL is not enabled."
+ },
+ { .key = {"ssl-crl-path"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Path to directory containing CRL. "
+ "Ignored if SSL is not enabled."
},
{ .key = {NULL} }
};