From ea57d269300a1f9cbfa1807d2f8370b50e8bfa8b Mon Sep 17 00:00:00 2001 From: Dhanuka Warusadura Date: Wed, 4 Aug 2021 18:19:49 +0530 Subject: [PATCH] Add TPM2 integration to secret file backend These changes add TPM2 derived encryption key to secret file backend. --- libsecret/secret-file-backend.c | 101 ++++++++++++++++++++++++++++++++ tool/meson.build | 8 +++ tool/test-secret-tool-tpm2.sh | 101 ++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100755 tool/test-secret-tool-tpm2.sh diff --git a/libsecret/secret-file-backend.c b/libsecret/secret-file-backend.c index 4896b47..7145f72 100644 --- a/libsecret/secret-file-backend.c +++ b/libsecret/secret-file-backend.c @@ -22,6 +22,7 @@ #include "secret-retrievable.h" #include "egg/egg-secure-memory.h" +#include "egg/egg-tpm2.h" EGG_SECURE_DECLARE (secret_file_backend); @@ -494,12 +495,112 @@ secret_file_backend_real_init_async (GAsyncInitable *initable, g_task_set_task_data (task, init, init_closure_free); g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_bus_get, task); } else { +#ifdef WITH_TPM + EggTpm2Context *context; + GFile *tpm2_file; + gchar *tpm2_file_path; + gboolean status; + GBytes *encrypted; + GBytes *decrypted; + + context = egg_tpm2_initialize (&error); + if (!context) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + path = g_file_get_path (file); + tpm2_file_path = g_strdup_printf ("%s.tpm2", path); + g_free(path); + tpm2_file = g_file_new_for_path (tpm2_file_path); + status = g_file_test (tpm2_file_path, G_FILE_TEST_EXISTS); + g_free (tpm2_file_path); + + if (!status) { + encrypted = egg_tpm2_generate_master_password ( + context, + &error); + if (!encrypted) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + gconstpointer contents; + gsize size; + contents = g_bytes_get_data (encrypted, &size); + status = g_file_replace_contents (tpm2_file, + contents, + size, + NULL, + FALSE, + G_FILE_CREATE_PRIVATE, + NULL, + cancellable, + &error); + if (!status) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + } else { + char *contents; + gsize length; + status = g_file_load_contents (tpm2_file, + cancellable, + &contents, + &length, + NULL, + &error); + if (!status) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + encrypted = g_bytes_new_take (contents, length); + } + + decrypted = egg_tpm2_decrypt_master_password (context, + encrypted, + &error); + g_bytes_unref (encrypted); + egg_tpm2_finalize (context); + if (!decrypted) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + gconstpointer data; + gsize size; + data = g_bytes_get_data(decrypted, &size); + password = secret_value_new (data, + size, + "text/plain"); + g_bytes_unref (decrypted); + g_async_initable_new_async (SECRET_TYPE_FILE_COLLECTION, + io_priority, + cancellable, + on_collection_new_async, + task, + "file", file, + "password", password, + NULL); + + g_object_unref (tpm2_file); + g_object_unref (file); + secret_value_unref (password); +#else g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "master password is not retrievable"); g_object_unref (task); return; +#endif } } diff --git a/tool/meson.build b/tool/meson.build index 13cb4c9..642cd59 100644 --- a/tool/meson.build +++ b/tool/meson.build @@ -17,3 +17,11 @@ if get_option('gcrypt') and host_machine.system() != 'windows' suite: 'secret-tool', ) endif + +if get_option('tpm2') + test('test-secret-tool-tpm2.sh', + find_program('test-secret-tool-tpm2.sh'), + env: test_env, + suite: 'secret-tool', + ) +endif diff --git a/tool/test-secret-tool-tpm2.sh b/tool/test-secret-tool-tpm2.sh new file mode 100755 index 0000000..c09b18d --- /dev/null +++ b/tool/test-secret-tool-tpm2.sh @@ -0,0 +1,101 @@ +#!/bin/sh + +set -e + +testdir=$PWD/test-secret-tool-tpm2-$$ +test -d "$testdir" || mkdir "$testdir" + +cleanup () { + rm -rf "$testdir" +} +trap cleanup 0 + +cd "$testdir" + +SECRET_BACKEND=file +export SECRET_BACKEND + +SECRET_FILE_TEST_PATH=$testdir/keyring +export SECRET_FILE_TEST_PATH + +: ${SECRET_TOOL="$abs_top_builddir"/tool/secret-tool} + +: ${DIFF=diff} + +echo 1..6 + +echo test1 | ${SECRET_TOOL} store --label label1 foo bar +if test $? -eq 0; then + echo "ok 1 /secret-tool/store1" +else + echo "not ok 1 /secret-tool/store1" +fi + +echo test2 | ${SECRET_TOOL} store --label label2 foo bar apple orange +if test $? -eq 0; then + echo "ok 2 /secret-tool/store2" +else + echo "not ok 2 /secret-tool/store2" +fi + +echo test1 > lookup.exp +${SECRET_TOOL} lookup foo bar > lookup.out +if ${DIFF} lookup.exp lookup.out > lookup.diff; then + echo "ok 3 /secret-tool/lookup" +else + echo "not ok 3 /secret-tool/lookup" + sed 's/^/# /' lookup.diff + exit 1 +fi + +cat > search.exp < search.out +if test $? -ne 0; then + echo "not ok 4 /secret-tool/search" + exit 1 +fi +if ${DIFF} search.exp search.out > search.diff; then + echo "ok 4 /secret-tool/search" +else + echo "not ok 4 /secret-tool/search" + sed 's/^/# /' search.diff + exit 1 +fi + +${SECRET_TOOL} clear apple orange +if test $? -eq 0; then + echo "ok 5 /secret-tool/clear" +else + echo "not ok 5 /secret-tool/clear" + exit 1 +fi + +cat > search-after-clear.exp < search-after-clear.out +if test $? -ne 0; then + echo "not ok 6 /secret-tool/search-after-clear" + exit 1 +fi +if ${DIFF} search-after-clear.exp search-after-clear.out > search-after-clear.diff; then + echo "ok 6 /secret-tool/search-after-clear" +else + echo "not ok 6 /secret-tool/search-after-clear" + sed 's/^/# /' search-after-clear.diff + exit 1 +fi