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