diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index 1b70f8aa4e..6ee438f401 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -304,6 +304,70 @@ _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, g_ptr_array_add (self->key_ascii_files, g_strdup (path)); } +/* Check if the file at @path is a directory, and add ascii key files that + * exist one level below the directory. If @path does not lead to a directory, + * the file is added. + */ +void +_ostree_gpg_verifier_add_key_ascii_files_check_dir (OstreeGpgVerifier *self, + const char *path, + GCancellable *cancellable, + GError **error) +{ + GFile *file; + GFileType file_type; + + file = g_file_new_for_path (path); + file_type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, cancellable); + + if (file_type == G_FILE_TYPE_DIRECTORY) + { + GFileEnumerator *direnum; + g_autofree char *sep = NULL; + + if (!g_str_has_suffix (path, "/")) + sep = g_strdup ("/"); + + direnum = g_file_enumerate_children (file, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NONE, cancellable, error); + if (direnum) + { + while (TRUE) + { + GFileInfo *child_info; + GFile *child; + const char *name; + guint32 type; + + if (!g_file_enumerator_iterate (direnum, &child_info, &child, + NULL, error)) + break; + if (child_info == NULL) + break; + + name = g_file_info_get_attribute_byte_string (child_info, "standard::name"); + type = g_file_info_get_attribute_uint32 (child_info, "standard::type"); + + if (type == G_FILE_TYPE_REGULAR) + { + g_autofree char *child_path = NULL; + + child_path = g_strjoin (sep, path, name, NULL); + + _ostree_gpg_verifier_add_key_ascii_file (self, child_path); + } + } + } + + g_object_unref (direnum); + g_object_unref (file); + } + else + { + _ostree_gpg_verifier_add_key_ascii_file (self, path); + } +} + gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, GFile *path, diff --git a/src/libostree/ostree-gpg-verifier.h b/src/libostree/ostree-gpg-verifier.h index 4fe62d98e7..567324050e 100644 --- a/src/libostree/ostree-gpg-verifier.h +++ b/src/libostree/ostree-gpg-verifier.h @@ -75,4 +75,10 @@ void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, void _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, const char *path); +void +_ostree_gpg_verifier_add_key_ascii_files_check_dir (OstreeGpgVerifier *self, + const char *path, + GCancellable *cancellable, + GError **error); + G_END_DECLS diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index fa3c2a940f..263478c2c4 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -5082,6 +5082,8 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, else if (remote_name != NULL) { g_autofree char *gpgkeypath = NULL; + char **gpgkeypath_list = NULL; + /* Add the remote's keyring file if it exists. */ g_autoptr(OstreeRemote) remote = NULL; @@ -5105,7 +5107,26 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, return NULL; if (gpgkeypath) - _ostree_gpg_verifier_add_key_ascii_file (verifier, gpgkeypath); + { + if (strchr (gpgkeypath, ';')) + { + gpgkeypath_list = g_strsplit (gpgkeypath, ";", -1); + } + else + { + _ostree_gpg_verifier_add_key_ascii_files_check_dir (verifier, gpgkeypath, cancellable, error); + } + } + + if (gpgkeypath_list) + { + for (char **iter = gpgkeypath_list; *iter != NULL; ++iter) + { + _ostree_gpg_verifier_add_key_ascii_files_check_dir (verifier, *iter, cancellable, error); + } + } + + g_strfreev (gpgkeypath_list); } if (add_global_keyring_dir) diff --git a/tests/test-remote-gpg-import.sh b/tests/test-remote-gpg-import.sh index f816429c4d..e5be824164 100755 --- a/tests/test-remote-gpg-import.sh +++ b/tests/test-remote-gpg-import.sh @@ -154,6 +154,64 @@ ${OSTREE} prune --refs-only ${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key3.asc R4 $(cat httpd-address)/ostree/gnomerepo ${OSTREE} pull R4:main >/dev/null +# Test gpgkeypath success with multiple keys to try +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/key1.asc;${test_tmpdir}/gpghome/key2.asc;${test_tmpdir}/gpghome/key3.asc" R7 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R7:main >/dev/null + +# Test gpgkeypath failure with multiple keys but none in keyring (invalid) +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/key1.asc;${test_tmpdir}/gpghome/key2.asc" R8 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R8:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with different key" +fi +assert_file_has_content err.txt "GPG signatures found, but none are in trusted keyring" + +# Test gpgkeypath success with directory containing a valid key +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/ R9 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R9:main >/dev/null + +# Test gpgkeypath failure with nonexistent directory +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/ R10 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R10:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "GPG: openat.*No such file or directory" + +# Test gpgkeypath failure with a directory containing a valid key and a nonexistent key +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/;${test_tmpdir}/gpghome/INVALIDKEYPATH.asc" R11 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R11:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key" +fi +assert_file_has_content err.txt "GPG: openat.*No such file or directory" + +# Test gpgkeypath success with a directory containing a valid key and an invalid key +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/;${test_tmpdir}/gpghome/key1.asc" R14 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R14:main >/dev/null + +# Test gpgkeypath failure with a nonexistent directory and a valid key +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/;${test_tmpdir}/gpghome/key3.asc" R12 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R12:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "GPG: openat.*No such file or directory" + +# Test gpgkeypath failure with a nonexistent directory and a nonexistent key +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/;${test_tmpdir}/gpghome/INVALIDKEYPATH.asc" R13 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R13:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "GPG: openat.*No such file or directory" + +# Test gpgkeypath success for trailing slash +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome" R15 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R15:main >/dev/null + +# Test gpgkeypath failure for empty string given with prefixed semicolon +${OSTREE} remote add --set=gpgkeypath=";${test_tmpdir}/gpghome/key3.asc" R16 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R16:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "GPG: openat.*No such file or directory" + rm repo/refs/remotes/* -rf ${OSTREE} prune --refs-only