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