mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-13 09:37:13 +03:00
Finalise zfs-tpm2-clear-key. Add manpages
This commit is contained in:
parent
0cf16ed2a2
commit
a007176d65
18
Makefile
18
Makefile
@ -31,7 +31,7 @@ VERAR := $(foreach l,TZPFMS,-D$(l)_VERSION='$($(l)_VERSION)')
|
||||
BINARY_SOURCES := $(sort $(wildcard $(SRCDIR)bin/*.cpp $(SRCDIR)bin/**/*.cpp))
|
||||
COMMON_SOURCES := $(filter-out $(BINARY_SOURCES),$(sort $(wildcard $(SRCDIR)*.cpp $(SRCDIR)**/*.cpp $(SRCDIR)**/**/*.cpp $(SRCDIR)**/**/**/*.cpp)))
|
||||
# TEST_SOURCES := $(sort $(wildcard $(TSTDIR)*.cpp $(TSTDIR)**/*.cpp $(TSTDIR)**/**/*.cpp $(TSTDIR)**/**/**/*.cpp))
|
||||
MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.md $(MANDIR)**/*.md))
|
||||
MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.md.pp))
|
||||
|
||||
|
||||
.PHONY : all clean build build-test man
|
||||
@ -48,17 +48,17 @@ clean :
|
||||
|
||||
build : $(subst $(SRCDIR)bin/,$(OUTDIR),$(subst .cpp,$(EXE),$(BINARY_SOURCES)))
|
||||
#build-test : $(OUTDIR)tzpfms-test$(EXE)
|
||||
man : $(subst $(MANDIR),$(OUTDIR)man/,$(MANPAGE_SOURCES))
|
||||
man : $(OUTDIR)man/index.txt
|
||||
|
||||
|
||||
#$(OUTDIR)tzpfms-test$(EXE) : $(subst $(TSTDIR),$(BLDDIR)test/,$(subst .cpp,$(OBJ),$(TEST_SOURCES))) $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(filter-out $(SRCDIR)main.cpp,$(SOURCES)))) $(patsubst ext/fmt/src/%.cc,$(BLDDIR)fmt/obj/%$(OBJ),$(wildcard ext/fmt/src/*.cc))
|
||||
# $(CXX) $(CXXAR) -o$@ $^ $(PIC) $(LDAR)
|
||||
|
||||
$(subst $(MANDIR),$(OUTDIR)man/,$(MANPAGE_SOURCES)) : $(MANDIR)index.txt $(MANPAGE_SOURCES)
|
||||
@rm -rf $(dir $@) && mkdir -p $(dir $@)
|
||||
cp $^ $(dir $@)
|
||||
$(RONN) $@
|
||||
$(RONN) -f $@
|
||||
$(OUTDIR)man/index.txt : $(MANDIR)index.txt $(patsubst $(MANDIR)%.pp,$(OUTDIR)man/%,$(MANPAGE_SOURCES))
|
||||
@mkdir -p $(dir $@)
|
||||
cp $< $(dir $@)
|
||||
$(RONN) --organization="tzpfms developers" $(filter-out $<,$^)
|
||||
$(RONN) --organization="tzpfms developers" -f $(filter-out $<,$^)
|
||||
|
||||
|
||||
$(OUTDIR)%$(EXE) : $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(SRCDIR)bin/%.cpp $(COMMON_SOURCES)))
|
||||
@ -73,3 +73,7 @@ $(OBJDIR)%$(OBJ) : $(SRCDIR)%.cpp
|
||||
$(BLDDIR)test/%$(OBJ) : $(TSTDIR)%.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CXXAR) $(INCAR) -I$(SRCDIR) $(VERAR) -c -o$@ $^
|
||||
|
||||
$(OUTDIR)man/%.md : $(MANDIR)%.md.pp $(sort $(wildcard $(MANDIR)*.h))
|
||||
@mkdir -p $(dir $@)
|
||||
$(AWK) '/^#include/ {gsub("\"", "", $$2); while((getline inc < ("$(dir $<)" $$2)) == 1) print inc; next} {print}' $< > $@
|
||||
|
@ -52,7 +52,6 @@ TZPFMS_VERSION := "0.0.0-$(shell git rev-list HEAD --count)"
|
||||
INCCMAKEAR := CXXFLAGS="$(INCCXXAR)"
|
||||
LNCMAKEAR := LDFLAGS="$(LNCXXAR)"
|
||||
|
||||
LDD ?= ldd
|
||||
AWK ?= awk
|
||||
RONN ?= ronn
|
||||
OBJ := .o
|
||||
|
17
man/backend-tpm2.h
Normal file
17
man/backend-tpm2.h
Normal file
@ -0,0 +1,17 @@
|
||||
## TPM2 back-end configuration
|
||||
|
||||
### Environment variables
|
||||
|
||||
* `TSS2_LOG`=:
|
||||
Any of: *NONE*, *ERROR*, *WARNING*, *INFO*, *DEBUG*, *TRACE*. Default: *WARNING*.
|
||||
|
||||
### TPM selection
|
||||
|
||||
The library `libtss2-tcti-default.so` can be linked to any of the `libtss2-tcti-*.so` libraries to select the default,
|
||||
otherwise `/dev/tpmrm0`, then `/dev/tpm0`, then `localhost:2321` will be tried, in order (see ESYS_CONTEXT(3)).
|
||||
|
||||
### See also
|
||||
|
||||
The tpm2-tss git repository at <https://github.com/tpm2-software/tpm2-tss> and the documentation at <https://tpm2-tss.readthedocs.io>.
|
||||
|
||||
The TPM 2.0 specifications, mainly at <<https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf>> and related pages.
|
16
man/common.h
Normal file
16
man/common.h
Normal file
@ -0,0 +1,16 @@
|
||||
## AUTHOR
|
||||
|
||||
Written by наб <<nabijaczleweli@nabijaczleweli.xyz>>
|
||||
|
||||
## SPECIAL THANKS
|
||||
|
||||
To all who support further development, in particular:
|
||||
|
||||
* ThePhD
|
||||
* Embark Studios
|
||||
|
||||
## REPORTING BUGS
|
||||
|
||||
<<https://todo.sr.ht/~nabijaczleweli/tzpfms>>
|
||||
|
||||
<<mailto:~nabijaczleweli/tzpfms@lists.sr.ht>>, archived at <<https://lists.sr.ht/~nabijaczleweli/tzpfms>>
|
8
man/index.txt
Normal file
8
man/index.txt
Normal file
@ -0,0 +1,8 @@
|
||||
zfs-tpm2-change-key(8) zfs-tpm2-change-key.8.ronn
|
||||
zfs-tpm2-load-key(8) zfs-tpm2-load-key.8.ronn
|
||||
zfs-tpm2-clear-key(8) zfs-tpm2-clear-key.8.ronn
|
||||
|
||||
zfs(8) https://manpages.debian.org/bullseye/zfsutils-linux/zfs.8.en.html
|
||||
tpm2_unseal(1) https://manpages.debian.org/bullseye/tpm2-tools/tpm2_unseal.1.en.html
|
||||
|
||||
ESYS_CONTEXT(3) https://www.mankier.com/3/ESYS_CONTEXT
|
56
man/zfs-tpm2-change-key.md.pp
Normal file
56
man/zfs-tpm2-change-key.md.pp
Normal file
@ -0,0 +1,56 @@
|
||||
zfs-tpm2-change-key(8) -- change ZFS dataset key to one stored on the TPM
|
||||
=========================================================================
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`zfs-tpm2-change-key` [-b file] <dataset>
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
To normalise `dataset`, zfs-tpm2-change-key(8) will open its encryption root in its stead.
|
||||
zfs-tpm2-change-key(8) will *never* create or destroy encryption roots; use **zfs(8) change-key** for that.
|
||||
|
||||
First, a connection is made to the TPM, which *must* be TPM-2.0-compatible.
|
||||
|
||||
If `dataset` was previously encrypted with tzpfms and the *TPM2* back-end was used, the previous key will be freed from the TPM.
|
||||
Otherwise, or in case of an error, data required for manual intervention will be printed to the standard error stream.
|
||||
|
||||
Next, a new wrapping key is be generated on the TPM, optionally backed up (see [OPTIONS][]),
|
||||
and sealed to a persistent object on the TPM under the owner hierarchy.
|
||||
|
||||
The following properties are set on `dataset`:
|
||||
|
||||
* `xyz.nabijaczleweli:tzpfms.backend`=`TPM2`
|
||||
* `xyz.nabijaczleweli:tzpfms.key`=*(ID of persistent object)*
|
||||
|
||||
`tzpfms.backend` identifies this dataset for work with *TPM2*-back-ended tzpfms tools
|
||||
(namely zfs-tpm2-change-key(8), zfs-tpm2-load-key(8), and zfs-tpm2-clear-key(8)).
|
||||
|
||||
`tzpfms.key` is an integer representing the sealed object;
|
||||
if needed, it can be passed to **tpm2_unseal(1) -c ${tzpfms.key}** or equivalent for back-up (see [OPTIONS][]).
|
||||
If you have a sealed key you can access with that or equivalent tool and set both of these properties, it will funxion seamlessly.
|
||||
|
||||
Finally, the equivalent of **zfs(8) change-key -o keylocation=prompt -o keyformat=raw dataset** is performed with the new key.
|
||||
If an error occurred, best effort is made to clean up the persistent object and properties,
|
||||
or to issue a note for manual intervention into the standard error stream.
|
||||
|
||||
A final verification should be made by running **zfs-tpm2-load-key(8) -n dataset**.
|
||||
If that command succeeds, all is well,
|
||||
but otherwise the dataset can be manually rolled back to a password with **zfs-tpm2-clear-key(8) dataset** (or, if that fails to work, **zfs(8) change-key -o keyformat=passphrase dataset**), and you are hereby asked to report a bug, please.
|
||||
|
||||
**zfs-tpm2-clear-key(8) dataset** can be used to free the TPM persistent object and go back to using a password.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
* `-b` *file*:
|
||||
Save a back-up of the key to *file*, which must not exist beforehand.
|
||||
This back-up **must** be stored securely, off-site.
|
||||
In case of a catastrophic event, the key can be loaded by running **zfs(8) load-key dataset < backup-file**.
|
||||
|
||||
#include "backend-tpm2.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
<<https://git.sr.ht/~nabijaczleweli/tzpfms>>
|
24
man/zfs-tpm2-clear-key.md.pp
Normal file
24
man/zfs-tpm2-clear-key.md.pp
Normal file
@ -0,0 +1,24 @@
|
||||
zfs-tpm2-clear-key(8) -- rewrap ZFS dataset key in passsword and clear tzpfms TPM2 metadata
|
||||
===========================================================================================
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`zfs-tpm2-clear-key` <dataset>
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
zfs-tpm2-clear-key(8), after verifying that `dataset` was encrypted with tzpfms backend *TPM2* will:
|
||||
|
||||
1. perform the equivalent of **zfs(8) change-key -o keylocation=prompt -o keyformat=passphrase dataset**,
|
||||
2. free the sealed key previously used to encrypt `dataset`,
|
||||
3. remove the `xyz.nabijaczleweli:tzpfms.{backend,key}` properties from `dataset`.
|
||||
|
||||
See zfs-tpm2-change-key(8) for a detailed description.
|
||||
|
||||
#include "backend-tpm2.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
<<https://git.sr.ht/~nabijaczleweli/tzpfms>>
|
25
man/zfs-tpm2-load-key.md.pp
Normal file
25
man/zfs-tpm2-load-key.md.pp
Normal file
@ -0,0 +1,25 @@
|
||||
zfs-tpm2-load-key(8) -- load tzpfms TPM2-encrypted ZFS dataset key
|
||||
==================================================================
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`zfs-tpm2-load-key` [-n] <dataset>
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
zfs-tpm2-load-key(8), after verifying that `dataset` was encrypted with tzpfms backend *TPM2* will unseal the key and load it into `dataset`.
|
||||
|
||||
See zfs-tpm2-change-key(8) for a detailed description.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
* `-n`:
|
||||
Do a no-op/dry run, can be used even if the key is already loaded. Equivalent to **zfs(8) load-key**'s `-n` option.
|
||||
|
||||
#include "backend-tpm2.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
<<https://git.sr.ht/~nabijaczleweli/tzpfms>>
|
@ -62,8 +62,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
TRY_MAIN(with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) {
|
||||
char *previous_backend{}, *previous_handle_s{};
|
||||
TRY_MAIN(lookup_userprop(zfs_get_user_props(dataset), PROPNAME_BACKEND, previous_backend));
|
||||
TRY_MAIN(lookup_userprop(zfs_get_user_props(dataset), PROPNAME_KEY, previous_handle_s));
|
||||
TRY_MAIN(lookup_userprop(dataset, PROPNAME_BACKEND, previous_backend));
|
||||
TRY_MAIN(lookup_userprop(dataset, PROPNAME_KEY, previous_handle_s));
|
||||
if(!!previous_backend ^ !!previous_handle_s)
|
||||
fprintf(stderr, "Inconsistent tzpfms metadata for %s: back-end is %s, but handle is %s?\n", zfs_get_name(dataset), previous_backend,
|
||||
previous_handle_s);
|
||||
@ -98,6 +98,9 @@ int main(int argc, char ** argv) {
|
||||
quickscope_wrapper persistent_clearer{[&] {
|
||||
if(!ok && tpm2_free_persistent(tpm2_ctx, tpm2_session, persistent_handle))
|
||||
fprintf(stderr, "Couldn't free persistent handle. You might need to run \"tpm2_evictcontrol -c 0x%X\" or equivalent!\n", persistent_handle);
|
||||
if(!ok && clear_key_props(dataset)) // Sync with zfs-tpm2-clear-key
|
||||
fprintf(stderr, "You might need to run \"zfs inherit %s %s\" and \"zfs inherit %s %s\"!\n", PROPNAME_BACKEND, zfs_get_name(dataset), PROPNAME_KEY,
|
||||
zfs_get_name(dataset));
|
||||
}};
|
||||
|
||||
TRY_MAIN(set_key_props(dataset, THIS_BACKEND, persistent_handle));
|
||||
|
@ -6,19 +6,32 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../main.hpp"
|
||||
#include "../tpm2.hpp"
|
||||
#include "../zfs.hpp"
|
||||
|
||||
|
||||
#define THIS_BACKEND "TPM2"
|
||||
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
return do_main(
|
||||
argc, argv, "", [&](auto) {},
|
||||
[&](auto dataset) {
|
||||
REQUIRE_KEY_LOADED(dataset);
|
||||
|
||||
TPMI_DH_PERSISTENT persistent_handle{};
|
||||
TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, persistent_handle));
|
||||
|
||||
if(zfs_crypto_rewrap(dataset, TRY_PTR("get clear rewrap args", clear_rewrap_args()), B_FALSE))
|
||||
return __LINE__; // Error printed by libzfs
|
||||
|
||||
if(clear_key_props(dataset)) {
|
||||
|
||||
TRY_MAIN(with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) {
|
||||
TRY_MAIN(tpm2_free_persistent(tpm2_ctx, tpm2_session, persistent_handle));
|
||||
return 0;
|
||||
}));
|
||||
|
||||
if(clear_key_props(dataset)) { // Sync with zfs-tpm2-change-key
|
||||
fprintf(stderr, "You might need to run \"zfs inherit %s %s\" and \"zfs inherit %s %s\"!\n", PROPNAME_BACKEND, zfs_get_name(dataset), PROPNAME_KEY,
|
||||
zfs_get_name(dataset));
|
||||
return __LINE__;
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "../fd.hpp"
|
||||
#include "../main.hpp"
|
||||
#include "../parse.hpp"
|
||||
#include "../tpm2.hpp"
|
||||
#include "../zfs.hpp"
|
||||
|
||||
@ -22,29 +21,8 @@ int main(int argc, char ** argv) {
|
||||
return do_main(
|
||||
argc, argv, "n", [&](auto) { noop = B_TRUE; },
|
||||
[&](auto dataset) {
|
||||
char *backend{}, *handle_s{};
|
||||
TRY_MAIN(lookup_userprop(zfs_get_user_props(dataset), PROPNAME_BACKEND, backend));
|
||||
|
||||
if(!backend) {
|
||||
fprintf(stderr, "Dataset %s not encrypted with tzpfms!\n", zfs_get_name(dataset));
|
||||
return __LINE__;
|
||||
}
|
||||
if(strcmp(backend, THIS_BACKEND)) {
|
||||
fprintf(stderr, "Dataset %s encrypted with tzpfms back-end %s, but we are %s.\n", zfs_get_name(dataset), backend, THIS_BACKEND);
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
TRY_MAIN(lookup_userprop(zfs_get_user_props(dataset), PROPNAME_KEY, handle_s));
|
||||
if(!handle_s) {
|
||||
fprintf(stderr, "Dataset %s missing key data.\n", zfs_get_name(dataset));
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
TPMI_DH_PERSISTENT handle{};
|
||||
if(parse_int(handle_s, handle)) {
|
||||
fprintf(stderr, "Dataset %s's handle %s not valid.\n", zfs_get_name(dataset), handle_s);
|
||||
return __LINE__;
|
||||
}
|
||||
TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, handle));
|
||||
|
||||
|
||||
uint8_t wrap_key[WRAPPING_KEY_LEN];
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <charconv>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
template <class T>
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include <tss2/tss2_common.h>
|
||||
#include <tss2/tss2_esys.h>
|
||||
#include <tss2/tss2_rc.h>
|
||||
|
43
src/zfs.cpp
43
src/zfs.cpp
@ -3,9 +3,13 @@
|
||||
|
||||
#include "zfs.hpp"
|
||||
#include "common.hpp"
|
||||
#include "main.hpp"
|
||||
#include "parse.hpp"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// Funxion statics pull in libc++'s __cxa_guard_acquire()
|
||||
static nvlist_t * rrargs{};
|
||||
@ -59,14 +63,19 @@ nvlist_t * clear_rewrap_args() {
|
||||
TRY_NVL(what, _try_retl); \
|
||||
})
|
||||
|
||||
// TODO: how does this interact with nested datasets?
|
||||
int lookup_userprop(nvlist_t * from, const char * name, char *& out) {
|
||||
int lookup_userprop(zfs_handle_t * in, const char * name, char *& out) {
|
||||
// xyz.nabijaczleweli:tzpfms.key:
|
||||
// value: '76B0286BEB3FAF57536C47D9A2BAD38157FD522A75A59E72867BBFD6AF167395'
|
||||
// source: 'owo/enc'
|
||||
|
||||
nvlist_t * vs{};
|
||||
TRY_LOOKUP("look up user property", nvlist_lookup_nvlist(from, name, &vs));
|
||||
TRY_LOOKUP("look up user property", nvlist_lookup_nvlist(zfs_get_user_props(in), name, &vs));
|
||||
|
||||
char * source{};
|
||||
TRY_LOOKUP("look up user property source", nvlist_lookup_string(vs, "source", &source));
|
||||
if(!source || strcmp(source, zfs_get_name(in)))
|
||||
return 0;
|
||||
|
||||
TRY_LOOKUP("look up user property value", nvlist_lookup_string(vs, "value", &out));
|
||||
return 0;
|
||||
}
|
||||
@ -98,3 +107,31 @@ int clear_key_props(zfs_handle_t * from) {
|
||||
TRY("delete tzpfms.key", zfs_prop_inherit(from, PROPNAME_KEY, B_FALSE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int parse_key_props(zfs_handle_t * in, const char * our_backend, uint32_t & handle) {
|
||||
char *backend{}, *handle_s{};
|
||||
TRY_MAIN(lookup_userprop(in, PROPNAME_BACKEND, backend));
|
||||
|
||||
if(!backend) {
|
||||
fprintf(stderr, "Dataset %s not encrypted with tzpfms!\n", zfs_get_name(in));
|
||||
return __LINE__;
|
||||
}
|
||||
if(strcmp(backend, our_backend)) {
|
||||
fprintf(stderr, "Dataset %s encrypted with tzpfms back-end %s, but we are %s.\n", zfs_get_name(in), backend, our_backend);
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
TRY_MAIN(lookup_userprop(in, PROPNAME_KEY, handle_s));
|
||||
if(!handle_s) {
|
||||
fprintf(stderr, "Dataset %s missing key data.\n", zfs_get_name(in));
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
if(parse_int(handle_s, handle)) {
|
||||
fprintf(stderr, "Dataset %s's handle %s not valid.\n", zfs_get_name(in), handle_s);
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,9 +6,6 @@
|
||||
|
||||
#include <libzfs.h>
|
||||
#include <sys/nvpair.h>
|
||||
// #include <sys/fs/zfs.h>
|
||||
//// #include <sys/zio_crypt.h>
|
||||
// #define WRAPPING_KEY_LEN 32
|
||||
|
||||
|
||||
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, _try_ret, strerror, __VA_ARGS__)
|
||||
@ -36,10 +33,13 @@ extern nvlist_t * clear_rewrap_args();
|
||||
/// Extract user property name from ZFS property list from to out.
|
||||
///
|
||||
/// Returns success but does not touch out on not found.
|
||||
extern int lookup_userprop(nvlist_t * from, const char * name, char *& out);
|
||||
extern int lookup_userprop(zfs_handle_t * from, const char * name, char *& out);
|
||||
|
||||
/// Set required decoding props on the dataset
|
||||
extern int set_key_props(zfs_handle_t * on, const char * backend, uint32_t handle);
|
||||
|
||||
/// Remove decoding props from the dataset
|
||||
extern int clear_key_props(zfs_handle_t * from);
|
||||
|
||||
/// Read in decoding props from the dataset
|
||||
extern int parse_key_props(zfs_handle_t * in, const char * our_backend, uint32_t & handle);
|
||||
|
Loading…
x
Reference in New Issue
Block a user