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