From 9c8ee8d68c8ae6d2ac6a8a40ec5bf1b83e03cac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Mon, 15 Nov 2021 18:36:52 +0100 Subject: [PATCH] Add $TZPFMS_PASSPHRASE_HELPER. Always include the TPM back-end and/or dataset name in password what-fors --- README.md | 1 + initrd/dracut/module-setup.sh | 1 - initrd/mount.h | 22 +++--- man/common.h | 2 + man/passphrase.h | 26 ++++++++ man/zfs-tpm1x-change-key.8.pp | 2 + man/zfs-tpm1x-load-key.8.pp | 2 + man/zfs-tpm2-change-key.8.pp | 2 + man/zfs-tpm2-clear-key.8.pp | 2 + man/zfs-tpm2-load-key.8.pp | 2 + src/bin/zfs-tpm1x-change-key.cpp | 5 +- src/bin/zfs-tpm1x-load-key.cpp | 6 +- src/bin/zfs-tpm2-change-key.cpp | 3 +- src/bin/zfs-tpm2-load-key.cpp | 2 +- src/fd.cpp | 111 +++++++++++++++++++++++++++---- src/fd.hpp | 2 +- src/tpm2.cpp | 25 ++++--- src/tpm2.hpp | 6 +- src/zfs.hpp | 9 ++- 19 files changed, 182 insertions(+), 49 deletions(-) create mode 100644 man/passphrase.h diff --git a/README.md b/README.md index 3308443..5a48944 100644 --- a/README.md +++ b/README.md @@ -122,3 +122,4 @@ To all who support further development on Patreon, in particular: * ThePhD * Embark Studios + * Jasper Bekkers diff --git a/initrd/dracut/module-setup.sh b/initrd/dracut/module-setup.sh index cebfff9..ec2758d 100755 --- a/initrd/dracut/module-setup.sh +++ b/initrd/dracut/module-setup.sh @@ -34,7 +34,6 @@ _install_tpm1x() { check() { command -v zfs-tpm-list > /dev/null || return 1 - # shellcheck disable=SC2154 if [ -n "$hostonly" ]; then _get_backend || return diff --git a/initrd/mount.h b/initrd/mount.h index 343f478..2bf4ff5 100644 --- a/initrd/mount.h +++ b/initrd/mount.h @@ -4,28 +4,26 @@ #define WITH_PROMPTABLE_TTY(REDIREXIONS) # This sucks a lot of ass, since we don't know the questions or the amount thereof beforehand # (0-2 (owner hierarchy/ownership + sealed object, both optional) best-case and 0-6 worst-case (both entered wrong twice)). - # Plymouth doesn't allow us to actually check what the splash status was, and ioctl(KDGETMODE) isn't reliable; - # ideally, we'd only clear the screen if we were making the switch, but not if the user was already switched to the log output. - # Instead, clear if there's a "quiet", leave alone otherwise, and always restore; - # cmdline option "plymouth.ignore-show-splash" can be used to disable splashes altogether, if desired. with_promptable_tty() { if plymouth --ping 2>/dev/null; then - plymouth hide-splash - # shellcheck disable=SC2217 - [ "${quiet:-n}" = "y" ] && printf '\033c' REDIREXIONS - - "$@" REDIREXIONS; ret="$?" - - plymouth show-splash + # shellcheck disable=SC2016 + TZPFMS_PASSPHRASE_HELPER='exec plymouth ask-for-password --prompt="$1: "' "$@" 2>/run/tzpfms-err; ret="$?" + [ -s /run/tzpfms-err ] && plymouth display-message --text="$(cat /run/tzpfms-err)" + elif [ -e /run/systemd/system ] && command -v systemd-ask-password > /dev/null; then # --no-tty matches zfs and actually works + # shellcheck disable=SC2016 + TZPFMS_PASSPHRASE_HELPER='exec systemd-ask-password --no-tty --id="tzpfms:$2" "$1: "' "$@" 2>/run/tzpfms-err; ret="$?" else # Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet" read -r printk _ < /proc/sys/kernel/printk [ "$printk" = "7" ] || echo 7 > /proc/sys/kernel/printk - "$@" REDIREXIONS; ret="$?" + TZPFMS_PASSPHRASE_HELPER="${TZPFMS_PASSPHRASE_HELPER:-}" "$@" REDIREXIONS; ret="$?" # allow overriding in cmdline, but always set to raze default [ "$printk" = "7" ] || echo "$printk" > /proc/sys/kernel/printk fi + [ -s /run/tzpfms-err ] && cat /run/tzpfms-err >&2 + [ -s /run/tzpfms-err ] && [ "$ret" -ne 0 ] && sed 's;^;'"$1"': ;' /run/tzpfms-err >> /dev/kmsg + rm -f /run/tzpfms-err return "$ret" } #endefine diff --git a/man/common.h b/man/common.h index 8b79a2e..cd716af 100644 --- a/man/common.h +++ b/man/common.h @@ -7,6 +7,8 @@ To all who support further development, in particular: ThePhD .It Embark Studios +.It +Jasper Bekkers .El . .Sh REPORTING BUGS diff --git a/man/passphrase.h b/man/passphrase.h new file mode 100644 index 0000000..399e40e --- /dev/null +++ b/man/passphrase.h @@ -0,0 +1,26 @@ +.\" SPDX-License-Identifier: MIT +. +.Sh ENVIRONMENT VARIABLES +.Bl -tag -compact -width "TZPFMS" +.It Ev TZPFMS_PASSPHRASE_HELPER +If set and nonempty, will be run as +.Dl Pa /bin/ Ns Nm sh Fl c Li \&"$TZPFMS_PASSPHRASE_HELPER" \&"$TZPFMS_PASSPHRASE_HELPER" Qo Ar prepared prompt Qc Qo Ar target Qc Qo Oo Li new Oc Qc Qo Oo Li again Oc Qc +to provide a passphrase, instead of reading from the standard input. +.Pp +The standard output stream of the helper is tied to an anonymous file and used in its entirety as the passphrase, except for a trailing new-line, if any. +The second argument contains either the dataset name or the element of the TPM hierarchy. +The third argument is +.Li new +if this is for a new passphrase, and the fourth is +.Li again +if it's the second prompt for that passphrase. +The first argument already contains all of this information, as a pre-formatted noun phrase. +.Pp +If the helper doesn't exist +.Pq the shell exits with Sy 127 , +a diagnostic is issued and the normal prompt is used as fall-back. +If it fails for any other reason, the prompting is aborted. +.Pp +An example value would be: +.No ' Ns Nm systemd-ask-password Fl -id Ns Li = Ns Qo Li tzpfms:\& Ns Ar $2 Qc Qo Ar $1 Ns Li ": " Qc Ns ' . +.El diff --git a/man/zfs-tpm1x-change-key.8.pp b/man/zfs-tpm1x-change-key.8.pp index 63f3c2b..15292c4 100644 --- a/man/zfs-tpm1x-change-key.8.pp +++ b/man/zfs-tpm1x-change-key.8.pp @@ -101,6 +101,8 @@ In case of a catastrophic event, the key can be loaded by running .Dl Nm zfs Cm load-key Ar dataset Li < Ar backup-file .El . +#include "passphrase.h" +. #include "backend-tpm1x.h" . #include "common.h" diff --git a/man/zfs-tpm1x-load-key.8.pp b/man/zfs-tpm1x-load-key.8.pp index 1278c76..03a2c55 100644 --- a/man/zfs-tpm1x-load-key.8.pp +++ b/man/zfs-tpm1x-load-key.8.pp @@ -39,6 +39,8 @@ Equivalent to option. .El . +#include "passphrase.h" +. #include "backend-tpm1x.h" . #include "common.h" diff --git a/man/zfs-tpm2-change-key.8.pp b/man/zfs-tpm2-change-key.8.pp index e740dd4..de329de 100644 --- a/man/zfs-tpm2-change-key.8.pp +++ b/man/zfs-tpm2-change-key.8.pp @@ -98,6 +98,8 @@ In case of a catastrophic event, the key can be loaded by running .Dl Nm zfs Cm load-key Ar dataset Li < Ar backup-file .El . +#include "passphrase.h" +. #include "backend-tpm2.h" . #include "common.h" diff --git a/man/zfs-tpm2-clear-key.8.pp b/man/zfs-tpm2-clear-key.8.pp index 85674e4..7fba368 100644 --- a/man/zfs-tpm2-clear-key.8.pp +++ b/man/zfs-tpm2-clear-key.8.pp @@ -36,6 +36,8 @@ See .Xr zfs-tpm2-change-key 8 for a detailed description. . +#include "passphrase.h" +. #include "backend-tpm2.h" . #include "common.h" diff --git a/man/zfs-tpm2-load-key.8.pp b/man/zfs-tpm2-load-key.8.pp index 2a2a59b..204ddf3 100644 --- a/man/zfs-tpm2-load-key.8.pp +++ b/man/zfs-tpm2-load-key.8.pp @@ -38,6 +38,8 @@ Equivalent to option. .El . +#include "passphrase.h" +. #include "backend-tpm1x.h" . #include "common.h" diff --git a/src/bin/zfs-tpm1x-change-key.cpp b/src/bin/zfs-tpm1x-change-key.cpp index 42e252f..f5391ff 100644 --- a/src/bin/zfs-tpm1x-change-key.cpp +++ b/src/bin/zfs-tpm1x-change-key.cpp @@ -60,9 +60,12 @@ int main(int argc, char ** argv) { }}; { + char what_for[ZFS_MAX_DATASET_NAME_LEN + 40 + 1]; + snprintf(what_for, sizeof(what_for), "%s TPM1.X wrapping key (or empty for none)", zfs_get_name(dataset)); + uint8_t * parent_key_passphrase{}; size_t parent_key_passphrase_len{}; - TRY_MAIN(read_new_passphrase("wrapping key (or empty for none)", parent_key_passphrase, parent_key_passphrase_len)); + TRY_MAIN(read_new_passphrase(what_for, parent_key_passphrase, parent_key_passphrase_len)); quickscope_wrapper parent_key_passphrase_deleter{[&] { free(parent_key_passphrase); }}; if(parent_key_passphrase_len) diff --git a/src/bin/zfs-tpm1x-load-key.cpp b/src/bin/zfs-tpm1x-load-key.cpp index 9647263..0b828c7 100644 --- a/src/bin/zfs-tpm1x-load-key.cpp +++ b/src/bin/zfs-tpm1x-load-key.cpp @@ -36,7 +36,7 @@ int main(int argc, char ** argv) { uint8_t wrap_key[WRAPPING_KEY_LEN]{}; TRY_MAIN(with_tpm1x_session([&](auto ctx, auto srk, auto srk_policy) { TSS_HOBJECT parent_key{}; - TRY_MAIN(try_policy_or_passphrase("load sealant key from blob (did you take ownership?)", "SRK", srk_policy, [&] { + TRY_MAIN(try_policy_or_passphrase("load sealant key from blob (did you take ownership?)", "TPM1.X SRK", srk_policy, [&] { return Tspi_Context_LoadKeyByBlob(ctx, srk, handle.parent_key_blob_len, handle.parent_key_blob, &parent_key); })); quickscope_wrapper parent_key_deleter{[&] { Tspi_Key_UnloadKey(parent_key); }}; @@ -59,10 +59,12 @@ int main(int argc, char ** argv) { TRY_TPM1X("load sealed object from blob", Tspi_SetAttribData(sealed_object, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, handle.sealed_object_blob_len, handle.sealed_object_blob)); + char what_for[ZFS_MAX_DATASET_NAME_LEN + 20 + 1]; + snprintf(what_for, sizeof(what_for), "%s TPM1.X wrapping key", zfs_get_name(dataset)); uint8_t * loaded_wrap_key{}; uint32_t loaded_wrap_key_len{}; - TRY_MAIN(try_policy_or_passphrase("unseal wrapping key", "wrapping key", parent_key_policy, + TRY_MAIN(try_policy_or_passphrase("unseal wrapping key", what_for, parent_key_policy, [&] { return Tspi_Data_Unseal(sealed_object, parent_key, &loaded_wrap_key_len, &loaded_wrap_key); })); if(loaded_wrap_key_len != sizeof(wrap_key)) { fprintf(stderr, "Wrong sealed data length (%" PRIu32 " != %zu): ", loaded_wrap_key_len, sizeof(wrap_key)); diff --git a/src/bin/zfs-tpm2-change-key.cpp b/src/bin/zfs-tpm2-change-key.cpp index 68f9fbd..b9f41ec 100644 --- a/src/bin/zfs-tpm2-change-key.cpp +++ b/src/bin/zfs-tpm2-change-key.cpp @@ -59,7 +59,8 @@ int main(int argc, char ** argv) { if(backup) TRY_MAIN(write_exact(backup, wrap_key, sizeof(wrap_key), 0400)); - TRY_MAIN(tpm2_seal(tpm2_ctx, tpm2_session, persistent_handle, tpm2_creation_metadata(zfs_get_name(dataset)), wrap_key, sizeof(wrap_key))); + TRY_MAIN(tpm2_seal(zfs_get_name(dataset), tpm2_ctx, tpm2_session, persistent_handle, tpm2_creation_metadata(zfs_get_name(dataset)), wrap_key, + sizeof(wrap_key))); bool ok = false; // Try to free the persistent handle if we're unsuccessful in actually using it later on quickscope_wrapper persistent_clearer{[&] { if(!ok && tpm2_free_persistent(tpm2_ctx, tpm2_session, persistent_handle)) diff --git a/src/bin/zfs-tpm2-load-key.cpp b/src/bin/zfs-tpm2-load-key.cpp index 8bef016..a5a664c 100644 --- a/src/bin/zfs-tpm2-load-key.cpp +++ b/src/bin/zfs-tpm2-load-key.cpp @@ -30,7 +30,7 @@ int main(int argc, char ** argv) { uint8_t wrap_key[WRAPPING_KEY_LEN]; TRY_MAIN(with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) { - TRY_MAIN(tpm2_unseal(tpm2_ctx, tpm2_session, handle, wrap_key, sizeof(wrap_key))); + TRY_MAIN(tpm2_unseal(zfs_get_name(dataset), tpm2_ctx, tpm2_session, handle, wrap_key, sizeof(wrap_key))); return 0; })); diff --git a/src/fd.cpp b/src/fd.cpp index ffbbe36..114cbc5 100644 --- a/src/fd.cpp +++ b/src/fd.cpp @@ -6,8 +6,10 @@ #include "main.hpp" #include +#include #include #include +#include #include #include @@ -18,7 +20,7 @@ int filled_fd(int & fd, const void * with, size_t with_len) { int pipes[2]; - TRY("create buffer pipe", pipe(pipes)); + TRY("create buffer pipe", pipe2(pipes, O_CLOEXEC)); quickscope_wrapper pipes_w_deleter{[=] { close(pipes[1]); }}; fd = pipes[0]; @@ -34,7 +36,7 @@ int filled_fd(int & fd, const void * with, size_t with_len) { int read_exact(const char * path, void * data, size_t len) { - auto infd = TRY("open input file", open(path, O_RDONLY)); + auto infd = TRY("open input file", open(path, O_RDONLY | O_CLOEXEC)); quickscope_wrapper infd_deleter{[=] { close(infd); }}; while(len) @@ -49,8 +51,8 @@ int read_exact(const char * path, void * data, size_t len) { int write_exact(const char * path, const void * data, size_t len, mode_t mode) { - auto outfd = TRY("create output file", open(path, O_WRONLY | O_CREAT | O_EXCL, mode)); - quickscope_wrapper infd_deleter{[=] { close(outfd); }}; + auto outfd = TRY("create output file", open(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode)); + quickscope_wrapper outfd_deleter{[=] { close(outfd); }}; while(len) { const auto rd = TRY("write to output file", write(outfd, data, len)); @@ -62,6 +64,76 @@ int write_exact(const char * path, const void * data, size_t len, mode_t mode) { } +#define TRY_HELPER(what, ...) TRY_GENERIC(what, , == -1, errno, -1, strerror, __VA_ARGS__) + +/// TRY_MAIN rules, plus -1 for ENOENT +static int get_key_material_helper(const char * helper, const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) { +#if __linux__ || __FreeBSD__ + auto outfd = TRY_HELPER("create helper output", memfd_create(whom, MFD_CLOEXEC)); +#else + int outfd; + char fname[8 + 10 + 1 + 20 + 1]; // 4294967296, 18446744073709551616 + auto pid = getpid(); + for(uint64_t i = 0; i < UINT64_MAX; ++i) { + snprintf(fname, sizeof(fname), "/tzpfms:%" PRIu32 ":%" PRIu64 "", static_cast(pid), i); + if((outfd = shm_open(fname, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0000)) != -1 || errno != EEXIST) + break; + } + TRY_HELPER("create helper output", outfd); + shm_unlink(fname); +#endif + quickscope_wrapper outfd_deleter{[=] { close(outfd); }}; + + switch(auto pid = TRY_HELPER("create child", fork())) { + case 0: // child + dup2(outfd, 1); + + char * msg; + if(asprintf(&msg, "%sassphrase for %s%s", newkey ? "New p" : "P", whom, again ? " (again)" : "") == -1) + msg = const_cast(whom); + execl("/bin/sh", "sh", "-c", helper, helper, msg, whom, newkey ? "new" : "", again ? "again" : "", nullptr); + fprintf(stderr, "exec(/bin/sh): %s\n", strerror(errno)); + _exit(127); + break; + + default: // parent + int err, ret; + while((ret = waitpid(pid, &err, 0)) == -1 && errno == EINTR) + ; + TRY("wait for helper", ret); + + if(WIFEXITED(err)) { + switch(WEXITSTATUS(err)) { + case 0: + struct stat sb; + fstat(outfd, &sb); + if(auto out = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, outfd, 0); out != MAP_FAILED) { + quickscope_wrapper out_deleter{[=] { munmap(out, sb.st_size); }}; + buf = static_cast(malloc(sb.st_size)); // TODO:if failed + len_out = sb.st_size; + memcpy(buf, out, sb.st_size); + // Trim ending newline, if any + if(buf[len_out - 1] == '\n') + buf[--len_out] = '\0'; + return 0; + } else + ; // error + + case 127: // enoent, error already written by shell or child + return -1; + + default: + fprintf(stderr, "Helper '%s' failed with %d.\n", helper, WEXITSTATUS(err)); + return __LINE__; + } + } else { + fprintf(stderr, "Helper '%s' died to signal %d: %s.\n", helper, WTERMSIG(err), strsignal(WTERMSIG(err))); + return __LINE__; + } + } +} + + /// Adapted from src:zfs's lib/libzfs/libzfs_crypto.c#get_key_material_raw() static int get_key_material_raw(const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) { static int caught_interrupt; @@ -79,7 +151,10 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint sigemptyset(&act.sa_mask); caught_interrupt = 0; - act.sa_handler = [](auto sig) { caught_interrupt = sig; }; + act.sa_handler = [](auto sig) { + caught_interrupt = sig; + fputs("^C\n", stderr); + }; sigaction(SIGINT, &act, &osigint); act.sa_handler = SIG_IGN; @@ -105,7 +180,7 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint // If we caught a signal, re-throw it now if(caught_interrupt != 0) - kill(getpid(), caught_interrupt); + raise(caught_interrupt); // Print the newline that was not echoed putchar('\n'); @@ -128,10 +203,8 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint break; default: // Trim ending newline, if any - if(buf[bytes - 1] == '\n') { - buf[bytes - 1] = '\0'; - --bytes; - } + if(buf[bytes - 1] == '\n') + buf[--bytes] = '\0'; break; } @@ -139,8 +212,20 @@ static int get_key_material_raw(const char * whom, bool again, bool newkey, uint return 0; } +static int get_key_material_dispatch(const char * whom, bool again, bool newkey, uint8_t *& buf, size_t & len_out) { + static const char * helper = getenv("TZPFMS_PASSPHRASE_HELPER"); + if(helper && *helper) { + if(auto err = get_key_material_helper(helper, whom, again, newkey, buf, len_out); err != -1) + return err; + else + helper = nullptr; + } + return get_key_material_raw(whom, again, newkey, buf, len_out); +} + + int read_known_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, size_t max_len) { - TRY_MAIN(get_key_material_raw(whom, false, false, buf, len_out)); + TRY_MAIN(get_key_material_dispatch(whom, false, false, buf, len_out)); if(len_out <= max_len) return 0; @@ -154,7 +239,7 @@ int read_known_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, s int read_new_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, size_t max_len) { uint8_t * first_passphrase{}; size_t first_passphrase_len{}; - TRY_MAIN(get_key_material_raw(whom, false, true, first_passphrase, first_passphrase_len)); + TRY_MAIN(get_key_material_dispatch(whom, false, true, first_passphrase, first_passphrase_len)); quickscope_wrapper first_passphrase_deleter{[&] { free(first_passphrase); }}; if(first_passphrase_len != 0 && first_passphrase_len < MIN_PASSPHRASE_LEN) @@ -164,7 +249,7 @@ int read_new_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, siz uint8_t * second_passphrase{}; size_t second_passphrase_len{}; - TRY_MAIN(get_key_material_raw(whom, true, true, second_passphrase, second_passphrase_len)); + TRY_MAIN(get_key_material_dispatch(whom, true, true, second_passphrase, second_passphrase_len)); quickscope_wrapper second_passphrase_deleter{[&] { free(second_passphrase); }}; if(second_passphrase_len != first_passphrase_len || memcmp(first_passphrase, second_passphrase, first_passphrase_len)) diff --git a/src/fd.hpp b/src/fd.hpp index 9f03a88..d803b14 100644 --- a/src/fd.hpp +++ b/src/fd.hpp @@ -37,5 +37,5 @@ extern int write_exact(const char * path, const void * data, size_t len, mode_t /// Prompt for passphrase for whom the user knows, up to max_len bytes extern int read_known_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, size_t max_len = SIZE_MAX); -/// Prompt twive for passphrase for whom the user is setting +/// Prompt twice for passphrase for whom the user is setting extern int read_new_passphrase(const char * whom, uint8_t *& buf, size_t & len_out, size_t max_len = SIZE_MAX); diff --git a/src/tpm2.cpp b/src/tpm2.cpp index c5ec618..4872fef 100644 --- a/src/tpm2.cpp +++ b/src/tpm2.cpp @@ -45,8 +45,8 @@ TPM2B_DATA tpm2_creation_metadata(const char * dataset_name) { const auto now = time(nullptr); const auto now_tm = localtime(&now); metadata.size = snprintf((char *)metadata.buffer, sizeof(metadata.buffer), "%s %d-%02d-%02dT%02d:%02d:%02d %s", dataset_name, // - now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, // - TZPFMS_VERSION) + + now_tm->tm_year + 1900, now_tm->tm_mon + 1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, // + TZPFMS_VERSION) + 1; metadata.size = metadata.size > sizeof(metadata.buffer) ? sizeof(metadata.buffer) : metadata.size; @@ -102,8 +102,8 @@ static int tpm2_find_unused_persistent_non_platform(ESYS_CONTEXT * tpm2_ctx, TPM return 0; } -int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT & persistent_handle, const TPM2B_DATA & metadata, void * data, - size_t data_len) { +int tpm2_seal(const char * dataset, ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT & persistent_handle, const TPM2B_DATA & metadata, + void * data, size_t data_len) { ESYS_TR primary_handle = ESYS_TR_NONE; quickscope_wrapper primary_handle_deleter{[&] { Esys_FlushContext(tpm2_ctx, primary_handle); }}; @@ -129,7 +129,7 @@ int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT TPM2B_CREATION_DATA * creation_data{}; TPM2B_DIGEST * creation_hash{}; TPMT_TK_CREATION * creation_ticket{}; - TRY_MAIN(try_or_passphrase("create primary encryption key", "owner hierarchy", tpm2_ctx, TPM2_RC_BAD_AUTH, ESYS_TR_RH_OWNER, [&] { + TRY_MAIN(try_or_passphrase("create primary encryption key", "TPM2 owner hierarchy", tpm2_ctx, TPM2_RC_BAD_AUTH, ESYS_TR_RH_OWNER, [&] { return Esys_CreatePrimary(tpm2_ctx, ESYS_TR_RH_OWNER, tpm2_session, ESYS_TR_NONE, ESYS_TR_NONE, &primary_sens, &pub, &metadata, &pcrs, &primary_handle, &public_ret, &creation_data, &creation_hash, &creation_ticket); })); @@ -166,9 +166,13 @@ int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT memcpy(secret_sens.sensitive.data.buffer, data, secret_sens.sensitive.data.size); { + char what_for[ZFS_MAX_DATASET_NAME_LEN + 38 + 1]; + snprintf(what_for, sizeof(what_for), "%s TPM2 wrapping key (or empty for none)", dataset); + uint8_t * passphrase{}; size_t passphrase_len{}; - TRY_MAIN(read_new_passphrase("wrapping key (or empty for none)", passphrase, passphrase_len, sizeof(TPM2B_SENSITIVE_CREATE::sensitive.userAuth.buffer))); + TRY_MAIN(read_new_passphrase("%s TPM2 wrapping key (or empty for none)", passphrase, passphrase_len, + sizeof(TPM2B_SENSITIVE_CREATE::sensitive.userAuth.buffer))); quickscope_wrapper passphrase_deleter{[&] { free(passphrase); }}; secret_sens.sensitive.userAuth.size = passphrase_len; @@ -214,14 +218,17 @@ int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT return 0; } -int tpm2_unseal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle, void * data, size_t data_len) { +int tpm2_unseal(const char * dataset, ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle, void * data, size_t data_len) { + char what_for[ZFS_MAX_DATASET_NAME_LEN + 18 + 1]; + snprintf(what_for, sizeof(what_for), "%s TPM2 wrapping key", dataset); + // Entirely fake and not flushable (tpm:parameter(1):value is out of range or is not correct for the context) ESYS_TR pandle; TRY_TPM2("convert persistent handle to object", Esys_TR_FromTPMPublic(tpm2_ctx, persistent_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &pandle)); TPM2B_SENSITIVE_DATA * unsealed{}; quickscope_wrapper unsealed_deleter{[=] { Esys_Free(unsealed); }}; - TRY_MAIN(try_or_passphrase("unseal wrapping key", "wrapping key", tpm2_ctx, TPM2_RC_AUTH_FAIL, pandle, + TRY_MAIN(try_or_passphrase("unseal wrapping key", what_for, tpm2_ctx, TPM2_RC_AUTH_FAIL, pandle, [&] { return Esys_Unseal(tpm2_ctx, pandle, tpm2_session, ESYS_TR_NONE, ESYS_TR_NONE, &unsealed); })); if(unsealed->size != data_len) @@ -236,7 +243,7 @@ int tpm2_free_persistent(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_ TRY_TPM2("convert persistent handle to object", Esys_TR_FromTPMPublic(tpm2_ctx, persistent_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &pandle)); ESYS_TR new_handle; - TRY_MAIN(try_or_passphrase("unpersist object", "owner hierarchy", tpm2_ctx, TPM2_RC_BAD_AUTH, ESYS_TR_RH_OWNER, + TRY_MAIN(try_or_passphrase("unpersist object", "TPM2 owner hierarchy", tpm2_ctx, TPM2_RC_BAD_AUTH, ESYS_TR_RH_OWNER, [&] { return Esys_EvictControl(tpm2_ctx, ESYS_TR_RH_OWNER, pandle, tpm2_session, ESYS_TR_NONE, ESYS_TR_NONE, 0, &new_handle); })); return 0; diff --git a/src/tpm2.hpp b/src/tpm2.hpp index 96a6f20..07377bb 100644 --- a/src/tpm2.hpp +++ b/src/tpm2.hpp @@ -48,7 +48,7 @@ extern TPM2B_DATA tpm2_creation_metadata(const char * dataset_name); extern int tpm2_parse_handle(const char * dataset_name, const char * handle_s, TPMI_DH_PERSISTENT & handle); extern int tpm2_generate_rand(ESYS_CONTEXT * tpm2_ctx, void * into, size_t length); -extern int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT & persistent_handle, const TPM2B_DATA & metadata, void * data, - size_t data_len); -extern int tpm2_unseal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle, void * data, size_t data_len); +extern int tpm2_seal(const char * dataset, ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT & persistent_handle, const TPM2B_DATA & metadata, + void * data, size_t data_len); +extern int tpm2_unseal(const char * dataset, ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle, void * data, size_t data_len); extern int tpm2_free_persistent(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle); diff --git a/src/zfs.hpp b/src/zfs.hpp index d935f5f..5c37731 100644 --- a/src/zfs.hpp +++ b/src/zfs.hpp @@ -20,11 +20,10 @@ /// Mimic libzfs error output -#define REQUIRE_KEY_LOADED(dataset) \ - do { \ - if(zfs_prop_get_int(dataset, ZFS_PROP_KEYSTATUS) == ZFS_KEYSTATUS_UNAVAILABLE) { \ - return fprintf(stderr, "Key change error: Key must be loaded.\n"), __LINE__; \ - } \ +#define REQUIRE_KEY_LOADED(dataset) \ + do { \ + if(zfs_prop_get_int(dataset, ZFS_PROP_KEYSTATUS) == ZFS_KEYSTATUS_UNAVAILABLE) \ + return fprintf(stderr, "Key change error: Key must be loaded.\n"), __LINE__; \ } while(0)