1 #include "system.h"
2 
3 #include <pthread.h>
4 
5 #include <rpm/rpmstring.h>
6 #include <rpm/rpmpgp.h>
7 #include <rpm/rpmfileutil.h>
8 #include <rpm/rpmlog.h>
9 #include <rpm/rpmkeyring.h>
10 #include <rpm/rpmbase64.h>
11 
12 #include "rpmio/digest.h"
13 
14 #include "debug.h"
15 
16 int _print_pkts = 0;
17 
18 struct rpmPubkey_s {
19     uint8_t *pkt;
20     size_t pktlen;
21     pgpKeyID_t keyid;
22     pgpDigParams pgpkey;
23     int nrefs;
24     pthread_rwlock_t lock;
25 };
26 
27 struct rpmKeyring_s {
28     struct rpmPubkey_s **keys;
29     size_t numkeys;
30     int nrefs;
31     pthread_rwlock_t lock;
32 };
33 
keyidcmp(const void * k1,const void * k2)34 static int keyidcmp(const void *k1, const void *k2)
35 {
36     const struct rpmPubkey_s *key1 = *(const struct rpmPubkey_s **) k1;
37     const struct rpmPubkey_s *key2 = *(const struct rpmPubkey_s **) k2;
38 
39     return memcmp(key1->keyid, key2->keyid, sizeof(key1->keyid));
40 }
41 
rpmKeyringNew(void)42 rpmKeyring rpmKeyringNew(void)
43 {
44     rpmKeyring keyring = xcalloc(1, sizeof(*keyring));
45     keyring->keys = NULL;
46     keyring->numkeys = 0;
47     keyring->nrefs = 1;
48     pthread_rwlock_init(&keyring->lock, NULL);
49     return keyring;
50 }
51 
rpmKeyringFree(rpmKeyring keyring)52 rpmKeyring rpmKeyringFree(rpmKeyring keyring)
53 {
54     if (keyring == NULL)
55 	return NULL;
56 
57     pthread_rwlock_wrlock(&keyring->lock);
58     if (--keyring->nrefs == 0) {
59 	if (keyring->keys) {
60 	    for (int i = 0; i < keyring->numkeys; i++) {
61 		keyring->keys[i] = rpmPubkeyFree(keyring->keys[i]);
62 	    }
63 	    free(keyring->keys);
64 	}
65 	pthread_rwlock_unlock(&keyring->lock);
66 	pthread_rwlock_destroy(&keyring->lock);
67 	free(keyring);
68     } else {
69 	pthread_rwlock_unlock(&keyring->lock);
70     }
71     return NULL;
72 }
73 
rpmKeyringFindKeyid(rpmKeyring keyring,rpmPubkey key)74 static rpmPubkey rpmKeyringFindKeyid(rpmKeyring keyring, rpmPubkey key)
75 {
76     rpmPubkey *found = NULL;
77     if (key && keyring->keys) {
78 	found = bsearch(&key, keyring->keys, keyring->numkeys,
79 			sizeof(*keyring->keys), keyidcmp);
80     }
81     return found ? *found : NULL;
82 }
83 
rpmKeyringAddKey(rpmKeyring keyring,rpmPubkey key)84 int rpmKeyringAddKey(rpmKeyring keyring, rpmPubkey key)
85 {
86     int rc = 1; /* assume already seen key */
87     if (keyring == NULL || key == NULL)
88 	return -1;
89 
90     /* check if we already have this key, but always wrlock for simplicity */
91     pthread_rwlock_wrlock(&keyring->lock);
92     if (!rpmKeyringFindKeyid(keyring, key)) {
93 	keyring->keys = xrealloc(keyring->keys,
94 				 (keyring->numkeys + 1) * sizeof(rpmPubkey));
95 	keyring->keys[keyring->numkeys] = rpmPubkeyLink(key);
96 	keyring->numkeys++;
97 	qsort(keyring->keys, keyring->numkeys, sizeof(*keyring->keys),
98 		keyidcmp);
99 	rc = 0;
100     }
101     pthread_rwlock_unlock(&keyring->lock);
102 
103     return rc;
104 }
105 
rpmKeyringLink(rpmKeyring keyring)106 rpmKeyring rpmKeyringLink(rpmKeyring keyring)
107 {
108     if (keyring) {
109 	pthread_rwlock_wrlock(&keyring->lock);
110 	keyring->nrefs++;
111 	pthread_rwlock_unlock(&keyring->lock);
112     }
113     return keyring;
114 }
115 
rpmPubkeyRead(const char * filename)116 rpmPubkey rpmPubkeyRead(const char *filename)
117 {
118     uint8_t *pkt = NULL;
119     size_t pktlen;
120     rpmPubkey key = NULL;
121 
122     if (pgpReadPkts(filename, &pkt, &pktlen) <= 0) {
123 	goto exit;
124     }
125     key = rpmPubkeyNew(pkt, pktlen);
126     free(pkt);
127 
128 exit:
129     return key;
130 }
131 
rpmPubkeyNew(const uint8_t * pkt,size_t pktlen)132 rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen)
133 {
134     rpmPubkey key = NULL;
135     pgpDigParams pgpkey = NULL;
136     pgpKeyID_t keyid;
137 
138     if (pkt == NULL || pktlen == 0)
139 	goto exit;
140 
141     if (pgpPubkeyKeyID(pkt, pktlen, keyid))
142 	goto exit;
143 
144     if (pgpPrtParams(pkt, pktlen, PGPTAG_PUBLIC_KEY, &pgpkey))
145 	goto exit;
146 
147     key = xcalloc(1, sizeof(*key));
148     key->pkt = xmalloc(pktlen);
149     key->pktlen = pktlen;
150     key->pgpkey = pgpkey;
151     key->nrefs = 1;
152     memcpy(key->pkt, pkt, pktlen);
153     memcpy(key->keyid, keyid, sizeof(keyid));
154     pthread_rwlock_init(&key->lock, NULL);
155 
156 exit:
157     return key;
158 }
159 
rpmGetSubkeys(rpmPubkey mainkey,int * count)160 rpmPubkey *rpmGetSubkeys(rpmPubkey mainkey, int *count)
161 {
162     rpmPubkey *subkeys = NULL;
163     pgpDigParams *pgpsubkeys = NULL;
164     int pgpsubkeysCount = 0;
165     int i;
166 
167     if (mainkey && !pgpPrtParamsSubkeys(mainkey->pkt, mainkey->pktlen,
168 			mainkey->pgpkey, &pgpsubkeys, &pgpsubkeysCount)) {
169 
170 	subkeys = xmalloc(pgpsubkeysCount * sizeof(*subkeys));
171 
172 	for (i = 0; i < pgpsubkeysCount; i++) {
173 	    rpmPubkey subkey = xcalloc(1, sizeof(*subkey));
174 	    subkeys[i] = subkey;
175 
176 	    /* Packets with all subkeys already stored in main key */
177 	    subkey->pkt = NULL;
178 	    subkey->pktlen = 0;
179 
180 	    subkey->pgpkey = pgpsubkeys[i];
181 	    memcpy(subkey->keyid, pgpsubkeys[i]->signid, sizeof(subkey->keyid));
182 	    subkey->nrefs = 1;
183 	    pthread_rwlock_init(&subkey->lock, NULL);
184 	}
185 	free(pgpsubkeys);
186     }
187     *count = pgpsubkeysCount;
188 
189     return subkeys;
190 }
191 
rpmPubkeyFree(rpmPubkey key)192 rpmPubkey rpmPubkeyFree(rpmPubkey key)
193 {
194     if (key == NULL)
195 	return NULL;
196 
197     pthread_rwlock_wrlock(&key->lock);
198     if (--key->nrefs == 0) {
199 	pgpDigParamsFree(key->pgpkey);
200 	free(key->pkt);
201 	pthread_rwlock_unlock(&key->lock);
202 	pthread_rwlock_destroy(&key->lock);
203 	free(key);
204     } else {
205 	pthread_rwlock_unlock(&key->lock);
206     }
207     return NULL;
208 }
209 
rpmPubkeyLink(rpmPubkey key)210 rpmPubkey rpmPubkeyLink(rpmPubkey key)
211 {
212     if (key) {
213 	pthread_rwlock_wrlock(&key->lock);
214 	key->nrefs++;
215 	pthread_rwlock_unlock(&key->lock);
216     }
217     return key;
218 }
219 
rpmPubkeyDig(rpmPubkey key)220 pgpDig rpmPubkeyDig(rpmPubkey key)
221 {
222     pgpDig dig = NULL;
223     static unsigned char zeros[] =
224 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
225     int rc;
226     if (key == NULL)
227 	return NULL;
228 
229     dig = pgpNewDig();
230 
231     pthread_rwlock_rdlock(&key->lock);
232     rc = pgpPrtPkts(key->pkt, key->pktlen, dig, _print_pkts);
233     pthread_rwlock_unlock(&key->lock);
234 
235     if (rc == 0) {
236 	pgpDigParams pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
237 	if (!pubp || !memcmp(pubp->signid, zeros, sizeof(pubp->signid)) ||
238 		pubp->time == 0 || pubp->userid == NULL) {
239 	    rc = -1;
240 	}
241     }
242 
243     if (rc)
244 	dig = pgpFreeDig(dig);
245 
246     return dig;
247 }
248 
rpmPubkeyBase64(rpmPubkey key)249 char * rpmPubkeyBase64(rpmPubkey key)
250 {
251     char *enc = NULL;
252 
253     if (key) {
254 	pthread_rwlock_rdlock(&key->lock);
255 	enc = rpmBase64Encode(key->pkt, key->pktlen, -1);
256 	pthread_rwlock_unlock(&key->lock);
257     }
258     return enc;
259 }
260 
rpmPubkeyPgpDigParams(rpmPubkey key)261 pgpDigParams rpmPubkeyPgpDigParams(rpmPubkey key)
262 {
263     pgpDigParams params= NULL;
264 
265     if (key) {
266 	params = key->pgpkey;
267     }
268     return params;
269 }
270 
findbySig(rpmKeyring keyring,pgpDigParams sig)271 static rpmPubkey findbySig(rpmKeyring keyring, pgpDigParams sig)
272 {
273     rpmPubkey key = NULL;
274 
275     if (keyring && sig) {
276 	struct rpmPubkey_s needle;
277 	memset(&needle, 0, sizeof(needle));
278 	memcpy(needle.keyid, sig->signid, sizeof(needle.keyid));
279 
280 	key = rpmKeyringFindKeyid(keyring, &needle);
281 	if (key) {
282 	    pgpDigParams pub = key->pgpkey;
283 	    /* Do the parameters match the signature? */
284 	    if ((sig->pubkey_algo != pub->pubkey_algo) ||
285 		    memcmp(sig->signid, pub->signid, sizeof(sig->signid))) {
286 		key = NULL;
287 	    }
288 	}
289     }
290     return key;
291 }
292 
rpmKeyringLookup(rpmKeyring keyring,pgpDig sig)293 rpmRC rpmKeyringLookup(rpmKeyring keyring, pgpDig sig)
294 {
295     pthread_rwlock_rdlock(&keyring->lock);
296 
297     rpmRC res = RPMRC_NOKEY;
298     pgpDigParams sigp = pgpDigGetParams(sig, PGPTAG_SIGNATURE);
299     rpmPubkey key = findbySig(keyring, sigp);
300 
301     if (key) {
302 	/*
303  	 * Callers expect sig to have the key data parsed into pgpDig
304  	 * on (successful) return, sigh. No need to check for return
305  	 * here as this is validated at rpmPubkeyNew() already.
306  	 */
307 	pgpPrtPkts(key->pkt, key->pktlen, sig, _print_pkts);
308 	res = RPMRC_OK;
309     }
310 
311     pthread_rwlock_unlock(&keyring->lock);
312     return res;
313 }
314 
rpmKeyringVerifySig(rpmKeyring keyring,pgpDigParams sig,DIGEST_CTX ctx)315 rpmRC rpmKeyringVerifySig(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX ctx)
316 {
317     rpmRC rc = RPMRC_FAIL;
318 
319     if (keyring)
320 	pthread_rwlock_rdlock(&keyring->lock);
321 
322     if (sig && ctx) {
323 	pgpDigParams pgpkey = NULL;
324 	rpmPubkey key = findbySig(keyring, sig);
325 
326 	if (key)
327 	    pgpkey = key->pgpkey;
328 
329 	/* We call verify even if key not found for a signature sanity check */
330 	rc = pgpVerifySignature(pgpkey, sig, ctx);
331     }
332 
333     if (keyring)
334 	pthread_rwlock_unlock(&keyring->lock);
335 
336     return rc;
337 }
338