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