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