Skip to content

Commit

Permalink
Encryption patch follow-up
Browse files Browse the repository at this point in the history
* PBKDF2 implementation changed to OpenSSL implementation.

* HKDF implementation moved to its own file and tests
  added to ensure correctness.

* Removed libzfs's now unnecessary dependency on libzpool
  and libicp.

* Ztest can now create and test encrypted datasets. This is
  currently disabled until issue openzfs#6526 is resolved, but
  otherwise functions as advertised.

* Several small bug fixes discovered after enabling ztest
  to run on encrypted datasets.

* Fixed coverity defects added by the encryption patch.

* Updated man pages for encrypted send / receive behavior.

* Fixed a bug where encrypted datasets could receive
  DRR_WRITE_EMBEDDED records.

* Minor code cleanups / consolidation.

Signed-off-by: Tom Caputi <[email protected]>
  • Loading branch information
Tom Caputi committed Oct 11, 2017
1 parent 94d49e8 commit 4807c0b
Show file tree
Hide file tree
Showing 41 changed files with 1,055 additions and 433 deletions.
14 changes: 12 additions & 2 deletions COPYRIGHT
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@ approved for release under LLNL-CODE-403049.

Unless otherwise noted, all files in this distribution are released
under the Common Development and Distribution License (CDDL).
Exceptions are noted within the associated source files. See the file
OPENSOLARIS.LICENSE for more information.
Exceptions are noted within the associated source files. A few notable
exceptions and their respective licenses include:

Skein Checksum Implementation: module/icp/algs/skein/THIRDPARTYLICENSE
AES Implementation: module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
AES Implementation: module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
PBKDF2 Implementation: lib/libzfs/THIRDPARTYLICENSE.openssl

This product includes software developed by the OpenSSL Project for use
in the OpenSSL Toolkit (http://www.openssl.org/)

See the file OPENSOLARIS.LICENSE for more information.

Refer to the git commit log for authoritative copyright attribution.
23 changes: 11 additions & 12 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7267,28 +7267,27 @@ zfs_do_change_key(int argc, char **argv)
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
if (keystatus != ZFS_KEYSTATUS_AVAILABLE) {
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);
if (ret != 0)
goto error;
if (ret != 0) {
nvlist_free(props);
zfs_close(zhp);
return (-1);
}
}

/* refresh the properties so the new keystatus is visable */
/* refresh the properties so the new keystatus is visible */
zfs_refresh_properties(zhp);
}

ret = zfs_crypto_rewrap(zhp, props, inheritkey);
if (ret != 0)
goto error;
if (ret != 0) {
nvlist_free(props);
zfs_close(zhp);
return (-1);
}

nvlist_free(props);
zfs_close(zhp);
return (0);

error:
if (props != NULL)
nvlist_free(props);
if (zhp != NULL)
zfs_close(zhp);
return (-1);
}

int
Expand Down
15 changes: 11 additions & 4 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8049,10 +8049,17 @@ main(int argc, char **argv)
* 'freeze' is a vile debugging abomination, so we treat
* it as such.
*/
char buf[16384];
int fd = open(ZFS_DEV, O_RDWR);
(void) strlcpy((void *)buf, argv[2], sizeof (buf));
return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
zfs_cmd_t zc = {"\0"};

(void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name));
ret = zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc);
if (ret != 0) {
(void) fprintf(stderr,
gettext("failed to freeze pool: %d\n"), errno);
ret = 1;
}

log_history = 0;
} else {
(void) fprintf(stderr, gettext("unrecognized "
"command '%s'\n"), cmdname);
Expand Down
117 changes: 102 additions & 15 deletions cmd/ztest/ztest.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ extern int zfs_abd_scatter_enabled;

static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
static char *ztest_wkeydata = "abcdefghijklmnopqrstuvwxyz012345";

typedef struct ztest_shared_ds {
uint64_t zd_seq;
Expand Down Expand Up @@ -1180,6 +1181,42 @@ ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
return (error);
}

static int
ztest_dmu_objset_own(const char *name, dmu_objset_type_t type,
boolean_t readonly, boolean_t decrypt, void *tag, objset_t **osp)
{
int err;

err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
if (decrypt && err == EACCES) {
char ddname[ZFS_MAX_DATASET_NAME_LEN];
dsl_crypto_params_t *dcp;
nvlist_t *crypto_args = fnvlist_alloc();
char *cp = NULL;

/* spa_keystore_load_wkey() expects a dsl dir name */
strcpy(ddname, name);
cp = strchr(ddname, '@');
if (cp != NULL)
*cp = '\0';

fnvlist_add_uint8_array(crypto_args, "wkeydata",
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);
VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, NULL,
crypto_args, &dcp));
err = spa_keystore_load_wkey(ddname, dcp, B_FALSE);
dsl_crypto_params_free(dcp, B_FALSE);
fnvlist_free(crypto_args);

if (err != 0)
return (err);

err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
}

return (err);
}


/*
* Object and range lock mechanics
Expand Down Expand Up @@ -3532,11 +3569,57 @@ ztest_objset_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
static int
ztest_dataset_create(char *dsname)
{
uint64_t zilset = ztest_random(100);
int err = dmu_objset_create(dsname, DMU_OST_OTHER, 0, NULL,
int err;
uint64_t rand;
dsl_crypto_params_t *dcp = NULL;

/*
* 50% of the time, we create encrypted datasets
* using a random cipher suite and a hard-coded
* wrapping key.
*/
rand = ztest_random(2);
if (rand != 0) {
nvlist_t *crypto_args = fnvlist_alloc();
nvlist_t *props = fnvlist_alloc();

/* slight bias towards the default cipher suite */
rand = ztest_random(ZIO_CRYPT_FUNCTIONS);
if (rand < ZIO_CRYPT_AES_128_CCM)
rand = ZIO_CRYPT_ON;

fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_ENCRYPTION), rand);
fnvlist_add_uint8_array(crypto_args, "wkeydata",
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);

/*
* These parameters aren't really used by the kernel. They
* are simply stored so that userspace knows how to load
* the wrapping key.
*/
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), ZFS_KEYFORMAT_RAW);
fnvlist_add_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt");
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL);
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 0ULL);

VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, props,
crypto_args, &dcp));

fnvlist_free(crypto_args);
fnvlist_free(props);
}

err = dmu_objset_create(dsname, DMU_OST_OTHER, 0, dcp,
ztest_objset_create_cb, NULL);
dsl_crypto_params_free(dcp, !!err);

if (err || zilset < 80)
rand = ztest_random(100);
if (err || rand < 80)
return (err);

if (ztest_opts.zo_verbose >= 5)
Expand All @@ -3556,7 +3639,8 @@ ztest_objset_destroy_cb(const char *name, void *arg)
/*
* Verify that the dataset contains a directory object.
*/
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, B_TRUE, FTAG, &os));
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
B_TRUE, FTAG, &os));
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
if (error != ENOENT) {
/* We could have crashed in the middle of destroying it */
Expand Down Expand Up @@ -3640,11 +3724,12 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
* (invoked from ztest_objset_destroy_cb()) should just throw it away.
*/
if (ztest_random(2) == 0 &&
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
B_TRUE, FTAG, &os) == 0) {
ztest_zd_init(zdtmp, NULL, os);
zil_replay(os, zdtmp, ztest_replay_vector);
ztest_zd_fini(zdtmp);
txg_wait_synced(dmu_objset_pool(os), 0);
dmu_objset_disown(os, B_TRUE, FTAG);
}

Expand All @@ -3659,8 +3744,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Verify that the destroyed dataset is no longer in the namespace.
*/
VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, B_TRUE,
FTAG, &os));
VERIFY3U(ENOENT, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
B_TRUE, FTAG, &os));

/*
* Verify that we can create a new dataset.
Expand All @@ -3674,7 +3759,7 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", name, error);
}

VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE,
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE,
FTAG, &os));

ztest_zd_init(zdtmp, NULL, os);
Expand Down Expand Up @@ -3710,10 +3795,11 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Verify that we cannot own an objset that is already owned.
*/
VERIFY3U(EBUSY, ==,
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE, FTAG, &os2));
VERIFY3U(EBUSY, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER,
B_FALSE, B_TRUE, FTAG, &os2));

zil_close(zilog);
txg_wait_synced(spa_get_dsl(os->os_spa), 0);
dmu_objset_disown(os, B_TRUE, FTAG);
ztest_zd_fini(zdtmp);
out:
Expand Down Expand Up @@ -3868,7 +3954,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
}

error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, B_TRUE,
error = ztest_dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, B_TRUE,
FTAG, &os);
if (error)
fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
Expand Down Expand Up @@ -6262,7 +6348,8 @@ ztest_dataset_open(int d)
}
ASSERT(error == 0 || error == EEXIST);

VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE, zd, &os));
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
B_TRUE, zd, &os));
(void) rw_unlock(&ztest_name_lock);

ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
Expand Down Expand Up @@ -6303,6 +6390,7 @@ ztest_dataset_close(int d)
ztest_ds_t *zd = &ztest_ds[d];

zil_close(zd->zd_zilog);
txg_wait_synced(spa_get_dsl(zd->zd_os->os_spa), 0);
dmu_objset_disown(zd->zd_os, B_TRUE, zd);

ztest_zd_fini(zd);
Expand Down Expand Up @@ -6355,7 +6443,7 @@ ztest_run(ztest_shared_t *zs)
ztest_spa = spa;

dmu_objset_stats_t dds;
VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
VERIFY0(ztest_dmu_objset_own(ztest_opts.zo_pool,
DMU_OST_ANY, B_TRUE, B_TRUE, FTAG, &os));
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
dmu_objset_fast_stat(os, &dds);
Expand Down Expand Up @@ -6582,11 +6670,10 @@ ztest_freeze(void)
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
ASSERT(spa_freeze_txg(spa) == UINT64_MAX);
VERIFY3U(0, ==, ztest_dataset_open(0));
ztest_dataset_close(0);

spa->spa_debug = B_TRUE;
ztest_spa = spa;
txg_wait_synced(spa_get_dsl(spa), 0);
ztest_dataset_close(0);
ztest_reguid(NULL, 0);

spa_close(spa, FTAG);
Expand Down
12 changes: 12 additions & 0 deletions config/user-libssl.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
dnl #
dnl # Check for libssl. Used for userspace password derivation via PBKDF2.
dnl #
AC_DEFUN([ZFS_AC_CONFIG_USER_LIBSSL], [
LIBSSL=
AC_CHECK_HEADER([openssl/evp.h], [], [AC_MSG_FAILURE([
*** evp.h missing, libssl-devel package required])])
AC_SUBST([LIBSSL], ["-lssl -lcrypto"])
AC_DEFINE([HAVE_LIBSSL], 1, [Define if you have libssl])
])
1 change: 1 addition & 0 deletions config/user.m4
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
ZFS_AC_CONFIG_USER_LIBBLKID
ZFS_AC_CONFIG_USER_LIBATTR
ZFS_AC_CONFIG_USER_LIBUDEV
ZFS_AC_CONFIG_USER_LIBSSL
ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
ZFS_AC_CONFIG_USER_RUNSTATEDIR
ZFS_AC_CONFIG_USER_MAKEDEV_IN_SYSMACROS
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ AC_CONFIG_FILES([
tests/zfs-tests/tests/functional/grow_pool/Makefile
tests/zfs-tests/tests/functional/grow_replicas/Makefile
tests/zfs-tests/tests/functional/history/Makefile
tests/zfs-tests/tests/functional/hkdf/Makefile
tests/zfs-tests/tests/functional/inheritance/Makefile
tests/zfs-tests/tests/functional/inuse/Makefile
tests/zfs-tests/tests/functional/large_files/Makefile
Expand Down
1 change: 1 addition & 0 deletions contrib/dracut/90zfs/module-setup.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ installkernel() {
instmods znvpair
instmods zavl
instmods zunicode
instmods icp
instmods spl
instmods zlib_deflate
instmods zlib_inflate
Expand Down
1 change: 1 addition & 0 deletions include/sys/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ COMMON_H = \
$(top_srcdir)/include/sys/dsl_userhold.h \
$(top_srcdir)/include/sys/edonr.h \
$(top_srcdir)/include/sys/efi_partition.h \
$(top_srcdir)/include/sys/hkdf.h \
$(top_srcdir)/include/sys/metaslab.h \
$(top_srcdir)/include/sys/metaslab_impl.h \
$(top_srcdir)/include/sys/mmp.h \
Expand Down
29 changes: 29 additions & 0 deletions include/sys/hkdf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* CDDL HEADER START
*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*
* CDDL HEADER END
*/

/*
* Copyright (c) 2017, Datto, Inc. All rights reserved.
*/

#ifndef _SYS_HKDF_H_
#define _SYS_HKDF_H_

#include <sys/types.h>

int hkdf_sha512(uint8_t *key_material, uint_t km_len, uint8_t *salt,
uint_t salt_len, uint8_t *info, uint_t info_len, uint8_t *output_key,
uint_t out_len);

#endif /* _SYS_HKDF_H_ */
Loading

0 comments on commit 4807c0b

Please sign in to comment.