Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
ffesti committed Nov 7, 2024
1 parent a43c404 commit a3fc1c0
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 36 deletions.
178 changes: 142 additions & 36 deletions lib/keystore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <string>

#include <fcntl.h>
#include <unistd.h>

#include <rpm/header.h>
#include <rpm/rpmbase64.h>
Expand All @@ -24,11 +25,11 @@ using namespace rpm;

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

rpmRC keystore_fs::load_keys(rpmtxn txn, rpmKeyring keyring)
static rpmRC load_keys_from_glob(rpmtxn txn, rpmKeyring keyring, string glob)
{
ARGV_t files = NULL;
/* XXX TODO: deal with chroot path issues */
char *pkpath = rpmGetPath(rpmtxnRootDir(txn), "%{_keyringpath}/*.key", NULL);
char *pkpath = rpmGetPath(rpmtxnRootDir(txn), glob.c_str(), NULL);

rpmlog(RPMLOG_DEBUG, "loading keyring from pubkeys in %s\n", pkpath);
if (rpmGlob(pkpath, NULL, &files)) {
Expand All @@ -55,6 +56,53 @@ rpmRC keystore_fs::load_keys(rpmtxn txn, rpmKeyring keyring)
return RPMRC_OK;
}

static rpmRC write_key_to_disk(rpmPubkey key, string & dir, string & filename, int replace, rpmFlags flags)
{
rpmRC rc = RPMRC_FAIL;
char *keyval = rpmPubkeyArmorWrap(key);
string tmppath = "";
string path = dir + "/" + filename;

if (replace) {
tmppath = dir + "/" + filename + ".new";
unlink(tmppath.c_str());
}

if (rpmMkdirs(NULL, dir.c_str())) {
rpmlog(RPMLOG_ERR, _("failed to create keyring directory %s: %s\n"),
path.c_str(), strerror(errno));
goto exit;
}

if (FD_t fd = Fopen(replace ? tmppath.c_str() : path.c_str(), "wx")) {
size_t keylen = strlen(keyval);
if (Fwrite(keyval, 1, keylen, fd) == keylen)
rc = RPMRC_OK;
Fclose(fd);
}
if (!rc && replace && rename(tmppath.c_str(), path.c_str()) != 0)
rc = RPMRC_FAIL;

if (rc) {
rpmlog(RPMLOG_ERR, _("failed to import key: %s: %s\n"),
replace ? tmppath.c_str() : path.c_str(), strerror(errno));
if (replace)
unlink(tmppath.c_str());
}

exit:
free(keyval);
return rc;
}


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

rpmRC keystore_fs::load_keys(rpmtxn txn, rpmKeyring keyring)
{
return load_keys_from_glob(txn, keyring, "%{_keyringpath}/*.key");
}

rpmRC keystore_fs::delete_key(rpmtxn txn, const string & keyid, const string & newname)
{
rpmRC rc = RPMRC_NOTFOUND;
Expand Down Expand Up @@ -82,55 +130,113 @@ rpmRC keystore_fs::delete_key(rpmtxn txn, rpmPubkey key)
rpmRC keystore_fs::import_key(rpmtxn txn, rpmPubkey key, int replace, rpmFlags flags)
{
rpmRC rc = RPMRC_FAIL;
const char *fp = rpmPubkeyFingerprintAsHex(key);
char *keyfmt = rstrscat(NULL, "gpg-pubkey-", fp, ".key", NULL);
char *keyval = rpmPubkeyArmorWrap(key);
char *path = rpmGenPath(rpmtxnRootDir(txn), "%{_keyringpath}/", keyfmt);
char *tmppath = NULL;
string fp = rpmPubkeyFingerprintAsHex(key);
string keyfmt = "gpg-pubkey-" + fp + ".key";
char *dir = rpmGenPath(rpmtxnRootDir(txn), "%{_keyringpath}/", NULL);
string dirstr = dir;

if (replace) {
rasprintf(&tmppath, "%s.new", path);
unlink(tmppath);
rc = write_key_to_disk(key, dirstr, keyfmt, replace, flags);

if (!rc && replace) {
/* find and delete the old pubkey entry */
if (delete_key(txn, fp, keyfmt) == RPMRC_NOTFOUND) {
/* make sure an old, short keyid version gets removed */
delete_key(txn, fp.substr(32), keyfmt);
}
}

if (rpmMkdirs(rpmtxnRootDir(txn), "%{_keyringpath}")) {
free(dir);
return rc;
}

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

static rpmRC acquire_write_lock(rpmtxn txn)
{
char * keyringpath = rpmGenPath(rpmtxnRootDir(txn), "%{_keyringpath}/", NULL);
char * lockpath = rpmGenPath(rpmtxnRootDir(txn), "%{_keyringpath}/", "writelock");
FILE* fp = NULL;
rpmRC rc = RPMRC_FAIL;

if (rpmMkdirs(NULL, keyringpath)) {
rpmlog(RPMLOG_ERR, _("failed to create keyring directory %s: %s\n"),
path, strerror(errno));
keyringpath, strerror(errno));
goto exit;
}

if (FD_t fd = Fopen(tmppath ? tmppath : path, "wx")) {
size_t keylen = strlen(keyval);
if (Fwrite(keyval, 1, keylen, fd) == keylen)
rc = RPMRC_OK;
Fclose(fd);
}
if (!rc && tmppath && rename(tmppath, path) != 0)
rc = RPMRC_FAIL;
fp = std::fopen(lockpath, "wx");

if (rc) {
rpmlog(RPMLOG_ERR, _("failed to import key: %s: %s\n"),
tmppath ? tmppath : path, strerror(errno));
if (tmppath)
unlink(tmppath);
if (!fp) {
rpmlog(RPMLOG_ERR, _("Can't acquire writelock for keyring at %s\n"), keyringpath);
} else {
rc = RPMRC_OK;
std::fclose(fp);
}

if (!rc && replace) {
/* find and delete the old pubkey entry */
if (delete_key(txn, fp, keyfmt) == RPMRC_NOTFOUND) {
/* make sure an old, short keyid version gets removed */
delete_key(txn, fp+32, keyfmt);
}
}
exit:
free(keyringpath);
free(lockpath);
return rc;
}

exit:
static void free_write_lock(rpmtxn txn)
{
char * path = rpmGenPath(rpmtxnRootDir(txn), "%{_keyringpath}/", "writelock");
unlink(path);
free(path);
free(keyval);
free(keyfmt);
free(tmppath);
}

rpmRC keystore_openpgp_cert_d::load_keys(rpmtxn txn, rpmKeyring keyring)
{
return load_keys_from_glob(txn, keyring, "%{_keyringpath}/*/*");
}

rpmRC keystore_openpgp_cert_d::delete_key(rpmtxn txn, rpmPubkey key)
{
rpmRC rc = RPMRC_NOTFOUND;

if (acquire_write_lock(txn) != RPMRC_OK)
return RPMRC_FAIL;

string fp = rpmPubkeyFingerprintAsHex(key);
string dir = fp.substr(0, 2);
string filename = fp.substr(2);
char * filepath = rpmGetPath(rpmtxnRootDir(txn), "%{_keyringpath}/", dir.c_str(), "/", filename.c_str(), NULL);
char * dirpath = rpmGetPath(rpmtxnRootDir(txn), "%{_keyringpath}/", dir.c_str(), NULL);

if (!access(filepath, F_OK))
rc = unlink(filepath) ? RPMRC_FAIL : RPMRC_OK;
/* unlink directory if empty */
unlink(dirpath);

free(filepath);
free(dirpath);
free_write_lock(txn);
return rc;
}

rpmRC keystore_openpgp_cert_d::import_key(rpmtxn txn, rpmPubkey key, int replace, rpmFlags flags)
{
rpmRC rc = RPMRC_NOTFOUND;

if ((rc = acquire_write_lock(txn)) == RPMRC_OK) {
string fp = rpmPubkeyFingerprintAsHex(key);
string dir = fp.substr(0, 2);
string filename = fp.substr(2);
char *dirpath = rpmGetPath(rpmtxnRootDir(txn), "%{_keyringpath}/", dir.c_str(), NULL);
string dirstr = dirpath;

rc = write_key_to_disk(key, dirstr, filename, replace, flags);

free_write_lock(txn);
free(dirpath);
}

return rc;
}

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

rpmRC keystore_rpmdb::load_keys(rpmtxn txn, rpmKeyring keyring)
{
Header h;
Expand Down
7 changes: 7 additions & 0 deletions lib/keystore.hh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ private:
rpmRC delete_key(rpmtxn txn, const std::string & keyid, unsigned int newinstance = 0);
};

class keystore_openpgp_cert_d : public keystore {
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);
};

}; /* namespace */

#endif /* _KEYSTORE_H */
2 changes: 2 additions & 0 deletions lib/rpmts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ static keystore *getKeystore(rpmts ts)
ts->keystore = new keystore_fs();
} else if (rstreq(krtype, "rpmdb")) {
ts->keystore = new keystore_rpmdb();
} else if (rstreq(krtype, "openpgp")) {
ts->keystore = new keystore_openpgp_cert_d();
} else {
/* Fall back to using rpmdb if unknown, for now at least */
rpmlog(RPMLOG_WARNING,
Expand Down
89 changes: 89 additions & 0 deletions tests/rpmsigdig.at
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,95 @@ runroot rpmkeys -Kv /data/RPMS/hello-2.0-1.x86_64.rpm /data/RPMS/hello-1.0-1.i38
RPMTEST_CLEANUP


AT_SETUP([rpmkeys key update (openpgp)])
AT_KEYWORDS([rpmkeys signature])
RPMDB_INIT
# root's .rpmmacros used to keep this build prefix independent
echo "%_keyring openpgp" >> "${RPMTEST}"/root/.rpmmacros
RPMTEST_CHECK([
runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
runroot rpmkeys -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm
],
[1],
[/data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm:
Header V4 EdDSA/SHA512 Signature, key ID 6323c42711450b6c: NOKEY
Header SHA256 digest: OK
Payload SHA256 digest: OK
],
[])

RPMTEST_CHECK([
runroot_other touch /usr/lib/sysimage/rpm/pubkeys/writelock
runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-add-subkey.asc
runroot_other rm /usr/lib/sysimage/rpm/pubkeys/writelock
],
[0],
[],
[error: Can't acquire writelock for keyring at /usr/lib/sysimage/rpm/pubkeys
error: /data/keys/rpm.org-rsa-2048-add-subkey.asc: key 1 import failed.
])


RPMTEST_CHECK([
runroot rpmkeys --list | wc -l
runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-add-subkey.asc
runroot rpmkeys --list | wc -l
],
[0],
[1
1
],
[])

RPMTEST_CHECK([
runroot rpmkeys -Kv /data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm
],
[0],
[/data/RPMS/hello-2.0-1.x86_64-signed-with-new-subkey.rpm:
Header V4 EdDSA/SHA512 Signature, Key Fingerprint: 771b18d3d7baa28734333c424344591e1964c5fc: OK
Header SHA256 digest: OK
Payload SHA256 digest: OK
],
[])

RPMTEST_CHECK([
runroot rpmkeys --delete abcd gimmekey 1111aaaa2222bbbb
],
[1],
[],
[error: invalid key id: abcd
error: invalid key id: gimmekey
error: key not found: 1111aaaa2222bbbb
])

RPMTEST_CHECK([
runroot rpmkeys --delete 1964c5fc
],
[0],
[],
[])

RPMTEST_CHECK([
runroot rpmkeys --list | wc -l
],
[0],
[0
],
[])
RPMTEST_CLEANUP
# ------------------------------
# Test rpmkeys write errors
AT_SETUP([[rpmkeys -K no space left on stdout]])
AT_KEYWORDS([rpmkeys digest])
RPMTEST_CHECK([
RPMDB_INIT[

runroot rpmkeys -Kv /data/RPMS/hello-2.0-1.x86_64.rpm /data/RPMS/hello-1.0-1.i386.rpm >/dev/full
]],255,,[[Error writing to log: No space left on device
]])
RPMTEST_CLEANUP


AT_SETUP([rpmkeys -Kv <reconstructed> 1])
AT_KEYWORDS([rpmkeys digest])
RPMDB_INIT
Expand Down

0 comments on commit a3fc1c0

Please sign in to comment.