This encryption plugin is based on libnacl <http://nacl.cace-project.eu/secretbox.html> and use crypto_secrebox/crypto_secretbox_open. Currently libnacl doesn't provide any shared library, to we need to link against libnacl.a. This may not work on x86_64, to fix that : - add -fPIC to okcompilers/c - move the content of crypto_onetimeauth/poly1305/amd64/constants.s to crypto_onetimeauth/poly1305/amd64/auth.s To enable NaCl on configure: ./configure --enable-nacl=yes --with-nacl-dir=/path/to/nacl/build/localhost Signed-off-by: Corentin Chary <corentin.chary@xxxxxxxxx> --- configure.ac | 68 +++++++- libglusterfs/src/protocol.h | 9 + transport/encryption/Makefile.am | 2 +- transport/encryption/nacl/Makefile.am | 1 + transport/encryption/nacl/src/Makefile.am | 16 ++ transport/encryption/nacl/src/nacl.c | 275 +++++++++++++++++++++++++++++ transport/encryption/nacl/src/nacl.h | 39 ++++ 7 files changed, 407 insertions(+), 3 deletions(-) create mode 100644 transport/encryption/nacl/Makefile.am create mode 100644 transport/encryption/nacl/src/Makefile.am create mode 100644 transport/encryption/nacl/src/nacl.c create mode 100644 transport/encryption/nacl/src/nacl.h diff --git a/configure.ac b/configure.ac index ef455fd..2e318b3 100644 --- a/configure.ac +++ b/configure.ac @@ -112,6 +112,8 @@ AC_CONFIG_FILES([Makefile transport/ib-verbs/Makefile transport/ib-verbs/src/Makefile transport/encryption/Makefile + transport/encryption/nacl/Makefile + transport/encryption/nacl/src/Makefile auth/Makefile auth/addr/Makefile auth/addr/src/Makefile @@ -163,7 +165,7 @@ fi AC_CHECK_TOOL([LD],[ld]) AC_CHECK_LIB([pthread], [pthread_mutex_init], , AC_MSG_ERROR([Posix threads library is required to build glusterfs])) - + AC_CHECK_FUNC([dlopen], [has_dlopen=yes], AC_CHECK_LIB([dl], [dlopen], , AC_MSG_ERROR([Dynamic linking library required to build glusterfs]))) @@ -244,6 +246,67 @@ fi AC_SUBST(FUSERMOUNT_SUBDIR) #end FUSERMOUNT section +# OPENSSL section +AC_CHECK_LIB([ssl], [EVP_BytesToKey], [HAVE_OPENSSL="yes"], [HAVE_OPENSSL="no"]) + +if test "x$HAVE_OPENSSL" = "xyes"; then + AC_DEFINE(HAVE_OPENSSL, 1, [found EVP_BytesToKey]) +fi +# end OPENSSL section + +# NACL section +nacl_arch="unknown" +case $host_cpu in + i*86) nacl_arch="x86";; + x86_64) nacl_arch="amd64";; + amd64) nacl_arch="amd64";; +esac + +AC_ARG_ENABLE([nacl], + AC_HELP_STRING([--disable-nacl], + [Do not build the ibverbs transport])) +AC_ARG_WITH(nacl-dir, + [ --with-nacl-dir=DIR nacl installed in DIR @<:@/usr@:>@], + [nacl_dir=$withval], + [nacl_dir='/usr']) + +if test x"$use_nacl" != "xno" -a x"$nacl_arch" = "xunknown" ; then + echo "nacl requested but $host_cpu CPU not supported." + exit 1 +fi + +if test "x$enable_nacl" != "xno" -a "x$HAVE_OPENSSL" = "xyes"; then + if test "x$nacl_dir" != "x"; then + LDFLAGS="$LDFLAGS -L$nacl_dir/lib/$nacl_arch" + AC_CHECK_HEADERS([$nacl_dir/include/$nacl_arch/crypto_secretbox.h]) + else + AC_CHECK_HEADERS([crypto_secretbox.h]) + fi + AC_CHECK_LIB([nacl], [crypto_nacl_base], [HAVE_NACL="yes"], [HAVE_NACL="no"]) +fi + +if test "x$enable_nacl" != "xno" -a "x$HAVE_NACL" = "xno"; then + echo "nacl requested but not found." + exit 1 +fi + +BUILD_NACL=no +if test "x$enable_nacl" != "xno" -a "x$HAVE_NACL" = "xyes"; then + NACL_SUBDIR=nacl + BUILD_NACL=yes + NACL_LIBDIR=${nacl_dir}/lib/${nacl_arch} + NACL_INCDIR=${nacl_dir}/include/${nacl_arch} + NACL_LDADD=${NACL_LIBDIR}/libnacl.a +fi +AC_SUBST(NACL_SUBDIR) +AC_SUBST(NACL_LIBDIR) +AC_SUBST(NACL_INCDIR) +AC_SUBST(NACL_LDADD) + +if test "x$HAVE_NACL" = "xyes"; then + AC_DEFINE(HAVE_NACL, 1, [found NaCl]) +fi +# end NACL section # EPOLL section AC_ARG_ENABLE([epoll], @@ -455,7 +518,7 @@ case $host_os in GF_LDADD="${ARGP_STANDALONE_LDADD}" if test "x$ac_cv_header_execinfo_h" = "xyes"; then GF_GLUSTERFS_LDFLAGS="-lexecinfo" - fi + fi GF_FUSE_LDADD="-liconv -lfuse" BUILD_LIBGLUSTERFSCLIENT=no LIBGLUSTERFSCLIENT_SUBDIR="" @@ -495,6 +558,7 @@ echo "GlusterFS configure summary" echo "===========================" echo "FUSE client : $BUILD_FUSE_CLIENT" echo "Infiniband verbs : $BUILD_IBVERBS" +echo "NaCl encryption : $BUILD_NACL" echo "epoll IO multiplex : $BUILD_EPOLL" echo "Berkeley-DB : $BUILD_BDB" echo "libglusterfsclient : $BUILD_LIBGLUSTERFSCLIENT" diff --git a/libglusterfs/src/protocol.h b/libglusterfs/src/protocol.h index 2341ec8..fe0e420 100644 --- a/libglusterfs/src/protocol.h +++ b/libglusterfs/src/protocol.h @@ -964,12 +964,21 @@ typedef struct { } __attribute__ ((packed)) gf_hdr_rsp_t; typedef struct { + char nonce[32]; + char crypto_hdr[32]; + char crypto_vec[32]; +} __attribute__ ((packed)) gf_hdr_nacl_t; + +typedef struct { uint64_t callid; uint32_t type; uint32_t op; uint32_t size; uint32_t crypto; union { + gf_hdr_nacl_t nacl; + } __attribute__ ((packed)); + union { gf_hdr_req_t req; gf_hdr_rsp_t rsp; } __attribute__ ((packed)); diff --git a/transport/encryption/Makefile.am b/transport/encryption/Makefile.am index e182a87..cdff0ca 100644 --- a/transport/encryption/Makefile.am +++ b/transport/encryption/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = +SUBDIRS = $(NACL_SUBDIR) CLEANFILES = diff --git a/transport/encryption/nacl/Makefile.am b/transport/encryption/nacl/Makefile.am new file mode 100644 index 0000000..f963eff --- /dev/null +++ b/transport/encryption/nacl/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src \ No newline at end of file diff --git a/transport/encryption/nacl/src/Makefile.am b/transport/encryption/nacl/src/Makefile.am new file mode 100644 index 0000000..c6c171a --- /dev/null +++ b/transport/encryption/nacl/src/Makefile.am @@ -0,0 +1,16 @@ +xlator_LTLIBRARIES = nacl.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/transport/encryption + +nacl_la_LDFLAGS = -module -avoidversion -lssl + +nacl_la_SOURCES = nacl.c +nacl_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la ${NACL_LIBDIR}/libnacl.a + +noinst_HEADERS = nacl.h + +AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) \ + -I$(NACL_INCDIR) + +CLEANFILES = + diff --git a/transport/encryption/nacl/src/nacl.c b/transport/encryption/nacl/src/nacl.c new file mode 100644 index 0000000..40f7e28 --- /dev/null +++ b/transport/encryption/nacl/src/nacl.c @@ -0,0 +1,275 @@ +/* + Copyright (c) 2009 commonIT + Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <ctype.h> +#include <sys/uio.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "xlator.h" +#include "transport.h" +#include "logging.h" +#include "protocol.h" +#include "iobuf.h" + +#include "nacl.h" + +#include <openssl/evp.h> + +#define NACL_ZERO_BYTES crypto_secretbox_ZEROBYTES +#define NACL_NONCE_BYTES crypto_secretbox_NONCEBYTES + +static char * +nacl_alloc(transport_crypto_t *this, size_t len, struct iobuf **ref) +{ + if (len + NACL_ZERO_BYTES > GF_UNIT_MB) { + char *p = CALLOC (1, len + NACL_ZERO_BYTES); + + if (!p) + return NULL; + return p; + } else { + *ref = iobuf_get (this->xl->ctx->iobuf_pool); + if (!*ref) + return NULL; + return (*ref)->ptr; + } +} + +static void +nacl_free(struct iobuf *iobuf, struct iobuf *ref, char *ptr) +{ + if (ref) + iobuf_unref (ref); + else if (!iobuf || ptr != iobuf->ptr) + FREE (ptr); +} + +static char * +nacl_join(transport_crypto_t *this, struct iobuf *iobuf, + char *buf, size_t len, char *prefix, struct iobuf **iobuf_p) +{ + if (len + NACL_ZERO_BYTES > GF_UNIT_MB) { + char *p = nacl_alloc(this, len + NACL_ZERO_BYTES, NULL); + + if (!p) + return NULL; + memcpy(p, prefix, NACL_ZERO_BYTES); + if (buf) + memcpy(p + NACL_ZERO_BYTES, buf, len); + else + memcpy(p + NACL_ZERO_BYTES, iobuf->ptr, len); + return p; + } else if (iobuf) { + memmove(iobuf->ptr + NACL_ZERO_BYTES, iobuf->ptr, len); + memcpy(iobuf->ptr, prefix, NACL_ZERO_BYTES); + return iobuf->ptr; + } else { + nacl_alloc(this, len, iobuf_p); + if (!*iobuf_p) + return NULL; + memcpy((*iobuf_p)->ptr, prefix, NACL_ZERO_BYTES); + memcpy((*iobuf_p)->ptr + NACL_ZERO_BYTES, buf, len); + return (*iobuf_p)->ptr; + } +} +static void +nacl_split(struct iobuf *iobuf, char *buf, size_t len, char *prefix, char *p) +{ + memcpy(prefix, p, NACL_ZERO_BYTES); + if (iobuf) + /* memmove because p could be iobuf->ptr */ + memmove(iobuf->ptr, p + NACL_ZERO_BYTES, len); + else + memcpy(buf, p + NACL_ZERO_BYTES, len); +} + +static int32_t +__nacl_work (transport_crypto_t *this, struct iobuf *iobuf, + char *buf, size_t len, char *prefix, + char *nonce, int encrypt) +{ + char *orig, *dest; + struct iobuf *orig_ref = NULL, *dest_ref = NULL; + nacl_private_t *priv; + int ret; + char n[32]; + + priv = this->xl_private; + memcpy (n, nonce, NACL_NONCE_BYTES); + //memset (n, 0, NACL_NONCE_BYTES); + orig = nacl_join (this, iobuf, buf, len, prefix, &orig_ref); + dest = nacl_alloc (this, len, &dest_ref); + if (!orig || !dest) + return -ENOMEM; + + if (encrypt) + memset (orig, 0, NACL_ZERO_BYTES); + + if (encrypt) + ret = crypto_secretbox ((u_char *)dest, (u_char *)orig, + len + NACL_ZERO_BYTES, + (u_char *)n, priv->k); + else + ret = crypto_secretbox_open ((u_char *)dest, (u_char *)orig, + len + NACL_ZERO_BYTES, + (u_char *)n, priv->k); + if (ret) + gf_log ("nacl", GF_LOG_ERROR, "error during %s." + " Check the passphrase.", + encrypt ? "encryption" : "decryption"); + nacl_split(iobuf, buf, len, prefix, dest); + + nacl_free(iobuf, orig_ref, orig); + nacl_free(NULL, dest_ref, dest); + return ret; +} + +static int32_t +nacl_iovec (transport_crypto_t *this, struct iovec *vector, int count, + char *prefix, char *nonce) +{ + size_t len; + int32_t ret; + struct iobuf *iobuf; + + if (!vector || !count) + return 0; + + iobuf = iobuf_get (this->xl->ctx->iobuf_pool); + if (!iobuf) + return -ENOMEM; + iov_unload (iobuf->ptr, vector, count); + len = iov_length (vector, count); + ret = __nacl_work (this, iobuf, NULL, len, prefix, nonce, 1); + iov_load (vector, count, iobuf->ptr); + iobuf_unref (iobuf); + return ret; +} + +int32_t +nacl_encrypt (transport_crypto_t *this, char *hdr, size_t len, + struct iovec *vector, int count) +{ + int32_t ret = 0; + int32_t n; + gf_hdr_common_t *h = (gf_hdr_common_t *)hdr; + nacl_private_t *priv; + + priv = this->xl_private; + + n = (h->callid << 16) ^ h->size ^ priv->time; + memcpy (h->nacl.nonce, (char *)&n, NACL_NONCE_BYTES); + + ret = __nacl_work (this, NULL, gf_param(h), len - GF_HDR_COMMON_SIZE, + h->nacl.crypto_hdr, h->nacl.nonce, 1); + if (ret) + return ret; + if (count) + ret = nacl_iovec (this, vector, count, h->nacl.crypto_vec, + h->nacl.nonce); + return ret; +} + +int32_t +nacl_decrypt (transport_crypto_t *this, char *hdr, size_t len, + struct iobuf *iobuf, size_t buflen) +{ + int32_t ret = 0; + gf_hdr_common_t *h = (gf_hdr_common_t *)hdr; + + ret = __nacl_work (this, NULL, gf_param(h), len - GF_HDR_COMMON_SIZE, + h->nacl.crypto_hdr, h->nacl.nonce, 0); + if (ret) + return ret; + if (buflen) + ret = __nacl_work (this, iobuf, NULL, buflen, + h->nacl.crypto_vec, h->nacl.nonce, 0); + return ret; +} + +static void +nacl_gen_key(nacl_private_t *priv, const char *pass) +{ + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + const EVP_MD *dgst = EVP_sha1(); + u_char key[cipher->key_len]; + u_char iv[cipher->iv_len]; + + /* GF_PROTOCOL_VERSION use as salt */ + EVP_BytesToKey(cipher, dgst, + (u_char *)GF_PROTOCOL_VERSION, (u_char *)pass, + strlen(pass), 1, key, iv); + + memcpy(priv->k, key, crypto_secretbox_KEYBYTES); +} + +int32_t +init (transport_crypto_t *crypto) +{ + nacl_private_t *priv; + char *password; + data_t *password_data; + + priv = CALLOC (1, sizeof (*priv)); + if (!priv) + return -ENOMEM; + + crypto->xl_private = priv; + crypto->magic = CRYPTO_MAGIC_NACL; + + + password_data = dict_get (crypto->xl->options, + "transport.crypto.passphrase"); + if (!password_data) { + gf_log ("nacl", GF_LOG_ERROR, "no passphrase specified"); + return -1; + } + + password = data_to_str (password_data); + nacl_gen_key(priv, password); + priv->time = time(NULL); + + gf_log ("nacl", GF_LOG_DEBUG, "nacl transport encryptor loaded"); + return 0; +} + +void +fini (transport_crypto_t *crypto) +{ + FREE (crypto->xl_private); + return; +} + +struct transport_crypto_ops tcops = { + .encrypt = nacl_encrypt, + .decrypt = nacl_decrypt, +}; + +struct volume_options options[] = { + { .key = {"transport.crypto.passphrase"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {NULL} }, +}; diff --git a/transport/encryption/nacl/src/nacl.h b/transport/encryption/nacl/src/nacl.h new file mode 100644 index 0000000..89e8f7a --- /dev/null +++ b/transport/encryption/nacl/src/nacl.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2009 commonIT + Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __NACL_H__ +#define __NACL_H__ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <crypto_secretbox.h> + +#define CRYPTO_MAGIC_NACL 58443 /* NaCl molar mass :) */ + +typedef struct { + unsigned char k[crypto_secretbox_KEYBYTES]; + time_t time; +} nacl_private_t; + + +#endif /* __ROT_13_H__ */ -- 1.6.4.4