예제 #1
0
zcrypt_key_t *
zcrypt_keystore_find_wrappingkey(spa_t *spa, uint64_t dsobj)
{
	zcrypt_keystore_node_t *zk;

	zk = zcrypt_keystore_find_node(spa, dsobj, B_FALSE);
	if (zk == NULL)
		return (NULL);

	return (zk->skn_wrapkey);
}
예제 #2
0
static void
dsl_keychain_clone_phys(dsl_dataset_t *src, dsl_dir_t *dd,
                        dmu_tx_t *tx, zcrypt_key_t *dwkey)
{
    objset_t *mos = dd->dd_pool->dp_meta_objset;
    uint64_t keychain = dsl_dir_phys(dd)->dd_keychain_obj;
    caddr_t wrappedkey = NULL;
    size_t wkeylen = 0;
    zcrypt_keystore_node_t *kn;
    zcrypt_keychain_node_t *n;
    uint64_t newest_txg = dsl_dataset_phys(src)->ds_creation_txg;

    kn = zcrypt_keystore_find_node(dsl_dataset_get_spa(src),
                                   src->ds_object, B_FALSE);
    if (kn == NULL) {
        kn = zcrypt_keystore_find_node(dsl_dataset_get_spa(src),
                                       dsl_dir_phys(src->ds_dir)->dd_head_dataset_obj, B_FALSE);
    }
    ASSERT(kn != NULL);
    ASSERT(dwkey != NULL);

    /*
     * Walk the in memory AVL tree representation of the keychain
     * creating new keychain entries using our wrappingkey, stopping
     * when we reach keychain entries created after the snapshot we
     * are cloning from.
     */
    mutex_enter(&kn->skn_lock);
    for (n = avl_first(&kn->skn_keychain);
            n != NULL && n->dkn_txg <= newest_txg;
            n = AVL_NEXT(&kn->skn_keychain, n)) {
        VERIFY(zcrypt_wrap_key(dwkey, n->dkn_key, &wrappedkey,
                               &wkeylen, zio_crypt_select_wrap(dwkey->zk_crypt)) == 0);
        VERIFY(zap_update_uint64(mos, keychain, &n->dkn_txg,
                                 1, 1, wkeylen, wrappedkey, tx) == 0);
        kmem_free(wrappedkey, wkeylen);
    }
    mutex_exit(&kn->skn_lock);
}
예제 #3
0
/*
 * zcrypt_key_lookup
 *
 * This function looks up the key we need based on the bookmark.
 * It returns a reference to the key that the caller should NOT free.
 * The caller should use zcrypt_key_hold/release()
 * On failure it returns NULL;
 */
zcrypt_key_t *
zcrypt_key_lookup(spa_t *spa, uint64_t objset, uint64_t txg)
{
	zcrypt_keystore_node_t *skn;
	zcrypt_keychain_node_t *dkn;
	crypto_mechanism_t mech = { 0 };
	zcrypt_key_t *key;

#if _KERNEL
    printk("zcrypt_key_lookup enter\n");
#endif

	skn = zcrypt_keystore_find_node(spa, objset, B_FALSE);
	if (skn == NULL)
		return (NULL);

	/* ZIL writes use txg 0 but we want the latest key */
	if (txg == 0)
		txg = -1UL;
	mutex_enter(&skn->skn_lock);
	dkn = zcrypt_keychain_find(skn->skn_keychain, txg);
	if (dkn == NULL) {
		mutex_exit(&skn->skn_lock);
		return (NULL);
	}
	key = dkn->dkn_key;
	if (key != NULL && !key->zk_ctx_tmpl_valid) {
		mech.cm_type = crypto_mech2id(
		    zio_crypt_table[key->zk_crypt].ci_mechname);
		if (crypto_create_ctx_template(&mech, &key->zk_key,
		    &key->zk_ctx_tmpl, KM_SLEEP) == CRYPTO_SUCCESS)
			key->zk_ctx_tmpl_valid = B_TRUE;
	}
	if (key != NULL && !key->zk_mac_ctx_tmpl_valid) {
		mech.cm_type = crypto_mech2id(SUN_CKM_SHA256_HMAC_GENERAL);
		if (crypto_create_ctx_template(&mech, &key->zk_mackey,
		    &key->zk_mac_ctx_tmpl, KM_SLEEP) == CRYPTO_SUCCESS)
			key->zk_mac_ctx_tmpl_valid = B_TRUE;
	}
	mutex_exit(&skn->skn_lock);

#if _KERNEL
    printk("zcrypt_key_lookup exit: key %p\n", key);
#endif
	return (key);
}
예제 #4
0
zfs_crypt_key_status_t
dsl_dataset_keystatus(dsl_dataset_t *ds, boolean_t dp_config_rwlock_held)
{
    /*
     * Sneaky way of determining if this is an encrypted dataset
     * by looking for a keychain obj so we can avoid calling
     * dsl_prop_get_ds and all the locking issues that can entail
     * given when we can be called.
     */
    if (ds == NULL)
        return (ZFS_CRYPT_KEY_UNAVAILABLE);
    if (ds->ds_dir != NULL && dsl_dir_phys(ds->ds_dir) != NULL &&
            dsl_dir_phys(ds->ds_dir)->dd_keychain_obj == 0) {
        return (ZFS_CRYPT_KEY_NONE);
    }
    if (zcrypt_keystore_find_node(dsl_dataset_get_spa(ds),
                                  ds->ds_object, dp_config_rwlock_held)) {
        return (ZFS_CRYPT_KEY_AVAILABLE);
    }
    return (ZFS_CRYPT_KEY_UNAVAILABLE);
}
예제 #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
int
dsl_crypto_key_load(const char *dsname, zcrypt_key_t *wrappingkey)
{
    dsl_dataset_t *ds;
    uint64_t crypt;
    int error;
    dsl_pool_t *dp;

    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);
    }

    /*
     * This is key load not key change so if ds->ds_key is already
     * set we fail.
     */
    if (zcrypt_keystore_find_node(dsl_dataset_get_spa(ds),
                                  ds->ds_object, B_FALSE) != NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (EEXIST);
    }

    /*
     * Find out what size of key we expect.
     *
     * For now the wrapping key size (and type) matches the size
     * of the dataset key, this may not always be the case
     * (particularly if we ever support wrapping dataset keys
     * with asymmetric keys (eg RSA)).
     *
     * When alternate wrapping keys are added it maybe done using
     * a index property.
     */
    rrw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER, FTAG);
    error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                            8, 1, &crypt, NULL/*, DSL_PROP_GET_EFFECTIVE*/);
    rrw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock, FTAG);
    if (error != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(crypt != ZIO_CRYPT_INHERIT);

    error = dsl_keychain_load(ds, crypt, wrappingkey);
    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (error);
}