1 /*
2 * Portions copyright 2002, 2003 Richard Laager.
3 * Copyright (c) 1996, 1997, 1998, 1999, Marc Horowitz. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Marc Horowitz.
17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY MARC HOROWITZ ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL MARC HOROWITZ BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 const char rcsid_kd_index_c[] =
39 "$Id: kd_index.c,v 1.16 2004/03/12 20:18:39 rlaager Exp $";
40
41 #include <openssl/md5.h>
42
43 #include <openssl/sha.h>
44
45 #if HAVE_STDIO_H
46 #include <stdio.h>
47 #endif
48
49 #if HAVE_STDLIB_H
50 #include <stdlib.h>
51 #endif
52
53 #if HAVE_STRING_H
54 #include <string.h>
55 #endif
56
57 #include "database.h"
58 #include "globals.h"
59 #include "llist.h"
60 #include "kd_internal.h"
61 #include "kd_search.h"
62 #include "kd_types.h"
63
64 typedef struct _gfu_state
65 {
66 unsigned char *ptr;
67 long len;
68 }
69 gfu_state;
70
71 int
get_first_userid(void * e,void * c)72 get_first_userid (void *e, void *c)
73 {
74 keys_elem *ke = (keys_elem *) e;
75 gfu_state *s = (gfu_state *) c;
76
77 /* if there was likely to be more than one key in one of these
78 lists, I'd deal with a truncation return, but it's not
79 worth it */
80
81 if (!s->ptr)
82 {
83 s->ptr = ke->primary->uidprint;
84 s->len = ke->primary->uidplen;
85 }
86
87 return (1);
88 }
89
90 typedef struct _gi_state
91 {
92 int verbose;
93 xbuffer *xb;
94 }
95 gi_state;
96
97 int
sigs_elem_genindex(void * e,void * c)98 sigs_elem_genindex (void *e, void *c)
99 {
100 sigs_elem *se = (sigs_elem *) e;
101 gi_state *s = (gi_state *) c;
102 llist keys;
103 error err;
104 gfu_state gfus;
105 char buf[512];
106
107 if (se->keyid.buf == NULL)
108 {
109 return xbuffer_append_str (s->xb,
110 "sig ???????? [X.509 Signature]\n");
111 }
112
113 llist_alloc (&keys);
114 err.str = err.buf;
115
116 if (!kd_get_keys_by_keyid (se->keyid.buf, &keys, &err))
117 {
118 if (err.fatal)
119 {
120 llist_free (&keys);
121 return (0);
122 }
123 }
124
125 if (llist_count (&keys))
126 {
127 gfus.ptr = NULL;
128
129 if (!llist_iterate (&keys, get_first_userid, (void *) &gfus))
130 return (0);
131
132 sprintf (buf, "sig %02X%02X%02X%02X %.*s\n",
133 se->keyid.buf[se->keyid.len - 4],
134 se->keyid.buf[se->keyid.len - 3],
135 se->keyid.buf[se->keyid.len - 2],
136 se->keyid.buf[se->keyid.len - 1], (int) gfus.len, gfus.ptr);
137 }
138 else
139 {
140 sprintf (buf,
141 "sig %02X%02X%02X%02X (Unknown signator, can't be checked)\n",
142 se->keyid.buf[se->keyid.len - 4],
143 se->keyid.buf[se->keyid.len - 3],
144 se->keyid.buf[se->keyid.len - 2],
145 se->keyid.buf[se->keyid.len - 1]);
146 }
147
148 llist_iterate (&keys, keys_elem_free, NULL);
149 llist_free (&keys);
150
151 if (!xbuffer_append_str (s->xb, buf))
152 return (0);
153
154 return (1);
155 }
156
157 int
userids_elem_genindex(void * e,void * c)158 userids_elem_genindex (void *e, void *c)
159 {
160 userids_elem *ue = (userids_elem *) e;
161 gi_state *s = (gi_state *) c;
162 char buf[512];
163
164 sprintf (buf, " %.*s\n",
165 ue->uidplen < 255 ? (int) ue->uidplen : 255, ue->uidprint);
166
167 if (!xbuffer_append_str (s->xb, buf))
168 return (0);
169
170 if (s->verbose)
171 {
172 if (!llist_iterate (&(ue->sigs), sigs_elem_genindex, c))
173 return (0);
174 }
175
176 return (1);
177 }
178
179 int
userids_elem_genmrindex(void * e,void * c)180 userids_elem_genmrindex (void *e, void *c)
181 {
182 userids_elem *ue = (userids_elem *) e;
183 gi_state *s = (gi_state *) c;
184 int i = 0;
185 char buf[512 + 5], tmp[512];
186
187 while (ue->uidplen && *(ue->uidprint))
188 {
189 if (*(ue->uidprint) == ':')
190 {
191 tmp[i++] = '%';
192 tmp[i++] = '3';
193 tmp[i++] = 'A';
194 }
195 else if (*(ue->uidprint) == '%')
196 {
197 tmp[i++] = '%';
198 tmp[i++] = '2';
199 tmp[i++] = '5';
200 }
201 else
202 tmp[i++] = *(ue->uidprint);
203
204 ue->uidprint++;
205 ue->uidplen--;
206
207 if (i > 509)
208 return (1);
209 }
210
211 /* For the sake of sanity, please do not change this format without
212 talking to David Shaw <dshaw@jabberwocky.com> first. */
213
214 sprintf (buf, "uid:%.*s\n", i, tmp);
215
216 if (!xbuffer_append_str (s->xb, buf))
217 return (0);
218
219 return (1);
220 }
221
222 typedef struct _keg_state
223 {
224 int flags;
225 xbuffer *xb;
226 }
227 keg_state;
228
229 int
keys_elem_genindex(void * e,void * c)230 keys_elem_genindex (void *e, void *c)
231 {
232
233 keys_elem *ke = (keys_elem *) e;
234 keg_state *s = (keg_state *) c;
235 gi_state gis;
236 char buf[512];
237 struct tm *c_tm;
238 MD5_CTX md5ctx;
239 SHA_CTX sha;
240 unsigned char hash[20];
241 int i;
242 unsigned int pos = 0;
243
244
245 /* pgp does gmtime, so we do, too */
246 c_tm = gmtime (&(ke->create_time));
247
248 sprintf (buf, "pub%c%5d%c/%02X%02X%02X%02X %04d/%02d/%02d %s%.*s\n",
249 (ke->disabled ? '-' : ' '),
250 (int) ke->modsigbits,
251 ((ke->keytype == 1) ? 'R' : 'D'),
252 ke->keyidbits.buf[4],
253 ke->keyidbits.buf[5],
254 ke->keyidbits.buf[6],
255 ke->keyidbits.buf[7],
256 c_tm->tm_year + 1900, c_tm->tm_mon + 1, c_tm->tm_mday,
257 (ke->revocation.len ?
258 "*** KEY REVOKED ***\n " : ""),
259 ke->primary->uidplen < 255 ? (int) ke->primary->uidplen : 255, ke->primary->uidprint);
260
261 if (!xbuffer_append_str (s->xb, buf))
262 return (0);
263
264 if (s->flags & KD_INDEX_FINGERPRINT)
265 {
266 if (ke->keyversion > 3)
267 {
268 SHA1_Init (&sha);
269 SHA1_Update (&sha, ke->pubkey.buf, ke->pubkey.len);
270 SHA1_Final (hash, &sha);
271 }
272 else
273 {
274 MD5_Init (&md5ctx);
275 MD5_Update (&md5ctx, ke->modbits.buf, ke->modbits.len);
276 MD5_Update (&md5ctx, ke->expbits.buf, ke->expbits.len);
277 MD5_Final (hash, &md5ctx);
278 }
279
280 pos = 0;
281 /* print longer SHA-1 hashes differently */
282 if (ke->keyversion > 3)
283 {
284 for (i = 0; i < 20; i += 2)
285 {
286 sprintf (&buf[pos], "%02X%02X ", hash[i], hash[i + 1]);
287 pos += 5; /* just added n chars... */
288 /* add another space halfway through... */
289 if (i == 8)
290 {
291 buf[pos] = ' ';
292 pos++;
293 }
294 } /* for i */
295 pos--; /* remove last space */
296 buf[pos] = '\n';
297 }
298 else
299 { /* version<=3 */
300 for (i = 0; i < 8; i++)
301 sprintf (buf + i * 3, "%02X ", hash[i]);
302 buf[24] = ' ';
303 for (i = 8; i < 16; i++)
304 sprintf (buf + 1 + i * 3, "%02X ", hash[i]);
305 buf[48] = '\n';
306 } /* if else on keytype */
307
308 if (!xbuffer_append_str (s->xb, " Key fingerprint = "))
309 return (0);
310 if (ke->keyversion > 3)
311 {
312 if (!xbuffer_append (s->xb, (unsigned char *) buf, 51))
313 return (0);
314 }
315 else
316 {
317 if (!xbuffer_append (s->xb, (unsigned char *) buf, 49))
318 return (0);
319 }
320 }
321
322 gis.verbose = (s->flags & KD_INDEX_VERBOSE);
323 gis.xb = s->xb;
324
325 if (s->flags & KD_INDEX_VERBOSE)
326 {
327 if (!llist_iterate (&(ke->primary->sigs), sigs_elem_genindex, &gis))
328 return (0);
329 }
330
331 if (!llist_iterate (&(ke->userids), userids_elem_genindex, &gis))
332 return (0);
333
334 return (1);
335 }
336
337 int
keys_elem_genmrindex(void * e,void * c)338 keys_elem_genmrindex (void *e, void *c)
339 {
340 keys_elem *ke = (keys_elem *) e;
341 keg_state *s = (keg_state *) c;
342 gi_state gis;
343 char buf[512];
344
345 /* For the sake of sanity, please do not change this format without
346 talking to David Shaw <dshaw@jabberwocky.com> first. */
347
348 /* It is possible to put the 16-digit keyid or fingerprint here,
349 but until the server can actually make use of all of the
350 available precision, it is misleading to include it in the
351 response. */
352 sprintf (buf, "pub:%02X%02X%02X%02X:%u:%u:%lu::%s%s\n",
353 ke->keyidbits.buf[4],
354 ke->keyidbits.buf[5],
355 ke->keyidbits.buf[6],
356 ke->keyidbits.buf[7],
357 ke->keytype, ke->modsigbits, (unsigned long) ke->create_time,
358 ke->revocation.len ? "r" : "", ke->disabled ? "d" : "");
359
360 if (!xbuffer_append_str (s->xb, buf))
361 return (0);
362
363 gis.verbose = (s->flags & KD_INDEX_VERBOSE);
364 gis.xb = s->xb;
365
366 if (!userids_elem_genmrindex (ke->primary, &gis))
367 return 0;
368
369 if (!llist_iterate (&(ke->userids), userids_elem_genmrindex, &gis))
370 return (0);
371
372 return (1);
373 }
374
375 typedef struct _kegc_state
376 {
377 FILE *out;
378 keg_state keg;
379 }
380 kegc_state;
381
382 int
keys_elem_genindex_cout(void * e,void * c)383 keys_elem_genindex_cout (void *e, void *c)
384 {
385 kegc_state *s = (kegc_state *) c;
386
387 if (!keys_elem_genindex (e, &s->keg))
388 fail ();
389
390 fwrite (s->keg.xb->buf, s->keg.xb->len, 1, s->out);
391
392 /* "remove" the data from the buffer, but don't free it.
393 this will save a lot of malloc/free calls */
394 s->keg.xb->len = 0;
395
396 return (1);
397 }
398
399 int
kd_index_1(unsigned char * userid,long len,int flags,int maxkeys,xbuffer * index,error * err)400 kd_index_1 (unsigned char *userid, long len, int flags,
401 int maxkeys, xbuffer * index, error * err)
402 {
403 keg_state kegs;
404 int ret;
405
406 /* This is called violating abstractions in the interest of
407 efficiency. Whee. */
408
409 if (flags & KD_INDEX_STDOUT)
410 {
411 kegc_state kegcs;
412 xbuffer buf;
413
414 xbuffer_alloc (&buf);
415
416 kegcs.out = stdout;
417 kegcs.keg.flags = flags;
418 kegcs.keg.xb = &buf;
419
420 ret = kd_search_1 (userid, len, flags & KD_SEARCH_FLAGS, maxkeys,
421 keys_elem_genindex_cout, NULL, &kegcs, err);
422
423 xbuffer_free (&buf);
424
425 return (ret);
426 }
427
428 kegs.flags = flags;
429 kegs.xb = index;
430
431 if (!kd_search_1 (userid, len, flags & KD_SEARCH_FLAGS, maxkeys,
432 flags & KD_INDEX_MR ? keys_elem_genmrindex :
433 keys_elem_genindex, NULL, &kegs, err))
434 return (0);
435
436 if (index->len == 0)
437 {
438 /* no matching keys in database */
439
440 err->fatal = 0;
441 err->str = "No matching keys in database";
442 return (0);
443 }
444
445 return (1);
446 }
447
448 int
kd_index(unsigned char * userid,long len,int flags,int maxkeys,unsigned char ** ret,long * retlen)449 kd_index (unsigned char *userid, long len, int flags, int maxkeys,
450 unsigned char **ret, long *retlen)
451 {
452 error err;
453 xbuffer index;
454
455 err.str = err.buf;
456 xbuffer_alloc (&index);
457
458 kd_log_start ("kd_index", userid, len, flags);
459
460 if (kd_index_1 (userid, len, flags, maxkeys, &index, &err))
461 {
462 *ret = index.buf;
463 *retlen = index.len;
464
465 kd_log_finish ("kd_index", 1);
466
467 return (1);
468 }
469
470 if (!err.fatal)
471 {
472 if (!(*ret = (unsigned char *) my_strdup (err.str)))
473 {
474 err.fatal = 1;
475 err.str = "Failed allocating space for error string";
476 dabort ();
477
478 /* fall through to fatal error handler */
479 }
480 else
481 {
482 *retlen = strlen ((char *) *ret);
483
484 kd_log_finish ("kd_index", 0);
485
486 return (0);
487 }
488 }
489
490 /* fatal errors */
491
492 if (err.fatal)
493 {
494 log_fatal ("kd_index", err.str);
495 /* never returns */
496 }
497
498 /* keep the compiler quiet */
499
500 return (0);
501 }
502