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