41fb832339453a17de76f4a06a497f4b3730dfa7
[gnupg.git] / kbx / keybox-search.c
1 /* keybox-search.c - Search operations
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "keybox-defs.h"
28
29 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
30                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
31 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
32
33
34 static ulong
35 get32 (const byte *buffer)
36 {
37   ulong a;
38   a =  *buffer << 24;
39   a |= buffer[1] << 16;
40   a |= buffer[2] << 8;
41   a |= buffer[3];
42   return a;
43 }
44
45 static ulong
46 get16 (const byte *buffer)
47 {
48   ulong a;
49   a =  *buffer << 8;
50   a |= buffer[1];
51   return a;
52 }
53
54
55
56 static int
57 blob_get_type (KEYBOXBLOB blob)
58 {
59   const unsigned char *buffer;
60   size_t length;
61
62   buffer = _keybox_get_blob_image (blob, &length);
63   if (length < 40)
64     return -1; /* blob too short */
65
66   return buffer[4];
67 }
68
69
70 static int
71 blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn)
72 {
73   size_t snlen;
74   const unsigned char *buffer;
75   size_t length;
76   size_t pos, off;
77   size_t nkeys, keyinfolen;
78   size_t nserial;
79
80   snlen = (sn[0] << 24) | (sn[1] << 16) | (sn[2] << 8) | sn[3];
81   sn += 4;
82
83   buffer = _keybox_get_blob_image (blob, &length);
84   if (length < 40)
85     return 0; /* blob too short */
86
87   /*keys*/
88   nkeys = get16 (buffer + 16);
89   keyinfolen = get16 (buffer + 18 );
90   if (keyinfolen < 28)
91     return 0; /* invalid blob */
92   pos = 20 + keyinfolen*nkeys;
93   if (pos+2 > length)
94     return 0; /* out of bounds */
95
96   /*serial*/
97   nserial = get16 (buffer+pos); 
98   off = pos + 2;
99   if (off+nserial > length)
100     return 0; /* out of bounds */
101
102   return nserial == snlen && !memcmp (buffer+off, sn, snlen);
103 }
104
105
106 static int
107 blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
108 {
109   const unsigned char *buffer;
110   size_t length;
111   size_t pos, off, len;
112   size_t nkeys, keyinfolen;
113   size_t nuids, uidinfolen;
114   size_t nserial;
115
116   buffer = _keybox_get_blob_image (blob, &length);
117   if (length < 40)
118     return 0; /* blob too short */
119
120   /*keys*/
121   nkeys = get16 (buffer + 16);
122   keyinfolen = get16 (buffer + 18 );
123   if (keyinfolen < 28)
124     return 0; /* invalid blob */
125   pos = 20 + keyinfolen*nkeys;
126   if (pos+2 > length)
127     return 0; /* out of bounds */
128
129   /*serial*/
130   nserial = get16 (buffer+pos); 
131   pos += 2 + nserial;
132   if (pos+4 > length)
133     return 0; /* out of bounds */
134
135   /* user ids*/
136   nuids = get16 (buffer + pos);  pos += 2;
137   uidinfolen = get16 (buffer + pos);  pos += 2;
138   if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
139     return 0; /* invalid blob */
140   if (pos + uidinfolen*nuids > length)
141     return 0; /* out of bounds */
142
143   if (idx < 0)
144     { /* compare all names starting with that (negated) index */
145       idx = -idx;
146       
147       for ( ;idx < nuids; idx++)
148         {
149           size_t mypos = pos;
150
151           mypos += idx*uidinfolen;
152           off = get32 (buffer+mypos);
153           len = get32 (buffer+mypos+4);
154           if (off+len > length)
155             return 0; /* error: better stop here out of bounds */
156           if (len < 2)
157             continue; /* empty name or 0 not stored */
158           len--;
159           if (len == namelen && !memcmp (buffer+off, name, len))
160             return 1; /* found */
161         }
162       return 0; /* not found */
163     }
164   else
165     {
166       if (idx > nuids)
167         return 0; /* no user ID with that idx */
168       pos += idx*uidinfolen;
169       off = get32 (buffer+pos);
170       len = get32 (buffer+pos+4);
171       if (off+len > length)
172         return 0; /* out of bounds */
173       if (len < 1)
174         return 0; /* empty name */
175       
176       return len == namelen && !memcmp (buffer+off, name, len);
177     }
178 }
179
180
181 /* compare all email addresses of the subject */
182 static int
183 blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen)
184 {
185   const unsigned char *buffer;
186   size_t length;
187   size_t pos, off, len;
188   size_t nkeys, keyinfolen;
189   size_t nuids, uidinfolen;
190   size_t nserial;
191   int idx;
192
193   /* fixme: this code is common to blob_cmp_mail */
194   buffer = _keybox_get_blob_image (blob, &length);
195   if (length < 40)
196     return 0; /* blob too short */
197
198   /*keys*/
199   nkeys = get16 (buffer + 16);
200   keyinfolen = get16 (buffer + 18 );
201   if (keyinfolen < 28)
202     return 0; /* invalid blob */
203   pos = 20 + keyinfolen*nkeys;
204   if (pos+2 > length)
205     return 0; /* out of bounds */
206
207   /*serial*/
208   nserial = get16 (buffer+pos); 
209   pos += 2 + nserial;
210   if (pos+4 > length)
211     return 0; /* out of bounds */
212
213   /* user ids*/
214   nuids = get16 (buffer + pos);  pos += 2;
215   uidinfolen = get16 (buffer + pos);  pos += 2;
216   if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
217     return 0; /* invalid blob */
218   if (pos + uidinfolen*nuids > length)
219     return 0; /* out of bounds */
220
221   if (namelen < 1)
222     return 0;
223
224   for (idx=1 ;idx < nuids; idx++)
225     {
226       size_t mypos = pos;
227       
228       mypos += idx*uidinfolen;
229       off = get32 (buffer+mypos);
230       len = get32 (buffer+mypos+4);
231       if (off+len > length)
232         return 0; /* error: better stop here out of bounds */
233       if (len < 2 || buffer[off] != '<')
234         continue; /* empty name or trailing 0 not stored */
235       len--; /* one back */
236       if ( len < 3 || buffer[off+len] != '>')
237         continue; /* not a prober email address */
238       len--; 
239       if (len == namelen && !memcmp (buffer+off+1, name, len))
240         return 1; /* found */
241     }
242   return 0; /* not found */
243 }
244
245
246
247 \f
248 /*
249   The has_foo functions are used as helpers for search 
250 */
251 #if 0
252 static int
253 has_short_kid (KEYBOXBLOB blob, u32 kid)
254 {
255   return 0;
256 }
257
258 static int
259 has_long_kid (KEYBOXBLOB blob, u32 *kid)
260 {
261   return 0;
262 }
263 #endif
264
265 static int
266 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
267 {
268   return 0;
269 }
270
271
272 static int
273 has_issuer (KEYBOXBLOB blob, const char *name)
274 {
275   size_t namelen;
276
277   return_val_if_fail (name, 0);
278
279   if (blob_get_type (blob) != BLOBTYPE_X509)
280     return 0;
281
282   namelen = strlen (name);
283   return blob_cmp_name (blob, 0 /* issuer */, name, namelen);
284 }
285
286 static int
287 has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn)
288 {
289   size_t namelen;
290
291   return_val_if_fail (name, 0);
292   return_val_if_fail (sn, 0);
293
294   if (blob_get_type (blob) != BLOBTYPE_X509)
295     return 0;
296
297   namelen = strlen (name);
298   
299   return (blob_cmp_sn (blob, sn)
300           && blob_cmp_name (blob, 0 /* issuer */, name, namelen));
301 }
302
303 static int
304 has_sn (KEYBOXBLOB blob, const unsigned char *sn)
305 {
306   return_val_if_fail (sn, 0);
307
308   if (blob_get_type (blob) != BLOBTYPE_X509)
309     return 0;
310   return blob_cmp_sn (blob, sn);
311 }
312
313 static int
314 has_subject (KEYBOXBLOB blob, const char *name)
315 {
316   size_t namelen;
317
318   return_val_if_fail (name, 0);
319
320   if (blob_get_type (blob) != BLOBTYPE_X509)
321     return 0;
322
323   namelen = strlen (name);
324   return blob_cmp_name (blob, 1 /* subject */, name, namelen);
325 }
326
327 static int
328 has_subject_or_alt (KEYBOXBLOB blob, const char *name)
329 {
330   size_t namelen;
331
332   return_val_if_fail (name, 0);
333
334   if (blob_get_type (blob) != BLOBTYPE_X509)
335     return 0;
336
337   namelen = strlen (name);
338   return blob_cmp_name (blob, -1 /* all subject names*/, name, namelen);
339 }
340
341
342 static int
343 has_mail (KEYBOXBLOB blob, const char *name)
344 {
345   size_t namelen;
346
347   return_val_if_fail (name, 0);
348
349   if (blob_get_type (blob) != BLOBTYPE_X509)
350     return 0;
351
352   namelen = strlen (name);
353   if (namelen && name[namelen-1] == '>')
354     namelen--;
355   return blob_cmp_mail (blob, name, namelen);
356 }
357
358
359 static void
360 release_sn_array (unsigned char **array, size_t size)
361 {
362   size_t n;
363
364   for (n=0; n < size; n++)
365     xfree (array[n]);
366   xfree (array);
367 }
368
369 \f
370 /*
371
372   The search API
373
374 */
375
376 int 
377 keybox_search_reset (KEYBOX_HANDLE hd)
378 {
379   if (!hd)
380     return KEYBOX_Invalid_Value;
381
382   if (hd->found.blob)
383     {
384       _keybox_release_blob (hd->found.blob);
385       hd->found.blob = NULL;
386     }
387
388   if (hd->fp)
389     {
390       fclose (hd->fp);
391       hd->fp = NULL;
392     }
393   hd->error = 0;
394   hd->eof = 0;
395   return 0;   
396 }
397
398 int 
399 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
400 {
401   int rc;
402   size_t n;
403   int need_words, any_skip;
404   KEYBOXBLOB blob = NULL;
405   unsigned char **sn_array = NULL;
406
407   if (!hd)
408     return KEYBOX_Invalid_Value;
409
410   /* clear last found result */
411   if (hd->found.blob)
412     {
413       _keybox_release_blob (hd->found.blob);
414       hd->found.blob = NULL;
415     }
416
417   if (hd->error)  
418     return hd->error; /* still in error state */
419   if (hd->eof)  
420     return -1; /* still EOF */
421
422   /* figure out what information we need */
423   need_words = any_skip = 0;
424   for (n=0; n < ndesc; n++) 
425     {
426       switch (desc[n].mode) 
427         {
428         case KEYDB_SEARCH_MODE_WORDS: 
429           need_words = 1;
430           break;
431         case KEYDB_SEARCH_MODE_FIRST:
432           /* always restart the search in this mode */
433           keybox_search_reset (hd);
434           break;
435         default:
436           break;
437         }
438       if (desc[n].skipfnc) 
439         any_skip = 1;
440       if (desc[n].sn_is_string && !sn_array)
441         {
442           sn_array = xtrycalloc (ndesc, sizeof *sn_array);
443           if (!sn_array)
444             return (hd->error = KEYBOX_Out_Of_Core);
445         }
446     }
447
448   if (!hd->fp)
449     {
450       hd->fp = fopen (hd->kb->fname, "rb");
451       if (!hd->fp)
452         {
453           xfree (sn_array);
454           return (hd->error = KEYBOX_File_Open_Error);
455         }
456     }
457
458   /* kludge: we need to convert an SN given as hexstring to it's
459      binary representation - in some cases we are not able to store it
460      in the search descriptor, because due to its usgae it is not
461      possible to free allocated memory */
462   if (sn_array)
463     {
464       const unsigned char *s;
465       int i, odd;
466       size_t snlen;
467
468       for (n=0; n < ndesc; n++) 
469         {
470           if (!desc[n].sn)
471             ;
472           else if (desc[n].sn_is_string)
473             {
474               unsigned char *sn;
475
476               s = desc[n].sn;
477               for (i=0; *s && *s != '/'; s++, i++)
478                 ;
479               odd = (i & 1);
480               snlen = (i+1)/2;
481               sn_array[n] = xtrymalloc (4+snlen);
482               if (!sn_array[n])
483                 {
484                   release_sn_array (sn_array, n);
485                   return (hd->error = KEYBOX_Out_Of_Core);
486                 }
487               sn = sn_array[n] + 4;
488               s = desc[n].sn;
489               if (odd)
490                 {
491                   *sn++ = xtoi_1 (s);
492                   s++;
493                 }
494               for (; *s && *s != '/';  s += 2)
495                 *sn++ = xtoi_2 (s);
496               assert (sn - sn_array[n] == 4+snlen);
497               sn = sn_array[n];
498               sn[0] = snlen >> 24;
499               sn[1] = snlen >> 16;
500               sn[2] = snlen >> 8;
501               sn[3] = snlen;
502             }
503           else
504             {
505               const unsigned char *sn;
506
507               sn = desc[n].sn;
508               snlen = (sn[0] << 24) | (sn[1] << 16) | (sn[2] << 8) | sn[3];
509               sn_array[n] = xtrymalloc (4+snlen);
510               if (!sn_array[n])
511                 {
512                   release_sn_array (sn_array, n);
513                   return (hd->error = KEYBOX_Out_Of_Core);
514                 }
515               memcpy (sn_array[n], sn, 4+snlen);
516             }
517         }
518     }
519
520
521   for (;;)
522     {
523       _keybox_release_blob (blob); blob = NULL;
524       rc = _keybox_read_blob (&blob, hd->fp);
525       if (rc)
526         break;
527
528       for (n=0; n < ndesc; n++) 
529         {
530           switch (desc[n].mode)
531             {
532             case KEYDB_SEARCH_MODE_NONE: 
533               never_reached ();
534               break;
535             case KEYDB_SEARCH_MODE_EXACT: 
536               if (has_subject_or_alt (blob, desc[n].u.name))
537                 goto found;
538               break;
539             case KEYDB_SEARCH_MODE_MAIL:
540               if (has_mail (blob, desc[n].u.name))
541                 goto found;
542               break;
543             case KEYDB_SEARCH_MODE_SUBSTR:
544             case KEYDB_SEARCH_MODE_MAILSUB:
545             case KEYDB_SEARCH_MODE_MAILEND:
546             case KEYDB_SEARCH_MODE_WORDS: 
547               never_reached (); /* not yet implemented */
548               break;
549             case KEYDB_SEARCH_MODE_ISSUER:
550               if (has_issuer (blob, desc[n].u.name))
551                 goto found;
552               break;
553             case KEYDB_SEARCH_MODE_ISSUER_SN:
554               if (has_issuer_sn (blob, desc[n].u.name,
555                                  sn_array? sn_array[n] : desc[n].sn))
556                 goto found;
557               break;
558             case KEYDB_SEARCH_MODE_SN:
559               if (has_sn (blob, sn_array? sn_array[n] : desc[n].sn))
560                 goto found;
561               break;
562             case KEYDB_SEARCH_MODE_SUBJECT:
563               if (has_subject (blob, desc[n].u.name))
564                 goto found;
565               break;
566             case KEYDB_SEARCH_MODE_SHORT_KID: 
567 /*                if (has_short_kid (blob, desc[n].u.kid[1])) */
568 /*                  goto found; */
569               break;
570             case KEYDB_SEARCH_MODE_LONG_KID:
571 /*                if (has_long_kid (blob, desc[n].u.kid)) */
572 /*                  goto found; */
573               break;
574             case KEYDB_SEARCH_MODE_FPR:
575               if (has_fingerprint (blob, desc[n].u.fpr))
576                 goto found;
577               break;
578             case KEYDB_SEARCH_MODE_FIRST: 
579               goto found;
580               break;
581             case KEYDB_SEARCH_MODE_NEXT: 
582               goto found;
583               break;
584             default: 
585               rc = KEYBOX_Invalid_Value;
586               goto found;
587             }
588         }
589       continue;
590     found:  
591       for (n=any_skip?0:ndesc; n < ndesc; n++) 
592         {
593 /*            if (desc[n].skipfnc */
594 /*                && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
595 /*              break; */
596         }
597       if (n == ndesc)
598         break; /* got it */
599     }
600   
601   if (!rc)
602     {
603       hd->found.blob = blob;
604     }
605   else if (rc == -1)
606     {
607       _keybox_release_blob (blob);
608       hd->eof = 1;
609     }
610   else 
611     {
612       _keybox_release_blob (blob);
613       hd->error = rc;
614     }
615
616   if (sn_array)
617     release_sn_array (sn_array, ndesc);
618
619   return rc;
620 }
621
622
623
624 \f
625 /*
626    Functions to return a certificate or a keyblock.  To be used after
627    a successful search operation.
628 */
629 #ifdef KEYBOX_WITH_X509
630 /*
631   Return the last found cert.  Caller must free it.
632  */
633 int
634 keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
635 {
636   const unsigned char *buffer;
637   size_t length;
638   size_t cert_off, cert_len;
639   KsbaReader reader = NULL;
640   KsbaCert cert = NULL;
641   int rc;
642
643   if (!hd)
644     return KEYBOX_Invalid_Value;
645   if (!hd->found.blob)
646     return KEYBOX_Nothing_Found;
647
648   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
649     return KEYBOX_Wrong_Blob_Type;
650
651   buffer = _keybox_get_blob_image (hd->found.blob, &length);
652   if (length < 40)
653     return KEYBOX_Blob_Too_Short;
654   cert_off = get32 (buffer+8);
655   cert_len = get32 (buffer+12);
656   if (cert_off+cert_len > length)
657     return KEYBOX_Blob_Too_Short;
658
659   reader = ksba_reader_new ();
660   if (!reader)
661     return KEYBOX_Out_Of_Core;
662   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
663   if (rc)
664     {
665       ksba_reader_release (reader);
666       /* fixme: need to map the error codes */
667       return KEYBOX_General_Error;
668     }
669
670   cert = ksba_cert_new ();
671   if (!cert)
672     {
673       ksba_reader_release (reader);
674       return KEYBOX_Out_Of_Core;
675     }
676
677   rc = ksba_cert_read_der (cert, reader);
678   if (rc)
679     {
680       ksba_cert_release (cert);
681       ksba_reader_release (reader);
682       /* fixme: need to map the error codes */
683       return KEYBOX_General_Error;
684     }
685
686   *r_cert = cert;
687   ksba_reader_release (reader);
688   return 0;
689 }
690
691 #endif /*KEYBOX_WITH_X509*/