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