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