2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / kbx / keybox-search.c
blobc7434cd93e62c011c772f9696be5056a892ed8d5
1 /* keybox-search.c - Search operations
2 * Copyright (C) 2001 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
27 #include "../jnlib/stringhelp.h" /* ascii_xxxx() */
28 #include "keybox-defs.h"
30 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
31 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
32 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
34 struct sn_array_s {
35 int snlen;
36 unsigned char *sn;
41 static ulong
42 get32 (const byte *buffer)
44 ulong a;
45 a = *buffer << 24;
46 a |= buffer[1] << 16;
47 a |= buffer[2] << 8;
48 a |= buffer[3];
49 return a;
52 static ulong
53 get16 (const byte *buffer)
55 ulong a;
56 a = *buffer << 8;
57 a |= buffer[1];
58 return a;
63 static int
64 blob_get_type (KEYBOXBLOB blob)
66 const unsigned char *buffer;
67 size_t length;
69 buffer = _keybox_get_blob_image (blob, &length);
70 if (length < 40)
71 return -1; /* blob too short */
73 return buffer[4];
77 static int
78 blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
80 const unsigned char *buffer;
81 size_t length;
82 size_t pos, off;
83 size_t nkeys, keyinfolen;
84 size_t nserial;
86 buffer = _keybox_get_blob_image (blob, &length);
87 if (length < 40)
88 return 0; /* blob too short */
90 /*keys*/
91 nkeys = get16 (buffer + 16);
92 keyinfolen = get16 (buffer + 18 );
93 if (keyinfolen < 28)
94 return 0; /* invalid blob */
95 pos = 20 + keyinfolen*nkeys;
96 if (pos+2 > length)
97 return 0; /* out of bounds */
99 /*serial*/
100 nserial = get16 (buffer+pos);
101 off = pos + 2;
102 if (off+nserial > length)
103 return 0; /* out of bounds */
105 return nserial == snlen && !memcmp (buffer+off, sn, snlen);
109 static int
110 blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
112 const unsigned char *buffer;
113 size_t length;
114 size_t pos, off;
115 size_t nkeys, keyinfolen;
116 int idx;
118 buffer = _keybox_get_blob_image (blob, &length);
119 if (length < 40)
120 return 0; /* blob too short */
122 /*keys*/
123 nkeys = get16 (buffer + 16);
124 keyinfolen = get16 (buffer + 18 );
125 if (keyinfolen < 28)
126 return 0; /* invalid blob */
127 pos = 20;
128 if (pos + keyinfolen*nkeys > length)
129 return 0; /* out of bounds */
131 for (idx=0; idx < nkeys; idx++)
133 off = pos + idx*keyinfolen;
134 if (!memcmp (buffer + off, fpr, 20))
135 return 1; /* found */
137 return 0; /* not found */
141 static int
142 blob_cmp_name (KEYBOXBLOB blob, int idx,
143 const char *name, size_t namelen, int substr)
145 const unsigned char *buffer;
146 size_t length;
147 size_t pos, off, len;
148 size_t nkeys, keyinfolen;
149 size_t nuids, uidinfolen;
150 size_t nserial;
152 buffer = _keybox_get_blob_image (blob, &length);
153 if (length < 40)
154 return 0; /* blob too short */
156 /*keys*/
157 nkeys = get16 (buffer + 16);
158 keyinfolen = get16 (buffer + 18 );
159 if (keyinfolen < 28)
160 return 0; /* invalid blob */
161 pos = 20 + keyinfolen*nkeys;
162 if (pos+2 > length)
163 return 0; /* out of bounds */
165 /*serial*/
166 nserial = get16 (buffer+pos);
167 pos += 2 + nserial;
168 if (pos+4 > length)
169 return 0; /* out of bounds */
171 /* user ids*/
172 nuids = get16 (buffer + pos); pos += 2;
173 uidinfolen = get16 (buffer + pos); pos += 2;
174 if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
175 return 0; /* invalid blob */
176 if (pos + uidinfolen*nuids > length)
177 return 0; /* out of bounds */
179 if (idx < 0)
180 { /* compare all names starting with that (negated) index */
181 idx = -idx;
183 for ( ;idx < nuids; idx++)
185 size_t mypos = pos;
187 mypos += idx*uidinfolen;
188 off = get32 (buffer+mypos);
189 len = get32 (buffer+mypos+4);
190 if (off+len > length)
191 return 0; /* error: better stop here out of bounds */
192 if (len < 2)
193 continue; /* empty name or 0 not stored */
194 len--;
195 if (substr)
197 if (ascii_memcasemem (buffer+off, len, name, namelen))
198 return 1; /* found */
200 else
202 if (len == namelen && !memcmp (buffer+off, name, len))
203 return 1; /* found */
206 return 0; /* not found */
208 else
210 if (idx > nuids)
211 return 0; /* no user ID with that idx */
212 pos += idx*uidinfolen;
213 off = get32 (buffer+pos);
214 len = get32 (buffer+pos+4);
215 if (off+len > length)
216 return 0; /* out of bounds */
217 if (len < 1)
218 return 0; /* empty name */
220 if (substr)
222 return !!ascii_memcasemem (buffer+off, len, name, namelen);
224 else
226 return len == namelen && !memcmp (buffer+off, name, len);
232 /* compare all email addresses of the subject. With SUBSTR given as
233 True a substring search is done in the mail address */
234 static int
235 blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
237 const unsigned char *buffer;
238 size_t length;
239 size_t pos, off, len;
240 size_t nkeys, keyinfolen;
241 size_t nuids, uidinfolen;
242 size_t nserial;
243 int idx;
245 /* fixme: this code is common to blob_cmp_mail */
246 buffer = _keybox_get_blob_image (blob, &length);
247 if (length < 40)
248 return 0; /* blob too short */
250 /*keys*/
251 nkeys = get16 (buffer + 16);
252 keyinfolen = get16 (buffer + 18 );
253 if (keyinfolen < 28)
254 return 0; /* invalid blob */
255 pos = 20 + keyinfolen*nkeys;
256 if (pos+2 > length)
257 return 0; /* out of bounds */
259 /*serial*/
260 nserial = get16 (buffer+pos);
261 pos += 2 + nserial;
262 if (pos+4 > length)
263 return 0; /* out of bounds */
265 /* user ids*/
266 nuids = get16 (buffer + pos); pos += 2;
267 uidinfolen = get16 (buffer + pos); pos += 2;
268 if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
269 return 0; /* invalid blob */
270 if (pos + uidinfolen*nuids > length)
271 return 0; /* out of bounds */
273 if (namelen < 1)
274 return 0;
276 for (idx=1 ;idx < nuids; idx++)
278 size_t mypos = pos;
280 mypos += idx*uidinfolen;
281 off = get32 (buffer+mypos);
282 len = get32 (buffer+mypos+4);
283 if (off+len > length)
284 return 0; /* error: better stop here out of bounds */
285 if (len < 2 || buffer[off] != '<')
286 continue; /* empty name or trailing 0 not stored */
287 len--; /* one back */
288 if ( len < 3 || buffer[off+len] != '>')
289 continue; /* not a proper email address */
290 len--;
291 if (substr)
293 if (ascii_memcasemem (buffer+off+1, len, name, namelen))
294 return 1; /* found */
296 else
298 if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
299 return 1; /* found */
302 return 0; /* not found */
309 The has_foo functions are used as helpers for search
311 #if 0
312 static int
313 has_short_kid (KEYBOXBLOB blob, u32 kid)
315 return 0;
318 static int
319 has_long_kid (KEYBOXBLOB blob, u32 *kid)
321 return 0;
323 #endif
325 static int
326 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
328 return blob_cmp_fpr (blob, fpr);
332 static int
333 has_issuer (KEYBOXBLOB blob, const char *name)
335 size_t namelen;
337 return_val_if_fail (name, 0);
339 if (blob_get_type (blob) != BLOBTYPE_X509)
340 return 0;
342 namelen = strlen (name);
343 return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
346 static int
347 has_issuer_sn (KEYBOXBLOB blob, const char *name,
348 const unsigned char *sn, int snlen)
350 size_t namelen;
352 return_val_if_fail (name, 0);
353 return_val_if_fail (sn, 0);
355 if (blob_get_type (blob) != BLOBTYPE_X509)
356 return 0;
358 namelen = strlen (name);
360 return (blob_cmp_sn (blob, sn, snlen)
361 && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
364 static int
365 has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
367 return_val_if_fail (sn, 0);
369 if (blob_get_type (blob) != BLOBTYPE_X509)
370 return 0;
371 return blob_cmp_sn (blob, sn, snlen);
374 static int
375 has_subject (KEYBOXBLOB blob, const char *name)
377 size_t namelen;
379 return_val_if_fail (name, 0);
381 if (blob_get_type (blob) != BLOBTYPE_X509)
382 return 0;
384 namelen = strlen (name);
385 return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
388 static int
389 has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
391 size_t namelen;
393 return_val_if_fail (name, 0);
395 if (blob_get_type (blob) != BLOBTYPE_X509)
396 return 0;
398 namelen = strlen (name);
399 return blob_cmp_name (blob, -1 /* all subject names*/, name,
400 namelen, substr);
404 static int
405 has_mail (KEYBOXBLOB blob, const char *name, int substr)
407 size_t namelen;
409 return_val_if_fail (name, 0);
411 if (blob_get_type (blob) != BLOBTYPE_X509)
412 return 0;
414 namelen = strlen (name);
415 if (namelen && name[namelen-1] == '>')
416 namelen--;
417 return blob_cmp_mail (blob, name, namelen, substr);
421 static void
422 release_sn_array (struct sn_array_s *array, size_t size)
424 size_t n;
426 for (n=0; n < size; n++)
427 xfree (array[n].sn);
428 xfree (array);
434 The search API
438 int
439 keybox_search_reset (KEYBOX_HANDLE hd)
441 if (!hd)
442 return KEYBOX_Invalid_Value;
444 if (hd->found.blob)
446 _keybox_release_blob (hd->found.blob);
447 hd->found.blob = NULL;
450 if (hd->fp)
452 fclose (hd->fp);
453 hd->fp = NULL;
455 hd->error = 0;
456 hd->eof = 0;
457 return 0;
460 int
461 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
463 int rc;
464 size_t n;
465 int need_words, any_skip;
466 KEYBOXBLOB blob = NULL;
467 struct sn_array_s *sn_array = NULL;
469 if (!hd)
470 return KEYBOX_Invalid_Value;
472 /* clear last found result */
473 if (hd->found.blob)
475 _keybox_release_blob (hd->found.blob);
476 hd->found.blob = NULL;
479 if (hd->error)
480 return hd->error; /* still in error state */
481 if (hd->eof)
482 return -1; /* still EOF */
484 /* figure out what information we need */
485 need_words = any_skip = 0;
486 for (n=0; n < ndesc; n++)
488 switch (desc[n].mode)
490 case KEYDB_SEARCH_MODE_WORDS:
491 need_words = 1;
492 break;
493 case KEYDB_SEARCH_MODE_FIRST:
494 /* always restart the search in this mode */
495 keybox_search_reset (hd);
496 break;
497 default:
498 break;
500 if (desc[n].skipfnc)
501 any_skip = 1;
502 if (desc[n].snlen == -1 && !sn_array)
504 sn_array = xtrycalloc (ndesc, sizeof *sn_array);
505 if (!sn_array)
506 return (hd->error = KEYBOX_Out_Of_Core);
510 if (!hd->fp)
512 hd->fp = fopen (hd->kb->fname, "rb");
513 if (!hd->fp)
515 xfree (sn_array);
516 return (hd->error = KEYBOX_File_Open_Error);
520 /* kludge: we need to convert an SN given as hexstring to it's
521 binary representation - in some cases we are not able to store it
522 in the search descriptor, because due to its usgae it is not
523 possible to free allocated memory */
524 if (sn_array)
526 const unsigned char *s;
527 int i, odd;
528 size_t snlen;
530 for (n=0; n < ndesc; n++)
532 if (!desc[n].sn)
534 else if (desc[n].snlen == -1)
536 unsigned char *sn;
538 s = desc[n].sn;
539 for (i=0; *s && *s != '/'; s++, i++)
541 odd = (i & 1);
542 snlen = (i+1)/2;
543 sn_array[n].sn = xtrymalloc (snlen);
544 if (!sn_array[n].sn)
546 release_sn_array (sn_array, n);
547 return (hd->error = KEYBOX_Out_Of_Core);
549 sn_array[n].snlen = snlen;
550 sn = sn_array[n].sn;
551 s = desc[n].sn;
552 if (odd)
554 *sn++ = xtoi_1 (s);
555 s++;
557 for (; *s && *s != '/'; s += 2)
558 *sn++ = xtoi_2 (s);
560 else
562 const unsigned char *sn;
564 sn = desc[n].sn;
565 snlen = desc[n].snlen;
566 sn_array[n].sn = xtrymalloc (snlen);
567 if (!sn_array[n].sn)
569 release_sn_array (sn_array, n);
570 return (hd->error = KEYBOX_Out_Of_Core);
572 sn_array[n].snlen = snlen;
573 memcpy (sn_array[n].sn, sn, snlen);
579 for (;;)
581 _keybox_release_blob (blob); blob = NULL;
582 rc = _keybox_read_blob (&blob, hd->fp);
583 if (rc)
584 break;
586 for (n=0; n < ndesc; n++)
588 switch (desc[n].mode)
590 case KEYDB_SEARCH_MODE_NONE:
591 never_reached ();
592 break;
593 case KEYDB_SEARCH_MODE_EXACT:
594 if (has_subject_or_alt (blob, desc[n].u.name, 0))
595 goto found;
596 break;
597 case KEYDB_SEARCH_MODE_MAIL:
598 if (has_mail (blob, desc[n].u.name, 0))
599 goto found;
600 break;
601 case KEYDB_SEARCH_MODE_MAILSUB:
602 if (has_mail (blob, desc[n].u.name, 1))
603 goto found;
604 break;
605 case KEYDB_SEARCH_MODE_SUBSTR:
606 if (has_subject_or_alt (blob, desc[n].u.name, 1))
607 goto found;
608 break;
609 case KEYDB_SEARCH_MODE_MAILEND:
610 case KEYDB_SEARCH_MODE_WORDS:
611 never_reached (); /* not yet implemented */
612 break;
613 case KEYDB_SEARCH_MODE_ISSUER:
614 if (has_issuer (blob, desc[n].u.name))
615 goto found;
616 break;
617 case KEYDB_SEARCH_MODE_ISSUER_SN:
618 if (has_issuer_sn (blob, desc[n].u.name,
619 sn_array? sn_array[n].sn : desc[n].sn,
620 sn_array? sn_array[n].snlen : desc[n].snlen))
621 goto found;
622 break;
623 case KEYDB_SEARCH_MODE_SN:
624 if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
625 sn_array? sn_array[n].snlen : desc[n].snlen))
626 goto found;
627 break;
628 case KEYDB_SEARCH_MODE_SUBJECT:
629 if (has_subject (blob, desc[n].u.name))
630 goto found;
631 break;
632 case KEYDB_SEARCH_MODE_SHORT_KID:
633 /* if (has_short_kid (blob, desc[n].u.kid[1])) */
634 /* goto found; */
635 break;
636 case KEYDB_SEARCH_MODE_LONG_KID:
637 /* if (has_long_kid (blob, desc[n].u.kid)) */
638 /* goto found; */
639 break;
640 case KEYDB_SEARCH_MODE_FPR:
641 case KEYDB_SEARCH_MODE_FPR20:
642 if (has_fingerprint (blob, desc[n].u.fpr))
643 goto found;
644 break;
645 case KEYDB_SEARCH_MODE_FIRST:
646 goto found;
647 break;
648 case KEYDB_SEARCH_MODE_NEXT:
649 goto found;
650 break;
651 default:
652 rc = KEYBOX_Invalid_Value;
653 goto found;
656 continue;
657 found:
658 for (n=any_skip?0:ndesc; n < ndesc; n++)
660 /* if (desc[n].skipfnc */
661 /* && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
662 /* break; */
664 if (n == ndesc)
665 break; /* got it */
668 if (!rc)
670 hd->found.blob = blob;
672 else if (rc == -1)
674 _keybox_release_blob (blob);
675 hd->eof = 1;
677 else
679 _keybox_release_blob (blob);
680 hd->error = rc;
683 if (sn_array)
684 release_sn_array (sn_array, ndesc);
686 return rc;
693 Functions to return a certificate or a keyblock. To be used after
694 a successful search operation.
696 #ifdef KEYBOX_WITH_X509
698 Return the last found cert. Caller must free it.
701 keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
703 const unsigned char *buffer;
704 size_t length;
705 size_t cert_off, cert_len;
706 KsbaReader reader = NULL;
707 KsbaCert cert = NULL;
708 int rc;
710 if (!hd)
711 return KEYBOX_Invalid_Value;
712 if (!hd->found.blob)
713 return KEYBOX_Nothing_Found;
715 if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
716 return KEYBOX_Wrong_Blob_Type;
718 buffer = _keybox_get_blob_image (hd->found.blob, &length);
719 if (length < 40)
720 return KEYBOX_Blob_Too_Short;
721 cert_off = get32 (buffer+8);
722 cert_len = get32 (buffer+12);
723 if (cert_off+cert_len > length)
724 return KEYBOX_Blob_Too_Short;
726 reader = ksba_reader_new ();
727 if (!reader)
728 return KEYBOX_Out_Of_Core;
729 rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
730 if (rc)
732 ksba_reader_release (reader);
733 /* fixme: need to map the error codes */
734 return KEYBOX_General_Error;
737 cert = ksba_cert_new ();
738 if (!cert)
740 ksba_reader_release (reader);
741 return KEYBOX_Out_Of_Core;
744 rc = ksba_cert_read_der (cert, reader);
745 if (rc)
747 ksba_cert_release (cert);
748 ksba_reader_release (reader);
749 /* fixme: need to map the error codes */
750 return KEYBOX_General_Error;
753 *r_cert = cert;
754 ksba_reader_release (reader);
755 return 0;
758 #endif /*KEYBOX_WITH_X509*/