mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-21 09:47:35 +03:00
Extract TPM 1.x code so it's less bad and more not horseshit
This commit is contained in:
parent
6df053a1b5
commit
6423713487
@ -7,26 +7,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <tss/platform.h>
|
||||
#include <tss/tspi.h>
|
||||
#include <tss/tss_structs.h>
|
||||
#include <tss/tss_typedef.h>
|
||||
|
||||
#include <trousers/trousers.h>
|
||||
|
||||
#include "../fd.hpp"
|
||||
#include "../main.hpp"
|
||||
#include "../parse.hpp"
|
||||
#include "../tpm2.hpp"
|
||||
#include "../tpm1x.hpp"
|
||||
#include "../zfs.hpp"
|
||||
|
||||
|
||||
#define THIS_BACKEND "TPM1.X"
|
||||
|
||||
// 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};
|
||||
|
||||
// ./src/swtpm_setup/swtpm_setup --tpmstate /home/nabijaczleweli/code/tzpfms/tpm1.x-state --createek --display --logfile /dev/stdout --overwrite
|
||||
// swtpm cuse -n tpm --tpmstate dir=/home/nabijaczleweli/code/tzpfms/tpm1.x-state --seccomp action=none --log level=10,file=/dev/fd/4 4>&1; sleep 0.5;
|
||||
// swtpm_ioctl -i /dev/tpm; sleep 0.5; TPM_DEVICE=/dev/tpm swtpm_bios; sleep 0.5; tcsd -f swtpm_ioctl -s /dev/tpm
|
||||
@ -39,176 +28,101 @@ int main(int argc, char ** argv) {
|
||||
[&](auto dataset) {
|
||||
REQUIRE_KEY_LOADED(dataset);
|
||||
|
||||
/// We don't use Tspi_Context_RegisterKey() and friends, so we don't touch the persistent storage database; as such, there is nothing to clean up.
|
||||
TRY_MAIN(verify_backend(dataset, THIS_BACKEND, [](auto) {}));
|
||||
|
||||
/// Mostly based on tpm_sealdata(1) from tpm-tools.
|
||||
|
||||
// All memory lives as long as this does
|
||||
TSS_HCONTEXT ctx{};
|
||||
fprintf(stderr, "Tspi_Context_Create() = %s\n", Trspi_Error_String(Tspi_Context_Create(&ctx)));
|
||||
fprintf(stderr, "Tspi_Context_Connect() = %s\n", Trspi_Error_String(Tspi_Context_Connect(ctx, nullptr)));
|
||||
quickscope_wrapper ctx_deleter{[&] {
|
||||
fprintf(stderr, "Tspi_Context_FreeMemory() = %s\n", Trspi_Error_String(Tspi_Context_FreeMemory(ctx, nullptr)));
|
||||
fprintf(stderr, "Tspi_Context_Close() = %s\n", Trspi_Error_String(Tspi_Context_Close(ctx)));
|
||||
}};
|
||||
|
||||
TSS_HTPM tpm_h{};
|
||||
fprintf(stderr, "Tspi_Context_GetTpmObject() = %s\n", Trspi_Error_String(Tspi_Context_GetTpmObject(ctx, &tpm_h)));
|
||||
return with_tpm1x_session([&](auto ctx, auto srk, auto srk_policy) {
|
||||
TSS_HTPM tpm_h{};
|
||||
TRY_TPM1X("extract TPM from context", Tspi_Context_GetTpmObject(ctx, &tpm_h));
|
||||
|
||||
|
||||
uint8_t * wrap_key{};
|
||||
fprintf(stderr, "Tspi_TPM_GetRandom() = %s\n", Trspi_Error_String(Tspi_TPM_GetRandom(tpm_h, WRAPPING_KEY_LEN, &wrap_key)));
|
||||
fprintf(stderr, "%u\n", WRAPPING_KEY_LEN);
|
||||
for(auto i = 0u; i < WRAPPING_KEY_LEN; ++i)
|
||||
fprintf(stderr, "%02X", wrap_key[i]);
|
||||
fprintf(stderr, "\n");
|
||||
uint8_t * wrap_key{};
|
||||
TRY_TPM1X("get random data from TPM", Tspi_TPM_GetRandom(tpm_h, WRAPPING_KEY_LEN, &wrap_key));
|
||||
if(backup)
|
||||
TRY_MAIN(write_exact(backup, wrap_key, WRAPPING_KEY_LEN, 0400));
|
||||
|
||||
|
||||
TSS_HKEY srk{};
|
||||
fprintf(stderr, "Tspi_Context_LoadKeyByUUID() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_LoadKeyByUUID(ctx, TSS_PS_TYPE_SYSTEM, TSS_UUID_SRK, &srk))); // if fails: need to take ownership
|
||||
TSS_HOBJECT parent_key{};
|
||||
TRY_TPM1X("prepare sealant key",
|
||||
Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_SIZE_2048 | TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE, &parent_key));
|
||||
quickscope_wrapper parent_key_deleter{[&] {
|
||||
Tspi_Key_UnloadKey(parent_key);
|
||||
Tspi_Context_CloseObject(ctx, parent_key);
|
||||
}};
|
||||
|
||||
TSS_HPOLICY srk_policy{};
|
||||
fprintf(stderr, "Tspi_GetPolicyObject() = %s\n", Trspi_Error_String(Tspi_GetPolicyObject(srk, TSS_POLICY_USAGE, &srk_policy)));
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(srk_policy) = %s\n", Trspi_Error_String(Tspi_Policy_AssignToObject(srk_policy, srk)));
|
||||
quickscope_wrapper srk_policy_deleter{
|
||||
[&] { fprintf(stderr, "Tspi_Policy_FlushSecret() = %s\n", Trspi_Error_String(Tspi_Policy_FlushSecret(srk_policy))); }};
|
||||
|
||||
uint8_t well_known[TPM_SHA1_160_HASH_LEN]{};
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(well known) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_SHA1, sizeof(well_known), well_known)));
|
||||
|
||||
TSS_HKEY parent_key{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(
|
||||
Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_SIZE_2048 | TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE, &parent_key)));
|
||||
|
||||
TSS_HKEY parent_key_policy{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &parent_key_policy)));
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(parent_key_policy) = %s\n", Trspi_Error_String(Tspi_Policy_AssignToObject(parent_key_policy, parent_key)));
|
||||
quickscope_wrapper parent_key_policy_deleter{
|
||||
[&] { fprintf(stderr, "Tspi_Policy_FlushSecret() = %s\n", Trspi_Error_String(Tspi_Policy_FlushSecret(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")));
|
||||
TSS_HPOLICY parent_key_policy{};
|
||||
TRY_TPM1X("create sealant key policy", Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &parent_key_policy));
|
||||
TRY_TPM1X("assign policy to sealant key", Tspi_Policy_AssignToObject(parent_key_policy, parent_key));
|
||||
quickscope_wrapper parent_key_policy_deleter{[&] {
|
||||
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")));
|
||||
|
||||
|
||||
auto err = Tspi_Key_CreateKey(parent_key, srk, 0);
|
||||
fprintf(stderr, "Tspi_Key_CreateKey() = %s\n", Trspi_Error_String(err));
|
||||
// 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
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(\"dupanina\") = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_PLAIN, strlen("dupanina"), (BYTE *)"dupanina")));
|
||||
TRY_MAIN(try_srk("create sealant key (did you take ownership?)", srk_policy, [&] { return Tspi_Key_CreateKey(parent_key, srk, 0); }));
|
||||
|
||||
fprintf(stderr, "Tspi_Key_CreateKey() = %s\n", Trspi_Error_String(Tspi_Key_CreateKey(parent_key, srk, 0)));
|
||||
}
|
||||
|
||||
fprintf(stderr, "Tspi_Key_LoadKey() = %s\n", Trspi_Error_String(Tspi_Key_LoadKey(parent_key, srk)));
|
||||
TRY_TPM1X("load sealant key", Tspi_Key_LoadKey(parent_key, srk));
|
||||
|
||||
|
||||
TSS_HKEY sealed_object{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL, &sealed_object)));
|
||||
TSS_HPOLICY sealed_object_policy{};
|
||||
fprintf(stderr, "Tspi_GetPolicyObject() = %s\n", Trspi_Error_String(Tspi_GetPolicyObject(srk, TSS_POLICY_USAGE, &sealed_object_policy)));
|
||||
TSS_HOBJECT sealed_object{};
|
||||
TSS_HPOLICY sealed_object_policy{};
|
||||
TRY_MAIN(tpm1x_prep_sealed_object(ctx, sealed_object, sealed_object_policy));
|
||||
quickscope_wrapper sealed_object_deleter{[&] {
|
||||
Tspi_Policy_FlushSecret(sealed_object_policy);
|
||||
Tspi_Context_CloseObject(ctx, sealed_object_policy);
|
||||
Tspi_Context_CloseObject(ctx, sealed_object);
|
||||
}};
|
||||
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(sealed_object) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_AssignToObject(sealed_object_policy, sealed_object)));
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(sealing_secret) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_SetSecret(sealed_object_policy, TSS_SECRET_MODE_SHA1, sizeof(sealing_secret), (uint8_t *)sealing_secret)));
|
||||
TSS_HOBJECT bound_pcrs{}; // See tpm_sealdata.c from src:tpm-tools for more on flags here
|
||||
TRY_TPM1X("create PCRs list", Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_PCRS, 0, &bound_pcrs));
|
||||
quickscope_wrapper bound_pcrs_deleter{[&] { Tspi_Context_CloseObject(ctx, bound_pcrs); }};
|
||||
|
||||
TSS_HKEY bound_pcrs{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(
|
||||
Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_PCRS, 0, &bound_pcrs))); // See tpm_sealdata.c from src:tpm-tools for more on flags here
|
||||
fprintf(stderr, "Tspi_Data_Seal() = %s\n", Trspi_Error_String(Tspi_Data_Seal(sealed_object, parent_key, WRAPPING_KEY_LEN, wrap_key, bound_pcrs)));
|
||||
|
||||
uint8_t * parent_key_blob{};
|
||||
uint32_t parent_key_blob_len{};
|
||||
fprintf(stderr, "Tspi_GetAttribData(parent_key) = %s\n",
|
||||
Trspi_Error_String(Tspi_GetAttribData(parent_key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &parent_key_blob_len, &parent_key_blob)));
|
||||
fprintf(stderr, "%u\n", parent_key_blob_len);
|
||||
for(auto i = 0u; i < parent_key_blob_len; ++i)
|
||||
fprintf(stderr, "%02X", parent_key_blob[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
uint8_t * sealed_object_blob{};
|
||||
uint32_t sealed_object_blob_len{};
|
||||
fprintf(stderr, "Tspi_GetAttribData(sealed_object) = %s\n",
|
||||
Trspi_Error_String(Tspi_GetAttribData(sealed_object, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, &sealed_object_blob_len,
|
||||
&sealed_object_blob)));
|
||||
fprintf(stderr, "%u\n", sealed_object_blob_len);
|
||||
for(auto i = 0u; i < sealed_object_blob_len; ++i)
|
||||
fprintf(stderr, "%02X", sealed_object_blob[i]);
|
||||
fprintf(stderr, "\n");
|
||||
TRY_TPM1X("seal wrapping key data", Tspi_Data_Seal(sealed_object, parent_key, WRAPPING_KEY_LEN, wrap_key, bound_pcrs));
|
||||
|
||||
|
||||
/*return 0;
|
||||
TRY_MAIN(with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) {
|
||||
char *previous_backend{}, *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);
|
||||
else if(previous_backend && previous_handle_s) {
|
||||
if(strcmp(previous_backend, THIS_BACKEND))
|
||||
fprintf(stderr,
|
||||
"Dataset %s was encrypted with tzpfms back-end %s before, but we are %s. You will have to free handle %s for back-end %s manually!\n",
|
||||
zfs_get_name(dataset), previous_backend, THIS_BACKEND, previous_handle_s, previous_backend);
|
||||
else {
|
||||
TPMI_DH_PERSISTENT previous_handle{};
|
||||
if(parse_int(previous_handle_s, previous_handle))
|
||||
fprintf(stderr, "Couldn't parse previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c %s\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle_s);
|
||||
else {
|
||||
if(tpm2_free_persistent(tpm2_ctx, tpm2_session, previous_handle))
|
||||
fprintf(stderr,
|
||||
"Couldn't free previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c 0x%X\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t * parent_key_blob{};
|
||||
uint32_t parent_key_blob_len{};
|
||||
TRY_TPM1X("get sealant key blob",
|
||||
Tspi_GetAttribData(parent_key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &parent_key_blob_len, &parent_key_blob));
|
||||
|
||||
uint8_t wrap_key[WRAPPING_KEY_LEN];
|
||||
TPMI_DH_PERSISTENT persistent_handle{};
|
||||
|
||||
TRY_MAIN(tpm2_generate_rand(tpm2_ctx, wrap_key, sizeof(wrap_key)));
|
||||
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)));
|
||||
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))
|
||||
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));
|
||||
}};*/
|
||||
uint8_t * sealed_object_blob{};
|
||||
uint32_t sealed_object_blob_len{};
|
||||
TRY_TPM1X("get sealed object blob", Tspi_GetAttribData(sealed_object, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB,
|
||||
&sealed_object_blob_len, &sealed_object_blob));
|
||||
|
||||
|
||||
auto handle = reinterpret_cast<char *>(TRY_PTR("allocate handle string", alloca(parent_key_blob_len * 2 + 1 + sealed_object_blob_len * 2 + 1)));
|
||||
{
|
||||
auto cur = handle;
|
||||
for(auto i = 0u; i < parent_key_blob_len; ++i, cur += 2)
|
||||
sprintf(cur, "%02X", parent_key_blob[i]);
|
||||
*cur++ = ':';
|
||||
for(auto i = 0u; i < sealed_object_blob_len; ++i, cur += 2)
|
||||
sprintf(cur, "%02X", sealed_object_blob[i]);
|
||||
*cur++ = '\0';
|
||||
}
|
||||
fprintf(stderr, "%s\n", handle);
|
||||
TRY_MAIN(set_key_props(dataset, THIS_BACKEND, handle));
|
||||
{
|
||||
// 1740 in testing; we probably have a lot of stack to spare, but don't try our luck
|
||||
auto handle = reinterpret_cast<char *>(TRY_PTR("allocate handle string", malloc(parent_key_blob_len * 2 + 1 + sealed_object_blob_len * 2 + 1)));
|
||||
quickscope_wrapper handle_deleter{[=] { free(handle); }};
|
||||
|
||||
{
|
||||
auto cur = handle;
|
||||
for(auto i = 0u; i < parent_key_blob_len; ++i, cur += 2)
|
||||
sprintf(cur, "%02X", parent_key_blob[i]);
|
||||
*cur++ = ':';
|
||||
for(auto i = 0u; i < sealed_object_blob_len; ++i, cur += 2)
|
||||
sprintf(cur, "%02X", sealed_object_blob[i]);
|
||||
*cur++ = '\0';
|
||||
}
|
||||
|
||||
TRY_MAIN(set_key_props(dataset, THIS_BACKEND, handle));
|
||||
}
|
||||
|
||||
|
||||
TRY_MAIN(change_key(dataset, wrap_key));
|
||||
if(auto err = change_key(dataset, wrap_key)) {
|
||||
if(clear_key_props(dataset)) // Sync with zfs-tpm2-{clear,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 err;
|
||||
}
|
||||
|
||||
// ok = true;
|
||||
// return 0;
|
||||
// }));
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -9,87 +9,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <tss/platform.h>
|
||||
#include <tss/tspi.h>
|
||||
#include <tss/tss_structs.h>
|
||||
#include <tss/tss_typedef.h>
|
||||
|
||||
#include <trousers/trousers.h>
|
||||
|
||||
#include "../fd.hpp"
|
||||
#include "../main.hpp"
|
||||
#include "../tpm1x.hpp"
|
||||
#include "../zfs.hpp"
|
||||
|
||||
|
||||
#define THIS_BACKEND "TPM1.X"
|
||||
|
||||
// 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};
|
||||
|
||||
|
||||
int fromxchar(uint8_t & out, char c) {
|
||||
switch(c) {
|
||||
case '0':
|
||||
out |= 0x0;
|
||||
return 0;
|
||||
case '1':
|
||||
out |= 0x1;
|
||||
return 0;
|
||||
case '2':
|
||||
out |= 0x2;
|
||||
return 0;
|
||||
case '3':
|
||||
out |= 0x3;
|
||||
return 0;
|
||||
case '4':
|
||||
out |= 0x4;
|
||||
return 0;
|
||||
case '5':
|
||||
out |= 0x5;
|
||||
return 0;
|
||||
case '6':
|
||||
out |= 0x6;
|
||||
return 0;
|
||||
case '7':
|
||||
out |= 0x7;
|
||||
return 0;
|
||||
case '8':
|
||||
out |= 0x8;
|
||||
return 0;
|
||||
case '9':
|
||||
out |= 0x9;
|
||||
return 0;
|
||||
case 'A':
|
||||
case 'a':
|
||||
out |= 0xA;
|
||||
return 0;
|
||||
case 'B':
|
||||
case 'b':
|
||||
out |= 0xB;
|
||||
return 0;
|
||||
case 'C':
|
||||
case 'c':
|
||||
out |= 0xC;
|
||||
return 0;
|
||||
case 'D':
|
||||
case 'd':
|
||||
out |= 0xD;
|
||||
return 0;
|
||||
case 'E':
|
||||
case 'e':
|
||||
out |= 0xE;
|
||||
return 0;
|
||||
case 'F':
|
||||
case 'f':
|
||||
out |= 0xF;
|
||||
return 0;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
auto noop = false;
|
||||
@ -100,117 +27,52 @@ int main(int argc, char ** argv) {
|
||||
|
||||
char * handle_s{};
|
||||
TRY_MAIN(parse_key_props(dataset, THIS_BACKEND, handle_s));
|
||||
fprintf(stderr, "handle=%u\n", strlen(handle_s));
|
||||
fprintf(stderr, "handle_s=%s\n", handle_s);
|
||||
|
||||
auto midpoint = strchr(handle_s, ':');
|
||||
if(!midpoint) {
|
||||
fprintf(stderr, "Dataset %s's handle %s not valid.\n", zfs_get_name(dataset), handle_s);
|
||||
return __LINE__;
|
||||
}
|
||||
*midpoint = '\0';
|
||||
fprintf(stderr, "handle=%u\n", strlen(handle_s));
|
||||
fprintf(stderr, "handle_s=%s\n", handle_s);
|
||||
tpm1x_handle handle{};
|
||||
TRY_MAIN(tpm1x_parse_handle(zfs_get_name(dataset), handle_s, handle));
|
||||
|
||||
auto parent_key_wide_blob = handle_s;
|
||||
auto sealed_object_wide_blob = midpoint + 1;
|
||||
|
||||
size_t parent_key_blob_len = strlen(parent_key_wide_blob) / 2;
|
||||
fprintf(stderr, "parent_key_blob_len=%u\n", parent_key_blob_len);
|
||||
// fprintf(stderr, "parent_key_blob=%s\n", parent_key_wide_blob);
|
||||
size_t sealed_object_blob_len = strlen(sealed_object_wide_blob) / 2;
|
||||
fprintf(stderr, "sealed_object_blob_len=%u\n", sealed_object_blob_len);
|
||||
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); }));
|
||||
quickscope_wrapper parent_key_deleter{[&] { Tspi_Key_UnloadKey(parent_key); }};
|
||||
|
||||
// Very likely on the order of 559+310; don't try our luck with alloca()
|
||||
void * blobs = TRY_PTR("allocate blob buffer", calloc(parent_key_blob_len + sealed_object_blob_len, 1));
|
||||
quickscope_wrapper blobs_deleter{[=] { free(blobs); }};
|
||||
TSS_HPOLICY parent_key_policy{};
|
||||
TRY_TPM1X("create sealant key policy", Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &parent_key_policy));
|
||||
TRY_TPM1X("assign policy to sealant key", Tspi_Policy_AssignToObject(parent_key_policy, parent_key));
|
||||
quickscope_wrapper parent_key_policy_deleter{[&] {
|
||||
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")));
|
||||
|
||||
auto parent_key_blob = static_cast<uint8_t *>(blobs);
|
||||
auto sealed_object_blob = static_cast<uint8_t *>(blobs) + parent_key_blob_len;
|
||||
|
||||
{
|
||||
auto cur = parent_key_wide_blob;
|
||||
for(size_t i = 0; i < parent_key_blob_len; ++i) {
|
||||
TRY("parse hex parent key blob", fromxchar(parent_key_blob[i], *cur++));
|
||||
parent_key_blob[i] <<= 4;
|
||||
TRY("parse hex parent key blob", fromxchar(parent_key_blob[i], *cur++));
|
||||
TSS_HOBJECT sealed_object{};
|
||||
TSS_HPOLICY sealed_object_policy{};
|
||||
TRY_MAIN(tpm1x_prep_sealed_object(ctx, sealed_object, sealed_object_policy));
|
||||
|
||||
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));
|
||||
|
||||
|
||||
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));
|
||||
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)
|
||||
fprintf(stderr, "%02X", loaded_wrap_key[i]);
|
||||
fprintf(stderr, "\n");
|
||||
return __LINE__;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto cur = sealed_object_wide_blob;
|
||||
for(size_t i = 0; i < sealed_object_blob_len; ++i) {
|
||||
TRY("parse hex parent key blob", fromxchar(sealed_object_blob[i], *cur++));
|
||||
sealed_object_blob[i] <<= 4;
|
||||
TRY("parse hex parent key blob", fromxchar(sealed_object_blob[i], *cur++));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// All memory lives as long as this does
|
||||
TSS_HCONTEXT ctx{};
|
||||
fprintf(stderr, "Tspi_Context_Create() = %s\n", Trspi_Error_String(Tspi_Context_Create(&ctx)));
|
||||
fprintf(stderr, "Tspi_Context_Connect() = %s\n", Trspi_Error_String(Tspi_Context_Connect(ctx, nullptr)));
|
||||
quickscope_wrapper ctx_deleter{[&] {
|
||||
fprintf(stderr, "Tspi_Context_FreeMemory() = %s\n", Trspi_Error_String(Tspi_Context_FreeMemory(ctx, nullptr)));
|
||||
fprintf(stderr, "Tspi_Context_Close() = %s\n", Trspi_Error_String(Tspi_Context_Close(ctx)));
|
||||
}};
|
||||
|
||||
|
||||
TSS_HKEY srk{};
|
||||
fprintf(stderr, "Tspi_Context_LoadKeyByUUID() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_LoadKeyByUUID(ctx, TSS_PS_TYPE_SYSTEM, TSS_UUID_SRK, &srk))); // if fails: need to take ownership
|
||||
|
||||
TSS_HPOLICY srk_policy{};
|
||||
fprintf(stderr, "Tspi_GetPolicyObject() = %s\n", Trspi_Error_String(Tspi_GetPolicyObject(srk, TSS_POLICY_USAGE, &srk_policy)));
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(srk_policy) = %s\n", Trspi_Error_String(Tspi_Policy_AssignToObject(srk_policy, srk)));
|
||||
quickscope_wrapper srk_policy_deleter{
|
||||
[&] { fprintf(stderr, "Tspi_Policy_FlushSecret() = %s\n", Trspi_Error_String(Tspi_Policy_FlushSecret(srk_policy))); }};
|
||||
|
||||
uint8_t well_known[TPM_SHA1_160_HASH_LEN]{};
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(well known) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_SHA1, sizeof(well_known), well_known)));
|
||||
|
||||
TSS_HKEY parent_key{};
|
||||
fprintf(stderr, "Tspi_Context_LoadKeyByBlob() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_LoadKeyByBlob(ctx, srk, parent_key_blob_len, parent_key_blob, &parent_key)));
|
||||
|
||||
TSS_HKEY parent_key_policy{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &parent_key_policy)));
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(parent_key_policy) = %s\n", Trspi_Error_String(Tspi_Policy_AssignToObject(parent_key_policy, parent_key)));
|
||||
quickscope_wrapper parent_key_policy_deleter{
|
||||
[&] { fprintf(stderr, "Tspi_Policy_FlushSecret() = %s\n", Trspi_Error_String(Tspi_Policy_FlushSecret(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")));
|
||||
|
||||
|
||||
TSS_HKEY sealed_object{};
|
||||
fprintf(stderr, "Tspi_Context_CreateObject() = %s\n",
|
||||
Trspi_Error_String(Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL, &sealed_object)));
|
||||
TSS_HPOLICY sealed_object_policy{};
|
||||
fprintf(stderr, "Tspi_GetPolicyObject() = %s\n", Trspi_Error_String(Tspi_GetPolicyObject(srk, TSS_POLICY_USAGE, &sealed_object_policy)));
|
||||
|
||||
fprintf(stderr, "Tspi_Policy_AssignToObject(sealed_object) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_AssignToObject(sealed_object_policy, sealed_object)));
|
||||
fprintf(stderr, "Tspi_Policy_SetSecret(sealing_secret) = %s\n",
|
||||
Trspi_Error_String(Tspi_Policy_SetSecret(sealed_object_policy, TSS_SECRET_MODE_SHA1, sizeof(sealing_secret), (uint8_t *)sealing_secret)));
|
||||
|
||||
fprintf(stderr, "Tspi_SetAttribData() = %s\n",
|
||||
Trspi_Error_String(
|
||||
Tspi_SetAttribData(sealed_object, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, sealed_object_blob_len, sealed_object_blob)));
|
||||
|
||||
|
||||
uint8_t * wrap_key{};
|
||||
uint32_t wrap_key_len{};
|
||||
fprintf(stderr, "Tspi_Data_Unseal() = %s\n", Trspi_Error_String(Tspi_Data_Unseal(sealed_object, parent_key, &wrap_key_len, &wrap_key)));
|
||||
fprintf(stderr, "%u\n", wrap_key_len);
|
||||
for(auto i = 0u; i < wrap_key_len; ++i)
|
||||
fprintf(stderr, "%02X", wrap_key[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
|
||||
// TODO: find out what fucks off with "Authorisation failed" on non-well-known
|
||||
memcpy(wrap_key, loaded_wrap_key, sizeof(wrap_key));
|
||||
return 0;
|
||||
}));
|
||||
|
||||
TRY_MAIN(load_key(dataset, wrap_key, noop));
|
||||
return 0;
|
||||
|
@ -36,31 +36,18 @@ int main(int argc, char ** argv) {
|
||||
//
|
||||
// tpm2_unseal -Q --object-context=0x81000000
|
||||
|
||||
TRY_MAIN(with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) {
|
||||
char *previous_backend{}, *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);
|
||||
else if(previous_backend && previous_handle_s) {
|
||||
if(strcmp(previous_backend, THIS_BACKEND))
|
||||
fprintf(stderr,
|
||||
"Dataset %s was encrypted with tzpfms back-end %s before, but we are %s. You will have to free handle %s for back-end %s manually!\n",
|
||||
zfs_get_name(dataset), previous_backend, THIS_BACKEND, previous_handle_s, previous_backend);
|
||||
return with_tpm2_session([&](auto tpm2_ctx, auto tpm2_session) {
|
||||
TRY_MAIN(verify_backend(dataset, THIS_BACKEND, [&](auto previous_handle_s) {
|
||||
TPMI_DH_PERSISTENT previous_handle{};
|
||||
if(parse_int(previous_handle_s, previous_handle))
|
||||
fprintf(stderr, "Couldn't parse previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c %s\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle_s);
|
||||
else {
|
||||
TPMI_DH_PERSISTENT previous_handle{};
|
||||
if(parse_int(previous_handle_s, previous_handle))
|
||||
fprintf(stderr, "Couldn't parse previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c %s\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle_s);
|
||||
else {
|
||||
if(tpm2_free_persistent(tpm2_ctx, tpm2_session, previous_handle))
|
||||
fprintf(stderr,
|
||||
"Couldn't free previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c 0x%X\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle);
|
||||
}
|
||||
if(tpm2_free_persistent(tpm2_ctx, tpm2_session, previous_handle))
|
||||
fprintf(stderr, "Couldn't free previous persistent handle for dataset %s. You might need to run \"tpm2_evictcontrol -c 0x%X\" or equivalent!\n",
|
||||
zfs_get_name(dataset), previous_handle);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
uint8_t wrap_key[WRAPPING_KEY_LEN];
|
||||
TPMI_DH_PERSISTENT persistent_handle{};
|
||||
@ -74,7 +61,7 @@ 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
|
||||
if(!ok && clear_key_props(dataset)) // Sync with zfs-tpm1x-change-key, 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));
|
||||
}};
|
||||
@ -93,8 +80,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
ok = true;
|
||||
return 0;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ int main(int argc, char ** argv) {
|
||||
return 0;
|
||||
}));
|
||||
|
||||
if(clear_key_props(dataset)) { // Sync with zfs-tpm2-change-key
|
||||
if(clear_key_props(dataset)) { // Sync with zfs-tpm1x-change-key, 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__;
|
||||
|
146
src/tpm1x.cpp
Normal file
146
src/tpm1x.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include "tpm1x.hpp"
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
// 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};
|
||||
|
||||
|
||||
static int fromxchar(uint8_t & out, char c);
|
||||
|
||||
|
||||
tpm1x_handle::~tpm1x_handle() {
|
||||
free(this->parent_key_blob);
|
||||
}
|
||||
|
||||
int tpm1x_parse_handle(const char * dataset_name, char * handle_s, tpm1x_handle & handle) {
|
||||
auto midpoint = strchr(handle_s, ':');
|
||||
if(!midpoint) {
|
||||
fprintf(stderr, "Dataset %s's handle %s not valid.\n", dataset_name, handle_s);
|
||||
return __LINE__;
|
||||
}
|
||||
*midpoint = '\0';
|
||||
|
||||
auto parent_key_wide_blob = handle_s;
|
||||
auto sealed_object_wide_blob = midpoint + 1;
|
||||
|
||||
handle.parent_key_blob_len = strlen(parent_key_wide_blob) / 2;
|
||||
handle.sealed_object_blob_len = strlen(sealed_object_wide_blob) / 2;
|
||||
|
||||
|
||||
handle.parent_key_blob = static_cast<uint8_t *>(TRY_PTR("allocate blob buffer", calloc(handle.parent_key_blob_len + handle.sealed_object_blob_len, 1)));
|
||||
handle.sealed_object_blob = handle.parent_key_blob + handle.parent_key_blob_len;
|
||||
|
||||
{
|
||||
auto cur = parent_key_wide_blob;
|
||||
for(size_t i = 0; i < handle.parent_key_blob_len; ++i) {
|
||||
TRY("parse hex parent key blob", fromxchar(handle.parent_key_blob[i], *cur++));
|
||||
handle.parent_key_blob[i] <<= 4;
|
||||
TRY("parse hex parent key blob", fromxchar(handle.parent_key_blob[i], *cur++));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto cur = sealed_object_wide_blob;
|
||||
for(size_t i = 0; i < handle.sealed_object_blob_len; ++i) {
|
||||
TRY("parse hex sealed object blob", fromxchar(handle.sealed_object_blob[i], *cur++));
|
||||
handle.sealed_object_blob[i] <<= 4;
|
||||
TRY("parse hex sealed object blob", fromxchar(handle.sealed_object_blob[i], *cur++));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tpm1x_prep_sealed_object(TSS_HCONTEXT ctx, TSS_HOBJECT & sealed_object, TSS_HPOLICY & sealed_object_policy) {
|
||||
bool ok = false;
|
||||
|
||||
TRY_TPM1X("create sealed object", Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL, &sealed_object));
|
||||
quickscope_wrapper sealed_object_deleter{[&] {
|
||||
if(!ok)
|
||||
Tspi_Context_CloseObject(ctx, sealed_object);
|
||||
}};
|
||||
TRY_TPM1X("create sealed object policy", Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &sealed_object_policy));
|
||||
quickscope_wrapper sealed_object_policy_deleter{[&] {
|
||||
if(!ok)
|
||||
Tspi_Context_CloseObject(ctx, sealed_object_policy);
|
||||
}};
|
||||
|
||||
TRY_TPM1X("assign policy to sealed object", Tspi_Policy_AssignToObject(sealed_object_policy, sealed_object));
|
||||
TRY_TPM1X("set secret on sealed object policy",
|
||||
Tspi_Policy_SetSecret(sealed_object_policy, TSS_SECRET_MODE_SHA1, sizeof(sealing_secret), (uint8_t *)sealing_secret));
|
||||
|
||||
ok = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// This feels suboptimal somehow, and yet
|
||||
static int fromxchar(uint8_t & out, char c) {
|
||||
switch(c) {
|
||||
case '0':
|
||||
out |= 0x0;
|
||||
return 0;
|
||||
case '1':
|
||||
out |= 0x1;
|
||||
return 0;
|
||||
case '2':
|
||||
out |= 0x2;
|
||||
return 0;
|
||||
case '3':
|
||||
out |= 0x3;
|
||||
return 0;
|
||||
case '4':
|
||||
out |= 0x4;
|
||||
return 0;
|
||||
case '5':
|
||||
out |= 0x5;
|
||||
return 0;
|
||||
case '6':
|
||||
out |= 0x6;
|
||||
return 0;
|
||||
case '7':
|
||||
out |= 0x7;
|
||||
return 0;
|
||||
case '8':
|
||||
out |= 0x8;
|
||||
return 0;
|
||||
case '9':
|
||||
out |= 0x9;
|
||||
return 0;
|
||||
case 'A':
|
||||
case 'a':
|
||||
out |= 0xA;
|
||||
return 0;
|
||||
case 'B':
|
||||
case 'b':
|
||||
out |= 0xB;
|
||||
return 0;
|
||||
case 'C':
|
||||
case 'c':
|
||||
out |= 0xC;
|
||||
return 0;
|
||||
case 'D':
|
||||
case 'd':
|
||||
out |= 0xD;
|
||||
return 0;
|
||||
case 'E':
|
||||
case 'e':
|
||||
out |= 0xE;
|
||||
return 0;
|
||||
case 'F':
|
||||
case 'f':
|
||||
out |= 0xF;
|
||||
return 0;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
88
src/tpm1x.hpp
Normal file
88
src/tpm1x.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <tss/platform.h>
|
||||
#include <tss/tspi.h>
|
||||
#include <tss/tss_structs.h>
|
||||
#include <tss/tss_typedef.h>
|
||||
|
||||
#include <trousers/trousers.h>
|
||||
|
||||
|
||||
#define TRY_TPM1X(what, ...) TRY_GENERIC(what, , != TPM_SUCCESS, _try_ret, __LINE__, Trspi_Error_String, __VA_ARGS__)
|
||||
|
||||
|
||||
template <class F>
|
||||
int with_tpm1x_session(F && func) {
|
||||
TSS_HCONTEXT ctx{}; // All memory lives as long as this does
|
||||
TRY_TPM1X("create TPM context", Tspi_Context_Create(&ctx));
|
||||
TRY_TPM1X("connect TPM context to TPM", Tspi_Context_Connect(ctx, nullptr));
|
||||
quickscope_wrapper ctx_deleter{[&] {
|
||||
Trspi_Error_String(Tspi_Context_FreeMemory(ctx, nullptr));
|
||||
Trspi_Error_String(Tspi_Context_Close(ctx));
|
||||
}};
|
||||
|
||||
|
||||
TSS_HOBJECT srk{};
|
||||
TRY_TPM1X("load SRK", Tspi_Context_LoadKeyByUUID(ctx, TSS_PS_TYPE_SYSTEM, TSS_UUID_SRK, &srk));
|
||||
|
||||
TSS_HPOLICY srk_policy{};
|
||||
TRY_TPM1X("get SRK policy", Tspi_GetPolicyObject(srk, TSS_POLICY_USAGE, &srk_policy));
|
||||
TRY_TPM1X("assign SRK policy", Tspi_Policy_AssignToObject(srk_policy, srk));
|
||||
quickscope_wrapper srk_policy_deleter{[&] { Trspi_Error_String(Tspi_Policy_FlushSecret(srk_policy)); }};
|
||||
|
||||
{
|
||||
uint8_t well_known[TPM_SHA1_160_HASH_LEN]{};
|
||||
TRY_TPM1X("set well-known secret on SRK policy", Tspi_Policy_SetSecret(srk_policy, TSS_SECRET_MODE_SHA1, sizeof(well_known), well_known));
|
||||
}
|
||||
|
||||
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.
|
||||
template <class F>
|
||||
int try_srk(const char * what, TSS_HPOLICY srk_policy, F && func) {
|
||||
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"));
|
||||
|
||||
err = func();
|
||||
}
|
||||
|
||||
// TRY_TPM1X() unrolled because no constexpr/string-literal-template arguments until C++20, which is not supported by GCC 8, which we need for Buster
|
||||
if(err != TPM_SUCCESS) {
|
||||
fprintf(stderr, "Couldn't %s: %s\n", what, Trspi_Error_String(err));
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct tpm1x_handle {
|
||||
uint8_t * parent_key_blob;
|
||||
uint8_t * sealed_object_blob;
|
||||
size_t parent_key_blob_len;
|
||||
size_t sealed_object_blob_len;
|
||||
|
||||
~tpm1x_handle();
|
||||
};
|
||||
|
||||
/// Parse handle blobs as stored in a ZFS property
|
||||
///
|
||||
/// 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);
|
||||
|
||||
|
||||
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);
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include <tss2/tss2_common.h>
|
||||
#include <tss2/tss2_esys.h>
|
||||
#include <tss2/tss2_rc.h>
|
||||
@ -50,6 +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_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);
|
||||
|
22
src/zfs.hpp
22
src/zfs.hpp
@ -7,6 +7,8 @@
|
||||
#include <libzfs.h>
|
||||
#include <sys/nvpair.h>
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
|
||||
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, _try_ret, strerror, __VA_ARGS__)
|
||||
|
||||
@ -54,3 +56,23 @@ extern int change_key(zfs_handle_t * on, const uint8_t * wrap_key);
|
||||
///
|
||||
/// wrap_key must be WRAPPING_KEY_LEN long.
|
||||
extern int load_key(zfs_handle_t * for_d, const uint8_t * wrap_key, bool noop);
|
||||
|
||||
/// Check back-end integrity; if the previous backend matches this_backend, run func(); otherwise warn.
|
||||
template <class F>
|
||||
int verify_backend(zfs_handle_t * on, const char * this_backend, F && func) {
|
||||
char *previous_backend{}, *previous_handle{};
|
||||
TRY_MAIN(lookup_userprop(on, PROPNAME_BACKEND, previous_backend));
|
||||
TRY_MAIN(lookup_userprop(on, PROPNAME_KEY, previous_handle));
|
||||
|
||||
if(!!previous_backend ^ !!previous_handle)
|
||||
fprintf(stderr, "Inconsistent tzpfms metadata for %s: back-end is %s, but handle is %s?\n", zfs_get_name(on), previous_backend, previous_handle);
|
||||
else if(previous_backend && previous_handle) {
|
||||
if(strcmp(previous_backend, this_backend))
|
||||
fprintf(stderr, "Dataset %s was encrypted with tzpfms back-end %s before, but we are %s. You will have to free handle %s for back-end %s manually!\n",
|
||||
zfs_get_name(on), previous_backend, this_backend, previous_handle, previous_backend);
|
||||
else
|
||||
func(previous_handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user