Base code for gpgsm --verify does work
[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
26 #include "keybox-defs.h"
27
28 static ulong
29 get32 (const byte *buffer)
30 {
31   ulong a;
32   a =  *buffer << 24;
33   a |= buffer[1] << 16;
34   a |= buffer[2] << 8;
35   a |= buffer[3];
36   return a;
37 }
38
39 static ulong
40 get16 (const byte *buffer)
41 {
42   ulong a;
43   a =  *buffer << 8;
44   a |= buffer[1];
45   return a;
46 }
47
48
49
50 static int
51 blob_get_type (KEYBOXBLOB blob)
52 {
53   const unsigned char *buffer;
54   size_t length;
55
56   buffer = _keybox_get_blob_image (blob, &length);
57   if (length < 40)
58     return -1; /* blob too short */
59
60   return buffer[4];
61 }
62
63
64 static int
65 blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn)
66 {
67   size_t snlen;
68   const unsigned char *buffer;
69   size_t length;
70   size_t pos, off;
71   size_t nkeys, keyinfolen;
72   size_t nserial;
73
74   snlen = (sn[0] << 24) | (sn[1] << 16) | (sn[2] << 8) | sn[3];
75   sn += 4;
76
77   buffer = _keybox_get_blob_image (blob, &length);
78   if (length < 40)
79     return 0; /* blob too short */
80
81   /*keys*/
82   nkeys = get16 (buffer + 16);
83   keyinfolen = get16 (buffer + 18 );
84   if (keyinfolen < 28)
85     return 0; /* invalid blob */
86   pos = 20 + keyinfolen*nkeys;
87   if (pos+2 > length)
88     return 0; /* out of bounds */
89
90   /*serial*/
91   nserial = get16 (buffer+pos); 
92   off = pos + 2;
93   if (off+nserial > length)
94     return 0; /* out of bounds */
95
96   return nserial == snlen && !memcmp (buffer+off, sn, snlen);
97 }
98
99 static int
100 blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
101 {
102   const unsigned char *buffer;
103   size_t length;
104   size_t pos, off, len;
105   size_t nkeys, keyinfolen;
106   size_t nuids, uidinfolen;
107   size_t nserial;
108
109   buffer = _keybox_get_blob_image (blob, &length);
110   if (length < 40)
111     return 0; /* blob too short */
112
113   /*keys*/
114   nkeys = get16 (buffer + 16);
115   keyinfolen = get16 (buffer + 18 );
116   if (keyinfolen < 28)
117     return 0; /* invalid blob */
118   pos = 20 + keyinfolen*nkeys;
119   if (pos+2 > length)
120     return 0; /* out of bounds */
121
122   /*serial*/
123   nserial = get16 (buffer+pos); 
124   pos += 2 + nserial;
125   if (pos+4 > length)
126     return 0; /* out of bounds */
127
128   /* user ids*/
129   nuids = get16 (buffer + pos);  pos += 2;
130   uidinfolen = get16 (buffer + pos);  pos += 2;
131   if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
132     return 0; /* invalid blob */
133   if (pos + uidinfolen*nuids > length)
134     return 0; /* out of bounds */
135
136   if (idx > nuids)
137     return 0; /* no user ID with that idx */
138   pos += idx*uidinfolen;
139   off = get32 (buffer+pos);
140   len = get32 (buffer+pos+4);
141   if (off+len > length)
142     return 0; /* out of bounds */
143   if (len < 2)
144     return 0; /* empty name or 0 not stored */
145   len--;
146   
147   return len == namelen && !memcmp (buffer+off, name, len);
148 }
149
150
151
152 \f
153 /*
154   The has_foo functions are used as helpers for search 
155 */
156 #if 0
157 static int
158 has_short_kid (KEYBOXBLOB blob, u32 kid)
159 {
160   return 0;
161 }
162
163 static int
164 has_long_kid (KEYBOXBLOB blob, u32 *kid)
165 {
166   return 0;
167 }
168 #endif
169
170 static int
171 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
172 {
173   return 0;
174 }
175
176
177 static int
178 has_issuer (KEYBOXBLOB blob, const char *name)
179 {
180   size_t namelen;
181
182   return_val_if_fail (name, 0);
183
184   if (blob_get_type (blob) != BLOBTYPE_X509)
185     return 0;
186
187   namelen = strlen (name);
188   return blob_cmp_name (blob, 0 /* issuer */, name, namelen);
189 }
190
191 static int
192 has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn)
193 {
194   size_t namelen;
195
196   return_val_if_fail (name, 0);
197   return_val_if_fail (sn, 0);
198
199   if (blob_get_type (blob) != BLOBTYPE_X509)
200     return 0;
201
202   namelen = strlen (name);
203   
204   return (blob_cmp_sn (blob, sn)
205           && blob_cmp_name (blob, 0 /* issuer */, name, namelen));
206 }
207
208 static int
209 has_subject (KEYBOXBLOB blob, const char *name)
210 {
211   size_t namelen;
212
213   return_val_if_fail (name, 0);
214
215   if (blob_get_type (blob) != BLOBTYPE_X509)
216     return 0;
217
218   namelen = strlen (name);
219   return blob_cmp_name (blob, 1 /* subject */, name, namelen);
220 }
221
222
223 \f
224 /*
225
226   The search API
227
228 */
229
230 int 
231 keybox_search_reset (KEYBOX_HANDLE hd)
232 {
233   if (!hd)
234     return KEYBOX_Invalid_Value;
235
236   if (hd->found.blob)
237     {
238       _keybox_release_blob (hd->found.blob);
239       hd->found.blob = NULL;
240     }
241
242   if (hd->fp)
243     {
244       fclose (hd->fp);
245       hd->fp = NULL;
246     }
247   hd->error = 0;
248   hd->eof = 0;
249   return 0;   
250 }
251
252 int 
253 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
254 {
255   int rc;
256   size_t n;
257   int need_words, any_skip;
258   KEYBOXBLOB blob = NULL;
259
260   if (!hd)
261     return KEYBOX_Invalid_Value;
262
263   /* clear last found result */
264   if (hd->found.blob)
265     {
266       _keybox_release_blob (hd->found.blob);
267       hd->found.blob = NULL;
268     }
269
270   if (hd->error)  
271     return hd->error; /* still in error state */
272   if (hd->eof)  
273     return -1; /* still EOF */
274
275   /* figure out what information we need */
276   need_words = any_skip = 0;
277   for (n=0; n < ndesc; n++) 
278     {
279       switch (desc[n].mode) 
280         {
281         case KEYDB_SEARCH_MODE_WORDS: 
282           need_words = 1;
283           break;
284         case KEYDB_SEARCH_MODE_FIRST:
285           /* always restart the search in this mode */
286           keybox_search_reset (hd);
287           break;
288         default:
289           break;
290         }
291       if (desc[n].skipfnc) 
292         any_skip = 1;
293     }
294
295   if (!hd->fp)
296     {
297       hd->fp = fopen (hd->kb->fname, "rb");
298       if (!hd->fp)
299           return (hd->error = KEYBOX_File_Open_Error);
300     }
301
302
303   for (;;)
304     {
305       _keybox_release_blob (blob); blob = NULL;
306       rc = _keybox_read_blob (&blob, hd->fp);
307       if (rc)
308         break;
309
310       for (n=0; n < ndesc; n++) 
311         {
312           switch (desc[n].mode)
313             {
314             case KEYDB_SEARCH_MODE_NONE: 
315               never_reached ();
316               break;
317             case KEYDB_SEARCH_MODE_EXACT: 
318             case KEYDB_SEARCH_MODE_SUBSTR:
319             case KEYDB_SEARCH_MODE_MAIL:
320             case KEYDB_SEARCH_MODE_MAILSUB:
321             case KEYDB_SEARCH_MODE_MAILEND:
322             case KEYDB_SEARCH_MODE_WORDS: 
323               never_reached (); /* not yet implemented */
324               break;
325             case KEYDB_SEARCH_MODE_ISSUER:
326               if (has_issuer (blob, desc[n].u.name))
327                 goto found;
328               break;
329             case KEYDB_SEARCH_MODE_ISSUER_SN:
330               if (has_issuer_sn (blob, desc[n].u.name, desc[n].sn))
331                 goto found;
332               break;
333             case KEYDB_SEARCH_MODE_SUBJECT:
334               if (has_subject (blob, desc[n].u.name))
335                 goto found;
336               break;
337             case KEYDB_SEARCH_MODE_SHORT_KID: 
338 /*                if (has_short_kid (blob, desc[n].u.kid[1])) */
339 /*                  goto found; */
340               break;
341             case KEYDB_SEARCH_MODE_LONG_KID:
342 /*                if (has_long_kid (blob, desc[n].u.kid)) */
343 /*                  goto found; */
344               break;
345             case KEYDB_SEARCH_MODE_FPR:
346               if (has_fingerprint (blob, desc[n].u.fpr))
347                 goto found;
348               break;
349             case KEYDB_SEARCH_MODE_FIRST: 
350               goto found;
351               break;
352             case KEYDB_SEARCH_MODE_NEXT: 
353               goto found;
354               break;
355             default: 
356               rc = KEYBOX_Invalid_Value;
357               goto found;
358             }
359         }
360       continue;
361     found:  
362       for (n=any_skip?0:ndesc; n < ndesc; n++) 
363         {
364 /*            if (desc[n].skipfnc */
365 /*                && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
366 /*              break; */
367         }
368       if (n == ndesc)
369         break; /* got it */
370     }
371   
372   if (!rc)
373     {
374       hd->found.blob = blob;
375     }
376   else if (rc == -1)
377     {
378       _keybox_release_blob (blob);
379       hd->eof = 1;
380     }
381   else 
382     {
383       _keybox_release_blob (blob);
384       hd->error = rc;
385     }
386
387   return rc;
388 }
389
390
391
392 \f
393 /*
394    Functions to return a certificate or a keyblock.  To be used after
395    a successful search operation.
396 */
397 #ifdef KEYBOX_WITH_X509
398 /*
399   Return the last found cert.  Caller must free it.
400  */
401 int
402 keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
403 {
404   const unsigned char *buffer;
405   size_t length;
406   size_t cert_off, cert_len;
407   KsbaReader reader = NULL;
408   KsbaCert cert = NULL;
409   int rc;
410
411   if (!hd)
412     return KEYBOX_Invalid_Value;
413   if (!hd->found.blob)
414     return KEYBOX_Nothing_Found;
415
416   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
417     return KEYBOX_Wrong_Blob_Type;
418
419   buffer = _keybox_get_blob_image (hd->found.blob, &length);
420   if (length < 40)
421     return KEYBOX_Blob_Too_Short;
422   cert_off = get32 (buffer+8);
423   cert_len = get32 (buffer+12);
424   if (cert_off+cert_len > length)
425     return KEYBOX_Blob_Too_Short;
426
427   reader = ksba_reader_new ();
428   if (!reader)
429     return KEYBOX_Out_Of_Core;
430   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
431   if (rc)
432     {
433       ksba_reader_release (reader);
434       /* fixme: need to map the error codes */
435       return KEYBOX_General_Error;
436     }
437
438   cert = ksba_cert_new ();
439   if (!cert)
440     {
441       ksba_reader_release (reader);
442       return KEYBOX_Out_Of_Core;
443     }
444
445   rc = ksba_cert_read_der (cert, reader);
446   if (rc)
447     {
448       ksba_cert_release (cert);
449       ksba_reader_release (reader);
450       /* fixme: need to map the error codes */
451       return KEYBOX_General_Error;
452     }
453
454   *r_cert = cert;
455   ksba_reader_release (reader);
456   return 0;
457 }
458
459 #endif /*KEYBOX_WITH_X509*/