b525630342
This change incorporates three major pieces: The first change is a keystore that manages wrapping and encryption keys for encrypted datasets. These commands mostly involve manipulating the new DSL Crypto Key ZAP Objects that live in the MOS. Each encrypted dataset has its own DSL Crypto Key that is protected with a user's key. This level of indirection allows users to change their keys without re-encrypting their entire datasets. The change implements the new subcommands "zfs load-key", "zfs unload-key" and "zfs change-key" which allow the user to manage their encryption keys and settings. In addition, several new flags and properties have been added to allow dataset creation and to make mounting and unmounting more convenient. The second piece of this patch provides the ability to encrypt, decyrpt, and authenticate protected datasets. Each object set maintains a Merkel tree of Message Authentication Codes that protect the lower layers, similarly to how checksums are maintained. This part impacts the zio layer, which handles the actual encryption and generation of MACs, as well as the ARC and DMU, which need to be able to handle encrypted buffers and protected data. The last addition is the ability to do raw, encrypted sends and receives. The idea here is to send raw encrypted and compressed data and receive it exactly as is on a backup system. This means that the dataset on the receiving system is protected using the same user key that is in use on the sending side. By doing so, datasets can be efficiently backed up to an untrusted system without fear of data being compromised. Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Jorgen Lundman <lundman@lundman.net> Signed-off-by: Tom Caputi <tcaputi@datto.com> Closes #494 Closes #5769
219 lines
7.4 KiB
C
219 lines
7.4 KiB
C
/*
|
|
* 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_DSL_CRYPT_H
|
|
#define _SYS_DSL_CRYPT_H
|
|
|
|
#include <sys/dmu_tx.h>
|
|
#include <sys/dmu.h>
|
|
#include <sys/zio_crypt.h>
|
|
#include <sys/spa.h>
|
|
#include <sys/dsl_dataset.h>
|
|
|
|
/*
|
|
* ZAP entry keys for DSL Crypto Keys stored on disk. In addition,
|
|
* ZFS_PROP_KEYFORMAT, ZFS_PROP_PBKDF2_SALT, and ZFS_PROP_PBKDF2_ITERS are
|
|
* also maintained here using their respective property names.
|
|
*/
|
|
#define DSL_CRYPTO_KEY_CRYPTO_SUITE "DSL_CRYPTO_SUITE"
|
|
#define DSL_CRYPTO_KEY_GUID "DSL_CRYPTO_GUID"
|
|
#define DSL_CRYPTO_KEY_IV "DSL_CRYPTO_IV"
|
|
#define DSL_CRYPTO_KEY_MAC "DSL_CRYPTO_MAC"
|
|
#define DSL_CRYPTO_KEY_MASTER_KEY "DSL_CRYPTO_MASTER_KEY_1"
|
|
#define DSL_CRYPTO_KEY_HMAC_KEY "DSL_CRYPTO_HMAC_KEY_1"
|
|
#define DSL_CRYPTO_KEY_ROOT_DDOBJ "DSL_CRYPTO_ROOT_DDOBJ"
|
|
#define DSL_CRYPTO_KEY_REFCOUNT "DSL_CRYPTO_REFCOUNT"
|
|
|
|
|
|
/*
|
|
* In-memory representation of a wrapping key. One of these structs will exist
|
|
* for each encryption root with its key loaded.
|
|
*/
|
|
typedef struct dsl_wrapping_key {
|
|
/* link on spa_keystore_t:sk_wkeys */
|
|
avl_node_t wk_avl_link;
|
|
|
|
/* keyformat property enum */
|
|
zfs_keyformat_t wk_keyformat;
|
|
|
|
/* the pbkdf2 salt, if the keyformat is of type passphrase */
|
|
uint64_t wk_salt;
|
|
|
|
/* the pbkdf2 iterations, if the keyformat is of type passphrase */
|
|
uint64_t wk_iters;
|
|
|
|
/* actual wrapping key */
|
|
crypto_key_t wk_key;
|
|
|
|
/* refcount of number of dsl_crypto_key_t's holding this struct */
|
|
refcount_t wk_refcnt;
|
|
|
|
/* dsl directory object that owns this wrapping key */
|
|
uint64_t wk_ddobj;
|
|
} dsl_wrapping_key_t;
|
|
|
|
/* enum of commands indicating special actions that should be run */
|
|
typedef enum dcp_cmd {
|
|
/* key creation commands */
|
|
DCP_CMD_NONE = 0, /* no specific command */
|
|
DCP_CMD_RAW_RECV, /* raw receive */
|
|
|
|
/* key changing commands */
|
|
DCP_CMD_NEW_KEY, /* rewrap key as an encryption root */
|
|
DCP_CMD_INHERIT, /* rewrap key with parent's wrapping key */
|
|
DCP_CMD_FORCE_NEW_KEY, /* change to encryption root without rewrap */
|
|
DCP_CMD_FORCE_INHERIT, /* inherit parent's key without rewrap */
|
|
|
|
DCP_CMD_MAX
|
|
} dcp_cmd_t;
|
|
|
|
/*
|
|
* This struct is a simple wrapper around all the parameters that are usually
|
|
* required to setup encryption. It exists so that all of the params can be
|
|
* passed around the kernel together for convenience.
|
|
*/
|
|
typedef struct dsl_crypto_params {
|
|
/* command indicating intended action */
|
|
dcp_cmd_t cp_cmd;
|
|
|
|
/* the encryption algorithm */
|
|
enum zio_encrypt cp_crypt;
|
|
|
|
/* keylocation property string */
|
|
char *cp_keylocation;
|
|
|
|
/* the wrapping key */
|
|
dsl_wrapping_key_t *cp_wkey;
|
|
} dsl_crypto_params_t;
|
|
|
|
/*
|
|
* In-memory representation of a DSL Crypto Key object. One of these structs
|
|
* (and corresponding on-disk ZAP object) will exist for each encrypted
|
|
* clone family that is mounted or otherwise reading protected data.
|
|
*/
|
|
typedef struct dsl_crypto_key {
|
|
/* link on spa_keystore_t:sk_dsl_keys */
|
|
avl_node_t dck_avl_link;
|
|
|
|
/* refcount of dsl_key_mapping_t's holding this key */
|
|
refcount_t dck_holds;
|
|
|
|
/* master key used to derive encryption keys */
|
|
zio_crypt_key_t dck_key;
|
|
|
|
/* wrapping key for syncing this structure to disk */
|
|
dsl_wrapping_key_t *dck_wkey;
|
|
|
|
/* on-disk object id */
|
|
uint64_t dck_obj;
|
|
} dsl_crypto_key_t;
|
|
|
|
/*
|
|
* In-memory mapping of a dataset object id to a DSL Crypto Key. This is used
|
|
* to look up the corresponding dsl_crypto_key_t from the zio layer for
|
|
* performing data encryption and decryption.
|
|
*/
|
|
typedef struct dsl_key_mapping {
|
|
/* link on spa_keystore_t:sk_key_mappings */
|
|
avl_node_t km_avl_link;
|
|
|
|
/* refcount of how many users are depending on this mapping */
|
|
refcount_t km_refcnt;
|
|
|
|
/* dataset this crypto key belongs to (index) */
|
|
uint64_t km_dsobj;
|
|
|
|
/* crypto key (value) of this record */
|
|
dsl_crypto_key_t *km_key;
|
|
} dsl_key_mapping_t;
|
|
|
|
/* in memory structure for holding all wrapping and dsl keys */
|
|
typedef struct spa_keystore {
|
|
/* lock for protecting sk_dsl_keys */
|
|
krwlock_t sk_dk_lock;
|
|
|
|
/* tree of all dsl_crypto_key_t's */
|
|
avl_tree_t sk_dsl_keys;
|
|
|
|
/* lock for protecting sk_key_mappings */
|
|
krwlock_t sk_km_lock;
|
|
|
|
/* tree of all dsl_key_mapping_t's, indexed by dsobj */
|
|
avl_tree_t sk_key_mappings;
|
|
|
|
/* lock for protecting the wrapping keys tree */
|
|
krwlock_t sk_wkeys_lock;
|
|
|
|
/* tree of all dsl_wrapping_key_t's, indexed by ddobj */
|
|
avl_tree_t sk_wkeys;
|
|
} spa_keystore_t;
|
|
|
|
int dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
|
|
nvlist_t *crypto_args, dsl_crypto_params_t **dcp_out);
|
|
void dsl_crypto_params_free(dsl_crypto_params_t *dcp, boolean_t unload);
|
|
void dsl_dataset_crypt_stats(struct dsl_dataset *ds, nvlist_t *nv);
|
|
int dsl_crypto_can_set_keylocation(const char *dsname, const char *keylocation);
|
|
|
|
void spa_keystore_init(spa_keystore_t *sk);
|
|
void spa_keystore_fini(spa_keystore_t *sk);
|
|
|
|
void spa_keystore_dsl_key_rele(spa_t *spa, dsl_crypto_key_t *dck, void *tag);
|
|
int spa_keystore_load_wkey_impl(spa_t *spa, dsl_wrapping_key_t *wkey);
|
|
int spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp,
|
|
boolean_t noop);
|
|
int spa_keystore_unload_wkey_impl(spa_t *spa, uint64_t ddobj);
|
|
int spa_keystore_unload_wkey(const char *dsname);
|
|
|
|
int spa_keystore_create_mapping_impl(spa_t *spa, uint64_t dsobj, dsl_dir_t *dd,
|
|
void *tag);
|
|
int spa_keystore_create_mapping(spa_t *spa, struct dsl_dataset *ds, void *tag);
|
|
int spa_keystore_remove_mapping(spa_t *spa, uint64_t dsobj, void *tag);
|
|
int spa_keystore_lookup_key(spa_t *spa, uint64_t dsobj, void *tag,
|
|
dsl_crypto_key_t **dck_out);
|
|
|
|
int dsl_crypto_populate_key_nvlist(struct dsl_dataset *ds, nvlist_t **nvl_out);
|
|
int dsl_crypto_recv_key(const char *poolname, uint64_t dsobj,
|
|
dmu_objset_type_t ostype, nvlist_t *nvl);
|
|
|
|
int spa_keystore_change_key(const char *dsname, dsl_crypto_params_t *dcp);
|
|
int dsl_dir_rename_crypt_check(dsl_dir_t *dd, dsl_dir_t *newparent);
|
|
int dsl_dataset_promote_crypt_check(dsl_dir_t *target, dsl_dir_t *origin);
|
|
void dsl_dataset_promote_crypt_sync(dsl_dir_t *target, dsl_dir_t *origin,
|
|
dmu_tx_t *tx);
|
|
int dmu_objset_create_crypt_check(dsl_dir_t *parentdd,
|
|
dsl_crypto_params_t *dcp);
|
|
void dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
|
|
struct dsl_dataset *origin, dsl_crypto_params_t *dcp, dmu_tx_t *tx);
|
|
uint64_t dsl_crypto_key_create_sync(uint64_t crypt, dsl_wrapping_key_t *wkey,
|
|
dmu_tx_t *tx);
|
|
int dmu_objset_clone_crypt_check(dsl_dir_t *parentdd, dsl_dir_t *origindd);
|
|
uint64_t dsl_crypto_key_clone_sync(dsl_dir_t *origindd, dmu_tx_t *tx);
|
|
void dsl_crypto_key_destroy_sync(uint64_t dckobj, dmu_tx_t *tx);
|
|
|
|
int spa_crypt_get_salt(spa_t *spa, uint64_t dsobj, uint8_t *salt);
|
|
int spa_do_crypt_mac_abd(boolean_t generate, spa_t *spa, uint64_t dsobj,
|
|
abd_t *abd, uint_t datalen, uint8_t *mac);
|
|
int spa_do_crypt_objset_mac_abd(boolean_t generate, spa_t *spa, uint64_t dsobj,
|
|
abd_t *abd, uint_t datalen, boolean_t byteswap);
|
|
int spa_do_crypt_abd(boolean_t encrypt, spa_t *spa, uint64_t dsobj,
|
|
const blkptr_t *bp, uint64_t txgid, uint_t datalen, abd_t *pabd,
|
|
abd_t *cabd, uint8_t *iv, uint8_t *mac, uint8_t *salt, boolean_t *no_crypt);
|
|
|
|
#endif
|