223 lines
4.5 KiB
C
223 lines
4.5 KiB
C
#include "system.h"
|
|
|
|
#include <rpm/rpmstring.h>
|
|
#include <rpm/rpmpgp.h>
|
|
#include <rpm/rpmfileutil.h>
|
|
#include <rpm/rpmlog.h>
|
|
#include <rpm/rpmkeyring.h>
|
|
|
|
#include "rpmio/base64.h"
|
|
#include "rpmio/digest.h"
|
|
|
|
#include "debug.h"
|
|
|
|
struct rpmPubkey_s {
|
|
uint8_t *pkt;
|
|
size_t pktlen;
|
|
pgpKeyID_t keyid;
|
|
int nrefs;
|
|
};
|
|
|
|
struct rpmKeyring_s {
|
|
struct rpmPubkey_s **keys;
|
|
size_t numkeys;
|
|
int nrefs;
|
|
};
|
|
|
|
static int keyidcmp(const void *k1, const void *k2)
|
|
{
|
|
const struct rpmPubkey_s *key1 = *(const struct rpmPubkey_s **) k1;
|
|
const struct rpmPubkey_s *key2 = *(const struct rpmPubkey_s **) k2;
|
|
|
|
return memcmp(key1->keyid, key2->keyid, sizeof(key1->keyid));
|
|
}
|
|
|
|
rpmKeyring rpmKeyringNew(void)
|
|
{
|
|
rpmKeyring keyring = xcalloc(1, sizeof(*keyring));
|
|
keyring->keys = NULL;
|
|
keyring->numkeys = 0;
|
|
keyring->nrefs = 0;
|
|
return rpmKeyringLink(keyring);
|
|
}
|
|
|
|
rpmKeyring rpmKeyringFree(rpmKeyring keyring)
|
|
{
|
|
if (keyring == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (keyring->nrefs > 1) {
|
|
return rpmKeyringUnlink(keyring);
|
|
}
|
|
|
|
if (keyring->keys) {
|
|
for (int i = 0; i < keyring->numkeys; i++) {
|
|
keyring->keys[i] = rpmPubkeyFree(keyring->keys[i]);
|
|
}
|
|
free(keyring->keys);
|
|
}
|
|
free(keyring);
|
|
return NULL;
|
|
}
|
|
|
|
static rpmPubkey rpmKeyringFindKeyid(rpmKeyring keyring, rpmPubkey key)
|
|
{
|
|
rpmPubkey *found = NULL;
|
|
found = bsearch(&key, keyring->keys, keyring->numkeys, sizeof(*keyring->keys), keyidcmp);
|
|
return found ? *found : NULL;
|
|
}
|
|
|
|
int rpmKeyringAddKey(rpmKeyring keyring, rpmPubkey key)
|
|
{
|
|
if (keyring == NULL || key == NULL)
|
|
return -1;
|
|
|
|
/* check if we already have this key */
|
|
if (rpmKeyringFindKeyid(keyring, key)) {
|
|
return 1;
|
|
}
|
|
|
|
keyring->keys = xrealloc(keyring->keys, (keyring->numkeys + 1) * sizeof(rpmPubkey));
|
|
keyring->keys[keyring->numkeys] = rpmPubkeyLink(key);
|
|
keyring->numkeys++;
|
|
qsort(keyring->keys, keyring->numkeys, sizeof(*keyring->keys), keyidcmp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
rpmKeyring rpmKeyringLink(rpmKeyring keyring)
|
|
{
|
|
if (keyring) {
|
|
keyring->nrefs++;
|
|
}
|
|
return keyring;
|
|
}
|
|
|
|
rpmKeyring rpmKeyringUnlink(rpmKeyring keyring)
|
|
{
|
|
if (keyring) {
|
|
keyring->nrefs--;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
rpmPubkey rpmPubkeyRead(const char *filename)
|
|
{
|
|
uint8_t *pkt = NULL;
|
|
size_t pktlen;
|
|
rpmPubkey key = NULL;
|
|
|
|
if (pgpReadPkts(filename, &pkt, &pktlen) <= 0) {
|
|
goto exit;
|
|
}
|
|
key = rpmPubkeyNew(pkt, pktlen);
|
|
free(pkt);
|
|
|
|
exit:
|
|
return key;
|
|
}
|
|
|
|
rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen)
|
|
{
|
|
rpmPubkey key = NULL;
|
|
|
|
if (pkt == NULL || pktlen == 0)
|
|
goto exit;
|
|
|
|
key = xcalloc(1, sizeof(*key));
|
|
pgpPubkeyFingerprint(pkt, pktlen, key->keyid);
|
|
key->pkt = xmalloc(pktlen);
|
|
key->pktlen = pktlen;
|
|
key->nrefs = 0;
|
|
memcpy(key->pkt, pkt, pktlen);
|
|
|
|
exit:
|
|
return rpmPubkeyLink(key);
|
|
}
|
|
|
|
rpmPubkey rpmPubkeyFree(rpmPubkey key)
|
|
{
|
|
if (key == NULL)
|
|
return NULL;
|
|
|
|
if (key->nrefs > 1)
|
|
return rpmPubkeyUnlink(key);
|
|
|
|
free(key->pkt);
|
|
free(key);
|
|
return NULL;
|
|
}
|
|
|
|
rpmPubkey rpmPubkeyLink(rpmPubkey key)
|
|
{
|
|
if (key) {
|
|
key->nrefs++;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
rpmPubkey rpmPubkeyUnlink(rpmPubkey key)
|
|
{
|
|
if (key) {
|
|
key->nrefs--;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
pgpDig rpmPubkeyDig(rpmPubkey key)
|
|
{
|
|
pgpDig dig = NULL;
|
|
static unsigned char zeros[] =
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
if (key == NULL)
|
|
return NULL;
|
|
|
|
dig = pgpNewDig();
|
|
if (pgpPrtPkts(key->pkt, key->pktlen, dig, 0) == 0) {
|
|
pgpDigParams pubp = &dig->pubkey;
|
|
if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid)) ||
|
|
!memcmp(pubp->time, zeros, sizeof(pubp->time)) ||
|
|
pubp->userid == NULL) {
|
|
dig = pgpFreeDig(dig);
|
|
}
|
|
}
|
|
return dig;
|
|
}
|
|
|
|
char * rpmPubkeyBase64(rpmPubkey key)
|
|
{
|
|
char *enc = NULL;
|
|
|
|
if (key) {
|
|
enc = b64encode(key->pkt, key->pktlen, -1);
|
|
}
|
|
return enc;
|
|
}
|
|
|
|
rpmRC rpmKeyringLookup(rpmKeyring keyring, pgpDig sig)
|
|
{
|
|
rpmRC res = RPMRC_NOKEY;
|
|
|
|
if (keyring && sig) {
|
|
pgpDigParams sigp = &sig->signature;
|
|
pgpDigParams pubp = &sig->pubkey;
|
|
struct rpmPubkey_s needle, *key;
|
|
needle.pkt = NULL;
|
|
needle.pktlen = 0;
|
|
memcpy(needle.keyid, sigp->signid, sizeof(needle.keyid));
|
|
|
|
if ((key = rpmKeyringFindKeyid(keyring, &needle))) {
|
|
/* Retrieve parameters from pubkey packet(s) */
|
|
(void) pgpPrtPkts(key->pkt, key->pktlen, sig, 0);
|
|
/* Do the parameters match the signature? */
|
|
if (sigp->pubkey_algo == pubp->pubkey_algo &&
|
|
memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) == 0) {
|
|
res = RPMRC_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|