* NEWS: Note --sig-keyserver-url and the ability to use a preferred
[gnupg.git] / kbx / keybox-search.c
1 /* keybox-search.c - Search operations
2  *      Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <errno.h>
27
28 #include "../jnlib/stringhelp.h" /* ascii_xxxx() */
29 #include "keybox-defs.h"
30
31 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
32                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
33 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
34
35 struct sn_array_s {
36     int snlen;
37     unsigned char *sn;
38 };
39
40
41
42 static ulong
43 get32 (const byte *buffer)
44 {
45   ulong a;
46   a =  *buffer << 24;
47   a |= buffer[1] << 16;
48   a |= buffer[2] << 8;
49   a |= buffer[3];
50   return a;
51 }
52
53 static ulong
54 get16 (const byte *buffer)
55 {
56   ulong a;
57   a =  *buffer << 8;
58   a |= buffer[1];
59   return a;
60 }
61
62
63
64 static int
65 blob_get_type (KEYBOXBLOB blob)
66 {
67   const unsigned char *buffer;
68   size_t length;
69
70   buffer = _keybox_get_blob_image (blob, &length);
71   if (length < 40)
72     return -1; /* blob too short */
73
74   return buffer[4];
75 }
76
77 static unsigned int
78 blob_get_blob_flags (KEYBOXBLOB blob)
79 {
80   const unsigned char *buffer;
81   size_t length;
82
83   buffer = _keybox_get_blob_image (blob, &length);
84   if (length < 8)
85     return 0; /* oops */
86
87   return get16 (buffer + 6);
88 }
89
90
91 static int
92 blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
93 {
94   const unsigned char *buffer;
95   size_t length;
96   size_t pos, off;
97   size_t nkeys, keyinfolen;
98   size_t nserial;
99
100   buffer = _keybox_get_blob_image (blob, &length);
101   if (length < 40)
102     return 0; /* blob too short */
103
104   /*keys*/
105   nkeys = get16 (buffer + 16);
106   keyinfolen = get16 (buffer + 18 );
107   if (keyinfolen < 28)
108     return 0; /* invalid blob */
109   pos = 20 + keyinfolen*nkeys;
110   if (pos+2 > length)
111     return 0; /* out of bounds */
112
113   /*serial*/
114   nserial = get16 (buffer+pos); 
115   off = pos + 2;
116   if (off+nserial > length)
117     return 0; /* out of bounds */
118
119   return nserial == snlen && !memcmp (buffer+off, sn, snlen);
120 }
121
122
123 static int
124 blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
125 {
126   const unsigned char *buffer;
127   size_t length;
128   size_t pos, off;
129   size_t nkeys, keyinfolen;
130   int idx;
131
132   buffer = _keybox_get_blob_image (blob, &length);
133   if (length < 40)
134     return 0; /* blob too short */
135
136   /*keys*/
137   nkeys = get16 (buffer + 16);
138   keyinfolen = get16 (buffer + 18 );
139   if (keyinfolen < 28)
140     return 0; /* invalid blob */
141   pos = 20;
142   if (pos + keyinfolen*nkeys > length)
143     return 0; /* out of bounds */
144
145   for (idx=0; idx < nkeys; idx++)
146     {
147       off = pos + idx*keyinfolen;
148       if (!memcmp (buffer + off, fpr, 20))
149         return 1; /* found */
150     }
151   return 0; /* not found */
152 }
153
154 static int
155 blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
156                    int fproff, int fprlen)
157 {
158   const unsigned char *buffer;
159   size_t length;
160   size_t pos, off;
161   size_t nkeys, keyinfolen;
162   int idx;
163
164   buffer = _keybox_get_blob_image (blob, &length);
165   if (length < 40)
166     return 0; /* blob too short */
167
168   /*keys*/
169   nkeys = get16 (buffer + 16);
170   keyinfolen = get16 (buffer + 18 );
171   if (keyinfolen < 28)
172     return 0; /* invalid blob */
173   pos = 20;
174   if (pos + keyinfolen*nkeys > length)
175     return 0; /* out of bounds */
176
177   for (idx=0; idx < nkeys; idx++)
178     {
179       off = pos + idx*keyinfolen;
180       if (!memcmp (buffer + off + fproff, fpr, fprlen))
181         return 1; /* found */
182     }
183   return 0; /* not found */
184 }
185
186
187 static int
188 blob_cmp_name (KEYBOXBLOB blob, int idx,
189                const char *name, size_t namelen, int substr)
190 {
191   const unsigned char *buffer;
192   size_t length;
193   size_t pos, off, len;
194   size_t nkeys, keyinfolen;
195   size_t nuids, uidinfolen;
196   size_t nserial;
197
198   buffer = _keybox_get_blob_image (blob, &length);
199   if (length < 40)
200     return 0; /* blob too short */
201
202   /*keys*/
203   nkeys = get16 (buffer + 16);
204   keyinfolen = get16 (buffer + 18 );
205   if (keyinfolen < 28)
206     return 0; /* invalid blob */
207   pos = 20 + keyinfolen*nkeys;
208   if (pos+2 > length)
209     return 0; /* out of bounds */
210
211   /*serial*/
212   nserial = get16 (buffer+pos); 
213   pos += 2 + nserial;
214   if (pos+4 > length)
215     return 0; /* out of bounds */
216
217   /* user ids*/
218   nuids = get16 (buffer + pos);  pos += 2;
219   uidinfolen = get16 (buffer + pos);  pos += 2;
220   if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
221     return 0; /* invalid blob */
222   if (pos + uidinfolen*nuids > length)
223     return 0; /* out of bounds */
224
225   if (idx < 0)
226     { /* compare all names starting with that (negated) index */
227       idx = -idx;
228       
229       for ( ;idx < nuids; idx++)
230         {
231           size_t mypos = pos;
232
233           mypos += idx*uidinfolen;
234           off = get32 (buffer+mypos);
235           len = get32 (buffer+mypos+4);
236           if (off+len > length)
237             return 0; /* error: better stop here out of bounds */
238           if (len < 1)
239             continue; /* empty name */
240           if (substr)
241             {
242               if (ascii_memcasemem (buffer+off, len, name, namelen))
243                 return 1; /* found */
244             }
245           else
246             {
247               if (len == namelen && !memcmp (buffer+off, name, len))
248                 return 1; /* found */
249             }
250         }
251       return 0; /* not found */
252     }
253   else
254     {
255       if (idx > nuids)
256         return 0; /* no user ID with that idx */
257       pos += idx*uidinfolen;
258       off = get32 (buffer+pos);
259       len = get32 (buffer+pos+4);
260       if (off+len > length)
261         return 0; /* out of bounds */
262       if (len < 1)
263         return 0; /* empty name */
264
265       if (substr)
266         {
267           return !!ascii_memcasemem (buffer+off, len, name, namelen);
268         }
269       else
270         {
271           return len == namelen && !memcmp (buffer+off, name, len);
272         }
273     }
274 }
275
276
277 /* compare all email addresses of the subject.  With SUBSTR given as
278    True a substring search is done in the mail address */
279 static int
280 blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
281 {
282   const unsigned char *buffer;
283   size_t length;
284   size_t pos, off, len;
285   size_t nkeys, keyinfolen;
286   size_t nuids, uidinfolen;
287   size_t nserial;
288   int idx;
289
290   /* fixme: this code is common to blob_cmp_mail */
291   buffer = _keybox_get_blob_image (blob, &length);
292   if (length < 40)
293     return 0; /* blob too short */
294
295   /*keys*/
296   nkeys = get16 (buffer + 16);
297   keyinfolen = get16 (buffer + 18 );
298   if (keyinfolen < 28)
299     return 0; /* invalid blob */
300   pos = 20 + keyinfolen*nkeys;
301   if (pos+2 > length)
302     return 0; /* out of bounds */
303
304   /*serial*/
305   nserial = get16 (buffer+pos); 
306   pos += 2 + nserial;
307   if (pos+4 > length)
308     return 0; /* out of bounds */
309
310   /* user ids*/
311   nuids = get16 (buffer + pos);  pos += 2;
312   uidinfolen = get16 (buffer + pos);  pos += 2;
313   if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
314     return 0; /* invalid blob */
315   if (pos + uidinfolen*nuids > length)
316     return 0; /* out of bounds */
317
318   if (namelen < 1)
319     return 0;
320
321   for (idx=1 ;idx < nuids; idx++)
322     {
323       size_t mypos = pos;
324       
325       mypos += idx*uidinfolen;
326       off = get32 (buffer+mypos);
327       len = get32 (buffer+mypos+4);
328       if (off+len > length)
329         return 0; /* error: better stop here out of bounds */
330       if (len < 2 || buffer[off] != '<')
331         continue; /* empty name or trailing 0 not stored */
332       len--; /* one back */
333       if ( len < 3 || buffer[off+len] != '>')
334         continue; /* not a proper email address */
335       len--; 
336       if (substr)
337         {
338           if (ascii_memcasemem (buffer+off+1, len, name, namelen))
339             return 1; /* found */
340         }
341       else
342         {
343           if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
344             return 1; /* found */
345         }
346     }
347   return 0; /* not found */
348 }
349
350
351
352 \f
353 /*
354   The has_foo functions are used as helpers for search 
355 */
356 static int
357 has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
358 {
359   return blob_cmp_fpr_part (blob, kid+4, 16, 4);
360 }
361
362 static int
363 has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
364 {
365   return blob_cmp_fpr_part (blob, kid, 12, 8);
366 }
367
368 static int
369 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
370 {
371   return blob_cmp_fpr (blob, fpr);
372 }
373
374
375 static int
376 has_issuer (KEYBOXBLOB blob, const char *name)
377 {
378   size_t namelen;
379
380   return_val_if_fail (name, 0);
381
382   if (blob_get_type (blob) != BLOBTYPE_X509)
383     return 0;
384
385   namelen = strlen (name);
386   return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
387 }
388
389 static int
390 has_issuer_sn (KEYBOXBLOB blob, const char *name,
391                const unsigned char *sn, int snlen)
392 {
393   size_t namelen;
394
395   return_val_if_fail (name, 0);
396   return_val_if_fail (sn, 0);
397
398   if (blob_get_type (blob) != BLOBTYPE_X509)
399     return 0;
400
401   namelen = strlen (name);
402   
403   return (blob_cmp_sn (blob, sn, snlen)
404           && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
405 }
406
407 static int
408 has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
409 {
410   return_val_if_fail (sn, 0);
411
412   if (blob_get_type (blob) != BLOBTYPE_X509)
413     return 0;
414   return blob_cmp_sn (blob, sn, snlen);
415 }
416
417 static int
418 has_subject (KEYBOXBLOB blob, const char *name)
419 {
420   size_t namelen;
421
422   return_val_if_fail (name, 0);
423
424   if (blob_get_type (blob) != BLOBTYPE_X509)
425     return 0;
426
427   namelen = strlen (name);
428   return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
429 }
430
431 static int
432 has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
433 {
434   size_t namelen;
435
436   return_val_if_fail (name, 0);
437
438   if (blob_get_type (blob) != BLOBTYPE_X509)
439     return 0;
440
441   namelen = strlen (name);
442   return blob_cmp_name (blob, -1 /* all subject names*/, name,
443                         namelen, substr);
444 }
445
446
447 static int
448 has_mail (KEYBOXBLOB blob, const char *name, int substr)
449 {
450   size_t namelen;
451
452   return_val_if_fail (name, 0);
453
454   if (blob_get_type (blob) != BLOBTYPE_X509)
455     return 0;
456
457   namelen = strlen (name);
458   if (namelen && name[namelen-1] == '>')
459     namelen--;
460   return blob_cmp_mail (blob, name, namelen, substr);
461 }
462
463
464 static void
465 release_sn_array (struct sn_array_s *array, size_t size)
466 {
467   size_t n;
468
469   for (n=0; n < size; n++)
470     xfree (array[n].sn);
471   xfree (array);
472 }
473
474 \f
475 /*
476
477   The search API
478
479 */
480
481 int 
482 keybox_search_reset (KEYBOX_HANDLE hd)
483 {
484   if (!hd)
485     return gpg_error (GPG_ERR_INV_VALUE);
486
487   if (hd->found.blob)
488     {
489       _keybox_release_blob (hd->found.blob);
490       hd->found.blob = NULL;
491     }
492
493   if (hd->fp)
494     {
495       fclose (hd->fp);
496       hd->fp = NULL;
497     }
498   hd->error = 0;
499   hd->eof = 0;
500   return 0;   
501 }
502
503
504 /* Note: When in ephemeral mode the search function does visit all
505    blobs but in standard mode, blobs flagged as ephemeral are ignored.  */
506 int 
507 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
508 {
509   int rc;
510   size_t n;
511   int need_words, any_skip;
512   KEYBOXBLOB blob = NULL;
513   struct sn_array_s *sn_array = NULL;
514
515   if (!hd)
516     return gpg_error (GPG_ERR_INV_VALUE);
517
518   /* clear last found result */
519   if (hd->found.blob)
520     {
521       _keybox_release_blob (hd->found.blob);
522       hd->found.blob = NULL;
523     }
524
525   if (hd->error)  
526     return hd->error; /* still in error state */
527   if (hd->eof)  
528     return -1; /* still EOF */
529
530   /* figure out what information we need */
531   need_words = any_skip = 0;
532   for (n=0; n < ndesc; n++) 
533     {
534       switch (desc[n].mode) 
535         {
536         case KEYDB_SEARCH_MODE_WORDS: 
537           need_words = 1;
538           break;
539         case KEYDB_SEARCH_MODE_FIRST:
540           /* always restart the search in this mode */
541           keybox_search_reset (hd);
542           break;
543         default:
544           break;
545         }
546       if (desc[n].skipfnc) 
547         any_skip = 1;
548       if (desc[n].snlen == -1 && !sn_array)
549         {
550           sn_array = xtrycalloc (ndesc, sizeof *sn_array);
551           if (!sn_array)
552             return (hd->error = gpg_error (gpg_err_code_from_errno (errno)));
553         }
554     }
555
556   if (!hd->fp)
557     {
558       hd->fp = fopen (hd->kb->fname, "rb");
559       if (!hd->fp)
560         {
561           hd->error = gpg_error (gpg_err_code_from_errno (errno));
562           xfree (sn_array);
563           return hd->error;
564         }
565     }
566
567   /* kludge: we need to convert an SN given as hexstring to it's
568      binary representation - in some cases we are not able to store it
569      in the search descriptor, because due to its usgae it is not
570      possible to free allocated memory */
571   if (sn_array)
572     {
573       const unsigned char *s;
574       int i, odd;
575       size_t snlen;
576
577       for (n=0; n < ndesc; n++) 
578         {
579           if (!desc[n].sn)
580             ;
581           else if (desc[n].snlen == -1)
582             {
583               unsigned char *sn;
584
585               s = desc[n].sn;
586               for (i=0; *s && *s != '/'; s++, i++)
587                 ;
588               odd = (i & 1);
589               snlen = (i+1)/2;
590               sn_array[n].sn = xtrymalloc (snlen);
591               if (!sn_array[n].sn)
592                 {
593                   hd->error = gpg_error (gpg_err_code_from_errno (errno));
594                   release_sn_array (sn_array, n);
595                   return hd->error;
596                 }
597               sn_array[n].snlen = snlen;
598               sn = sn_array[n].sn;
599               s = desc[n].sn;
600               if (odd)
601                 {
602                   *sn++ = xtoi_1 (s);
603                   s++;
604                 }
605               for (; *s && *s != '/';  s += 2)
606                 *sn++ = xtoi_2 (s);
607             }
608           else
609             {
610               const unsigned char *sn;
611
612               sn = desc[n].sn;
613               snlen = desc[n].snlen;
614               sn_array[n].sn = xtrymalloc (snlen);
615               if (!sn_array[n].sn)
616                 {
617                   hd->error = gpg_error (gpg_err_code_from_errno (errno));
618                   release_sn_array (sn_array, n);
619                   return hd->error;
620                 }
621               sn_array[n].snlen = snlen;
622               memcpy (sn_array[n].sn, sn, snlen);
623             }
624         }
625     }
626
627
628   for (;;)
629     {
630       unsigned int blobflags;
631
632       _keybox_release_blob (blob); blob = NULL;
633       rc = _keybox_read_blob (&blob, hd->fp);
634       if (rc)
635         break;
636
637       blobflags = blob_get_blob_flags (blob);
638       if (!hd->ephemeral && (blobflags & 2))
639         continue; /* not in ephemeral mode but blob is flagged ephemeral */
640
641       for (n=0; n < ndesc; n++) 
642         {
643           switch (desc[n].mode)
644             {
645             case KEYDB_SEARCH_MODE_NONE: 
646               never_reached ();
647               break;
648             case KEYDB_SEARCH_MODE_EXACT: 
649               if (has_subject_or_alt (blob, desc[n].u.name, 0))
650                 goto found;
651               break;
652             case KEYDB_SEARCH_MODE_MAIL:
653               if (has_mail (blob, desc[n].u.name, 0))
654                 goto found;
655               break;
656             case KEYDB_SEARCH_MODE_MAILSUB:
657               if (has_mail (blob, desc[n].u.name, 1))
658                 goto found;
659               break;
660             case KEYDB_SEARCH_MODE_SUBSTR:
661               if (has_subject_or_alt (blob, desc[n].u.name, 1))
662                 goto found;
663               break;
664             case KEYDB_SEARCH_MODE_MAILEND:
665             case KEYDB_SEARCH_MODE_WORDS: 
666               never_reached (); /* not yet implemented */
667               break;
668             case KEYDB_SEARCH_MODE_ISSUER:
669               if (has_issuer (blob, desc[n].u.name))
670                 goto found;
671               break;
672             case KEYDB_SEARCH_MODE_ISSUER_SN:
673               if (has_issuer_sn (blob, desc[n].u.name,
674                                  sn_array? sn_array[n].sn : desc[n].sn,
675                                  sn_array? sn_array[n].snlen : desc[n].snlen))
676                 goto found;
677               break;
678             case KEYDB_SEARCH_MODE_SN:
679               if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
680                                 sn_array? sn_array[n].snlen : desc[n].snlen))
681                 goto found;
682               break;
683             case KEYDB_SEARCH_MODE_SUBJECT:
684               if (has_subject (blob, desc[n].u.name))
685                 goto found;
686               break;
687             case KEYDB_SEARCH_MODE_SHORT_KID: 
688               if (has_short_kid (blob, desc[n].u.kid))
689                 goto found;
690               break;
691             case KEYDB_SEARCH_MODE_LONG_KID:
692               if (has_long_kid (blob, desc[n].u.kid))
693                 goto found;
694               break;
695             case KEYDB_SEARCH_MODE_FPR:
696             case KEYDB_SEARCH_MODE_FPR20:
697               if (has_fingerprint (blob, desc[n].u.fpr))
698                 goto found;
699               break;
700             case KEYDB_SEARCH_MODE_FIRST: 
701               goto found;
702               break;
703             case KEYDB_SEARCH_MODE_NEXT: 
704               goto found;
705               break;
706             default: 
707               rc = gpg_error (GPG_ERR_INV_VALUE);
708               goto found;
709             }
710         }
711       continue;
712     found:  
713       for (n=any_skip?0:ndesc; n < ndesc; n++) 
714         {
715 /*            if (desc[n].skipfnc */
716 /*                && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
717 /*              break; */
718         }
719       if (n == ndesc)
720         break; /* got it */
721     }
722   
723   if (!rc)
724     {
725       hd->found.blob = blob;
726     }
727   else if (rc == -1)
728     {
729       _keybox_release_blob (blob);
730       hd->eof = 1;
731     }
732   else 
733     {
734       _keybox_release_blob (blob);
735       hd->error = rc;
736     }
737
738   if (sn_array)
739     release_sn_array (sn_array, ndesc);
740
741   return rc;
742 }
743
744
745
746 \f
747 /*
748    Functions to return a certificate or a keyblock.  To be used after
749    a successful search operation.
750 */
751 #ifdef KEYBOX_WITH_X509
752 /*
753   Return the last found cert.  Caller must free it.
754  */
755 int
756 keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
757 {
758   const unsigned char *buffer;
759   size_t length;
760   size_t cert_off, cert_len;
761   KsbaReader reader = NULL;
762   KsbaCert cert = NULL;
763   int rc;
764
765   if (!hd)
766     return gpg_error (GPG_ERR_INV_VALUE);
767   if (!hd->found.blob)
768     return gpg_error (GPG_ERR_NOTHING_FOUND);
769
770   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
771     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
772
773   buffer = _keybox_get_blob_image (hd->found.blob, &length);
774   if (length < 40)
775     return gpg_error (GPG_ERR_TOO_SHORT);
776   cert_off = get32 (buffer+8);
777   cert_len = get32 (buffer+12);
778   if (cert_off+cert_len > length)
779     return gpg_error (GPG_ERR_TOO_SHORT);
780
781   reader = ksba_reader_new ();
782   if (!reader)
783     return gpg_error (GPG_ERR_ENOMEM);
784   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
785   if (rc)
786     {
787       ksba_reader_release (reader);
788       /* fixme: need to map the error codes */
789       return gpg_error (GPG_ERR_GENERAL);
790     }
791
792   cert = ksba_cert_new ();
793   if (!cert)
794     {
795       ksba_reader_release (reader);
796       return gpg_error (GPG_ERR_ENOMEM);
797     }
798
799   rc = ksba_cert_read_der (cert, reader);
800   if (rc)
801     {
802       ksba_cert_release (cert);
803       ksba_reader_release (reader);
804       /* fixme: need to map the error codes */
805       return gpg_error (GPG_ERR_GENERAL);
806     }
807
808   *r_cert = cert;
809   ksba_reader_release (reader);
810   return 0;
811 }
812
813 #endif /*KEYBOX_WITH_X509*/