Blame rpmio/rpmkeyring.c

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
}