diff --git a/src/bin/zfs-tpm1x-change-key.cpp b/src/bin/zfs-tpm1x-change-key.cpp index 15539c4..744ec02 100644 --- a/src/bin/zfs-tpm1x-change-key.cpp +++ b/src/bin/zfs-tpm1x-change-key.cpp @@ -40,40 +40,7 @@ int main(int argc, char ** argv) { REQUIRE_KEY_LOADED(dataset); - // TSS_RESULT Tspi_Context_Create(TSS_HCONTEXT* phContext); - // TSS_RESULT Tspi_Context_Connect(TSS_HCONTEXT hLocalContext, UNICODE* wszDestination); - // TSS_RESULT Tspi_Context_GetTpmObject(TSS_HCONTEXT hContext, TSS_HTPM* phTPM); - // - // TSS_RESULT Tspi_TPM_GetRandom(TSS_HTPM hTPM, UINT32 size, BYTE** random); - // - // - // TSS_RESULT Tspi_Context_LoadKeyByUUID(TSS_HCONTEXT hContext, TSS_FLAG persistentStorageType, - // TSS_UUID uuidData, TSS_HKEY* phKey); - // - // - // TSS_RESULT Tspi_Context_CreateObject(TSS_HCONTEXT hContext, TSS_FLAG objectType, - // TSS_FLAG initFlags, TSS_HOBJECT* phObject); - // TSS_RESULT Tspi_Key_CreateKey(TSS_HKEY hKey, TSS_HKEY hWrappingKey, TSS_HPCRS hPcrComposite); - // - // - // TSS_RESULT Tspi_Data_Seal(TSS_HENCDATA hEncData, TSS_HKEY hEncKey, - // UINT32 ulDataLength, BYTE* rgbDataToSeal, - // TSS_HPCRS hPcrComposite); - // - // - // TSS_RESULT Tspi_Policy_SetSecret(TSS_HPOLICY hPolicy, TSS_FLAG secretMode, - // UINT32 ulSecretLength, BYTE* rgbSecret); - // - // TSS_RESULT Tspi_Policy_AssignToObject(TSS_HPOLICY hPolicy, TSS_HOBJECT hObject); - // - // TSS_RESULT Tspi_Context_FreeMemory(TSS_HCONTEXT hContext, BYTE* rgbMemory); - // TSS_RESULT Tspi_Context_Close(TSS_HCONTEXT hLocalContext); - // - // - // TSS_RESULT Tspi_GetAttribData(TSS_HOBJECT hObject, TSS_FLAG attribFlag, - // TSS_FLAG subFlag, UINT32* pulAttribDataSize, - // BYTE** prgbAttribData); - + /// Mostly based on See tpm_sealdata(1) from tpm-tools. // All memory lives as long as this does TSS_HCONTEXT ctx{}; @@ -230,29 +197,13 @@ int main(int argc, char ** argv) { *cur++ = ':'; for(auto i = 0u; i < sealed_object_blob_len; ++i, cur += 2) sprintf(cur, "%02X", sealed_object_blob[i]); - *cur++ = '\0'; + *cur++ = '\0'; } fprintf(stderr, "%s\n", handle); TRY_MAIN(set_key_props(dataset, THIS_BACKEND, handle)); - /// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY; - /// this user-proofs the set-up, and means we don't have to touch the filesysten: - /// instead, get an FD, write the raw key data there, dup() it onto stdin, - /// let libzfs read it, then restore stdin - int key_fd; - TRY_MAIN(filled_fd(key_fd, wrap_key, WRAPPING_KEY_LEN)); - quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }}; - - - TRY_MAIN(with_stdin_at(key_fd, [&] { - if(zfs_crypto_rewrap(dataset, TRY_PTR("get rewrap args", rewrap_args()), B_FALSE)) - return __LINE__; // Error printed by libzfs - else - printf("Key for %s changed\n", zfs_get_name(dataset)); - - return 0; - })); + TRY_MAIN(change_key(dataset, wrap_key)); // ok = true; // return 0; diff --git a/src/bin/zfs-tpm2-change-key.cpp b/src/bin/zfs-tpm2-change-key.cpp index 4aa24c1..006abcd 100644 --- a/src/bin/zfs-tpm2-change-key.cpp +++ b/src/bin/zfs-tpm2-change-key.cpp @@ -89,24 +89,7 @@ int main(int argc, char ** argv) { TRY_MAIN(set_key_props(dataset, THIS_BACKEND, persistent_handle_s)); } - /// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY; - /// this user-proofs the set-up, and means we don't have to touch the filesysten: - /// instead, get an FD, write the raw key data there, dup() it onto stdin, - /// let libzfs read it, then restore stdin - - int key_fd; - TRY_MAIN(filled_fd(key_fd, wrap_key, WRAPPING_KEY_LEN)); - quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }}; - - - TRY_MAIN(with_stdin_at(key_fd, [&] { - if(zfs_crypto_rewrap(dataset, TRY_PTR("get rewrap args", rewrap_args()), B_FALSE)) - return __LINE__; // Error printed by libzfs - else - printf("Key for %s changed\n", zfs_get_name(dataset)); - - return 0; - })); + TRY_MAIN(change_key(dataset, wrap_key)); ok = true; return 0; diff --git a/src/bin/zfs-tpm2-clear-key.cpp b/src/bin/zfs-tpm2-clear-key.cpp index 3eea699..21ab666 100644 --- a/src/bin/zfs-tpm2-clear-key.cpp +++ b/src/bin/zfs-tpm2-clear-key.cpp @@ -19,8 +19,12 @@ int main(int argc, char ** argv) { [&](auto dataset) { REQUIRE_KEY_LOADED(dataset); + char * persistent_handle_s{}; + TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, persistent_handle_s)); + TPMI_DH_PERSISTENT persistent_handle{}; - TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, persistent_handle)); + TRY_MAIN(tpm2_parse_handle(zfs_get_name(dataset), persistent_handle_s, persistent_handle)); + if(zfs_crypto_rewrap(dataset, TRY_PTR("get clear rewrap args", clear_rewrap_args()), B_FALSE)) return __LINE__; // Error printed by libzfs diff --git a/src/bin/zfs-tpm2-load-key.cpp b/src/bin/zfs-tpm2-load-key.cpp index cb45098..8bef016 100644 --- a/src/bin/zfs-tpm2-load-key.cpp +++ b/src/bin/zfs-tpm2-load-key.cpp @@ -17,12 +17,15 @@ int main(int argc, char ** argv) { - auto noop = B_FALSE; + auto noop = false; return do_main( - argc, argv, "n", "[-n]", [&](auto) { noop = B_TRUE; }, + argc, argv, "n", "[-n]", [&](auto) { noop = true; }, [&](auto dataset) { + char * handle_s{}; + TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, handle_s)); + TPMI_DH_PERSISTENT handle{}; - TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, handle)); + TRY_MAIN(tpm2_parse_handle(zfs_get_name(dataset), handle_s, handle)); uint8_t wrap_key[WRAPPING_KEY_LEN]; @@ -32,20 +35,7 @@ int main(int argc, char ** argv) { })); - int key_fd; - TRY_MAIN(filled_fd(key_fd, (void *)wrap_key, sizeof(wrap_key))); - quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }}; - - - TRY_MAIN(with_stdin_at(key_fd, [&] { - if(zfs_crypto_load_key(dataset, noop, nullptr)) - return __LINE__; // Error printed by libzfs - else - printf("Key for %s %s\n", zfs_get_name(dataset), noop ? "OK" : "loaded"); - - return 0; - })); - + TRY_MAIN(load_key(dataset, wrap_key, noop)); return 0; }); } diff --git a/src/tpm2.cpp b/src/tpm2.cpp index ea34389..cb9e815 100644 --- a/src/tpm2.cpp +++ b/src/tpm2.cpp @@ -3,6 +3,7 @@ #include "tpm2.hpp" #include "main.hpp" +#include "parse.hpp" #include #include @@ -24,6 +25,16 @@ TPM2B_DATA tpm2_creation_metadata(const char * dataset_name) { } +int tpm2_parse_handle(const char * dataset_name, const char * handle_s, TPMI_DH_PERSISTENT & handle) { + if(parse_int(handle_s, handle)) { + fprintf(stderr, "Dataset %s's handle %s not valid.\n", dataset_name, handle_s); + return __LINE__; + } + + return 0; +} + + int tpm2_generate_rand(ESYS_CONTEXT * tpm2_ctx, void * into, size_t length) { TPM2B_DIGEST * rand{}; TRY_TPM2("get random data from TPM", Esys_GetRandom(tpm2_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, length, &rand)); @@ -42,7 +53,7 @@ int tpm2_generate_rand(ESYS_CONTEXT * tpm2_ctx, void * into, size_t length) { static int tpm2_find_unused_persistent_non_platform(ESYS_CONTEXT * tpm2_ctx, TPMI_DH_PERSISTENT & persistent_handle) { TPMS_CAPABILITY_DATA * cap; // TODO: check for more data? TRY_TPM2("Read used persistent TPM handles", Esys_GetCapability(tpm2_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_HANDLES, TPM2_PERSISTENT_FIRST, - TPM2_MAX_CAP_HANDLES, nullptr, &cap)); + TPM2_MAX_CAP_HANDLES, nullptr, &cap)); quickscope_wrapper cap_deleter{[=] { Esys_Free(cap); }}; persistent_handle = 0; @@ -94,8 +105,9 @@ 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_TPM2("create primary encryption key", 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)); + TRY_TPM2("create primary encryption key", + 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)); quickscope_wrapper creation_ticket_deleter{[=] { Esys_Free(creation_ticket); }}; quickscope_wrapper creation_hash_deleter{[=] { Esys_Free(creation_hash); }}; quickscope_wrapper creation_data_deleter{[=] { Esys_Free(creation_data); }}; @@ -141,7 +153,7 @@ int tpm2_seal(ESYS_CONTEXT * tpm2_ctx, ESYS_TR tpm2_session, TPMI_DH_PERSISTENT TPM2B_DIGEST * creation_hash{}; TPMT_TK_CREATION * creation_ticket{}; TRY_TPM2("create key seal", Esys_Create(tpm2_ctx, primary_handle, tpm2_session, ESYS_TR_NONE, ESYS_TR_NONE, &secret_sens, &pub, &metadata, &pcrs, - &sealant_private, &sealant_public, &creation_data, &creation_hash, &creation_ticket)); + &sealant_private, &sealant_public, &creation_data, &creation_hash, &creation_ticket)); quickscope_wrapper creation_ticket_deleter{[=] { Esys_Free(creation_ticket); }}; quickscope_wrapper creation_hash_deleter{[=] { Esys_Free(creation_hash); }}; quickscope_wrapper creation_data_deleter{[=] { Esys_Free(creation_data); }}; diff --git a/src/tpm2.hpp b/src/tpm2.hpp index 6f97f35..066a9b2 100644 --- a/src/tpm2.hpp +++ b/src/tpm2.hpp @@ -46,6 +46,9 @@ int with_tpm2_session(F && func) { extern TPM2B_DATA tpm2_creation_metadata(const char * dataset_name); +/// Parse a persistent handle name as stored in a ZFS property +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); diff --git a/src/zfs.cpp b/src/zfs.cpp index 849c371..7017d41 100644 --- a/src/zfs.cpp +++ b/src/zfs.cpp @@ -4,7 +4,6 @@ #include "zfs.hpp" #include "common.hpp" #include "main.hpp" -#include "parse.hpp" #include @@ -102,8 +101,8 @@ int clear_key_props(zfs_handle_t * from) { } -int parse_key_props(zfs_handle_t * in, const char * our_backend, uint32_t & handle) { - char *backend{}, *handle_s{}; +int parse_key_props(zfs_handle_t * in, const char * our_backend, char *& handle) { + char *backend{}; TRY_MAIN(lookup_userprop(in, PROPNAME_BACKEND, backend)); if(!backend) { @@ -115,16 +114,11 @@ int parse_key_props(zfs_handle_t * in, const char * our_backend, uint32_t & hand return __LINE__; } - TRY_MAIN(lookup_userprop(in, PROPNAME_KEY, handle_s)); - if(!handle_s) { + TRY_MAIN(lookup_userprop(in, PROPNAME_KEY, handle)); + if(!handle) { 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; } diff --git a/src/zfs.hpp b/src/zfs.hpp index 65f90ba..f007633 100644 --- a/src/zfs.hpp +++ b/src/zfs.hpp @@ -42,4 +42,15 @@ extern int set_key_props(zfs_handle_t * on, const char * backend, const char * h 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); +extern int parse_key_props(zfs_handle_t * in, const char * our_backend, char *& handle); + + +/// Rewrap key on on to wrap_key. +/// +/// wrap_key must be WRAPPING_KEY_LEN long. +extern int change_key(zfs_handle_t * on, const uint8_t * wrap_key); + +/// (Try to) load key wrap_key for for_d. +/// +/// wrap_key must be WRAPPING_KEY_LEN long. +extern int load_key(zfs_handle_t * for_d, const uint8_t * wrap_key, bool noop); diff --git a/src/zfs_meat.cpp b/src/zfs_meat.cpp new file mode 100644 index 0000000..9a8a80b --- /dev/null +++ b/src/zfs_meat.cpp @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT */ + + +#include "fd.hpp" +#include "main.hpp" +#include "zfs.hpp" + +#include +// #include +#define WRAPPING_KEY_LEN 32 + + +template +static int with_stdin_at_buffer(const void * buf, size_t buf_len, F && func) { + int key_fd; + TRY_MAIN(filled_fd(key_fd, buf, buf_len)); + quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }}; + + return with_stdin_at(key_fd, func); +} + + +int change_key(zfs_handle_t * on, const uint8_t * wrap_key) { + /// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY; + /// this user-proofs the set-up, and means we don't have to touch the filesysten: + /// instead, get an FD, write the raw key data there, dup() it onto stdin, + /// let libzfs read it, then restore stdin + + return with_stdin_at_buffer(wrap_key, WRAPPING_KEY_LEN, [&] { + if(zfs_crypto_rewrap(on, TRY_PTR("get rewrap args", rewrap_args()), B_FALSE)) + return __LINE__; // Error printed by libzfs + else + printf("Key for %s changed\n", zfs_get_name(on)); + + return 0; + }); +} + + +int load_key(zfs_handle_t * for_d, const uint8_t * wrap_key, bool noop) { + return with_stdin_at_buffer(wrap_key, WRAPPING_KEY_LEN, [&] { + if(zfs_crypto_load_key(for_d, noop ? B_TRUE : B_FALSE, nullptr)) + return __LINE__; // Error printed by libzfs + else + printf("Key for %s %s\n", zfs_get_name(for_d), noop ? "OK" : "loaded"); + + return 0; + }); +}