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