[libsecret: 1/2] Add TPM2 integration to secret file backend




commit ea57d269300a1f9cbfa1807d2f8370b50e8bfa8b
Author: Dhanuka Warusadura <csx tuta io>
Date:   Wed Aug 4 18:19:49 2021 +0530

    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(+)
---
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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]