mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-21 09:47:35 +03:00
Prompt for passphrase (or empty for none) in TPM1.X
This commit is contained in:
parent
cc4716c569
commit
675a0c40b7
@ -58,13 +58,23 @@ int main(int argc, char ** argv) {
|
||||
Tspi_Policy_FlushSecret(parent_key_policy);
|
||||
Tspi_Context_CloseObject(ctx, parent_key_policy);
|
||||
}};
|
||||
// TODO: this is where we'd prompt for a password if we supported it yet
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(\"adenozynotrójfosforan\") = %s\n",
|
||||
Trspi_Error_String(
|
||||
Tspi_Policy_SetSecret(parent_key_policy, TSS_SECRET_MODE_PLAIN, strlen("adenozynotrójfosforan"), (BYTE *)"adenozynotrójfosforan")));
|
||||
|
||||
{
|
||||
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));
|
||||
quickscope_wrapper parent_key_passphrase_deleter{[&] { free(parent_key_passphrase); }};
|
||||
|
||||
TRY_MAIN(try_srk("create sealant key (did you take ownership?)", srk_policy, [&] { return Tspi_Key_CreateKey(parent_key, srk, 0); }));
|
||||
if(parent_key_passphrase_len)
|
||||
TRY_TPM1X("assign passphrase to parent_key key",
|
||||
Tspi_Policy_SetSecret(parent_key_policy, TSS_SECRET_MODE_PLAIN, parent_key_passphrase_len, parent_key_passphrase));
|
||||
else
|
||||
TRY_TPM1X("assign default sealant key secret",
|
||||
Tspi_Policy_SetSecret(parent_key_policy, TSS_SECRET_MODE_SHA1, sizeof(parent_key_secret), (BYTE *)parent_key_secret));
|
||||
}
|
||||
|
||||
TRY_MAIN(try_policy_or_passphrase("create sealant key (did you take ownership?)", "SRK", srk_policy,
|
||||
[&] { return Tspi_Key_CreateKey(parent_key, srk, 0); }));
|
||||
|
||||
TRY_TPM1X("load sealant key", Tspi_Key_LoadKey(parent_key, srk));
|
||||
|
||||
|
@ -35,8 +35,9 @@ 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_srk("load sealant key from blob (did you take ownership?)", srk_policy,
|
||||
[&] { return Tspi_Context_LoadKeyByBlob(ctx, srk, handle.parent_key_blob_len, handle.parent_key_blob, &parent_key); }));
|
||||
TRY_MAIN(try_policy_or_passphrase("load sealant key from blob (did you take ownership?)", "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); }};
|
||||
|
||||
TSS_HPOLICY parent_key_policy{};
|
||||
@ -46,9 +47,8 @@ int main(int argc, char ** argv) {
|
||||
Tspi_Policy_FlushSecret(parent_key_policy);
|
||||
Tspi_Context_CloseObject(ctx, parent_key_policy);
|
||||
}};
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(\"adenozynotrójfosforan\") = %s\n",
|
||||
Trspi_Error_String(
|
||||
Tspi_Policy_SetSecret(parent_key_policy, TSS_SECRET_MODE_PLAIN, strlen("adenozynotrójfosforan"), (BYTE *)"adenozynotrójfosforan")));
|
||||
TRY_TPM1X("assign default sealant key secret",
|
||||
Tspi_Policy_SetSecret(parent_key_policy, TSS_SECRET_MODE_SHA1, sizeof(parent_key_secret), (BYTE *)parent_key_secret));
|
||||
|
||||
|
||||
TSS_HOBJECT sealed_object{};
|
||||
@ -61,7 +61,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
uint8_t * loaded_wrap_key{};
|
||||
uint32_t loaded_wrap_key_len{};
|
||||
TRY_TPM1X("unseal wrapping key", Tspi_Data_Unseal(sealed_object, parent_key, &loaded_wrap_key_len, &loaded_wrap_key));
|
||||
TRY_MAIN(try_policy_or_passphrase("unseal wrapping key", "wrapping key", 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 (%u != %zu):", loaded_wrap_key_len, sizeof(wrap_key));
|
||||
for(auto i = 0u; i < loaded_wrap_key_len; ++i)
|
||||
|
111
src/fd.cpp
111
src/fd.cpp
@ -3,9 +3,12 @@
|
||||
|
||||
#include "fd.hpp"
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
@ -55,3 +58,111 @@ int write_exact(const char * path, const void * data, size_t len, mode_t mode) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// 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;
|
||||
|
||||
struct termios old_term;
|
||||
struct sigaction osigint, osigtstp;
|
||||
|
||||
len_out = 0;
|
||||
|
||||
auto from_tty = isatty(0);
|
||||
if(from_tty) {
|
||||
// Handle SIGINT and ignore SIGSTP.
|
||||
// This is necessary to restore the state of the terminal.
|
||||
struct sigaction act {};
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
caught_interrupt = 0;
|
||||
act.sa_handler = [](auto sig) { caught_interrupt = sig; };
|
||||
sigaction(SIGINT, &act, &osigint);
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGTSTP, &act, &osigtstp);
|
||||
|
||||
// Prompt for the key
|
||||
printf("%s %spassphrase for %s: ", again ? "Re-enter" : "Enter", newkey ? "new " : "", whom);
|
||||
fflush(stdout);
|
||||
|
||||
// Disable the terminal echo for key input
|
||||
tcgetattr(0, &old_term);
|
||||
|
||||
auto new_term = old_term;
|
||||
new_term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
||||
TRY("disable echo", tcsetattr(0, TCSAFLUSH, &new_term));
|
||||
}
|
||||
quickscope_wrapper stdin_restorer{[&] {
|
||||
if(from_tty) {
|
||||
// Reset the terminal
|
||||
tcsetattr(0, TCSAFLUSH, &old_term);
|
||||
sigaction(SIGINT, &osigint, nullptr);
|
||||
sigaction(SIGTSTP, &osigtstp, nullptr);
|
||||
|
||||
// If we caught a signal, re-throw it now
|
||||
if(caught_interrupt != 0)
|
||||
kill(getpid(), caught_interrupt);
|
||||
|
||||
// Print the newline that was not echoed
|
||||
putchar('\n');
|
||||
}
|
||||
}};
|
||||
|
||||
|
||||
// Read the key material
|
||||
size_t buflen{};
|
||||
errno = 0;
|
||||
auto bytes = getline((char **)&buf, &buflen, stdin);
|
||||
switch(bytes) {
|
||||
case -1:
|
||||
if(errno != 0)
|
||||
TRY("read in passphrase", bytes);
|
||||
else // EOF
|
||||
bytes = 0;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
// Trim ending newline, if any
|
||||
if(buf[bytes - 1] == '\n') {
|
||||
buf[bytes - 1] = '\0';
|
||||
--bytes;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
len_out = bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_known_passphrase(const char * whom, uint8_t *& buf, size_t & len_out) {
|
||||
return get_key_material_raw(whom, false, false, buf, len_out);
|
||||
}
|
||||
|
||||
int read_new_passphrase(const char * whom, uint8_t *& buf, size_t & len_out) {
|
||||
uint8_t * first_passphrase{};
|
||||
size_t first_passphrase_len{};
|
||||
TRY_MAIN(get_key_material_raw(whom, false, true, first_passphrase, first_passphrase_len));
|
||||
quickscope_wrapper first_passphrase_deleter{[&] { free(first_passphrase); }};
|
||||
|
||||
uint8_t * second_passphrase{};
|
||||
size_t second_passphrase_len{};
|
||||
TRY_MAIN(get_key_material_raw(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)) {
|
||||
fprintf(stderr, "Provided keys do not match.\n");
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
if(second_passphrase_len) {
|
||||
buf = second_passphrase;
|
||||
second_passphrase = nullptr;
|
||||
} else
|
||||
buf = nullptr;
|
||||
|
||||
len_out = second_passphrase_len;
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,3 +32,6 @@ extern int read_exact(const char * path, void * data, size_t len);
|
||||
|
||||
/// Write exactly len bytes from data into path, or error
|
||||
extern int write_exact(const char * path, const void * data, size_t len, mode_t mode);
|
||||
|
||||
extern int read_known_passphrase(const char * whom, uint8_t *& buf, size_t & len_out);
|
||||
extern int read_new_passphrase(const char * whom, uint8_t *& buf, size_t & len_out);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/// Used as secret for the sealed object itself
|
||||
// I just got this out of /dev/random
|
||||
static const constexpr uint8_t sealing_secret[TPM_SHA1_160_HASH_LEN]{0xB9, 0xEE, 0x71, 0x5D, 0xBE, 0x4B, 0x24, 0x3F, 0xAA, 0x81,
|
||||
0xEA, 0x04, 0x30, 0x6E, 0x06, 0x37, 0x10, 0x38, 0x3E, 0x35};
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
|
||||
#include "common.hpp"
|
||||
#include "fd.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tss/platform.h>
|
||||
#include <tss/tspi.h>
|
||||
@ -17,6 +21,12 @@
|
||||
#define TRY_TPM1X(what, ...) TRY_GENERIC(what, , != TPM_SUCCESS, _try_ret, __LINE__, Trspi_Error_String, __VA_ARGS__)
|
||||
|
||||
|
||||
/// Used as default secret if passphrase wasn't provided for wrapping key for the sealed object
|
||||
// I just got this out of /dev/random
|
||||
static const constexpr uint8_t parent_key_secret[TPM_SHA1_160_HASH_LEN]{0xCE, 0x4C, 0xF6, 0x77, 0x87, 0x5B, 0x5E, 0xB8, 0x99, 0x35,
|
||||
0x91, 0xD5, 0xA9, 0xAF, 0x1E, 0xD2, 0x4A, 0x3A, 0x87, 0x36};
|
||||
|
||||
|
||||
template <class F>
|
||||
int with_tpm1x_session(F && func) {
|
||||
TSS_HCONTEXT ctx{}; // All memory lives as long as this does
|
||||
@ -44,15 +54,26 @@ int with_tpm1x_session(F && func) {
|
||||
return func(ctx, srk, srk_policy);
|
||||
}
|
||||
|
||||
/// Try to run func() with the current SRK policy (well-known by default); if it fails, prompt for password and reattempt.
|
||||
/// Try to run func() with the current policy; if it fails, prompt for passphrase and reattempt up to three total times.
|
||||
template <class F>
|
||||
int try_srk(const char * what, TSS_HPOLICY srk_policy, F && func) {
|
||||
int try_policy_or_passphrase(const char * what, const char * what_for, TSS_HPOLICY policy, F && func) {
|
||||
auto get_passphrase = [&] {
|
||||
BYTE * pass{};
|
||||
size_t pass_len{};
|
||||
TRY_MAIN(read_known_passphrase(what_for, pass, pass_len));
|
||||
quickscope_wrapper pass_deleter{[&] { free(pass); }};
|
||||
|
||||
TRY_TPM1X("set passphrase secret on policy", Tspi_Policy_SetSecret(policy, TSS_SECRET_MODE_PLAIN, pass_len, pass));
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto err = func();
|
||||
// Equivalent to TSS_ERROR_LAYER(err) == TSS_LAYER_TPM && TSS_ERROR_CODE(err) == TPM_E_AUTHFAIL
|
||||
if((err & TSS_LAYER_TSP) == TSS_LAYER_TPM && (err & TSS_MAX_ERROR) == TPM_E_AUTHFAIL) {
|
||||
// TODO: read SRK password from stdin here
|
||||
TRY_TPM1X("set password secret on SRK policy", Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_PLAIN, strlen("dupanina"), (BYTE *)"dupanina"));
|
||||
for(int i = 0; ((err & TSS_LAYER_TSP) == TSS_LAYER_TPM && (err & TSS_MAX_ERROR) == TPM_E_AUTHFAIL) && i < 3; ++i) {
|
||||
if(i)
|
||||
fprintf(stderr, "Couldn't %s: %s\n", what, Trspi_Error_String(err));
|
||||
|
||||
TRY_MAIN(get_passphrase());
|
||||
err = func();
|
||||
}
|
||||
|
||||
@ -80,9 +101,5 @@ struct tpm1x_handle {
|
||||
/// The stored handle is in the form [%X:%X] where the first blob is the parent key and the second is the sealed data.
|
||||
extern int tpm1x_parse_handle(const char * dataset_name, char * handle_s, tpm1x_handle & handle);
|
||||
|
||||
|
||||
/// Create sealed object, assign a policy and a known secret to it.
|
||||
extern int tpm1x_prep_sealed_object(TSS_HCONTEXT ctx, TSS_HOBJECT & sealed_object, TSS_HPOLICY & sealed_object_policy);
|
||||
// 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_free_persistent(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT persistent_handle);
|
||||
|
Loading…
x
Reference in New Issue
Block a user