Unification of the search descriptor usage.
[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 we need to parse the
461    certificate. Fixme: We might want 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, u32 lkid)
534 {
535   unsigned char buf[4];
536   buf[0] = lkid >> 24;
537   buf[1] = lkid >> 16;
538   buf[2] = lkid >> 8;
539   buf[3] = lkid;
540   return blob_cmp_fpr_part (blob, buf, 16, 4);
541 }
542
543 static inline int
544 has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid)
545 {
546   unsigned char buf[8];
547   buf[0] = mkid >> 24;
548   buf[1] = mkid >> 16;
549   buf[2] = mkid >> 8;
550   buf[3] = mkid;
551   buf[4] = lkid >> 24;
552   buf[5] = lkid >> 16;
553   buf[6] = lkid >> 8;
554   buf[7] = lkid;
555   return blob_cmp_fpr_part (blob, buf, 12, 8);
556 }
557
558 static inline int
559 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
560 {
561   return blob_cmp_fpr (blob, fpr);
562 }
563
564 static inline int
565 has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
566 {
567 #ifdef KEYBOX_WITH_X509
568   if (blob_get_type (blob) == BLOBTYPE_X509)
569     return blob_x509_has_grip (blob, grip);
570 #endif
571   return 0;
572 }
573
574
575 static inline int
576 has_issuer (KEYBOXBLOB blob, const char *name)
577 {
578   size_t namelen;
579
580   return_val_if_fail (name, 0);
581
582   if (blob_get_type (blob) != BLOBTYPE_X509)
583     return 0;
584
585   namelen = strlen (name);
586   return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
587 }
588
589 static inline int
590 has_issuer_sn (KEYBOXBLOB blob, const char *name,
591                const unsigned char *sn, int snlen)
592 {
593   size_t namelen;
594
595   return_val_if_fail (name, 0);
596   return_val_if_fail (sn, 0);
597
598   if (blob_get_type (blob) != BLOBTYPE_X509)
599     return 0;
600
601   namelen = strlen (name);
602   
603   return (blob_cmp_sn (blob, sn, snlen)
604           && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
605 }
606
607 static inline int
608 has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
609 {
610   return_val_if_fail (sn, 0);
611
612   if (blob_get_type (blob) != BLOBTYPE_X509)
613     return 0;
614   return blob_cmp_sn (blob, sn, snlen);
615 }
616
617 static inline int
618 has_subject (KEYBOXBLOB blob, const char *name)
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 /* subject */, name, namelen, 0);
629 }
630
631 static inline int
632 has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
633 {
634   size_t namelen;
635
636   return_val_if_fail (name, 0);
637
638   if (blob_get_type (blob) != BLOBTYPE_X509)
639     return 0;
640
641   namelen = strlen (name);
642   return blob_cmp_name (blob, -1 /* all subject names*/, name,
643                         namelen, substr);
644 }
645
646
647 static inline int
648 has_mail (KEYBOXBLOB blob, const char *name, int substr)
649 {
650   size_t namelen;
651
652   return_val_if_fail (name, 0);
653
654   if (blob_get_type (blob) != BLOBTYPE_X509)
655     return 0;
656
657   namelen = strlen (name);
658   if (namelen && name[namelen-1] == '>')
659     namelen--;
660   return blob_cmp_mail (blob, name, namelen, substr);
661 }
662
663
664 static void
665 release_sn_array (struct sn_array_s *array, size_t size)
666 {
667   size_t n;
668
669   for (n=0; n < size; n++)
670     xfree (array[n].sn);
671   xfree (array);
672 }
673
674 \f
675 /*
676
677   The search API
678
679 */
680
681 int 
682 keybox_search_reset (KEYBOX_HANDLE hd)
683 {
684   if (!hd)
685     return gpg_error (GPG_ERR_INV_VALUE);
686
687   if (hd->found.blob)
688     {
689       _keybox_release_blob (hd->found.blob);
690       hd->found.blob = NULL;
691     }
692
693   if (hd->fp)
694     {
695       fclose (hd->fp);
696       hd->fp = NULL;
697     }
698   hd->error = 0;
699   hd->eof = 0;
700   return 0;   
701 }
702
703
704 /* Note: When in ephemeral mode the search function does visit all
705    blobs but in standard mode, blobs flagged as ephemeral are ignored.  */
706 int 
707 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
708 {
709   int rc;
710   size_t n;
711   int need_words, any_skip;
712   KEYBOXBLOB blob = NULL;
713   struct sn_array_s *sn_array = NULL;
714
715   if (!hd)
716     return gpg_error (GPG_ERR_INV_VALUE);
717
718   /* clear last found result */
719   if (hd->found.blob)
720     {
721       _keybox_release_blob (hd->found.blob);
722       hd->found.blob = NULL;
723     }
724
725   if (hd->error)  
726     return hd->error; /* still in error state */
727   if (hd->eof)  
728     return -1; /* still EOF */
729
730   /* figure out what information we need */
731   need_words = any_skip = 0;
732   for (n=0; n < ndesc; n++) 
733     {
734       switch (desc[n].mode) 
735         {
736         case KEYDB_SEARCH_MODE_WORDS: 
737           need_words = 1;
738           break;
739         case KEYDB_SEARCH_MODE_FIRST:
740           /* always restart the search in this mode */
741           keybox_search_reset (hd);
742           break;
743         default:
744           break;
745         }
746       if (desc[n].skipfnc) 
747         any_skip = 1;
748       if (desc[n].snlen == -1 && !sn_array)
749         {
750           sn_array = xtrycalloc (ndesc, sizeof *sn_array);
751           if (!sn_array)
752             return (hd->error = gpg_error_from_syserror ());
753         }
754     }
755
756   (void)need_words;  /* Not yet implemented.  */
757
758   if (!hd->fp)
759     {
760       hd->fp = fopen (hd->kb->fname, "rb");
761       if (!hd->fp)
762         {
763           hd->error = gpg_error_from_syserror ();
764           xfree (sn_array);
765           return hd->error;
766         }
767     }
768
769   /* Kludge: We need to convert an SN given as hexstring to its binary
770      representation - in some cases we are not able to store it in the
771      search descriptor, because due to the way we use it, it is not
772      possible to free allocated memory. */
773   if (sn_array)
774     {
775       const unsigned char *s;
776       int i, odd;
777       size_t snlen;
778
779       for (n=0; n < ndesc; n++) 
780         {
781           if (!desc[n].sn)
782             ;
783           else if (desc[n].snlen == -1)
784             {
785               unsigned char *sn;
786
787               s = desc[n].sn;
788               for (i=0; *s && *s != '/'; s++, i++)
789                 ;
790               odd = (i & 1);
791               snlen = (i+1)/2;
792               sn_array[n].sn = xtrymalloc (snlen);
793               if (!sn_array[n].sn)
794                 {
795                   hd->error = gpg_error_from_syserror ();
796                   release_sn_array (sn_array, n);
797                   return hd->error;
798                 }
799               sn_array[n].snlen = snlen;
800               sn = sn_array[n].sn;
801               s = desc[n].sn;
802               if (odd)
803                 {
804                   *sn++ = xtoi_1 (s);
805                   s++;
806                 }
807               for (; *s && *s != '/';  s += 2)
808                 *sn++ = xtoi_2 (s);
809             }
810           else
811             {
812               const unsigned char *sn;
813
814               sn = desc[n].sn;
815               snlen = desc[n].snlen;
816               sn_array[n].sn = xtrymalloc (snlen);
817               if (!sn_array[n].sn)
818                 {
819                   hd->error = gpg_error_from_syserror ();
820                   release_sn_array (sn_array, n);
821                   return hd->error;
822                 }
823               sn_array[n].snlen = snlen;
824               memcpy (sn_array[n].sn, sn, snlen);
825             }
826         }
827     }
828
829
830   for (;;)
831     {
832       unsigned int blobflags;
833
834       _keybox_release_blob (blob); blob = NULL;
835       rc = _keybox_read_blob (&blob, hd->fp);
836       if (rc)
837         break;
838
839       if (blob_get_type (blob) == BLOBTYPE_HEADER)
840         continue;
841
842
843       blobflags = blob_get_blob_flags (blob);
844       if (!hd->ephemeral && (blobflags & 2))
845         continue; /* Not in ephemeral mode but blob is flagged ephemeral.  */
846
847       for (n=0; n < ndesc; n++) 
848         {
849           switch (desc[n].mode)
850             {
851             case KEYDB_SEARCH_MODE_NONE: 
852               never_reached ();
853               break;
854             case KEYDB_SEARCH_MODE_EXACT: 
855               if (has_subject_or_alt (blob, desc[n].u.name, 0))
856                 goto found;
857               break;
858             case KEYDB_SEARCH_MODE_MAIL:
859               if (has_mail (blob, desc[n].u.name, 0))
860                 goto found;
861               break;
862             case KEYDB_SEARCH_MODE_MAILSUB:
863               if (has_mail (blob, desc[n].u.name, 1))
864                 goto found;
865               break;
866             case KEYDB_SEARCH_MODE_SUBSTR:
867               if (has_subject_or_alt (blob, desc[n].u.name, 1))
868                 goto found;
869               break;
870             case KEYDB_SEARCH_MODE_MAILEND:
871             case KEYDB_SEARCH_MODE_WORDS: 
872               never_reached (); /* not yet implemented */
873               break;
874             case KEYDB_SEARCH_MODE_ISSUER:
875               if (has_issuer (blob, desc[n].u.name))
876                 goto found;
877               break;
878             case KEYDB_SEARCH_MODE_ISSUER_SN:
879               if (has_issuer_sn (blob, desc[n].u.name,
880                                  sn_array? sn_array[n].sn : desc[n].sn,
881                                  sn_array? sn_array[n].snlen : desc[n].snlen))
882                 goto found;
883               break;
884             case KEYDB_SEARCH_MODE_SN:
885               if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
886                                 sn_array? sn_array[n].snlen : desc[n].snlen))
887                 goto found;
888               break;
889             case KEYDB_SEARCH_MODE_SUBJECT:
890               if (has_subject (blob, desc[n].u.name))
891                 goto found;
892               break;
893             case KEYDB_SEARCH_MODE_SHORT_KID: 
894               if (has_short_kid (blob, desc[n].u.kid[1]))
895                 goto found;
896               break;
897             case KEYDB_SEARCH_MODE_LONG_KID:
898               if (has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]))
899                 goto found;
900               break;
901             case KEYDB_SEARCH_MODE_FPR:
902             case KEYDB_SEARCH_MODE_FPR20:
903               if (has_fingerprint (blob, desc[n].u.fpr))
904                 goto found;
905               break;
906             case KEYDB_SEARCH_MODE_KEYGRIP:
907               if (has_keygrip (blob, desc[n].u.grip))
908                 goto found;
909               break;
910             case KEYDB_SEARCH_MODE_FIRST: 
911               goto found;
912               break;
913             case KEYDB_SEARCH_MODE_NEXT: 
914               goto found;
915               break;
916             default: 
917               rc = gpg_error (GPG_ERR_INV_VALUE);
918               goto found;
919             }
920         }
921       continue;
922     found:  
923       for (n=any_skip?0:ndesc; n < ndesc; n++) 
924         {
925 /*            if (desc[n].skipfnc */
926 /*                && desc[n].skipfnc (desc[n].skipfncvalue, aki, NULL)) */
927 /*              break; */
928         }
929       if (n == ndesc)
930         break; /* got it */
931     }
932   
933   if (!rc)
934     {
935       hd->found.blob = blob;
936     }
937   else if (rc == -1)
938     {
939       _keybox_release_blob (blob);
940       hd->eof = 1;
941     }
942   else 
943     {
944       _keybox_release_blob (blob);
945       hd->error = rc;
946     }
947
948   if (sn_array)
949     release_sn_array (sn_array, ndesc);
950
951   return rc;
952 }
953
954
955
956 \f
957 /*
958    Functions to return a certificate or a keyblock.  To be used after
959    a successful search operation.
960 */
961 #ifdef KEYBOX_WITH_X509
962 /*
963   Return the last found cert.  Caller must free it.
964  */
965 int
966 keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert)
967 {
968   const unsigned char *buffer;
969   size_t length;
970   size_t cert_off, cert_len;
971   ksba_reader_t reader = NULL;
972   ksba_cert_t cert = NULL;
973   int rc;
974
975   if (!hd)
976     return gpg_error (GPG_ERR_INV_VALUE);
977   if (!hd->found.blob)
978     return gpg_error (GPG_ERR_NOTHING_FOUND);
979
980   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
981     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
982
983   buffer = _keybox_get_blob_image (hd->found.blob, &length);
984   if (length < 40)
985     return gpg_error (GPG_ERR_TOO_SHORT);
986   cert_off = get32 (buffer+8);
987   cert_len = get32 (buffer+12);
988   if (cert_off+cert_len > length)
989     return gpg_error (GPG_ERR_TOO_SHORT);
990
991   rc = ksba_reader_new (&reader);
992   if (rc)
993     return rc;
994   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
995   if (rc)
996     {
997       ksba_reader_release (reader);
998       /* fixme: need to map the error codes */
999       return gpg_error (GPG_ERR_GENERAL);
1000     }
1001
1002   rc = ksba_cert_new (&cert);
1003   if (rc)
1004     {
1005       ksba_reader_release (reader);
1006       return rc;
1007     }
1008
1009   rc = ksba_cert_read_der (cert, reader);
1010   if (rc)
1011     {
1012       ksba_cert_release (cert);
1013       ksba_reader_release (reader);
1014       /* fixme: need to map the error codes */
1015       return gpg_error (GPG_ERR_GENERAL);
1016     }
1017
1018   *r_cert = cert;
1019   ksba_reader_release (reader);
1020   return 0;
1021 }
1022
1023 #endif /*KEYBOX_WITH_X509*/
1024
1025 /* Return the flags named WHAT at the address of VALUE. IDX is used
1026    only for certain flags and should be 0 if not required. */
1027 int
1028 keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value)
1029 {
1030   const unsigned char *buffer;
1031   size_t length;
1032   gpg_err_code_t ec;
1033
1034   (void)idx; /* Not yet used.  */
1035
1036   if (!hd)
1037     return gpg_error (GPG_ERR_INV_VALUE);
1038   if (!hd->found.blob)
1039     return gpg_error (GPG_ERR_NOTHING_FOUND);
1040
1041   buffer = _keybox_get_blob_image (hd->found.blob, &length);
1042   ec = get_flag_from_image (buffer, length, what, value);
1043   return ec? gpg_error (ec):0;
1044 }
1045