From 5c1549a73171f041da01260e8e21745961f2a080 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ale=C5=A1=20Mat=C4=9Bj?= Date: Mon, 29 Mar 2021 09:22:09 +0200 Subject: [PATCH] [PATCH] Hardening: add signature check with rpmcliVerifySignatures This api is not ideal but works for now. We don't have to set installroot for the used transaction because we set keyring which is used to retrieve the keys. = changelog = msg: Hardening: add signature check with rpmcliVerifySignatures type: security resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1932079 CVE-2021-3445 RhBug:1932079 RhBug:1932089 RhBug:1932090 Related: CVE-2021-3421, CVE-2021-20271 Gbp-Pq: Name 0014-Hardening-add-signature-check-with-rpmcliVerifySigna.patch --- libdnf/dnf-keyring.cpp | 52 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/libdnf/dnf-keyring.cpp b/libdnf/dnf-keyring.cpp index eec58c6..62a6248 100644 --- a/libdnf/dnf-keyring.cpp +++ b/libdnf/dnf-keyring.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "catch-error.hpp" #include "dnf-types.h" @@ -216,6 +218,26 @@ dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try return TRUE; } CATCH_TO_GERROR(FALSE) +static int +rpmcliverifysignatures_log_handler_cb(rpmlogRec rec, rpmlogCallbackData data) +{ + GString **string =(GString **) data; + + /* create string if required */ + if (*string == NULL) + *string = g_string_new(""); + + /* if text already exists, join them */ + if ((*string)->len > 0) + g_string_append(*string, ": "); + g_string_append(*string, rpmlogRecMessage(rec)); + + /* remove the trailing /n which rpm does */ + if ((*string)->len > 0) + g_string_truncate(*string,(*string)->len - 1); + return 0; +} + /** * dnf_keyring_check_untrusted_file: */ @@ -232,6 +254,10 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring, rpmtd td = NULL; rpmts ts = NULL; + char *path = g_strdup(filename); + char *path_array[2] = {path, NULL}; + g_autoptr(GString) rpm_error = NULL; + /* open the file for reading */ fd = Fopen(filename, "r.fdio"); if (fd == NULL) { @@ -252,9 +278,27 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring, goto out; } - /* we don't want to abort on missing keys */ ts = rpmtsCreate(); - rpmtsSetVSFlags(ts, _RPMVSF_NOSIGNATURES); + + if (rpmtsSetKeyring(ts, keyring) < 0) { + g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, "failed to set keyring"); + goto out; + } + rpmtsSetVfyLevel(ts, RPMSIG_SIGNATURE_TYPE); + rpmlogSetCallback(rpmcliverifysignatures_log_handler_cb, &rpm_error); + + // rpm doesn't provide any better API call than rpmcliVerifySignatures (which is for CLI): + // - use path_array as input argument + // - gather logs via callback because we don't want to print anything if check is successful + if (rpmcliVerifySignatures(ts, (char * const*) path_array)) { + g_set_error(error, + DNF_ERROR, + DNF_ERROR_GPG_SIGNATURE_INVALID, + "%s could not be verified.\n%s", + filename, + (rpm_error ? rpm_error->str : "UNKNOWN ERROR")); + goto out; + } /* read in the file */ rc = rpmReadPackageFile(ts, fd, filename, &hdr); @@ -318,6 +362,10 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring, g_debug("%s has been verified as trusted", filename); ret = TRUE; out: + rpmlogSetCallback(NULL, NULL); + + if (path != NULL) + g_free(path); if (dig != NULL) pgpFreeDig(dig); if (td != NULL) { -- 2.30.2