diff --git a/docs/man/rpmkeys.8.md b/docs/man/rpmkeys.8.md index 1b27f06247..e56d6458fd 100644 --- a/docs/man/rpmkeys.8.md +++ b/docs/man/rpmkeys.8.md @@ -27,6 +27,8 @@ The general forms of rpm digital signature commands are **rpmkeys** {**-e\|\--erase\|-d\|\--delete**} *FINGERPRINT \...* +**rpmkeys** {**\--rebuild**} \[*\--drop_backends*\] \[*--\include_backend_backend BACKEND*\] \[*--\include_backend_backend BACKEND*\] + **rpmkeys** {**-K\|\--checksig**} *PACKAGE\_FILE \...* The **\--checksig** option checks all the digests and signatures @@ -64,6 +66,22 @@ Erase the key(s) designated by *FINGERPRINT*. For example: **rpmkeys** **\--erase 771b18d3d7baa28734333c424344591e1964c5fc** +Rebuild the key storage: + +**rpmkeys** **\--rebuild** + +Recreate the public key storage. Update to the latest format and drop +unreadable keys. This will fail if there are public keys in other +storage backends. + +Adding **\--drop_backends** will delete those keys during rebuilding. + +Adding **\--include_backend BACKEND** will keep the keys from the given +backend and add it to the configured one during rebuilding. +The parameter can be given more than once. Valid values for the backends +are **rpmdb**, **fs**, **openpgp**. This can be used to convert from +one key storage to another. + SEE ALSO ======== diff --git a/include/rpm/rpmkeyring.h b/include/rpm/rpmkeyring.h index d0764b6f81..51e3ac9040 100644 --- a/include/rpm/rpmkeyring.h +++ b/include/rpm/rpmkeyring.h @@ -23,7 +23,8 @@ extern "C" { typedef enum rpmKeyringModifyMode_e { RPMKEYRING_ADD = 1, RPMKEYRING_REPLACE = 2, - RPMKEYRING_DELETE = 3 + RPMKEYRING_DELETE = 3, + RPMKEYRING_MERGE = 4, } rpmKeyringModifyMode; @@ -39,6 +40,13 @@ rpmKeyring rpmKeyringNew(void); */ rpmKeyring rpmKeyringFree(rpmKeyring keyring); +/** \ingroup rpmkeyring + * Check if there are no keys in the keyring. + * @param keyring keyring handle + * @return 1 if keyring is empy, 0 otherwise + */ +int rpmKeyringIsEmpty(rpmKeyring keyring); + /** \ingroup rpmkeyring * Add a public key to keyring. * @param keyring keyring handle @@ -133,6 +141,15 @@ rpmPubkey rpmPubkeyFree(rpmPubkey key); */ rpmPubkey rpmPubkeyLink(rpmPubkey key); + +/** \ingroup rpmkeyring + * Return pubkey as raw bytes + * @param key Pubkey + * @param pkt key data + * @param pktlen Length of key data + */ +void rpmPubkeyRawData(rpmPubkey key, unsigned const char ** pkt, size_t * pktlen); + /** \ingroup rpmkeyring * Return base64 encoding of pubkey * @param key Pubkey diff --git a/include/rpm/rpmts.h b/include/rpm/rpmts.h index 86ca62e0ef..162cfe26f4 100644 --- a/include/rpm/rpmts.h +++ b/include/rpm/rpmts.h @@ -754,6 +754,8 @@ rpmtsi rpmtsiInit(rpmts ts); */ rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types); +rpmRC rpmtsRebuildKeystore(rpmts ts, char ** loadBackends, int flags); + #ifdef __cplusplus } #endif diff --git a/lib/keystore.cc b/lib/keystore.cc index 382a028e83..112ecb140e 100644 --- a/lib/keystore.cc +++ b/lib/keystore.cc @@ -1,6 +1,8 @@ #include "system.h" +#include #include +#include #include #include @@ -18,11 +20,13 @@ #include #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); @@ -96,6 +100,63 @@ static rpmRC write_key_to_disk(rpmPubkey key, string & dir, string & filename, i return rc; } +rpmRC rpm::check_backends(rpmtxn txn, rpmts ts) +{ + rpmRC rc = RPMRC_OK; + + keystore_fs ks_fs = {}; + keystore_rpmdb ks_rpmdb = {}; + keystore_openpgp_cert_d ks_opengpg = {}; + + for (keystore *ks : std::vector {&ks_fs, &ks_rpmdb, &ks_opengpg}) { + if (ks->get_name() == ts->keystore->get_name()) + continue; + rpmKeyring keyring = rpmKeyringNew(); + ks->load_keys(txn, keyring); + if (!rpmKeyringIsEmpty(keyring)) { + rpmlog(RPMLOG_WARNING, _("there are public keys in the %s backend which is not the one configured (%s); use rpmkeys --rebuild to integrate or discard them\n"), ks->get_name().c_str(), ts->keystore->get_name().c_str()); + rc = RPMRC_FAIL; + } + rpmKeyringFree(keyring); + } + return rc; +} + +rpmRC rebuild_dir(rpmtxn txn, keystore * store, rpmKeyring keys) +{ + + auto macros = rpm::macros(); + std::string keyringpath = rpm::expand_path({"%{_keyringpath}"}); + std::string path = rpm::expand_path({rpmtxnRootDir(txn), keyringpath}); + std::string oldpath = path + ".rpmold/"; + std::error_code ec = {}; + rpmRC rc = RPMRC_OK; + macros.push("_keyringpath", "", (keyringpath + ".tmp/").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(path, oldpath, ec); + fs::rename(path + ".tmp", path, ec); + if (ec) { + rpmlog(RPMLOG_ERR, _("can't move new key store to %s: %s.\n"), path.c_str(), ec.message().c_str()); + rc = RPMRC_FAIL; + } + fs::remove_all(oldpath); + + exit: + macros.pop("_keyringpath"); + + return rc; +} /*****************************************************************************/ @@ -150,6 +211,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) @@ -235,6 +301,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) @@ -336,6 +408,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 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); diff --git a/lib/keystore.hh b/lib/keystore.hh index 53fd53530a..c17ecb6996 100644 --- a/lib/keystore.hh +++ b/lib/keystore.hh @@ -8,20 +8,26 @@ namespace rpm { +rpmRC check_backends(rpmtxn txn, rpmts ts); + class keystore { public: + virtual std::string get_name() { return "None"; }; 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; }; class keystore_fs : public keystore { public: + virtual std::string get_name() { return "fs"; }; 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 = ""); @@ -29,9 +35,11 @@ private: class keystore_rpmdb : public keystore { public: + virtual std::string get_name() { return "rpmdb"; }; 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); @@ -39,9 +47,11 @@ private: class keystore_openpgp_cert_d : public keystore { public: + virtual std::string get_name() { return "openpgp"; }; 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 */ diff --git a/lib/rpmts.cc b/lib/rpmts.cc index e01ddf92f9..e604ed4e70 100644 --- a/lib/rpmts.cc +++ b/lib/rpmts.cc @@ -9,6 +9,8 @@ #include #include +#include + #include #include /* rpmReadPackage etc */ #include @@ -31,6 +33,7 @@ #include "rpmts_internal.hh" #include "rpmte_internal.hh" #include "rpmlog_internal.hh" +#include "rpmmacro_internal.hh" #include "misc.hh" #include "rpmtriggers.hh" @@ -38,6 +41,7 @@ using std::string; using namespace rpm; +namespace fs = std::filesystem; /** * Iterator across transaction elements, forward on install, backward on erase. @@ -299,6 +303,7 @@ static void loadKeyring(rpmts ts) rpmtxn txn = rpmtxnBegin(ts, RPMTXN_READ); if (txn) { ts->keystore->load_keys(txn, ts->keyring); + check_backends(txn, ts); rpmtxnEnd(txn); } } @@ -321,7 +326,6 @@ rpmRC rpmtxnImportPubkey(rpmtxn txn, const unsigned char * pkt, size_t pktlen) rpmRC rc = RPMRC_FAIL; /* assume failure */ char *lints = NULL; rpmPubkey pubkey = NULL; - rpmPubkey oldkey = NULL; rpmKeyring keyring = NULL; int krc; @@ -353,26 +357,13 @@ rpmRC rpmtxnImportPubkey(rpmtxn txn, const unsigned char * pkt, size_t pktlen) if ((pubkey = rpmPubkeyNew(pkt, pktlen)) == NULL) goto exit; - oldkey = rpmKeyringLookupKey(keyring, pubkey); - if (oldkey) { - rpmPubkey mergedkey = NULL; - if (rpmPubkeyMerge(oldkey, pubkey, &mergedkey) != RPMRC_OK) - goto exit; - if (!mergedkey) { - rc = RPMRC_OK; /* already have key */ - goto exit; - } - rpmPubkeyFree(pubkey); - pubkey = mergedkey; - } - - krc = rpmKeyringModify(keyring, pubkey, oldkey ? RPMKEYRING_REPLACE : RPMKEYRING_ADD); + krc = rpmKeyringModify(keyring, pubkey, RPMKEYRING_MERGE); if (krc < 0) goto exit; /* If we dont already have the key, make a persistent record of it */ if (krc == 0) { - rc = ts->keystore->import_key(txn, pubkey, oldkey ? 1 : 0); + rc = ts->keystore->import_key(txn, pubkey, 1); } else { rc = RPMRC_OK; /* already have key */ } @@ -380,7 +371,6 @@ rpmRC rpmtxnImportPubkey(rpmtxn txn, const unsigned char * pkt, size_t pktlen) exit: /* Clean up. */ rpmPubkeyFree(pubkey); - rpmPubkeyFree(oldkey); rpmKeyringFree(keyring); return rc; @@ -410,6 +400,95 @@ rpmRC rpmtxnDeletePubkey(rpmtxn txn, rpmPubkey key) return rc; } +rpmRC rpmtsRebuildKeystore(rpmts ts, char ** loadBackends, int flags) +{ + rpmRC rc = RPMRC_OK; + rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE); + rpmVSFlags oflags = rpmtsVSFlags(ts); + + rpmtsOpenDB(ts, O_RDWR); + + /* XXX keyring wont load if sigcheck disabled, force it temporarily */ + rpmtsSetVSFlags(ts, (oflags & ~RPMVSF_MASK_NOSIGNATURES)); + + keystore * ts_keystore = getKeystore(ts); + rpmKeyring keyring = rpmKeyringNew(); + + keystore_fs ks_fs = {}; + keystore_rpmdb ks_rpmdb = {}; + keystore_openpgp_cert_d ks_opengpg = {}; + + for (keystore * ks: std::vector{&ks_fs, &ks_rpmdb, &ks_opengpg}) { + rpmKeyring kr = rpmKeyringNew(); + ks->load_keys(txn, kr); + + char ** name = loadBackends; + if (name) { + for (;*name; name++) { + if (!strcmp(*name, ks->get_name().c_str())) + break; + + } + } + + /* backend not to be included */ + if (ks->get_name() != ts->keystore->get_name() && (!name || !*name)) { + if (!rpmKeyringIsEmpty(kr) && !flags) { + rpmlog(RPMLOG_ERR, _("public key backend %s is not empty\n"), + ks->get_name().c_str()); + rpmKeyringFree(kr); + rc = RPMRC_FAIL; + goto exit; + } + rpmKeyringFree(kr); + continue; + } + + rpmKeyringIterator iter = rpmKeyringInitIterator(kr, 0); + rpmPubkey key = NULL; + while ((key = rpmKeyringIteratorNext(iter)) != NULL) { + const unsigned char * pkt = NULL; + size_t pktlen = 0; + char *lints = 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); + rpmKeyringFree(kr); + } + + rc = ts_keystore->rebuild(txn, keyring); + + if (dynamic_cast(ts_keystore)) { + 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); + } + + exit: + + ts->keyring = rpmKeyringFree(ts->keyring); + rpmKeyringFree(keyring); + rpmtxnEnd(txn); + rpmtsSetVSFlags(ts, oflags); + + return rc; +} + rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen) { rpmRC rc = RPMRC_FAIL; diff --git a/rpmio/rpmkeyring.cc b/rpmio/rpmkeyring.cc index 4ed4facbb9..0cfad81a0d 100644 --- a/rpmio/rpmkeyring.cc +++ b/rpmio/rpmkeyring.cc @@ -71,6 +71,14 @@ rpmKeyring rpmKeyringFree(rpmKeyring keyring) return NULL; } +int rpmKeyringIsEmpty(rpmKeyring keyring) +{ + if (!keyring) return 1; + rdlock lock(keyring->mutex); + return keyring->keys.empty(); +} + + rpmKeyringIterator rpmKeyringInitIterator(rpmKeyring keyring, int unused) { if (!keyring || unused != 0) @@ -120,11 +128,31 @@ rpmKeyringIterator rpmKeyringIteratorFree(rpmKeyringIterator iterator) int rpmKeyringModify(rpmKeyring keyring, rpmPubkey key, rpmKeyringModifyMode mode) { int rc = 1; /* assume already seen key */ + rpmPubkey mergedkey = NULL; if (keyring == NULL || key == NULL) return -1; - if (mode != RPMKEYRING_ADD && mode != RPMKEYRING_DELETE && mode != RPMKEYRING_REPLACE) + if (mode < RPMKEYRING_ADD || mode > RPMKEYRING_MERGE) return -1; + if (mode == RPMKEYRING_MERGE) { + rpmPubkey oldkey = rpmKeyringLookupKey(keyring, key); + if (oldkey) { + if (rpmPubkeyMerge(oldkey, key, &mergedkey) != RPMRC_OK) { + rpmPubkeyFree(oldkey); + return -1; + } + if (!mergedkey) { + mode = RPMKEYRING_ADD; + } else { + key = mergedkey; + mode = RPMKEYRING_REPLACE; + } + rpmPubkeyFree(oldkey); + } else { + mode = RPMKEYRING_ADD; + } + } + /* check if we already have this key, but always wrlock for simplicity */ wrlock lock(keyring->mutex); auto range = keyring->keys.equal_range(key->keyid); @@ -147,7 +175,8 @@ int rpmKeyringModify(rpmKeyring keyring, rpmPubkey key, rpmKeyringModifyMode mod rpmPubkeyFree(item->second); keyring->keys.erase(item); rc = 0; - } else if ((item == range.second && mode == RPMKEYRING_ADD) || mode == RPMKEYRING_REPLACE) { + } + if ((item == range.second && mode == RPMKEYRING_ADD) || mode == RPMKEYRING_REPLACE) { int subkeysCount = 0; rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount); keyring->keys.insert({key->keyid, rpmPubkeyLink(key)}); @@ -162,6 +191,8 @@ int rpmKeyringModify(rpmKeyring keyring, rpmPubkey key, rpmKeyringModifyMode mod free(subkeys); rc = 0; } + /* strip initial nref */ + rpmPubkeyFree(mergedkey); return rc; } @@ -343,6 +374,17 @@ rpmPubkey rpmPubkeyLink(rpmPubkey key) return key; } +void rpmPubkeyRawData(rpmPubkey key, unsigned const char ** pkt, size_t * pktlen) +{ + if (key) { + *pkt = key->pkt.data(); + *pktlen = key->pkt.size(); + } else { + *pkt = NULL; + *pktlen = 0; + } +} + char * rpmPubkeyBase64(rpmPubkey key) { char *enc = NULL; diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at index c07c712b82..8198f0316d 100644 --- a/tests/rpmsigdig.at +++ b/tests/rpmsigdig.at @@ -1924,3 +1924,171 @@ hello-1.0.tar.gz:(none) ], []) RPMTEST_CLEANUP + +AT_SETUP([keyring rebuild rpmdb]) +AT_KEYWORDS([rpmkeys signature]) +RPMDB_INIT + +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-ed25519-test.pub +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring openpgp" \ + --import /data/keys/rpm.org-rsa-2048-add-subkey.asc +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/alice.asc + +RPMTEST_CHECK([[ +runroot rpmkeys --define "_keyring rpmdb" --rebuild +]], +[2], +[], +[error: public key backend fs is not empty +]) + +RPMTEST_CHECK([[ +runroot rpmkeys --define "_keyring rpmdb" --rebuild --include_backend fs --include_backend openpgp +runroot rpm -qa gpg-pubkey +runroot rpmkeys --define "_keyring rpmdb" --list +echo "===============================================" +runroot rpmkeys --define "_keyring fs" --list +runroot rpmkeys --define "_keyring openpgp" --list +runroot rpmkeys --define "_keyring rpmdb" -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm | grep "Header OpenPGP" +]], +[0], +[gpg-pubkey-771b18d3d7baa28734333c424344591e1964c5fc-58e63918 +gpg-pubkey-152bb32fd9ca982797e835cfb0645aec757bf69e-661d22a8 +gpg-pubkey-b6542f92f30650c36b6f41bcb3a771bfeb04e625-62521e00 +771b18d3d7baa28734333c424344591e1964c5fc rpm.org RSA testkey public key +152bb32fd9ca982797e835cfb0645aec757bf69e rpm.org ed25519 testkey public key +b6542f92f30650c36b6f41bcb3a771bfeb04e625 Alice public key +=============================================== + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK +], +[ignore]) +RPMTEST_CLEANUP + +AT_SETUP([keyring rebuild rpmdb 2]) +AT_KEYWORDS([rpmkeys signature]) +RPMDB_INIT + +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-ed25519-test.pub +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring openpgp" \ + --import /data/keys/rpm.org-rsa-2048-add-subkey.asc +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/alice.asc + +RPMTEST_CHECK([[ +runroot rpmkeys --define "_keyring rpmdb" --rebuild --include_backend openpgp --drop_backends +runroot rpm -qa gpg-pubkey +runroot rpmkeys --define "_keyring rpmdb" --list +echo "===============================================" +runroot rpmkeys --define "_keyring fs" --list +runroot rpmkeys --define "_keyring openpgp" --list +runroot rpmkeys --define "_keyring rpmdb" -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm | grep "Header OpenPGP" +]], +[0], +[gpg-pubkey-771b18d3d7baa28734333c424344591e1964c5fc-58e63918 +gpg-pubkey-152bb32fd9ca982797e835cfb0645aec757bf69e-661d22a8 +771b18d3d7baa28734333c424344591e1964c5fc rpm.org RSA testkey public key +152bb32fd9ca982797e835cfb0645aec757bf69e rpm.org ed25519 testkey public key +=============================================== + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK +], +[ignore]) +RPMTEST_CLEANUP + +AT_SETUP([keyring rebuild fs]) +AT_KEYWORDS([rpmkeys signature]) +RPMDB_INIT + +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-ed25519-test.pub +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring openpgp" \ + --import /data/keys/rpm.org-rsa-2048-add-subkey.asc +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/alice.asc + +RPMTEST_CHECK([[ +runroot rpmkeys --define "_keyring fs" --rebuild --include_backend rpmdb --include_backend openpgp +runroot rpmkeys --define "_keyring fs" --list +echo "===============================================" +runroot rpmkeys --define "_keyring rpmdb" --list +runroot rpmkeys --define "_keyring openpgp" --list +runroot rpmkeys --define "_keyring fs" -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm | grep "Header OpenPGP" +]], +[0], +[771b18d3d7baa28734333c424344591e1964c5fc rpm.org RSA testkey public key +152bb32fd9ca982797e835cfb0645aec757bf69e rpm.org ed25519 testkey public key +b6542f92f30650c36b6f41bcb3a771bfeb04e625 Alice public key +=============================================== + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK +], +[ignore]) + +RPMTEST_CLEANUP + +AT_SETUP([keyring rebuild openpgp]) +AT_KEYWORDS([rpmkeys signature]) +RPMDB_INIT + +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring rpmdb" \ + --import /data/keys/rpm.org-ed25519-test.pub +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/rpm.org-rsa-2048-test.pub +runroot rpmkeys \ + --define "_keyring openpgp" \ + --import /data/keys/rpm.org-rsa-2048-add-subkey.asc +runroot rpmkeys \ + --define "_keyring fs" \ + --import /data/keys/alice.asc + +RPMTEST_CHECK([[ +runroot rpmkeys --define "_keyring openpgp" --rebuild --include_backend fs --include_backend rpmdb +runroot rpmkeys --define "_keyring openpgp" --list +echo "===============================================" +runroot rpmkeys --define "_keyring fs" --list +runroot rpmkeys --define "_keyring rpmdb" --list +runroot rpmkeys --define "_keyring openpgp" -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm | grep "Header OpenPGP" +]], +[0], +[771b18d3d7baa28734333c424344591e1964c5fc rpm.org RSA testkey public key +152bb32fd9ca982797e835cfb0645aec757bf69e rpm.org ed25519 testkey public key +b6542f92f30650c36b6f41bcb3a771bfeb04e625 Alice public key +=============================================== + Header OpenPGP V4 EdDSA/SHA512 signature, key fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK +], +[ignore]) + +RPMTEST_CLEANUP diff --git a/tools/rpmkeys.cc b/tools/rpmkeys.cc index 89a2a7131e..98e23a1214 100644 --- a/tools/rpmkeys.cc +++ b/tools/rpmkeys.cc @@ -15,10 +15,13 @@ enum modes { MODE_DELKEY = (1 << 2), MODE_LISTKEY = (1 << 3), MODE_EXPORTKEY = (1 << 4), + MODE_REBUILD = (1 << 5), }; static int mode = 0; static int test = 0; +static char ** backends = NULL; +static int rebuildflags = 0; static struct poptOption keyOptsTable[] = { { "checksig", 'K', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_CHECKSIG, @@ -35,6 +38,12 @@ static struct poptOption keyOptsTable[] = { N_("Erase keys from RPM keyring"), NULL }, { "list", 'l', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_LISTKEY, N_("list keys from RPM keyring"), NULL }, + { "rebuild", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_REBUILD, + N_("rebuild the keyring - convert to current backend"), NULL }, + { "include_backend", '\0', POPT_ARG_ARGV, &backends, 0, + N_("include other backends when rebuilding current backend"), NULL }, + { "drop_backends", '\0', POPT_ARG_NONE, &rebuildflags, 0, + N_("drop keys from other backends when rebuilding"), NULL }, POPT_TABLEEND }; @@ -149,7 +158,8 @@ int main(int argc, char *argv[]) args = (ARGV_const_t) poptGetArgs(optCon); - if (args == NULL && mode != MODE_LISTKEY && mode != MODE_EXPORTKEY) + if (args == NULL && mode != MODE_LISTKEY && mode != MODE_EXPORTKEY && + mode != MODE_REBUILD) argerror(_("no arguments given")); ts = rpmtsCreate(); @@ -183,6 +193,23 @@ int main(int argc, char *argv[]) ec = matchingKeys(ts, args, printKey); break; } + case MODE_REBUILD: + { + + if (backends) { + for (char** strptr = backends; *strptr; strptr++) { + if (!strcmp(*strptr, "rpmdb") && + !strcmp(*strptr, "fs") && + !strcmp(*strptr, "rpmpgp")) { + rpmlog(RPMLOG_ERR, _("unknown backend: %s\n"), *strptr); + ec = -1; + break; + } + } + } + ec = rpmtsRebuildKeystore(ts, backends, rebuildflags); + break; + } default: argerror(_("only one major mode may be specified")); } @@ -192,6 +219,10 @@ int main(int argc, char *argv[]) rpmcliFini(optCon); fflush(stderr); fflush(stdout); + if (backends) + for (char** strptr = backends; *strptr; strptr++) + free(*strptr); + free(backends); if (ferror(stdout) || ferror(stderr)) return 255; /* I/O error */ return ec;