示例#1
0
void
zcrypt_keystore_fini(spa_t *spa)
{
	void *cookie;
	avl_tree_t *tree;
	zcrypt_keystore_node_t *node;

	if (spa->spa_keystore == NULL)
		return;

	rw_enter(&spa->spa_keystore->sk_lock, RW_WRITER);
	/*
	 * Note we don't bother with the refcnt of the keys in here
	 * because this function can't return failure so we just need to
	 * destroy everything.
	 */
	cookie = NULL;
	tree = &spa->spa_keystore->sk_dslkeys;
	while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) {
		mutex_enter(&node->skn_lock);
		(void) zcrypt_keychain_fini(node->skn_keychain);
		zcrypt_key_free(node->skn_wrapkey);
		mutex_exit(&node->skn_lock);
		bzero(node, sizeof (zcrypt_keystore_node_t));
		kmem_free(node, sizeof (zcrypt_keystore_node_t));
	}
	avl_destroy(tree);

	rw_exit(&spa->spa_keystore->sk_lock);
	rw_destroy(&spa->spa_keystore->sk_lock);
	kmem_free(spa->spa_keystore, sizeof (zcrypt_keystore_t));
	spa->spa_keystore = NULL;
}
示例#2
0
static int
zcrypt_keychain_fini(avl_tree_t keychain)
{
	void *cookie = NULL;
	zcrypt_keychain_node_t *node = NULL;

#if 0
	while (AVL_NEXT(&keychain, node) != NULL) {
		if (!refcount_is_zero(&node->dkn_key->zk_refcnt))
			return (EBUSY);
	}
#endif

	while ((node = avl_destroy_nodes(&keychain, &cookie)) != NULL) {
		zcrypt_key_free(node->dkn_key);
		kmem_free(node, sizeof (zcrypt_keychain_node_t));
	}
	avl_destroy(&keychain);

	return (0);
}
示例#3
0
int
zcrypt_keystore_remove(spa_t *spa, uint64_t dsobj)
{
	zcrypt_keystore_node_t zk_tofind;
	zcrypt_keystore_node_t *zk;
	avl_tree_t *tree;
	int err = 0;

	ASSERT(spa->spa_keystore != NULL);

	zk_tofind.skn_os = dsobj;
	tree = &spa->spa_keystore->sk_dslkeys;

	rw_enter(&spa->spa_keystore->sk_lock, RW_WRITER);
	zk = avl_find(tree, &zk_tofind, NULL);
	if (zk == NULL) {
		goto out;
	}
	mutex_enter(&zk->skn_lock);

	err = zcrypt_keychain_fini(zk->skn_keychain);
	if (err != 0) {
		mutex_exit(&zk->skn_lock);
		goto out;
	}
	zcrypt_key_free(zk->skn_wrapkey);
	zk->skn_wrapkey = NULL;
	mutex_exit(&zk->skn_lock);
	mutex_destroy(&zk->skn_lock);

	avl_remove(tree, zk);
	kmem_free(zk, sizeof (zcrypt_keystore_node_t));
out:
	rw_exit(&spa->spa_keystore->sk_lock);

	return (err);
}
示例#4
0
int
dsl_crypto_key_change(char *dsname, zcrypt_key_t *newkey, nvlist_t *props)
{
    struct wkey_change_arg *ca;
    struct kcnode *kcn;
    dsl_dataset_t *ds;
    dsl_props_arg_t pa;
    spa_t *spa;
    int err;
    //dsl_sync_task_group_t *dstg;
    zcrypt_key_t *oldkey;
    dsl_pool_t *dp;

    ASSERT(newkey != NULL);
    ASSERT(dsname != NULL);

    err = dsl_pool_hold(dsname, FTAG, &dp);
    if (err != 0)
        return (err);

    if ((err = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (err);
    }

    /*
     * Take the spa lock here so that new datasets can't get
     * created below us while we are doing a wrapping key change.
     * This is to avoid them being created with the wrong inherited
     * wrapping key.
     */
    err = spa_open(dsname, &spa, FTAG);
    if (err)
        return (err);

    oldkey = zcrypt_key_copy(zcrypt_keystore_find_wrappingkey(spa,
                             ds->ds_object));
    if (oldkey == NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        spa_close(spa, FTAG);
        return (ENOENT);
    }
    ca = kmem_alloc(sizeof (struct wkey_change_arg), KM_SLEEP);
    ca->ca_new_key = newkey;
    ca->ca_old_key = oldkey;
    ca->ca_parent = dsname;
    ca->ca_props = props;

    list_create(&ca->ca_nodes, sizeof (struct kcnode),
                offsetof(struct kcnode, kc_node));

    zcrypt_key_hold(ca->ca_old_key, FTAG);
    zcrypt_key_hold(ca->ca_new_key, FTAG);

    //ca->ca_ds = dsl_sync_task_group_create(spa_get_dsl(spa));

    err = dmu_objset_find(dsname, dsl_crypto_key_change_find,
                          ca, DS_FIND_CHILDREN);

    /*
     * If this is the "top" dataset in this keychange it gets
     * the keysource and salt properties updated.
     */
    pa.pa_props = props;
    pa.pa_source = ZPROP_SRC_LOCAL;
    //pa.pa_flags = 0;
    //pa.pa_zone = curzone;
    //dsl_sync_task_create(ca->ca_dstg, NULL, dsl_props_set_sync, ds, &pa, 2);

    dsl_props_set(dsname, ZPROP_SRC_LOCAL, props);

    //if (err == 0)
    //err = dsl_sync_task_group_wait(dstg);

    while ((kcn = list_head(&ca->ca_nodes))) {
        list_remove(&ca->ca_nodes, kcn);
        dsl_dataset_rele(kcn->kc_ds, kcn);
        kmem_free(kcn, sizeof (struct kcnode));
    }

    //dsl_sync_task_group_destroy(ca->ca_dstg);

    /*
     * We are finished so release and free both the old and new keys.
     * We can free even the new key because everyone got a copy of it
     * not a reference to this one.
     */
    zcrypt_key_release(ca->ca_old_key, FTAG);
    zcrypt_key_free(ca->ca_old_key);
    zcrypt_key_release(ca->ca_new_key, FTAG);
    zcrypt_key_free(ca->ca_new_key);

    kmem_free(ca, sizeof (struct wkey_change_arg));
    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);

    spa_close(spa, FTAG);

    return (err);
}
示例#5
0
/*
 * dsl_crypto_key_change
 *
 * The old key must already be present in memory since the user interface
 * doesn't provide away to prompt or retrieve the old key.
 */
static void
dsl_crypto_key_change_sync(void *arg1, dmu_tx_t *tx)
{
    struct wkey_change_arg *ca = arg1;
    dsl_dataset_t *ds = ca->ca_ds;
    size_t wkeylen;
    char *wkeybuf = NULL;
    zcrypt_key_t *txgkey;
    zap_cursor_t zc;
    zap_attribute_t za;
    objset_t *mos;
    uint64_t keychain_zapobj;
    spa_t *spa;
    zcrypt_keystore_node_t *zkn;

    ASSERT(RRW_WRITE_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock));

    mos = ds->ds_dir->dd_pool->dp_meta_objset;
    keychain_zapobj = dsl_dir_phys(ds->ds_dir)->dd_keychain_obj;

    /*
     * To allow for the case were the keychains of child datasets
     * are not loaded (ie an explicit 'zfs key -u tank/fs/sub' had
     * been done some time before doing 'zfs key -c tank/fs') we itterate
     * over the zap objects on disk rather than copying from the
     * in memory keystore node.
     */
    for (zap_cursor_init(&zc, mos, keychain_zapobj);
            zap_cursor_retrieve(&zc, &za) == 0;
            zap_cursor_advance(&zc)) {
        wkeylen = za.za_num_integers;
        wkeybuf = kmem_alloc(wkeylen, KM_SLEEP);
        VERIFY(zap_lookup_uint64(mos, keychain_zapobj,
                                 (uint64_t *)za.za_name, 1, 1, wkeylen, wkeybuf) == 0);
        VERIFY(zcrypt_unwrap_key(ca->ca_old_key,
                                 ds->ds_objset->os_crypt, wkeybuf, wkeylen, &txgkey) == 0);
        kmem_free(wkeybuf, wkeylen);
        VERIFY(zcrypt_wrap_key(ca->ca_new_key, txgkey,
                               &wkeybuf, &wkeylen,
                               zio_crypt_select_wrap(ds->ds_objset->os_crypt)) == 0);
        zcrypt_key_free(txgkey);
        VERIFY(zap_update_uint64(mos, keychain_zapobj,
                                 (uint64_t *)za.za_name, 1, 1, wkeylen, wkeybuf, tx) == 0);
        kmem_free(wkeybuf, wkeylen);
    }

    zap_cursor_fini(&zc);

    spa = dsl_dataset_get_spa(ds);

    /*
     * If the wrapping key is loaded switch the in memory copy now.
     */
    zkn = zcrypt_keystore_find_node(spa, ds->ds_object, B_FALSE);
    if (zkn != NULL) {
        zcrypt_key_free(zkn->skn_wrapkey);
        zkn->skn_wrapkey = zcrypt_key_copy(ca->ca_new_key);
    }

    spa_history_log_internal(spa, "key change", tx,
                             "succeeded dataset = %llu", ds->ds_object);
}
示例#6
0
int
dsl_crypto_key_new(const char *dsname)
{
    dsl_dataset_t *ds;
    objset_t *os;
    zcrypt_keystore_node_t *skn;
    spa_t *spa;
    struct knarg arg;
    int error;
    dsl_pool_t *dp;
    void *cookie;

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

    if ((error = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (dsl_dataset_is_snapshot(ds)) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    if ((error = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (os->os_crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(os->os_crypt != ZIO_CRYPT_INHERIT);

    /*
     * Need the keychain and wrapping key to already be available.
     */
    spa = dsl_dataset_get_spa(ds);
    skn = zcrypt_keystore_find_node(spa, ds->ds_object, B_FALSE);
    if (skn == NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOENT);
    }

    ASSERT(ds != NULL);
    ASSERT(ds->ds_objset != NULL);

    //zil_suspend_dmu_sync(dmu_objset_zil(os));
    zil_suspend(dsname, &cookie);

    arg.kn_skn = skn;
    arg.kn_txgkey = zcrypt_key_gen(os->os_crypt);
    arg.kn_ds = ds;
    zcrypt_key_hold(skn->skn_wrapkey, FTAG);
    VERIFY(zcrypt_wrap_key(skn->skn_wrapkey, arg.kn_txgkey,
                           &arg.kn_wkeybuf, &arg.kn_wkeylen,
                           zio_crypt_select_wrap(os->os_crypt)) == 0);

    error = dsl_sync_task(spa->spa_name, dsl_crypto_key_new_check,
                          dsl_crypto_key_new_sync, &arg, 1,
                          ZFS_SPACE_CHECK_NONE);

    kmem_free(arg.kn_wkeybuf, arg.kn_wkeylen);

    zcrypt_key_release(skn->skn_wrapkey, FTAG);

    //zil_resume_dmu_sync(dmu_objset_zil(os));
    zil_resume(os);

    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);

    if (error)
        zcrypt_key_free(arg.kn_txgkey);
    return (error);
}
示例#7
0
/*
 * dsl_crypto_key_clone
 *
 * Our caller (dmu_objset_create_sync) must have a lock on the dataset.
 */
int
dsl_crypto_key_clone(dsl_dir_t *dd, dsl_dataset_phys_t *dsphys,
                     uint64_t dsobj, dsl_dataset_t *clone_origin,
                     dsl_crypto_ctx_t *ctx, dmu_tx_t *tx)
{
    zcrypt_key_t *txgkey;
    zcrypt_key_t *wrappingkey = NULL;
    dsl_dataset_t *origin;
    uint64_t crypt;
    spa_t *spa = dd->dd_pool->dp_spa;
    int error = 0;

    ASSERT(ctx != NULL);

    if (BP_IS_HOLE(&dsphys->ds_bp)) {
        origin = ctx->dcc_origin_ds;
    } else {
        origin = clone_origin;
    }
    ASSERT(origin != NULL);

    /*
     * Need to look at the value of crypt on the origin snapshot
     * since it is sticky for encryption.
     */
    VERIFY(dsl_prop_get_ds(origin, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                           8, 1, &crypt,/* DSL_PROP_GET_EFFECTIVE,*/ NULL) == 0);

    if (crypt == ZIO_CRYPT_OFF) {
        return (0);
    }

    wrappingkey = ctx->dcc_wrap_key;

    dsl_keychain_create_obj(dd, tx);
    dsl_keychain_clone_phys(origin, dd, tx, wrappingkey);

    if (ctx->dcc_salt != 0) {
        objset_t *mos = dd->dd_pool->dp_meta_objset;
        uint64_t props_zapobj = dsl_dir_phys(dd)->dd_props_zapobj;

        error = zap_update(mos, props_zapobj,
                           zfs_prop_to_name(ZFS_PROP_SALT), 8, 1,
                           (void *)&ctx->dcc_salt, tx);
    }

    if (ctx->dcc_clone_newkey) {
        caddr_t wkeybuf;
        size_t wkeylen;
        /*
         * Generate a new key and add it to the keychain
         * to be valid from this txg onwards.
         */
        zcrypt_key_hold(wrappingkey, FTAG);
        txgkey = zcrypt_key_gen(crypt);
        VERIFY(zcrypt_wrap_key(wrappingkey, txgkey,
                               &wkeybuf, &wkeylen, zio_crypt_select_wrap(crypt)) == 0);
        zcrypt_key_release(wrappingkey, FTAG);
        dsl_keychain_set_key(dd, tx, wkeybuf, wkeylen,
                             dsphys->ds_creation_time);
        kmem_free(wkeybuf, wkeylen);
        zcrypt_key_free(txgkey);
        spa_history_log_internal(spa, "key create", tx,
                                 "rekey succeeded dataset = %llu from dataset = %llu",
                                 dsobj, clone_origin->ds_object);
    } else {
        spa_history_log_internal(spa, "key create", tx,
                                 "succeeded dataset = %llu from dataset = %llu",
                                 dsobj, clone_origin->ds_object);
    }

    if (wrappingkey != NULL) {
        error = dsl_keychain_load_dd(dd, dsobj, crypt, wrappingkey);
    }

    return (error);
}
示例#8
0
/*
 * dsl_crypto_key_gen - Generate dataset key
 *
 * Generate a new key for this dataset based on its encryption property type.
 * Store the key as a usable zcrypt_key_t in the in memory keystore and
 * put the wrapped version of it in the on disk keychain.
 *
 * returns 0 on success
 */
int
dsl_crypto_key_create(dsl_dir_t *dd, dsl_dataset_phys_t *dsphys,
                      uint64_t dsobj, dsl_crypto_ctx_t *ctx, dmu_tx_t *tx)
{
    int error = -1;
#ifdef DEBUG
    zcrypt_key_t *debugkey;
#endif /* DEBUG */
    zcrypt_key_t *wrappingkey, *dslkey;
    caddr_t wkeybuf = NULL;
    size_t wkeylen = 0;
    uint64_t crypt;
    spa_t *spa = dd->dd_pool->dp_spa;
    zcrypt_keystore_node_t *skn;

    if (ctx == NULL) {
        return (0);
    }

    crypt = ctx->dcc_crypt;
    if (crypt == ZIO_CRYPT_OFF || crypt == ZIO_CRYPT_INHERIT) {
        return (0);
    }

    crypt = zio_crypt_select(crypt, ZIO_CRYPT_ON_VALUE);
    wrappingkey = ctx->dcc_wrap_key;
    skn = zcrypt_keystore_insert(spa, dsobj, wrappingkey);
    if (skn == NULL) {
        error = ENOKEY;
        goto out;
    }

    dslkey = zcrypt_key_gen(crypt);
    zcrypt_key_hold(wrappingkey, FTAG);
    error = zcrypt_wrap_key(wrappingkey, dslkey,
                            &wkeybuf, &wkeylen, zio_crypt_select_wrap(crypt));
    if (error != 0) {
        zcrypt_key_free(dslkey);
        spa_history_log_internal(spa, "key create", tx,
                                 "failed dataset = %llu unable to wrap key", dsobj, error);
        goto out;
    }
    dsl_keychain_create_obj(dd, tx);
    dsl_keychain_set_key(dd, tx, wkeybuf, wkeylen,
                         dsphys->ds_creation_time);
    zcrypt_keychain_insert(&skn->skn_keychain,
                           dsphys->ds_creation_txg, dslkey);
    if (ctx->dcc_salt != 0) {
        objset_t *mos = dd->dd_pool->dp_meta_objset;
        uint64_t props_zapobj = dsl_dir_phys(dd)->dd_props_zapobj;

        error = zap_update(mos, props_zapobj,
                           zfs_prop_to_name(ZFS_PROP_SALT), 8, 1,
                           (void *)&ctx->dcc_salt, tx);
    }
    if (error == 0)
        spa_history_log_internal(spa, "key create", tx,
                                 "succeeded dataset = %llu", dsobj);
#ifdef DEBUG
    ASSERT3U(zcrypt_unwrap_key(wrappingkey, crypt,
                               wkeybuf, wkeylen, &debugkey), ==, 0);
    zcrypt_key_compare(dslkey, debugkey);
    zcrypt_key_free(debugkey);
#endif /* DEBUG */
out:
    zcrypt_key_release(wrappingkey, FTAG);
    if (wkeylen > 0) {
        kmem_free(wkeybuf, wkeylen);
    }

    return (error);
}
示例#9
0
/*
 * zcrypt_unwrap_key
 *
 * Using the provided wrapping key unwrap the key into a zcrypt_key_t.
 *
 * Allocates a zcrypt_key_t using kmem_alloc(), caller should free
 * using zcrypt_key_free().
 *
 * returns 0 on success
 */
int
zcrypt_unwrap_key(zcrypt_key_t *wk, uint64_t crypt,
    caddr_t wkeybuf, size_t wkeylen, zcrypt_key_t **zck)
{
	crypto_mechanism_t wmech;
	crypto_data_t wkey_cdt, ptkey_cdt;
	zcrypt_key_t *tmpzck;
	caddr_t uwrapkey, uwrapmac;
	size_t uwrapkeylen, uwrapmaclen;
	size_t keylen;
	int ret;
	zcrypt_key_phys_t *wkeyphys = (zcrypt_key_phys_t *)wkeybuf;
	uint64_t wcrypt;

	ASSERT(wkeybuf != NULL);
	ASSERT(wkeylen != 0);

	/*
	 * We maybe unwrapping a key of a smaller length than the wrapping
	 * key so unwrapbuflen and keylen need to take that into account.
	 *
	 * The incoming wkey also has the iv stored at the start.
	 */
	wcrypt = wkeyphys->zkp_crypt;
	ASSERT3U(wcrypt, <, ZIO_CRYPT_WRAP_FUNCTIONS);

	wmech.cm_type = crypto_mech2id(
	    zio_crypt_wrap_table[wcrypt].cwi_mechname);
	if (wmech.cm_type == CRYPTO_MECH_INVALID) {
		return (EINVAL);
	}
	keylen = zio_crypt_table[crypt].ci_keylen;

	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_SLEEP);
		ccmp->ulNonceSize = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_kiv;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		ccmp->ulDataSize = keylen + ccmp->ulMACSize;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_SLEEP);
		gcmp->ulIvLen = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_kiv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	uwrapkeylen = keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen;
	uwrapkey = kmem_zalloc(uwrapkeylen, KM_SLEEP);

	SET_CRYPTO_DATA(ptkey_cdt, uwrapkey, uwrapkeylen);
	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_key,
	    keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);

	ret = crypto_decrypt(&wmech, &wkey_cdt, &wk->zk_key,
	    NULL, &ptkey_cdt, NULL);
	kmem_free(wmech.cm_param, wmech.cm_param_len);
	if (ret != CRYPTO_SUCCESS) {
		kmem_free(uwrapkey, uwrapkeylen);
		zck = NULL;
		return (ret);
	}

	tmpzck = zcrypt_key_allocate();
	tmpzck->zk_key.ck_format = CRYPTO_KEY_RAW;
	tmpzck->zk_key.ck_data = kmem_alloc(keylen, KM_SLEEP);
	tmpzck->zk_key.ck_length = keylen * 8;
	tmpzck->zk_crypt = crypt;
	bcopy(uwrapkey, tmpzck->zk_key.ck_data, keylen);
	kmem_free(uwrapkey, uwrapkeylen);

	/* Now the HMAC-SHA256 key which we know is 32 bytes */
	keylen = 32;
	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_SLEEP);
		ccmp->ulNonceSize = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_miv;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		ccmp->ulDataSize = keylen + ccmp->ulMACSize;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_SLEEP);
		gcmp->ulIvLen = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_miv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	uwrapmaclen = keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen;
	uwrapmac = kmem_zalloc(uwrapmaclen, KM_SLEEP);

	SET_CRYPTO_DATA(ptkey_cdt, uwrapmac, uwrapmaclen);
	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_mackey,
	    keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);

	ret = crypto_decrypt(&wmech, &wkey_cdt, &wk->zk_key,
	    NULL, &ptkey_cdt, NULL);
	kmem_free(wmech.cm_param, wmech.cm_param_len);
	if (ret != CRYPTO_SUCCESS) {
		zcrypt_key_free(tmpzck);
		kmem_free(uwrapmac, uwrapmaclen);
		zck = NULL;
		return (ret);
	}

	tmpzck->zk_mackey.ck_format = CRYPTO_KEY_RAW;
	tmpzck->zk_mackey.ck_data = kmem_alloc(keylen, KM_SLEEP);
	tmpzck->zk_mackey.ck_length = keylen * 8;
	bcopy(uwrapmac, tmpzck->zk_mackey.ck_data, keylen);
	kmem_free(uwrapmac, uwrapmaclen);

	*zck = tmpzck;
	return (0);
}