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