summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--libglusterfs/src/globals.h4
-rw-r--r--rpc/rpc-transport/socket/src/socket.c260
-rw-r--r--tests/features/dh1024.pem5
-rw-r--r--tests/features/openssl.cnf.in41
-rw-r--r--tests/features/ssl-ciphers.t204
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c131
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h6
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-set.c30
8 files changed, 523 insertions, 158 deletions
diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h
index 8b513d03646..3f91363a7c9 100644
--- a/libglusterfs/src/globals.h
+++ b/libglusterfs/src/globals.h
@@ -37,7 +37,7 @@
*/
#define GD_OP_VERSION_MIN 1 /* MIN is the fresh start op-version, mostly
should not change */
-#define GD_OP_VERSION_MAX GD_OP_VERSION_3_7_3 /* MAX VERSION is the maximum
+#define GD_OP_VERSION_MAX GD_OP_VERSION_3_7_4 /* MAX VERSION is the maximum
count in VME table, should
keep changing with
introduction of newer
@@ -53,6 +53,8 @@
#define GD_OP_VERSION_3_7_3 30703 /* Op-version for GlusterFS 3.7.3 */
+#define GD_OP_VERSION_3_7_4 30704 /* Op-version for GlusterFS 3.7.4 */
+
#define GD_OP_VER_PERSISTENT_AFR_XATTRS GD_OP_VERSION_3_6_0
#include "xlator.h"
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} }
};
diff --git a/tests/features/dh1024.pem b/tests/features/dh1024.pem
new file mode 100644
index 00000000000..fe514bd4ee5
--- /dev/null
+++ b/tests/features/dh1024.pem
@@ -0,0 +1,5 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAL2k+efZ6g50PpL41G96IaRw2OTH921yhHMNSXBE/K+R6oTkJFcNJs1N
+q+a1Ko2xCBDa5MgvudqWep6PvE06rzEaJPW8ITdu8j3Eo9T1rorJ3CctpE/CaRl2
+7v4DNe+Mho6q1MPlG5PfXEZWgbT7tjn/Y6lwD/B2CoMzAx+4DXgbAgEC
+-----END DH PARAMETERS-----
diff --git a/tests/features/openssl.cnf.in b/tests/features/openssl.cnf.in
new file mode 100644
index 00000000000..1fce34b11b9
--- /dev/null
+++ b/tests/features/openssl.cnf.in
@@ -0,0 +1,41 @@
+[ req ]
+distinguished_name = req_distinguished_name
+x509_extensions = v3_ca
+[ req_distinguished_name ]
+commonName = Common Name
+commonName_max = 64
+[ v3_ca ]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+basicConstraints = CA:true
+[ ca ]
+default_ca = CA_default
+[ CA_default ]
+dir = @TMPDIR@
+certs = $dir/certs
+crl_dir = $dir/crl
+database = $dir/index.txt
+unique_subjecta = no
+new_certs_dir = $dir/newcerts
+certificate = $dir/ca.crt
+serial = $dir/serial
+crl = $dir/crl.pem
+private_key = $dir/self.key
+x509_extensions = usr_cert
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 365
+default_crl_days = 30
+crl_extensions = crl_ext
+default_md = sha256
+preserve = no
+policy = policy_test
+[ policy_test ]
+commonName = supplied
+[ usr_cert ]
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+crlDistributionPoints = URI:file://@TMPDIR@/crl.pem
+[ crl_ext ]
+authorityKeyIdentifier = keyid:always,issuer:always
diff --git a/tests/features/ssl-ciphers.t b/tests/features/ssl-ciphers.t
new file mode 100644
index 00000000000..9ee7fc6c16f
--- /dev/null
+++ b/tests/features/ssl-ciphers.t
@@ -0,0 +1,204 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+brick_port() {
+ $CLI volume status $1 | awk '
+ ($3 == "") { p = $0; next; }
+ { $0 = p $0; p = ""; }
+ /^Brick/ { print $3; }
+ '
+}
+
+wait_mount() {
+ i=1
+ while [ $i -lt $CONFIG_UPDATE_TIMEOUT ] ; do
+ sleep 1
+ i=$(( $i + 1 ))
+ mounted=`mount|awk -v m=$1 '
+ BEGIN {r = "N";}
+ ($3 == m) {r = "Y"; exit;}
+ END {print r;}
+ '`
+ if [ "x${mounted}" = "xY" ] ; then
+ ls $M0 2>/dev/null || continue
+ break;
+ fi
+ done
+
+ if [ "x${mounted}" = "xY" ] ; then
+ ls $M0 2>/dev/null || mounted="N"
+ fi
+
+ echo $mounted
+}
+
+openssl_connect() {
+ ssl_opt="-verify 3 -verify_return_error -CAfile $SSL_CA"
+ ssl_opt="$ssl_opt -crl_check_all -CApath $TMPDIR"
+ CIPHER=`echo "" |
+ openssl s_client $ssl_opt $@ 2>/dev/null |
+ awk '/^ Cipher/{print $3}'`
+ if [ "x${CIPHER}" = "x" -o "x${CIPHER}" = "x0000" ] ; then
+ echo "N"
+ else
+ echo "Y"
+ fi
+}
+
+cleanup;
+mkdir -p $B0
+mkdir -p $M0
+
+TMPDIR=`mktemp -d /tmp/${0##*/}.XXXXXX`
+TEST test -d $TMPDIR
+
+SSL_KEY=$TMPDIR/self.key
+SSL_CSR=$TMPDIR/self.csr
+SSL_CERT=$TMPDIR/self.crt
+SSL_CA=$TMPDIR/ca.crt
+SSL_CFG=$TMPDIR/openssl.cnf
+SSL_CRL=$TMPDIR/crl.pem
+
+sed "s|@TMPDIR@|${TMPDIR}|" `pwd`/`dirname $0`/openssl.cnf.in > $SSL_CFG
+
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume info;
+
+TEST openssl genrsa -out $SSL_KEY 1024 2>/dev/null
+TEST openssl req -config $SSL_CFG -new -key $SSL_KEY -x509 \
+ -subj /CN=CA -out $SSL_CA
+TEST openssl req -config $SSL_CFG -new -key $SSL_KEY \
+ -subj /CN=$H0 -out $SSL_CSR
+
+echo "01" > $TMPDIR/serial
+TEST touch $TMPDIR/index.txt $TMPDIR/index.txx.attr
+TEST mkdir -p $TMPDIR/certs $TMPDIR/newcerts $TMPDIR/crl
+TEST openssl ca -batch -config $SSL_CFG -in $SSL_CSR -out $SSL_CERT 2>&1
+
+touch $SSL_CRL
+CRLHASH=`openssl x509 -hash -fingerprint -noout -in $SSL_CA|sed -n '1s/$/.r0/p'`
+ln -sf $SSL_CRL $TMPDIR/$CRLHASH
+TEST openssl ca -config $SSL_CFG -gencrl -out $SSL_CRL 2>&1
+
+
+TEST $CLI volume create $V0 $H0:$B0/1
+TEST $CLI volume set $V0 server.ssl on
+TEST $CLI volume set $V0 client.ssl on
+TEST $CLI volume set $V0 ssl.private-key $SSL_KEY
+TEST $CLI volume set $V0 ssl.own-cert $SSL_CERT
+TEST $CLI volume set $V0 ssl.ca-list $SSL_CA
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+
+BRICK_PORT=`brick_port $V0`
+
+# Test we can connect
+EXPECT "Y" openssl_connect -connect $H0:$BRICK_PORT
+
+# Test SSLv2 protocol fails
+EXPECT "N" openssl_connect -ssl2 -connect $H0:$BRICK_PORT
+
+# Test SSLv3 protocol fails
+EXPECT "N" openssl_connect -ssl3 -connect $H0:$BRICK_PORT
+
+# Test TLSv1 protocol fails
+EXPECT "N" openssl_connect -tls1 -connect $H0:$BRICK_PORT
+
+# Test a HIGH CBC cipher
+EXPECT "Y" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT
+
+# Test EECDH
+EXPECT "Y" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT
+
+# test MD5 fails
+EXPECT "N" openssl_connect -cipher DES-CBC3-MD5 -connect $H0:$BRICK_PORT
+
+# test RC4 fails
+EXPECT "N" openssl_connect -cipher RC4-SHA -connect $H0:$BRICK_PORT
+
+# test eNULL fails
+EXPECT "N" openssl_connect -cipher NULL-SHA256 -connect $H0:$BRICK_PORT
+
+# test SHA2
+EXPECT "Y" openssl_connect -cipher AES256-SHA256 -connect $H0:$BRICK_PORT
+
+# test GCM
+EXPECT "Y" openssl_connect -cipher AES256-GCM-SHA384 -connect $H0:$BRICK_PORT
+
+# Test DH fails without DH params
+EXPECT "N" openssl_connect -cipher EDH -connect $H0:$BRICK_PORT
+
+# Test DH with DH params
+TEST $CLI volume set $V0 ssl.dh-param `pwd`/`dirname $0`/dh1024.pem
+EXPECT "`pwd`/`dirname $0`/dh1024.pem" volume_option $V0 ssl.dh-param
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+EXPECT "Y" openssl_connect -cipher EDH -connect $H0:$BRICK_PORT
+
+# Test the cipher-list option
+TEST $CLI volume set $V0 ssl.cipher-list AES256-SHA
+EXPECT AES256-SHA volume_option $V0 ssl.cipher-list
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+EXPECT "Y" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT
+EXPECT "N" openssl_connect -cipher AES128-SHA -connect $H0:$BRICK_PORT
+
+# Test the ec-curve option
+TEST $CLI volume set $V0 ssl.cipher-list EECDH:EDH:!TLSv1
+EXPECT EECDH:EDH:!TLSv1 volume_option $V0 ssl.cipher-list
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+EXPECT "N" openssl_connect -cipher AES256-SHA -connect $H0:$BRICK_PORT
+EXPECT "Y" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT
+
+TEST $CLI volume set $V0 ssl.ec-curve invalid
+EXPECT invalid volume_option $V0 ssl.ec-curve
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+EXPECT "N" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT
+
+TEST $CLI volume set $V0 ssl.ec-curve secp521r1
+EXPECT secp521r1 volume_option $V0 ssl.ec-curve
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count
+EXPECT "Y" openssl_connect -cipher EECDH -connect $H0:$BRICK_PORT
+
+# test revocation
+# no need to restart the volume since the options are used
+# by the client here.
+TEST $CLI volume set $V0 ssl.crl-path $TMPDIR
+EXPECT $TMPDIR volume_option $V0 ssl.crl-path
+$GFS --volfile-id=$V0 --volfile-server=$H0 $M0
+EXPECT "Y" wait_mount $M0
+TEST_FILE=`mktemp $M0/${0##*/}.XXXXXX`
+TEST test -f $TEST_FILE
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
+
+TEST openssl ca -batch -config $SSL_CFG -revoke $SSL_CERT 2>&1
+TEST openssl ca -config $SSL_CFG -gencrl -out $SSL_CRL 2>&1
+
+# Failed once revoked
+$GFS --volfile-id=$V0 --volfile-server=$H0 $M0
+EXPECT "N" wait_mount $M0
+TEST ! test -f $TEST_FILE
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
+
+# Succeed with CRL disabled
+TEST $CLI volume set $V0 ssl.crl-path NULL
+EXPECT NULL volume_option $V0 ssl.crl-path
+$GFS --volfile-id=$V0 --volfile-server=$H0 $M0
+EXPECT "Y" wait_mount $M0
+TEST test -f $TEST_FILE
+
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
+
+rm -rf $TMPDIR
+cleanup;
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 75f64fad2c0..5ac392c309e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -37,6 +37,20 @@
extern struct volopt_map_entry glusterd_volopt_map[];
+#define RPC_SET_OPT(XL, CLI_OPT, XLATOR_OPT, ERROR_CMD) do { \
+ char *_value = NULL; \
+ \
+ if (dict_get_str (set_dict, CLI_OPT, &_value) == 0) { \
+ if (xlator_set_option (XL, \
+ "transport.socket." XLATOR_OPT, _value) != 0) { \
+ gf_msg ("glusterd", GF_LOG_WARNING, errno, \
+ GD_MSG_XLATOR_SET_OPT_FAIL, \
+ "failed to set " XLATOR_OPT); \
+ ERROR_CMD; \
+ } \
+ } \
+} while (0 /* CONSTCOND */)
+
/*********************************************
*
* xlator generation / graph manipulation API
@@ -2071,25 +2085,14 @@ brick_graph_add_server (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
return -1;
}
- if (dict_get_str (set_dict, SSL_CERT_DEPTH_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cert-depth", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, 0,
- GD_MSG_XLATOR_SET_OPT_FAIL,
- "failed to set ssl-cert-depth");
- return -1;
- }
- }
-
- if (dict_get_str (set_dict, SSL_CIPHER_LIST_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cipher-list", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, 0,
- GD_MSG_XLATOR_SET_OPT_FAIL,
- "failed to set ssl-cipher-list");
- return -1;
- }
- }
+ RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", return -1);
+ RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT,"ssl-private-key", return -1);
+ RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", return -1);
+ RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", return -1);
+ RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cetificate-depth", return -1);
+ RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT,"ssl-cipher-list", return -1);
+ RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", return -1);
+ RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", return -1);
if (username) {
memset (key, 0, sizeof (key));
@@ -2165,26 +2168,22 @@ brick_graph_add_pump (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
if (NULL == ptranst)
return -1;
- if (dict_get_str (set_dict, SSL_CERT_DEPTH_OPT, &value) == 0) {
- ret = xlator_set_option (rbxl, "ssl-cert-depth", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, errno,
- GD_MSG_DICT_GET_FAILED,
- "failed to set ssl-cert-depth");
- return -1;
- }
- }
-
- if (dict_get_str (set_dict, SSL_CIPHER_LIST_OPT, &value) == 0) {
- ret = xlator_set_option (rbxl, "ssl-cipher-list",
- value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, errno,
- GD_MSG_DICT_GET_FAILED,
- "failed to set ssl-cipher-list");
- return -1;
- }
- }
+ RPC_SET_OPT(rbxl, SSL_OWN_CERT_OPT, "ssl-own-cert",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_PRIVATE_KEY_OPT,"ssl-private-key",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_CA_LIST_OPT, "ssl-ca-list",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_CRL_PATH_OPT, "ssl-crl-path",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_CERT_DEPTH_OPT, "ssl-cetificate-depth",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_CIPHER_LIST_OPT,"ssl-cipher-list",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_DH_PARAM_OPT, "ssl-dh-param",
+ return -1);
+ RPC_SET_OPT(rbxl, SSL_EC_CURVE_OPT, "ssl-ec-curve",
+ return -1);
if (username) {
ret = xlator_set_option (rbxl, "username", username);
@@ -2743,25 +2742,14 @@ volgen_graph_build_client (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
}
}
- if (dict_get_str (set_dict, SSL_CERT_DEPTH_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cert-depth", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, errno,
- GD_MSG_DICT_GET_FAILED,
- "failed to set ssl-cert-depth");
- goto err;
- }
- }
-
- if (dict_get_str (set_dict, SSL_CIPHER_LIST_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cipher-list", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, errno,
- GD_MSG_DICT_GET_FAILED,
- "failed to set ssl-cipher-list");
- goto err;
- }
- }
+ RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", goto err);
+ RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT,"ssl-private-key", goto err);
+ RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", goto err);
+ RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", goto err);
+ RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cetificate-depth", goto err);
+ RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT,"ssl-cipher-list", goto err);
+ RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", goto err);
+ RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", goto err);
return xl;
err:
@@ -5007,25 +4995,14 @@ glusterd_snapdsvc_generate_volfile (volgen_graph_t *graph,
if (ret)
return -1;
- if (dict_get_str (set_dict, SSL_CERT_DEPTH_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cert-depth", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, 0,
- GD_MSG_XLATOR_SET_OPT_FAIL,
- "failed to set ssl-cert-depth");
- return -1;
- }
- }
-
- if (dict_get_str (set_dict, SSL_CIPHER_LIST_OPT, &value) == 0) {
- ret = xlator_set_option (xl, "ssl-cipher-list", value);
- if (ret) {
- gf_msg ("glusterd", GF_LOG_WARNING, 0,
- GD_MSG_XLATOR_SET_OPT_FAIL,
- "failed to set ssl-cipher-list");
- return -1;
- }
- }
+ RPC_SET_OPT(xl, SSL_OWN_CERT_OPT, "ssl-own-cert", return -1);
+ RPC_SET_OPT(xl, SSL_PRIVATE_KEY_OPT,"ssl-private-key", return -1);
+ RPC_SET_OPT(xl, SSL_CA_LIST_OPT, "ssl-ca-list", return -1);
+ RPC_SET_OPT(xl, SSL_CRL_PATH_OPT, "ssl-crl-path", return -1);
+ RPC_SET_OPT(xl, SSL_CERT_DEPTH_OPT, "ssl-cetificate-depth", return -1);
+ RPC_SET_OPT(xl, SSL_CIPHER_LIST_OPT,"ssl-cipher-list", return -1);
+ RPC_SET_OPT(xl, SSL_DH_PARAM_OPT, "ssl-dh-param", return -1);
+ RPC_SET_OPT(xl, SSL_EC_CURVE_OPT, "ssl-ec-curve", return -1);
username = glusterd_auth_get_username (volinfo);
passwd = glusterd_auth_get_password (volinfo);
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h
index 9a0c9798a9e..cbd3cf38d51 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.h
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h
@@ -40,8 +40,14 @@
#define AUTH_REJECT_OPT_KEY "auth.addr.*.reject"
#define NFS_DISABLE_OPT_KEY "nfs.*.disable"
+#define SSL_OWN_CERT_OPT "ssl.own-cert"
+#define SSL_PRIVATE_KEY_OPT "ssl.private-key"
+#define SSL_CA_LIST_OPT "ssl.ca-list"
+#define SSL_CRL_PATH_OPT "ssl.crl-path"
#define SSL_CERT_DEPTH_OPT "ssl.certificate-depth"
#define SSL_CIPHER_LIST_OPT "ssl.cipher-list"
+#define SSL_DH_PARAM_OPT "ssl.dh-param"
+#define SSL_EC_CURVE_OPT "ssl.ec-curve"
typedef enum {
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
index f1413dbf525..eb079d072b6 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
@@ -1077,6 +1077,26 @@ struct volopt_map_entry glusterd_volopt_map[] = {
},
/* Generic transport options */
+ { .key = SSL_OWN_CERT_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-own-cert",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
+ { .key = SSL_PRIVATE_KEY_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-private-key",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
+ { .key = SSL_CA_LIST_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-ca-list",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
+ { .key = SSL_CRL_PATH_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-crl-path",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
{ .key = SSL_CERT_DEPTH_OPT,
.voltype = "rpc-transport/socket",
.option = "!ssl-cert-depth",
@@ -1087,6 +1107,16 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.option = "!ssl-cipher-list",
.op_version = GD_OP_VERSION_3_6_0,
},
+ { .key = SSL_DH_PARAM_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-dh-param",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
+ { .key = SSL_EC_CURVE_OPT,
+ .voltype = "rpc-transport/socket",
+ .option = "!ssl-ec-curve",
+ .op_version = GD_OP_VERSION_3_7_4,
+ },
/* Performance xlators enable/disbable options */
{ .key = "performance.write-behind",