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