Add TPM2 integration to secret file backend

These changes add TPM2 derived encryption key to secret
file backend.
This commit is contained in:
Dhanuka Warusadura 2021-08-04 18:19:49 +05:30
parent 2f0558fe57
commit ea57d26930
3 changed files with 210 additions and 0 deletions

View File

@ -22,6 +22,7 @@
#include "secret-retrievable.h" #include "secret-retrievable.h"
#include "egg/egg-secure-memory.h" #include "egg/egg-secure-memory.h"
#include "egg/egg-tpm2.h"
EGG_SECURE_DECLARE (secret_file_backend); 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_task_set_task_data (task, init, init_closure_free);
g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_bus_get, task); g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_bus_get, task);
} else { } 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_task_return_new_error (task,
G_IO_ERROR, G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT, G_IO_ERROR_INVALID_ARGUMENT,
"master password is not retrievable"); "master password is not retrievable");
g_object_unref (task); g_object_unref (task);
return; return;
#endif
} }
} }

View File

@ -17,3 +17,11 @@ if get_option('gcrypt') and host_machine.system() != 'windows'
suite: 'secret-tool', suite: 'secret-tool',
) )
endif 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

101
tool/test-secret-tool-tpm2.sh Executable file
View File

@ -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