Changed wording of passphrase checking messages.
[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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <errno.h>
26
27 #include "../jnlib/stringhelp.h" /* ascii_xxxx() */
28
29 #include "keybox-defs.h"
30 #include <gcrypt.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 #ifdef KEYBOX_WITH_X509
459 /* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
460    We don't have the keygrips as meta data, thus wen need to parse the
461    certificate. Fixme: We might wat to return proper error codes
462    instead of failing a search for invalid certificates etc.  */
463 static int
464 blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
465 {
466   int rc;
467   const unsigned char *buffer;
468   size_t length;
469   size_t cert_off, cert_len;
470   ksba_reader_t reader = NULL;
471   ksba_cert_t cert = NULL;
472   ksba_sexp_t p = NULL;
473   gcry_sexp_t s_pkey;
474   unsigned char array[20];
475   unsigned char *rcp;
476   size_t n;
477   
478   buffer = _keybox_get_blob_image (blob, &length);
479   if (length < 40)
480     return 0; /* Too short. */
481   cert_off = get32 (buffer+8);
482   cert_len = get32 (buffer+12);
483   if (cert_off+cert_len > length)
484     return 0; /* Too short.  */
485
486   rc = ksba_reader_new (&reader);
487   if (rc)
488     return 0; /* Problem with ksba. */
489   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
490   if (rc)
491     goto failed;
492   rc = ksba_cert_new (&cert);
493   if (rc)
494     goto failed;
495   rc = ksba_cert_read_der (cert, reader);
496   if (rc)
497     goto failed;
498   p = ksba_cert_get_public_key (cert);
499   if (!p)
500     goto failed;
501   n = gcry_sexp_canon_len (p, 0, NULL, NULL);
502   if (!n)
503     goto failed;
504   rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
505   if (rc)
506     {
507       gcry_sexp_release (s_pkey);
508       goto failed;
509     }
510   rcp = gcry_pk_get_keygrip (s_pkey, array);
511   gcry_sexp_release (s_pkey);
512   if (!rcp)
513     goto failed; /* Can't calculate keygrip. */
514
515   xfree (p);
516   ksba_cert_release (cert);
517   ksba_reader_release (reader);
518   return !memcmp (array, grip, 20);
519  failed:
520   xfree (p);
521   ksba_cert_release (cert);
522   ksba_reader_release (reader);
523   return 0;
524 }
525 #endif /*KEYBOX_WITH_X509*/
526
527
528 \f
529 /*
530   The has_foo functions are used as helpers for search 
531 */
532 static inline int
533 has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
534 {
535   return blob_cmp_fpr_part (blob, kid+4, 16, 4);
536 }
537
538 static inline int
539 has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
540 {
541   return blob_cmp_fpr_part (blob, kid, 12, 8);
542 }
543
544 static inline int
545 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
546 {
547   return blob_cmp_fpr (blob, fpr);
548 }
549
550 static inline int
551 has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
552 {
553 #ifdef KEYBOX_WITH_X509
554   if (blob_get_type (blob) == BLOBTYPE_X509)
555     return blob_x509_has_grip (blob, grip);
556 #endif
557   return 0;
558 }
559
560
561 static inline int
562 has_issuer (KEYBOXBLOB blob, const char *name)
563 {
564   size_t namelen;
565
566   return_val_if_fail (name, 0);
567
568   if (blob_get_type (blob) != BLOBTYPE_X509)
569     return 0;
570
571   namelen = strlen (name);
572   return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
573 }
574
575 static inline int
576 has_issuer_sn (KEYBOXBLOB blob, const char *name,
577                const unsigned char *sn, int snlen)
578 {
579   size_t namelen;
580
581   return_val_if_fail (name, 0);
582   return_val_if_fail (sn, 0);
583
584   if (blob_get_type (blob) != BLOBTYPE_X509)
585     return 0;
586
587   namelen = strlen (name);
588   
589   return (blob_cmp_sn (blob, sn, snlen)
590           && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
591 }
592
593 static inline int
594 has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
595 {
596   return_val_if_fail (sn, 0);
597
598   if (blob_get_type (blob) != BLOBTYPE_X509)
599     return 0;
600   return blob_cmp_sn (blob, sn, snlen);
601 }
602
603 static inline int
604 has_subject (KEYBOXBLOB blob, const char *name)
605 {
606   size_t namelen;
607
608   return_val_if_fail (name, 0);
609
610   if (blob_get_type (blob) != BLOBTYPE_X509)
611     return 0;
612
613   namelen = strlen (name);
614   return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
615 }
616
617 static inline int
618 has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
619 {
620   size_t namelen;
621
622   return_val_if_fail (name, 0);
623
624   if (blob_get_type (blob) != BLOBTYPE_X509)
625     return 0;
626
627   namelen = strlen (name);
628   return blob_cmp_name (blob, -1 /* all subject names*/, name,
629                         namelen, substr);
630 }
631
632
633 static inline int
634 has_mail (KEYBOXBLOB blob, const char *name, int substr)
635 {
636   size_t namelen;
637
638   return_val_if_fail (name, 0);
639
640   if (blob_get_type (blob) != BLOBTYPE_X509)
641     return 0;
642
643   namelen = strlen (name);
644   if (namelen && name[namelen-1] == '>')
645     namelen--;
646   return blob_cmp_mail (blob, name, namelen, substr);
647 }
648
649
650 static void
651 release_sn_array (struct sn_array_s *array, size_t size)
652 {
653   size_t n;
654
655   for (n=0; n < size; n++)
656     xfree (array[n].sn);
657   xfree (array);
658 }
659
660 \f
661 /*
662
663   The search API
664
665 */
666
667 int 
668 keybox_search_reset (KEYBOX_HANDLE hd)
669 {
670   if (!hd)
671     return gpg_error (GPG_ERR_INV_VALUE);
672
673   if (hd->found.blob)
674     {
675       _keybox_release_blob (hd->found.blob);
676       hd->found.blob = NULL;
677     }
678
679   if (hd->fp)
680     {
681       fclose (hd->fp);
682       hd->fp = NULL;
683     }
684   hd->error = 0;
685   hd->eof = 0;
686   return 0;   
687 }
688
689
690 /* Note: When in ephemeral mode the search function does visit all
691    blobs but in standard mode, blobs flagged as ephemeral are ignored.  */
692 int 
693 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
694 {
695   int rc;
696   size_t n;
697   int need_words, any_skip;
698   KEYBOXBLOB blob = NULL;
699   struct sn_array_s *sn_array = NULL;
700
701   if (!hd)
702     return gpg_error (GPG_ERR_INV_VALUE);
703
704   /* clear last found result */
705   if (hd->found.blob)
706     {
707       _keybox_release_blob (hd->found.blob);
708       hd->found.blob = NULL;
709     }
710
711   if (hd->error)  
712     return hd->error; /* still in error state */
713   if (hd->eof)  
714     return -1; /* still EOF */
715
716   /* figure out what information we need */
717   need_words = any_skip = 0;
718   for (n=0; n < ndesc; n++) 
719     {
720       switch (desc[n].mode) 
721         {
722         case KEYDB_SEARCH_MODE_WORDS: 
723           need_words = 1;
724           break;
725         case KEYDB_SEARCH_MODE_FIRST:
726           /* always restart the search in this mode */
727           keybox_search_reset (hd);
728           break;
729         default:
730           break;
731         }
732       if (desc[n].skipfnc) 
733         any_skip = 1;
734       if (desc[n].snlen == -1 && !sn_array)
735         {
736           sn_array = xtrycalloc (ndesc, sizeof *sn_array);
737           if (!sn_array)
738             return (hd->error = gpg_error (gpg_err_code_from_errno (errno)));
739         }
740     }
741
742   if (!hd->fp)
743     {
744       hd->fp = fopen (hd->kb->fname, "rb");
745       if (!hd->fp)
746         {
747           hd->error = gpg_error (gpg_err_code_from_errno (errno));
748           xfree (sn_array);
749           return hd->error;
750         }
751     }
752
753   /* kludge: we need to convert an SN given as hexstring to it's
754      binary representation - in some cases we are not able to store it
755      in the search descriptor, because due to its usage it is not
756      possible to free allocated memory */
757   if (sn_array)
758     {
759       const unsigned char *s;
760       int i, odd;
761       size_t snlen;
762
763       for (n=0; n < ndesc; n++) 
764         {
765           if (!desc[n].sn)
766             ;
767           else if (desc[n].snlen == -1)
768             {
769               unsigned char *sn;
770
771               s = desc[n].sn;
772               for (i=0; *s && *s != '/'; s++, i++)
773                 ;
774               odd = (i & 1);
775               snlen = (i+1)/2;
776               sn_array[n].sn = xtrymalloc (snlen);
777               if (!sn_array[n].sn)
778                 {
779                   hd->error = gpg_error (gpg_err_code_from_errno (errno));
780                   release_sn_array (sn_array, n);
781                   return hd->error;
782                 }
783               sn_array[n].snlen = snlen;
784               sn = sn_array[n].sn;
785               s = desc[n].sn;
786               if (odd)
787                 {
788                   *sn++ = xtoi_1 (s);
789                   s++;
790                 }
791               for (; *s && *s != '/';  s += 2)
792                 *sn++ = xtoi_2 (s);
793             }
794           else
795             {
796               const unsigned char *sn;
797
798               sn = desc[n].sn;
799               snlen = desc[n].snlen;
800               sn_array[n].sn = xtrymalloc (snlen);
801               if (!sn_array[n].sn)
802                 {
803                   hd->error = gpg_error (gpg_err_code_from_errno (errno));
804                   release_sn_array (sn_array, n);
805                   return hd->error;
806                 }
807               sn_array[n].snlen = snlen;
808               memcpy (sn_array[n].sn, sn, snlen);
809             }
810         }
811     }
812
813
814   for (;;)
815     {
816       unsigned int blobflags;
817
818       _keybox_release_blob (blob); blob = NULL;
819       rc = _keybox_read_blob (&blob, hd->fp);
820       if (rc)
821         break;
822
823       if (blob_get_type (blob) == BLOBTYPE_HEADER)
824         continue;
825
826
827       blobflags = blob_get_blob_flags (blob);
828       if (!hd->ephemeral && (blobflags & 2))
829         continue; /* Not in ephemeral mode but blob is flagged ephemeral.  */
830
831       for (n=0; n < ndesc; n++) 
832         {
833           switch (desc[n].mode)
834             {
835             case KEYDB_SEARCH_MODE_NONE: 
836               never_reached ();
837               break;
838             case KEYDB_SEARCH_MODE_EXACT: 
839               if (has_subject_or_alt (blob, desc[n].u.name, 0))
840                 goto found;
841               break;
842             case KEYDB_SEARCH_MODE_MAIL:
843               if (has_mail (blob, desc[n].u.name, 0))
844                 goto found;
845               break;
846             case KEYDB_SEARCH_MODE_MAILSUB:
847               if (has_mail (blob, desc[n].u.name, 1))
848                 goto found;
849               break;
850             case KEYDB_SEARCH_MODE_SUBSTR:
851               if (has_subject_or_alt (blob, desc[n].u.name, 1))
852                 goto found;
853               break;
854             case KEYDB_SEARCH_MODE_MAILEND:
855             case KEYDB_SEARCH_MODE_WORDS: 
856               never_reached (); /* not yet implemented */
857               break;
858             case KEYDB_SEARCH_MODE_ISSUER:
859               if (has_issuer (blob, desc[n].u.name))
860                 goto found;
861               break;
862             case KEYDB_SEARCH_MODE_ISSUER_SN:
863               if (has_issuer_sn (blob, desc[n].u.name,
864                                  sn_array? sn_array[n].sn : desc[n].sn,
865                                  sn_array? sn_array[n].snlen : desc[n].snlen))
866                 goto found;
867               break;
868             case KEYDB_SEARCH_MODE_SN:
869               if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
870                                 sn_array? sn_array[n].snlen : desc[n].snlen))
871                 goto found;
872               break;
873             case KEYDB_SEARCH_MODE_SUBJECT:
874               if (has_subject (blob, desc[n].u.name))
875                 goto found;
876               break;
877             case KEYDB_SEARCH_MODE_SHORT_KID: 
878               if (has_short_kid (blob, desc[n].u.kid))
879                 goto found;
880               break;
881             case KEYDB_SEARCH_MODE_LONG_KID:
882               if (has_long_kid (blob, desc[n].u.kid))
883                 goto found;
884               break;
885             case KEYDB_SEARCH_MODE_FPR:
886             case KEYDB_SEARCH_MODE_FPR20:
887               if (has_fingerprint (blob, desc[n].u.fpr))
888                 goto found;
889               break;
890             case KEYDB_SEARCH_MODE_KEYGRIP:
891               if (has_keygrip (blob, desc[n].u.grip))
892                 goto found;
893               break;
894             case KEYDB_SEARCH_MODE_FIRST: 
895               goto found;
896               break;
897             case KEYDB_SEARCH_MODE_NEXT: 
898               goto found;
899               break;
900             default: 
901               rc = gpg_error (GPG_ERR_INV_VALUE);
902               goto found;
903             }
904         }
905       continue;
906     found:  
907       for (n=any_skip?0:ndesc; n < ndesc; n++) 
908         {
909 /*            if (desc[n].skipfnc */
910 /*                && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
911 /*              break; */
912         }
913       if (n == ndesc)
914         break; /* got it */
915     }
916   
917   if (!rc)
918     {
919       hd->found.blob = blob;
920     }
921   else if (rc == -1)
922     {
923       _keybox_release_blob (blob);
924       hd->eof = 1;
925     }
926   else 
927     {
928       _keybox_release_blob (blob);
929       hd->error = rc;
930     }
931
932   if (sn_array)
933     release_sn_array (sn_array, ndesc);
934
935   return rc;
936 }
937
938
939
940 \f
941 /*
942    Functions to return a certificate or a keyblock.  To be used after
943    a successful search operation.
944 */
945 #ifdef KEYBOX_WITH_X509
946 /*
947   Return the last found cert.  Caller must free it.
948  */
949 int
950 keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert)
951 {
952   const unsigned char *buffer;
953   size_t length;
954   size_t cert_off, cert_len;
955   ksba_reader_t reader = NULL;
956   ksba_cert_t cert = NULL;
957   int rc;
958
959   if (!hd)
960     return gpg_error (GPG_ERR_INV_VALUE);
961   if (!hd->found.blob)
962     return gpg_error (GPG_ERR_NOTHING_FOUND);
963
964   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
965     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
966
967   buffer = _keybox_get_blob_image (hd->found.blob, &length);
968   if (length < 40)
969     return gpg_error (GPG_ERR_TOO_SHORT);
970   cert_off = get32 (buffer+8);
971   cert_len = get32 (buffer+12);
972   if (cert_off+cert_len > length)
973     return gpg_error (GPG_ERR_TOO_SHORT);
974
975   rc = ksba_reader_new (&reader);
976   if (rc)
977     return rc;
978   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
979   if (rc)
980     {
981       ksba_reader_release (reader);
982       /* fixme: need to map the error codes */
983       return gpg_error (GPG_ERR_GENERAL);
984     }
985
986   rc = ksba_cert_new (&cert);
987   if (rc)
988     {
989       ksba_reader_release (reader);
990       return rc;
991     }
992
993   rc = ksba_cert_read_der (cert, reader);
994   if (rc)
995     {
996       ksba_cert_release (cert);
997       ksba_reader_release (reader);
998       /* fixme: need to map the error codes */
999       return gpg_error (GPG_ERR_GENERAL);
1000     }
1001
1002   *r_cert = cert;
1003   ksba_reader_release (reader);
1004   return 0;
1005 }
1006
1007 #endif /*KEYBOX_WITH_X509*/
1008
1009 /* Return the flags named WHAT at the address of VALUE. IDX is used
1010    only for certain flags and should be 0 if not required. */
1011 int
1012 keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value)
1013 {
1014   const unsigned char *buffer;
1015   size_t length;
1016   gpg_err_code_t ec;
1017
1018   if (!hd)
1019     return gpg_error (GPG_ERR_INV_VALUE);
1020   if (!hd->found.blob)
1021     return gpg_error (GPG_ERR_NOTHING_FOUND);
1022
1023   buffer = _keybox_get_blob_image (hd->found.blob, &length);
1024   ec = get_flag_from_image (buffer, length, what, value);
1025   return ec? gpg_error (ec):0;
1026 }
1027