diff options
author | Emmanuel Dreyfus <manu@netbsd.org> | 2015-07-30 13:54:51 +0200 |
---|---|---|
committer | Kaleb KEITHLEY <kkeithle@redhat.com> | 2015-08-05 04:51:43 -0700 |
commit | 28fc199d5dc92a69eb2b899bbea23548dc14a39b (patch) | |
tree | e56099991bcf6579651cc7b021b26e52ce1ebd26 | |
parent | a0919d638a889f03a5bd804cf4c3a63084680fce (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.h | 4 | ||||
-rw-r--r-- | rpc/rpc-transport/socket/src/socket.c | 260 | ||||
-rw-r--r-- | tests/features/dh1024.pem | 5 | ||||
-rw-r--r-- | tests/features/openssl.cnf.in | 41 | ||||
-rw-r--r-- | tests/features/ssl-ciphers.t | 204 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 131 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.h | 6 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-set.c | 30 |
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", |