예제 #1
0
zcrypt_key_t *
zcrypt_key_copy(zcrypt_key_t *src)
{
	zcrypt_key_t *dst;
	size_t rklen;
	if (src == NULL)
		return (NULL);

	zcrypt_key_hold(src, FTAG);
	ASSERT(src->zk_key.ck_format == CRYPTO_KEY_RAW);
	dst = zcrypt_key_allocate();
	dst->zk_crypt = src->zk_crypt;

	rklen = src->zk_key.ck_length / 8;
	if (rklen != 0) {
		dst->zk_key.ck_data = kmem_alloc(rklen, KM_SLEEP);
		bcopy(src->zk_key.ck_data, dst->zk_key.ck_data, rklen);
		dst->zk_key.ck_format = src->zk_key.ck_format;
		dst->zk_key.ck_length = src->zk_key.ck_length;
	}

	rklen = src->zk_mackey.ck_length / 8;
	if (rklen != 0) {
		dst->zk_mackey.ck_data = kmem_alloc(rklen, KM_SLEEP);
		bcopy(src->zk_mackey.ck_data, dst->zk_mackey.ck_data, rklen);
		dst->zk_mackey.ck_format = src->zk_mackey.ck_format;
		dst->zk_mackey.ck_length = src->zk_mackey.ck_length;
	}

	zcrypt_key_release(src, FTAG);

	return (dst);
}
예제 #2
0
int
dsl_keychain_load_dd(dsl_dir_t *dd, uint64_t dsobj,
                     int crypt, zcrypt_key_t *wrappingkey)
{
    zap_cursor_t zc;
    zap_attribute_t za;
    objset_t *mos = dd->dd_pool->dp_meta_objset;
    uint64_t keychain_zapobj = dsl_dir_phys(dd)->dd_keychain_obj;
    zcrypt_key_t *txgkey;
    zcrypt_keystore_node_t *skn;
    caddr_t wrappedkey;
    size_t wkeylen;
    spa_t *spa = dd->dd_pool->dp_spa;
    int unwrapped = 0, entries = 0;

    /*
     * Basic algorithm is start with the ds_keychain_obj
     * and iterate using zap_cursor_*() unwraping the
     * values (the actual encryption keys) into zcrypt_key_t's
     * and calling zcrypt_keychain_insert() to put them into the dsl AVL
     * tree of keys.
     */
    zcrypt_key_hold(wrappingkey, FTAG);
    skn = zcrypt_keystore_insert(spa, dsobj, wrappingkey);
    ASSERT(skn != NULL);
    mutex_enter(&skn->skn_lock);
    for (zap_cursor_init(&zc, mos, keychain_zapobj);
            zap_cursor_retrieve(&zc, &za) == 0;
            zap_cursor_advance(&zc)) {
        entries++;
        wkeylen = za.za_num_integers;
        wrappedkey = kmem_alloc(wkeylen, KM_SLEEP);
        VERIFY3U(zap_lookup_uint64(mos, keychain_zapobj,
                                   (uint64_t *)&za.za_name, 1, 1,
                                   za.za_num_integers, wrappedkey), ==, 0);
        if (zcrypt_unwrap_key(wrappingkey, crypt,
                              wrappedkey, wkeylen, &txgkey) != 0) {
            kmem_free(wrappedkey, wkeylen);
            continue;
        }
        unwrapped++;
        kmem_free(wrappedkey, wkeylen);
        zcrypt_keychain_insert(&skn->skn_keychain,
                               *(uint64_t *)za.za_name, txgkey);
    }
    zap_cursor_fini(&zc);

    mutex_exit(&skn->skn_lock);
    zcrypt_key_release(wrappingkey, FTAG);

    if (entries > 0 && unwrapped == 0) {
        /* Wrong wrapping key passed */
        (void) zcrypt_keystore_remove(spa, dsobj);
        return (EACCES);
    }

    /*
     * If we didn't unwrap everything we have possible corruption.
     * If an attempt is ever made to decrypt blocks either we won't
     * find the key (ENOKEY) or we will use the wrong key which
     * will result in the MAC failing to verify so  ECKSUM will be
     * set in zio->io_error which will result in an ereport being
     * logged because the zio_read() failed.
     * When we are running DEBUG lets ASSERT this instead.
     */
    ASSERT3U(entries, ==, unwrapped);

    return (0);
}
예제 #3
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);
}
예제 #4
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);
}
예제 #5
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);
}
예제 #6
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);
}