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