libdnf/0025-tests-Add-tests-for-dnf_keyring_add_public_key.patch
2026-05-19 15:12:41 -04:00

308 lines
12 KiB
Diff

From 72252383942769f8ad7858e3d5abe2cb64488371 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Fri, 13 Mar 2026 17:40:15 +0100
Subject: [PATCH 25/30] tests: Add tests for dnf_keyring_add_public_key()
Upstream commit: dc3f0098e30a9154f530ea4fc31c500927a7ad01
This patch covers a behaviour of the current code.
---
CMakeLists.txt | 4 +
data/tests/dnf_keyring_add_public_key/input | 1 +
.../dnf_keyring_add_public_key/input.rsa.sig | 16 ++
data/tests/dnf_keyring_add_public_key/rsa.pub | 28 +++
tests/libdnf/dnf-self-test.c | 178 ++++++++++++++++++
5 files changed, 227 insertions(+)
create mode 100644 data/tests/dnf_keyring_add_public_key/input
create mode 100644 data/tests/dnf_keyring_add_public_key/input.rsa.sig
create mode 100644 data/tests/dnf_keyring_add_public_key/rsa.pub
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6444c374..601a0e6a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,10 @@ pkg_check_modules(REPO REQUIRED librepo>=1.15.0)
include_directories(${REPO_INCLUDE_DIRS})
link_directories(${REPO_LIBRARY_DIRS})
pkg_check_modules(RPM REQUIRED rpm>=4.15.0)
+if (RPM_VERSION VERSION_GREATER_EQUAL "5.99.90")
+ add_definitions(-DRPM_HAS_KEYIDASHEX)
+endif()
+
pkg_check_modules(SMARTCOLS REQUIRED smartcols)
pkg_check_modules(SQLite3 REQUIRED sqlite3)
diff --git a/data/tests/dnf_keyring_add_public_key/input b/data/tests/dnf_keyring_add_public_key/input
new file mode 100644
index 00000000..8e27be7d
--- /dev/null
+++ b/data/tests/dnf_keyring_add_public_key/input
@@ -0,0 +1 @@
+text
diff --git a/data/tests/dnf_keyring_add_public_key/input.rsa.sig b/data/tests/dnf_keyring_add_public_key/input.rsa.sig
new file mode 100644
index 00000000..1a7b17a2
--- /dev/null
+++ b/data/tests/dnf_keyring_add_public_key/input.rsa.sig
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEmwLYgf5BhenqUueIiM2DpLXlaUUFAmmz/J4ACgkQiM2DpLXl
+aUVvjBAAzHQ3zM2rF8Wl7O8Gpl0N2Kk38vrggX10BAAOr1Wzk3mdt1DNFvd14NBQ
++kTxRV/aJeT4Ke1ANmoFOWKVxC4tzk7+uuggCG/DspanvwsG+//V9myQjEnJa90S
+iBGOc1Lav1KjmqL0gfaFPFAYmCjIKMD5tFGTS6RFvhMe4ubcxXwCPIZ3HBvgWbV7
+ytREarfh/yF/piPr5HTS/4FhBXM6zN1AzdOjUSE47tySwg86P6q9uhi3UBNU9gDd
+OFoG6S226O2Ei0yXh/3I5LkFGk6MSY+WWsmQVrF5Sjl1gelpQItkDOXguCc33e61
+cIvAbpxQQTesYJCeAKSqjumU6JbsEMHxlei9gFDJN222gbne43kKJaO6L+AUwzqX
+cgZcD/7QUgibQZ/oOHt4TAtjMBAx5mpuehS9YocS66NcDgaJwIesKLGzcZ4x9s+B
+xZzOLacf/cqiw1QPxqg17TezIluGrOcmlOvcGF+OosiTQ9NXm3pFWhiltYducXrI
+4RrHDsVK8omTbGOv1s07fxOD/Xfz0KcCiMkQ+PF8lk/xBp/J3jDRvYBnZ51WV1b5
+LIshhdfBgz3hDrwnFLFzhFmOhcQeadlExwHkI1PVe9QfvEUjB4Q8SlnGp93NlFey
+MepVIf+b6t/SSxfZ6RR9UgWRGEUkAq0iiakM4V7MHMCoW6cpav0=
+=IvX3
+-----END PGP SIGNATURE-----
diff --git a/data/tests/dnf_keyring_add_public_key/rsa.pub b/data/tests/dnf_keyring_add_public_key/rsa.pub
new file mode 100644
index 00000000..3bd696a6
--- /dev/null
+++ b/data/tests/dnf_keyring_add_public_key/rsa.pub
@@ -0,0 +1,28 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBGlveh0BEADjFxE8ZyYa/LJ0eEQqgKgapOhSXjGGSZxQ3nlNF853lpsg9ywj
+oMRkej4QLk1QpYHCbubIPQShiigqp4Z556+ZBGZhb0neT5BsnHgwkFPmrK0F4H5S
+alZpJg8nR3dZJURAwEdJk0HFyN+ULmAtQKY/+aYXPGpDsBl31nxOVqH4XZfaPFPX
+pJy23cDGZWTOvzpfPt4b/IpoMD0czbeD8hBBTGl2Es3cf4g9g8TTB3m3H/irYxzh
+W8THDI8jWGfKSklMywuG101AFIzhm2wAv6pZe5AOyVwPMAWoXuRbdYf47LDPKc+k
+1gOTMRJ19+I0aNw0nIdxv6Jygcv8PyCvqzJcQTWlHb3LAu9Bgvg3DrjlioT2IJve
+ZxrgoPhPg7d8UC8uM8advwc/1Mf0T62pQ9EoyvHk6ZlB4ls7Blo5kk7UNk39ZLdj
+28aeYMtBx+ej3OYVrdbezL+3ph9FEaPdfzS4Gc/vDOYqkVaAaKdAGvDArSG9Ipvp
+CDb/mvHspb+krkov3OLd3YqZy1lJhkG0C/RCISaulXjOOp1jnIEZw2JkiJcfKpi7
+GudrnuQ5DUig5ouFPYsjG2aBt7WJlhdw5O6D23tojqC2z2NSlI7vdBIUle1ptvpS
+V9U5YWq+ZkbraGe5mMn38jMMy+VX1LPYDrDnt1zN74+X9oHOzxJTRJjw0QARAQAB
+tBh0ZXN0IDx0ZXN0UlNBQGxvY2FsaG9zdD6JAlEEEwEKADsWIQSbAtiB/kGF6epS
+54iIzYOkteVpRQUCaW96HQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAK
+CRCIzYOkteVpRYzKD/9rCuXbl5oYcRRyRRriCL1+TmookI8tpv8aUURPtKfBx0xf
+OQWj79UbKYeGLgPPyjvHAuP5eCSoVKwhHcDobrAHPjiJuJDbnc9b0/BD2XqRwbZJ
+iEOZD1uYLz2y98e2OnbtLOxI7ZjVDQs0xPhF1hvcUcHIXRk+dQpGf6mDqx5Oo702
+5GwtwtWU6tJP/xyO8VQdt19/6R1ogHa5sOu+HgW7V7lZBHOJSx+Q7bNwuAbpd4B6
+aj8+wh6nKQiEhxr3NKQwADsymXtI3/+nKNvYTSYSfNYPg/r/YbMXxywC2s3HmrCd
+N/MP387Hx/ZIbsSEgAsZm8ooyJkhkcEgwPDo4/uRPqAYE/TVgFlehzinT08hVhxk
+Ca7+mBPSvUeLj9hzGbftdFFuWmubPPXqI4NsXP4yso2/edXLFjvLJyIw1tVrkXOP
+Pzd9O/LfGJlSWAA+kItePgAQOZqJbtWvlengGsRP2wBUKJJSlF4XYKZULwkr9wf/
+SuUlQNFXnGO2bQ0l9/5XpBPN0Izm1sgSlK6EC9ChY/T2XyN0PvPahBYFkeZVhco2
+qxJ9lftw9nX+lPaBPUE//m/Gsa3uqwJcccbgZmH38nIBBNGk+HFZwl97KZ2MwpHT
+E5O5sl98hspB3TFKDmpNXbbC7NZOgr176q4j9ZclDPwe3C9HY+W50pwYF5MDAw==
+=+Uwk
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/libdnf/dnf-self-test.c b/tests/libdnf/dnf-self-test.c
index 452cf20a..b171d948 100644
--- a/tests/libdnf/dnf-self-test.c
+++ b/tests/libdnf/dnf-self-test.c
@@ -22,10 +22,18 @@
#include "libdnf/libdnf.h"
+#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <fcntl.h>
#include <glib/gstdio.h>
+#include <rpm/rpmcrypto.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmpgp.h>
+#include <rpm/rpmts.h>
+
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(rpmts, rpmtsFree, NULL)
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(rpmKeyring, rpmKeyringFree, NULL)
/**
* cd_test_get_filename:
@@ -57,6 +65,174 @@ dnf_lock_state_changed_cb(DnfLock *lock, guint bitfield, gpointer user_data)
_dnf_lock_state_changed++;
}
+/* Verify a signature in @signature_filename for data in @data_filename using
+ * RPM keyring @keyring.
+ * Return 0 on successul verification, 1 on failed verification, -1 on
+ * internal error. */
+static int
+verifyfile(rpmKeyring keyring, const char *data_filename, const char *signature_filename)
+{
+ gchar *data = NULL;
+ size_t data_size;
+ gchar *signature = NULL;
+ size_t signature_size;
+ pgpDigParams parsed_signature = NULL;
+ DIGEST_CTX digest_context = NULL;
+ rpmRC verification_result;
+
+ if (!g_file_get_contents(data_filename, &data, &data_size, NULL)) {
+ printf("Failed to load data from %s\n", data_filename);
+ return -1;
+ }
+
+ if (!g_file_get_contents(signature_filename, &signature, &signature_size, NULL)) {
+ printf("Failed to load a signature\n");
+ g_free(data);
+ return -1;
+ }
+
+ if (0 != pgpPrtParams((uint8_t *)signature, signature_size, PGPTAG_SIGNATURE, &parsed_signature)) {
+ printf("Failed to parse an OpenPGP signature in %s\n", signature_filename);
+ g_free(signature);
+ g_free(data);
+ return -1;
+ }
+
+ digest_context = rpmDigestInit(pgpDigParamsAlgo(parsed_signature, PGPVAL_HASHALGO), RPMDIGEST_NONE);
+ if (digest_context == NULL) {
+ printf("Failed to initialize a digest context\n");
+ (void)pgpDigParamsFree(parsed_signature);
+ g_free(signature);
+ g_free(data);
+ return -1;
+ }
+
+ if (0 != rpmDigestUpdate(digest_context, data, data_size)) {
+ printf("Failed to compute a digest from the data\n");
+ (void)rpmDigestFinal(digest_context, NULL, NULL, 0);
+ (void)pgpDigParamsFree(parsed_signature);
+ g_free(signature);
+ g_free(data);
+ return -1;
+ }
+
+ verification_result = rpmKeyringVerifySig(keyring, parsed_signature, digest_context);
+
+ (void)rpmDigestFinal(digest_context, NULL, NULL, 0);
+ (void)pgpDigParamsFree(parsed_signature);
+ g_free(signature);
+ g_free(data);
+
+ return (verification_result == RPMRC_OK ? 0 : 1);
+}
+
+/* This function imports keys from @key_filename with
+ * dnf_keyring_add_public_key() and then verifies a signature in
+ * @signature_filename on data in @data_filename against the imported keys.
+ * Key import status returns in @import_passed and @import_error arguments,
+ * signature verification status in @verification_passed argument. Dies on
+ * internal errors. */
+static void
+import_and_verify(gboolean *import_passed, GError **import_error, gboolean *verification_passed,
+ const char *key_filename, const char *data_filename, const char *signature_filename) {
+ g_assert_nonnull(import_passed);
+ g_assert_nonnull(import_error);
+ g_assert_nonnull(verification_passed);
+ g_assert_nonnull(key_filename);
+ g_assert_nonnull(data_filename);
+ g_assert_nonnull(signature_filename);
+
+ g_assert_cmpint(0, ==, rpmReadConfigFiles(NULL, NULL));
+
+ g_auto(rpmts) ts = rpmtsCreate();
+ g_assert_nonnull(ts);
+
+ g_assert_cmpint(0, ==, rpmtsSetRootDir(ts, NULL));
+
+ g_auto(rpmKeyring) keyring = rpmtsGetKeyring(ts, 1);
+ g_assert_nonnull(keyring);
+
+ /* Make sure a signature verification fails before the import. */
+ g_debug("File %s verification against signature %s before importing %s should fail",
+ data_filename, signature_filename, key_filename);
+ g_assert_cmpint (0, !=, verifyfile(keyring, data_filename, signature_filename));
+
+ /* Do the import. */
+ *import_passed = dnf_keyring_add_public_key(keyring, key_filename, import_error);
+ if (*import_passed) {
+ g_debug("Import passed.\n");
+ } else {
+ g_debug("Import failed\n");
+ }
+
+ /* Perform the the signature verification after the import and return the result. */
+ g_debug("File %s verification against signature %s after importing %s:\n",
+ data_filename, signature_filename, key_filename);
+ *verification_passed = (0 == verifyfile(keyring, data_filename, signature_filename));
+ if (*verification_passed) {
+ g_debug("Verification passed.\n");
+ } else {
+ g_debug("Verification failed\n");
+ }
+}
+
+/* This test suite exhibits dnf_keyring_add_public_key() which imports keys
+ * from a file to an in-memory keyring. This keyring is never stored into RPM
+ * database, or its adjacent in-filesystem key store. Therefore one cannot
+ * test an effect of the import by inspecting the RPM database for the
+ * synthetic gpg-pubkey packages.
+ *
+ * RPM 6 supports inspecting in-memory keyrings with rpmKeyringInitIterator()
+ * and rpmKeyringIteratorNext() functions. But we want support RPM older than
+ * that. Therefore this test suite does that by verifying a signature of data
+ * signed with the supposedly imported keys. */
+
+/* Test importing a valid key. */
+static void
+dnf_keyring_add_public_key_valid(void)
+{
+ g_autofree gchar *key_filename = NULL;
+ g_autofree gchar *data_filename = NULL;
+ g_autofree gchar *signature_filename = NULL;
+ gboolean import_passed;
+ g_autoptr(GError) import_error = NULL;
+ gboolean verification_passed;
+
+ key_filename = dnf_test_get_filename("dnf_keyring_add_public_key/rsa.pub");
+ data_filename = dnf_test_get_filename("dnf_keyring_add_public_key/input");
+ signature_filename = dnf_test_get_filename("dnf_keyring_add_public_key/input.rsa.sig");
+
+ import_and_verify(&import_passed, &import_error, &verification_passed,
+ key_filename, data_filename, signature_filename);
+ g_assert_true(import_passed);
+ g_assert_no_error(import_error);
+ g_clear_error(&import_error);
+ g_assert_true(verification_passed);
+}
+
+/* Test importing an invalid key. */
+static void
+dnf_keyring_add_public_key_invalid(void)
+{
+ g_autofree gchar *key_filename = NULL;
+ g_autofree gchar *data_filename = NULL;
+ g_autofree gchar *signature_filename = NULL;
+ gboolean import_passed;
+ g_autoptr(GError) import_error = NULL;
+ gboolean verification_passed;
+
+ key_filename = dnf_test_get_filename("dnf_keyring_add_public_key/input");
+ data_filename = dnf_test_get_filename("dnf_keyring_add_public_key/input");
+ signature_filename = dnf_test_get_filename("dnf_keyring_add_public_key/input.rsa.sig");
+
+ import_and_verify(&import_passed, &import_error, &verification_passed,
+ key_filename, data_filename, signature_filename);
+ g_assert_false(import_passed);
+ g_assert_nonnull(import_error);
+ g_clear_error(&import_error);
+ g_assert_false(verification_passed);
+}
+
static void
dnf_lock_func(void)
{
@@ -1274,6 +1450,8 @@ main(int argc, char **argv)
g_test_add_func("/libdnf/repo_loader{cache-dir-check}", dnf_repo_loader_cache_dir_check_func);
g_test_add_func("/libdnf/context", dnf_context_func);
g_test_add_func("/libdnf/context{cache-clean-check}", dnf_context_cache_clean_check_func);
+ g_test_add_func("/libdnf/dnf_keyring_add_public_key[valid]", dnf_keyring_add_public_key_valid);
+ g_test_add_func("/libdnf/dnf_keyring_add_public_key[invalid]", dnf_keyring_add_public_key_invalid);
g_test_add_func("/libdnf/lock", dnf_lock_func);
g_test_add_func("/libdnf/lock[threads]", dnf_lock_threads_func);
g_test_add_func("/libdnf/split_releasever", dnf_split_releasever_func);
--
2.53.0