mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-13 09:37:13 +03:00
Add $TZPFMS_PASSPHRASE_HELPER. Always include the TPM back-end and/or dataset name in password what-fors
This commit is contained in:
parent
74ec450e16
commit
9c8ee8d68c
@ -122,3 +122,4 @@ To all who support further development on Patreon, in particular:
|
||||
|
||||
* ThePhD
|
||||
* Embark Studios
|
||||
* Jasper Bekkers
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -7,6 +7,8 @@ To all who support further development, in particular:
|
||||
ThePhD
|
||||
.It
|
||||
Embark Studios
|
||||
.It
|
||||
Jasper Bekkers
|
||||
.El
|
||||
.
|
||||
.Sh REPORTING BUGS
|
||||
|
26
man/passphrase.h
Normal file
26
man/passphrase.h
Normal file
@ -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
|
@ -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"
|
||||
|
@ -39,6 +39,8 @@ Equivalent to
|
||||
option.
|
||||
.El
|
||||
.
|
||||
#include "passphrase.h"
|
||||
.
|
||||
#include "backend-tpm1x.h"
|
||||
.
|
||||
#include "common.h"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -38,6 +38,8 @@ Equivalent to
|
||||
option.
|
||||
.El
|
||||
.
|
||||
#include "passphrase.h"
|
||||
.
|
||||
#include "backend-tpm1x.h"
|
||||
.
|
||||
#include "common.h"
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}));
|
||||
|
||||
|
111
src/fd.cpp
111
src/fd.cpp
@ -6,8 +6,10 @@
|
||||
#include "main.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -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<uint32_t>(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<char *>(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<uint8_t *>(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))
|
||||
|
@ -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);
|
||||
|
25
src/tpm2.cpp
25
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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user