|
|
2ff057 |
#include "system.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <pthread.h>
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <rpm/rpmstring.h>
|
|
|
2ff057 |
#include <rpm/rpmpgp.h>
|
|
|
2ff057 |
#include <rpm/rpmfileutil.h>
|
|
|
2ff057 |
#include <rpm/rpmlog.h>
|
|
|
2ff057 |
#include <rpm/rpmkeyring.h>
|
|
|
2ff057 |
#include <rpm/rpmbase64.h>
|
|
|
2ff057 |
|
|
|
2ff057 |
#include "rpmio/digest.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#include "debug.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
struct rpmPubkey_s {
|
|
|
2ff057 |
uint8_t *pkt;
|
|
|
2ff057 |
size_t pktlen;
|
|
|
2ff057 |
pgpKeyID_t keyid;
|
|
|
2ff057 |
pgpDigParams pgpkey;
|
|
|
2ff057 |
int nrefs;
|
|
|
2ff057 |
pthread_rwlock_t lock;
|
|
|
2ff057 |
};
|
|
|
2ff057 |
|
|
|
2ff057 |
struct rpmKeyring_s {
|
|
|
2ff057 |
struct rpmPubkey_s **keys;
|
|
|
2ff057 |
size_t numkeys;
|
|
|
2ff057 |
int nrefs;
|
|
|
2ff057 |
pthread_rwlock_t lock;
|
|
|
2ff057 |
};
|
|
|
2ff057 |
|
|
|
2ff057 |
static int keyidcmp(const void *k1, const void *k2)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
const struct rpmPubkey_s *key1 = *(const struct rpmPubkey_s **) k1;
|
|
|
2ff057 |
const struct rpmPubkey_s *key2 = *(const struct rpmPubkey_s **) k2;
|
|
|
2ff057 |
|
|
|
2ff057 |
return memcmp(key1->keyid, key2->keyid, sizeof(key1->keyid));
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmKeyring rpmKeyringNew(void)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmKeyring keyring = xcalloc(1, sizeof(*keyring));
|
|
|
2ff057 |
keyring->keys = NULL;
|
|
|
2ff057 |
keyring->numkeys = 0;
|
|
|
2ff057 |
keyring->nrefs = 1;
|
|
|
2ff057 |
pthread_rwlock_init(&keyring->lock, NULL);
|
|
|
2ff057 |
return keyring;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmKeyring rpmKeyringFree(rpmKeyring keyring)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (keyring == NULL)
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
pthread_rwlock_wrlock(&keyring->lock);
|
|
|
2ff057 |
if (--keyring->nrefs == 0) {
|
|
|
2ff057 |
if (keyring->keys) {
|
|
|
2ff057 |
for (int i = 0; i < keyring->numkeys; i++) {
|
|
|
2ff057 |
keyring->keys[i] = rpmPubkeyFree(keyring->keys[i]);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(keyring->keys);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
pthread_rwlock_destroy(&keyring->lock);
|
|
|
2ff057 |
free(keyring);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static rpmPubkey rpmKeyringFindKeyid(rpmKeyring keyring, rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmPubkey *found = NULL;
|
|
|
2ff057 |
found = bsearch(&key, keyring->keys, keyring->numkeys, sizeof(*keyring->keys), keyidcmp);
|
|
|
2ff057 |
return found ? *found : NULL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmKeyringAddKey(rpmKeyring keyring, rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
int rc = 1; /* assume already seen key */
|
|
|
2ff057 |
if (keyring == NULL || key == NULL)
|
|
|
2ff057 |
return -1;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* check if we already have this key, but always wrlock for simplicity */
|
|
|
2ff057 |
pthread_rwlock_wrlock(&keyring->lock);
|
|
|
2ff057 |
if (!rpmKeyringFindKeyid(keyring, key)) {
|
|
|
2ff057 |
keyring->keys = xrealloc(keyring->keys,
|
|
|
2ff057 |
(keyring->numkeys + 1) * sizeof(rpmPubkey));
|
|
|
2ff057 |
keyring->keys[keyring->numkeys] = rpmPubkeyLink(key);
|
|
|
2ff057 |
keyring->numkeys++;
|
|
|
2ff057 |
qsort(keyring->keys, keyring->numkeys, sizeof(*keyring->keys),
|
|
|
2ff057 |
keyidcmp);
|
|
|
2ff057 |
rc = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmKeyring rpmKeyringLink(rpmKeyring keyring)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (keyring) {
|
|
|
2ff057 |
pthread_rwlock_wrlock(&keyring->lock);
|
|
|
2ff057 |
keyring->nrefs++;
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return keyring;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmPubkey rpmPubkeyRead(const char *filename)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
uint8_t *pkt = NULL;
|
|
|
2ff057 |
size_t pktlen;
|
|
|
2ff057 |
rpmPubkey key = NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (pgpReadPkts(filename, &pkt, &pktlen) <= 0) {
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
key = rpmPubkeyNew(pkt, pktlen);
|
|
|
2ff057 |
free(pkt);
|
|
|
2ff057 |
|
|
|
2ff057 |
exit:
|
|
|
2ff057 |
return key;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmPubkey key = NULL;
|
|
|
2ff057 |
pgpDigParams pgpkey = NULL;
|
|
|
2ff057 |
pgpKeyID_t keyid;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (pkt == NULL || pktlen == 0)
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (pgpPubkeyKeyID(pkt, pktlen, keyid))
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (pgpPrtParams(pkt, pktlen, PGPTAG_PUBLIC_KEY, &pgpkey))
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
|
|
|
2ff057 |
key = xcalloc(1, sizeof(*key));
|
|
|
2ff057 |
key->pkt = xmalloc(pktlen);
|
|
|
2ff057 |
key->pktlen = pktlen;
|
|
|
2ff057 |
key->pgpkey = pgpkey;
|
|
|
2ff057 |
key->nrefs = 1;
|
|
|
2ff057 |
memcpy(key->pkt, pkt, pktlen);
|
|
|
2ff057 |
memcpy(key->keyid, keyid, sizeof(keyid));
|
|
|
2ff057 |
pthread_rwlock_init(&key->lock, NULL);
|
|
|
2ff057 |
|
|
|
2ff057 |
exit:
|
|
|
2ff057 |
return key;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmPubkey *rpmGetSubkeys(rpmPubkey mainkey, int *count)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmPubkey *subkeys = NULL;
|
|
|
2ff057 |
pgpDigParams *pgpsubkeys = NULL;
|
|
|
2ff057 |
int pgpsubkeysCount = 0;
|
|
|
2ff057 |
int i;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (mainkey && !pgpPrtParamsSubkeys(mainkey->pkt, mainkey->pktlen,
|
|
|
2ff057 |
mainkey->pgpkey, &pgpsubkeys, &pgpsubkeysCount)) {
|
|
|
2ff057 |
|
|
|
2ff057 |
subkeys = xmalloc(pgpsubkeysCount * sizeof(*subkeys));
|
|
|
2ff057 |
|
|
|
2ff057 |
for (i = 0; i < pgpsubkeysCount; i++) {
|
|
|
2ff057 |
rpmPubkey subkey = xcalloc(1, sizeof(*subkey));
|
|
|
2ff057 |
subkeys[i] = subkey;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Packets with all subkeys already stored in main key */
|
|
|
2ff057 |
subkey->pkt = NULL;
|
|
|
2ff057 |
subkey->pktlen = 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
subkey->pgpkey = pgpsubkeys[i];
|
|
|
2ff057 |
memcpy(subkey->keyid, pgpsubkeys[i]->signid, sizeof(subkey->keyid));
|
|
|
2ff057 |
subkey->nrefs = 1;
|
|
|
2ff057 |
pthread_rwlock_init(&subkey->lock, NULL);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(pgpsubkeys);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
*count = pgpsubkeysCount;
|
|
|
2ff057 |
|
|
|
2ff057 |
return subkeys;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmPubkey rpmPubkeyFree(rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (key == NULL)
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
pthread_rwlock_wrlock(&key->lock);
|
|
|
2ff057 |
if (--key->nrefs == 0) {
|
|
|
2ff057 |
pgpDigParamsFree(key->pgpkey);
|
|
|
2ff057 |
free(key->pkt);
|
|
|
2ff057 |
pthread_rwlock_unlock(&key->lock);
|
|
|
2ff057 |
pthread_rwlock_destroy(&key->lock);
|
|
|
2ff057 |
free(key);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
pthread_rwlock_unlock(&key->lock);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmPubkey rpmPubkeyLink(rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (key) {
|
|
|
2ff057 |
pthread_rwlock_wrlock(&key->lock);
|
|
|
2ff057 |
key->nrefs++;
|
|
|
2ff057 |
pthread_rwlock_unlock(&key->lock);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return key;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
pgpDig rpmPubkeyDig(rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
pgpDig dig = NULL;
|
|
|
2ff057 |
static unsigned char zeros[] =
|
|
|
2ff057 |
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
2ff057 |
int rc;
|
|
|
2ff057 |
if (key == NULL)
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
dig = pgpNewDig();
|
|
|
2ff057 |
|
|
|
2ff057 |
pthread_rwlock_rdlock(&key->lock);
|
|
|
2ff057 |
rc = pgpPrtPkts(key->pkt, key->pktlen, dig, 0);
|
|
|
2ff057 |
pthread_rwlock_unlock(&key->lock);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rc == 0) {
|
|
|
2ff057 |
pgpDigParams pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
|
|
|
2ff057 |
if (!pubp || !memcmp(pubp->signid, zeros, sizeof(pubp->signid)) ||
|
|
|
2ff057 |
pubp->time == 0 || pubp->userid == NULL) {
|
|
|
2ff057 |
rc = -1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rc)
|
|
|
2ff057 |
dig = pgpFreeDig(dig);
|
|
|
2ff057 |
|
|
|
2ff057 |
return dig;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
char * rpmPubkeyBase64(rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
char *enc = NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (key) {
|
|
|
2ff057 |
pthread_rwlock_rdlock(&key->lock);
|
|
|
2ff057 |
enc = rpmBase64Encode(key->pkt, key->pktlen, -1);
|
|
|
2ff057 |
pthread_rwlock_unlock(&key->lock);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return enc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
pgpDigParams rpmPubkeyPgpDigParams(rpmPubkey key)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
pgpDigParams params= NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (key) {
|
|
|
2ff057 |
params = key->pgpkey;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return params;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static rpmPubkey findbySig(rpmKeyring keyring, pgpDigParams sig)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmPubkey key = NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (keyring && sig) {
|
|
|
2ff057 |
struct rpmPubkey_s needle;
|
|
|
2ff057 |
memset(&needle, 0, sizeof(needle));
|
|
|
2ff057 |
memcpy(needle.keyid, sig->signid, sizeof(needle.keyid));
|
|
|
2ff057 |
|
|
|
2ff057 |
key = rpmKeyringFindKeyid(keyring, &needle);
|
|
|
2ff057 |
if (key) {
|
|
|
2ff057 |
pgpDigParams pub = key->pgpkey;
|
|
|
2ff057 |
/* Do the parameters match the signature? */
|
|
|
2ff057 |
if ((sig->pubkey_algo != pub->pubkey_algo) ||
|
|
|
2ff057 |
memcmp(sig->signid, pub->signid, sizeof(sig->signid))) {
|
|
|
2ff057 |
key = NULL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return key;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmRC rpmKeyringLookup(rpmKeyring keyring, pgpDig sig)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
pthread_rwlock_rdlock(&keyring->lock);
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmRC res = RPMRC_NOKEY;
|
|
|
2ff057 |
pgpDigParams sigp = pgpDigGetParams(sig, PGPTAG_SIGNATURE);
|
|
|
2ff057 |
rpmPubkey key = findbySig(keyring, sigp);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (key) {
|
|
|
2ff057 |
/*
|
|
|
2ff057 |
* Callers expect sig to have the key data parsed into pgpDig
|
|
|
2ff057 |
* on (successful) return, sigh. No need to check for return
|
|
|
2ff057 |
* here as this is validated at rpmPubkeyNew() already.
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
pgpPrtPkts(key->pkt, key->pktlen, sig, 0);
|
|
|
2ff057 |
res = RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
return res;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmRC rpmKeyringVerifySig(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX ctx)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmRC rc = RPMRC_FAIL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (keyring)
|
|
|
2ff057 |
pthread_rwlock_rdlock(&keyring->lock);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (sig && ctx) {
|
|
|
2ff057 |
pgpDigParams pgpkey = NULL;
|
|
|
2ff057 |
rpmPubkey key = findbySig(keyring, sig);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (key)
|
|
|
2ff057 |
pgpkey = key->pgpkey;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* We call verify even if key not found for a signature sanity check */
|
|
|
2ff057 |
rc = pgpVerifySignature(pgpkey, sig, ctx);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (keyring)
|
|
|
2ff057 |
pthread_rwlock_unlock(&keyring->lock);
|
|
|
2ff057 |
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|