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