Skip to content

Commit

Permalink
Implement rpmkeys --rebuild
Browse files Browse the repository at this point in the history
This rebuild the public key storage. If _keyring is set to a new value
keys from old storage are moved there and the old stores are deleted.
Keys are stored in the latest format. Keys no longer accepted are
dropped.

Resolves: #3347
  • Loading branch information
ffesti committed Nov 28, 2024
1 parent b40aa9f commit f886b2c
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 1 deletion.
10 changes: 10 additions & 0 deletions docs/man/rpmkeys.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The general forms of rpm digital signature commands are

**rpmkeys** {**-e\|\--erase\|-d\|\--delete**} *FINGERPRINT \...*

**rpmkeys** {**\--rebuild**}

**rpmkeys** {**-K\|\--checksig**} *PACKAGE\_FILE \...*

The **\--checksig** option checks all the digests and signatures
Expand Down Expand Up @@ -64,6 +66,14 @@ Erase the key(s) designated by *FINGERPRINT*. For example:

**rpmkeys** **\--erase 771b18d3d7baa28734333c424344591e1964c5fc**

Rebuild the key storage:

**rpmkeys** **\--rebuild**

If the storage backend was changed the keys will be moved. Outdated or
no longer supported keys will be dropped. Keys will be stored in the newest
storage format.

SEE ALSO
========

Expand Down
2 changes: 2 additions & 0 deletions include/rpm/rpmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,8 @@ rpmtsi rpmtsiInit(rpmts ts);
*/
rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types);

rpmRC rpmtsRebuildKeystore(rpmts ts);

#ifdef __cplusplus
}
#endif
Expand Down
104 changes: 104 additions & 0 deletions lib/keystore.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "system.h"

#include <filesystem>
#include <string>
#include <set>

#include <fcntl.h>
#include <unistd.h>
Expand All @@ -18,11 +20,13 @@
#include <rpm/rpmtypes.h>

#include "rpmts_internal.hh"
#include "rpmmacro_internal.hh"

#include "debug.h"

using std::string;
using namespace rpm;
namespace fs = std::filesystem;

static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp);

Expand Down Expand Up @@ -96,6 +100,50 @@ static rpmRC write_key_to_disk(rpmPubkey key, string & dir, string & filename, i
return rc;
}

rpmRC rebuild_dir(rpmtxn txn, keystore * store, rpmKeyring keys)
{

auto macros = rpm::macros();
auto [mrc, keyringpath] = macros.expand("%{_keyringpath}");
while ('/' == keyringpath.back())
keyringpath.pop_back();
std::string path = rpm::expand_path({rpmtxnRootDir(txn), keyringpath});
std::string tmppath = keyringpath + ".tmp/";
std::string oldpath = keyringpath + ".rpmold/";
std::error_code ec = {};
rpmRC rc = RPMRC_OK;

macros.push("_keyringpath", "", tmppath.c_str(), 0);

rpmPubkey key = NULL;
auto iter = rpmKeyringInitIterator(keys, 0);
while ((rc == RPMRC_OK) && (key = rpmKeyringIteratorNext(iter))) {
rc = store->import_key(txn, key, 0, 0);
}
rpmKeyringIteratorFree(iter);

if (rc != RPMRC_OK)
goto exit;

/* Ignore errors from (re)moving old directory as it might not exist */
fs::rename(rpm::join_path({std::string(rpmtxnRootDir(txn)), keyringpath}),
rpm::join_path({rpmtxnRootDir(txn), oldpath}), ec);
fs::rename(rpm::join_path({std::string(rpmtxnRootDir(txn)),
keyringpath + ".tmp"}),
rpm::join_path({rpmtxnRootDir(txn), keyringpath}), ec);
if (ec) {
rpmlog(RPMLOG_ERR, _("can't move new key store to %s: %s.\n"), rpm::join_path({rpmtxnRootDir(txn), keyringpath}).c_str(), ec.message().c_str());
rc = RPMRC_FAIL;
}
fs::remove_all(rpm::join_path({rpmtxnRootDir(txn), oldpath}));

exit:
macros.pop("_keyringpath");

return rc;
}



/*****************************************************************************/

Expand Down Expand Up @@ -150,6 +198,11 @@ rpmRC keystore_fs::import_key(rpmtxn txn, rpmPubkey key, int replace, rpmFlags f
return rc;
}

rpmRC keystore_fs::rebuild(rpmtxn txn, rpmKeyring keys)
{
return rebuild_dir(txn, this, keys);
}

/*****************************************************************************/

static int acquire_write_lock(rpmtxn txn)
Expand Down Expand Up @@ -235,6 +288,12 @@ rpmRC keystore_openpgp_cert_d::import_key(rpmtxn txn, rpmPubkey key, int replace
return rc;
}

rpmRC keystore_openpgp_cert_d::rebuild(rpmtxn txn, rpmKeyring keys)
{
return rebuild_dir(txn, this, keys);
}


/*****************************************************************************/

rpmRC keystore_rpmdb::load_keys(rpmtxn txn, rpmKeyring keyring)
Expand Down Expand Up @@ -330,6 +389,51 @@ rpmRC keystore_rpmdb::import_key(rpmtxn txn, rpmPubkey key, int replace, rpmFlag
return rc;
}

rpmRC keystore_rpmdb::rebuild(rpmtxn txn, rpmKeyring keys)
{
rpmRC rc = RPMRC_OK;
std::set<unsigned int> packages = {};
Header h = NULL;
rpmPubkey key = NULL;

auto iter = rpmKeyringInitIterator(keys, 0);
while ((key = rpmKeyringIteratorNext(iter))) {
if (makePubkeyHeader(rpmtxnTs(txn), key, &h) != 0) {
rpmlog(RPMLOG_ERR, _("can't create header for key %s\n"),
rpmPubkeyFingerprintAsHex(key));
rc = RPMRC_FAIL;
break;
}
if ((rc = rpmtsImportHeader(txn, h, 0)) != RPMRC_OK) {
headerFree(h);
rpmlog(RPMLOG_ERR, _("can't add header to rpmdb for key %s\n"),
rpmPubkeyFingerprintAsHex(key));
break;
}
packages.insert(headerGetInstance(h));
headerFree(h);
}
rpmKeyringIteratorFree(iter);

if (rc != RPMRC_OK) {
return rc;
}

rpmdbMatchIterator mi = rpmtsInitIterator(rpmtxnTs(txn), RPMDBI_NAME, "gpg-pubkey", 0);
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (!packages.count(headerGetInstance(h))) {
rpmRC rrc = rpmdbRemove(rpmtsGetRdb(rpmtxnTs(txn)), headerGetInstance(h)) ?
RPMRC_FAIL : RPMRC_OK;
if (rc != RPMRC_OK) {
rpmlog(RPMLOG_WARNING, "can't remove key %s", headerGetString(h, RPMTAG_NEVR));
rc = rrc;
}
}
}
rpmdbFreeIterator(mi);
return rc;
}

static void addGpgProvide(Header h, const char *n, const char *v)
{
rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
Expand Down
4 changes: 4 additions & 0 deletions lib/keystore.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public:
virtual rpmRC load_keys(rpmtxn txn, rpmKeyring keyring) = 0;
virtual rpmRC import_key(rpmtxn txn, rpmPubkey key, int replace = 1, rpmFlags flags = 0) = 0;
virtual rpmRC delete_key(rpmtxn txn, rpmPubkey key) = 0;
virtual rpmRC rebuild(rpmtxn txn, rpmKeyring keys) = 0;

virtual ~keystore() = default;
};
Expand All @@ -22,6 +23,7 @@ public:
virtual rpmRC load_keys(rpmtxn txn, rpmKeyring keyring);
virtual rpmRC import_key(rpmtxn txn, rpmPubkey key, int replace = 1, rpmFlags flags = 0);
virtual rpmRC delete_key(rpmtxn txn, rpmPubkey key);
virtual rpmRC rebuild(rpmtxn txn, rpmKeyring keys);

private:
rpmRC delete_key(rpmtxn txn, const std::string & keyid, const std::string & newname = "");
Expand All @@ -32,6 +34,7 @@ public:
virtual rpmRC load_keys(rpmtxn txn, rpmKeyring keyring);
virtual rpmRC import_key(rpmtxn txn, rpmPubkey key, int replace = 1, rpmFlags flags = 0);
virtual rpmRC delete_key(rpmtxn txn, rpmPubkey key);
virtual rpmRC rebuild(rpmtxn txn, rpmKeyring keys);

private:
rpmRC delete_key(rpmtxn txn, const std::string & keyid, unsigned int newinstance = 0);
Expand All @@ -42,6 +45,7 @@ public:
virtual rpmRC load_keys(rpmtxn txn, rpmKeyring keyring);
virtual rpmRC import_key(rpmtxn txn, rpmPubkey key, int replace = 1, rpmFlags flags = 0);
virtual rpmRC delete_key(rpmtxn txn, rpmPubkey key);
virtual rpmRC rebuild(rpmtxn txn, rpmKeyring keys);
};

}; /* namespace */
Expand Down
75 changes: 75 additions & 0 deletions lib/rpmts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <fcntl.h>
#include <errno.h>

#include <filesystem>

#include <rpm/rpmtypes.h>
#include <rpm/rpmlib.h> /* rpmReadPackage etc */
#include <rpm/rpmmacro.h>
Expand All @@ -31,13 +33,15 @@
#include "rpmts_internal.hh"
#include "rpmte_internal.hh"
#include "rpmlog_internal.hh"
#include "rpmmacro_internal.hh"
#include "misc.hh"
#include "rpmtriggers.hh"

#include "debug.h"

using std::string;
using namespace rpm;
namespace fs = std::filesystem;

/**
* Iterator across transaction elements, forward on install, backward on erase.
Expand Down Expand Up @@ -395,6 +399,77 @@ rpmRC rpmtxnDeletePubkey(rpmtxn txn, rpmPubkey key)
return rc;
}

rpmRC rpmtsRebuildKeystore(rpmts ts)
{
rpmRC rc = RPMRC_OK;
rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE);
rpmVSFlags oflags = rpmtsVSFlags(ts);

ts->keyring = rpmKeyringFree(ts->keyring);
rpmtsOpenDB(ts, O_RDWR);

/* XXX keyring wont load if sigcheck disabled, force it temporarily */
rpmtsSetVSFlags(ts, (oflags & ~RPMVSF_MASK_NOSIGNATURES));

rpmKeyring keyring = rpmKeyringNew();

keystore_fs ks_fs = {};
rpmKeyring keyring_fs = rpmKeyringNew();
ks_fs.load_keys(txn, keyring);

keystore_rpmdb ks_rpmdb = {};
rpmKeyring keyring_rpmdb = rpmKeyringNew();
ks_rpmdb.load_keys(txn, keyring_rpmdb);

keystore_openpgp_cert_d ks_opengpg = {};
rpmKeyring keyring_openpgp = rpmKeyringNew();
ks_opengpg.load_keys(txn, keyring_openpgp);

for (auto kr: {keyring_fs, keyring_rpmdb, keyring_openpgp}) {
rpmKeyringIterator iter = rpmKeyringInitIterator(kr, 0);
rpmPubkey key = NULL;
const unsigned char * pkt = NULL;
size_t pktlen = 0;
char *lints = NULL;
while ((key = rpmKeyringIteratorNext(iter)) != NULL) {
rpmPubkeyRawData(key, &pkt, &pktlen);
int lrc = pgpPubKeyLint(pkt, pktlen, &lints) ;
if (lints) {
if (lrc != RPMRC_OK)
rpmlog(RPMLOG_WARNING, "dropping public key %s:\n", rpmPubkeyFingerprintAsHex(key));
rpmlog(RPMLOG_WARNING, "%s\n", lints);
free(lints);
if (lrc != RPMRC_OK)
continue;
}
rpmKeyringModify(keyring, key, RPMKEYRING_MERGE);
}
rpmKeyringIteratorFree(iter);
}

keystore * ks = getKeystore(ts);
rc = ks->rebuild(txn, keyring);

if (dynamic_cast<keystore_rpmdb*>(ks)) {
fs::remove_all(rpm::expand_path({rpmtxnRootDir(txn),
"%{_keyringpath}"}));
} else {
/* remove all gpg-pubkey packages */
rpmKeyring kr = rpmKeyringNew();
ks_rpmdb.rebuild(txn, kr);
rpmKeyringFree(kr);
}

rpmKeyringFree(keyring);
rpmKeyringFree(keyring_fs);
rpmKeyringFree(keyring_rpmdb);
rpmKeyringFree(keyring_openpgp);
rpmtxnEnd(txn);
rpmtsSetVSFlags(ts, oflags);

return rc;
}

rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
{
rpmRC rc = RPMRC_FAIL;
Expand Down
Loading

0 comments on commit f886b2c

Please sign in to comment.