summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@gnu.org>2021-08-12 15:49:24 +0000
committerDaiki Ueno <ueno@gnu.org>2021-08-12 15:49:24 +0000
commit4e79431f4b99f91622443a402d354d332b727198 (patch)
tree95e8bfbc235153b5e4b66d34122ba7d409b7d92f
parent2f0558fe577eca8b45acf22dc7734b0cc30dd753 (diff)
parentea57d269300a1f9cbfa1807d2f8370b50e8bfa8b (diff)
downloadlibsecret-4e79431f4b99f91622443a402d354d332b727198.tar.gz
Merge branch 'tpm-integration' into 'master'
Add TPM2 integration to secret file backend See merge request GNOME/libsecret!90
-rw-r--r--libsecret/secret-file-backend.c101
-rw-r--r--tool/meson.build8
-rwxr-xr-xtool/test-secret-tool-tpm2.sh101
3 files changed, 210 insertions, 0 deletions
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 <<EOF
+[no path]
+label = label1
+secret = test1
+
+[no path]
+label = label2
+secret = test2
+
+EOF
+
+${SECRET_TOOL} search foo bar | sed '/^created\|^modified/d' > 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 <<EOF
+[no path]
+label = label1
+secret = test1
+
+EOF
+
+${SECRET_TOOL} search foo bar | sed '/^created\|^modified/d' > 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