* certlist.c (cert_usable_p): New.
[gnupg.git] / sm / verify.c
1 /* verify.c - Verify a messages signature
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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.h"
34 #include "keydb.h"
35 #include "i18n.h"
36
37 /* fixme: Move this to jnlib */
38 static char *
39 strtimestamp (time_t atime)
40 {
41   char *buffer = xmalloc (15);
42   
43   if (atime < 0) 
44     strcpy (buffer, "????" "-??" "-??");
45   else if (!atime)
46     strcpy (buffer, "none");
47   else
48     {
49       struct tm *tp;
50       
51       tp = gmtime( &atime );
52       sprintf (buffer, "%04d-%02d-%02d",
53                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday);
54     }
55   return buffer;
56 }
57
58
59
60 /* Hash the data for a detached signature */
61 static void
62 hash_data (int fd, GCRY_MD_HD md)
63 {
64   FILE *fp;
65   char buffer[4096];
66   int nread;
67
68   fp = fdopen ( dup (fd), "rb");
69   if (!fp)
70     {
71       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
72       return;
73     }
74
75   do 
76     {
77       nread = fread (buffer, 1, DIM(buffer), fp);
78       gcry_md_write (md, buffer, nread);
79     }
80   while (nread);
81   if (ferror (fp))
82       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
83   fclose (fp);
84 }
85
86
87
88 \f
89 /* Perform a verify operation.  To verify detached signatures, data_fd
90    must be different than -1.  With OUT_FP given and a non-detached
91    signature, the signed material is written to that stream. */
92 int
93 gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
94 {
95   int i, rc;
96   Base64Context b64reader = NULL;
97   Base64Context b64writer = NULL;
98   KsbaError err;
99   KsbaReader reader;
100   KsbaWriter writer = NULL;
101   KsbaCMS cms = NULL;
102   KsbaStopReason stopreason;
103   KsbaCert cert;
104   KEYDB_HANDLE kh;
105   GCRY_MD_HD data_md = NULL;
106   int signer;
107   const char *algoid;
108   int algo;
109   int is_detached;
110   FILE *fp = NULL;
111
112   kh = keydb_new (0);
113   if (!kh)
114     {
115       log_error (_("failed to allocated keyDB handle\n"));
116       rc = GNUPG_General_Error;
117       goto leave;
118     }
119
120
121   fp = fdopen ( dup (in_fd), "rb");
122   if (!fp)
123     {
124       log_error ("fdopen() failed: %s\n", strerror (errno));
125       rc = seterr (IO_Error);
126       goto leave;
127     }
128
129   rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
130   if (rc)
131     {
132       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
133       goto leave;
134     }
135
136   if (out_fp)
137     {
138       rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
139       if (rc)
140         {
141           log_error ("can't create writer: %s\n", gnupg_strerror (rc));
142           goto leave;
143         }
144     }
145
146   cms = ksba_cms_new ();
147   if (!cms)
148     {
149       rc = seterr (Out_Of_Core);
150       goto leave;
151     }
152
153   err = ksba_cms_set_reader_writer (cms, reader, writer);
154   if (err)
155     {
156       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
157                  ksba_strerror (err));
158       rc = map_ksba_err (err);
159       goto leave;
160     }
161
162   data_md = gcry_md_open (0, 0);
163   if (!data_md)
164     {
165       rc = map_gcry_err (gcry_errno());
166       log_error ("md_open failed: %s\n", gcry_strerror (-1));
167       goto leave;
168     }
169   if (DBG_HASHING)
170     gcry_md_start_debug (data_md, "vrfy.data");
171
172   is_detached = 0;
173   do 
174     {
175       err = ksba_cms_parse (cms, &stopreason);
176       if (err)
177         {
178           log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
179           rc = map_ksba_err (err);
180           goto leave;
181         }
182
183       if (stopreason == KSBA_SR_NEED_HASH)
184         {
185           is_detached = 1;
186           log_debug ("Detached signature\n");
187         }
188
189       if (stopreason == KSBA_SR_NEED_HASH
190           || stopreason == KSBA_SR_BEGIN_DATA)
191         { /* We are now able to enable the hash algorithms */
192           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
193             {
194               algo = gcry_md_map_name (algoid);
195               if (!algo)
196                 log_error ("unknown hash algorithm `%s'\n",
197                            algoid? algoid:"?");
198               else
199                 gcry_md_enable (data_md, algo);
200             }
201           if (is_detached)
202             {
203               if (data_fd == -1)
204                 log_info ("detached signature w/o data "
205                           "- assuming certs-only\n");
206               else
207                 hash_data (data_fd, data_md);  
208             }
209           else
210             {
211               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
212             }
213         }
214       else if (stopreason == KSBA_SR_END_DATA)
215         { /* The data bas been hashed */
216
217         }
218     }
219   while (stopreason != KSBA_SR_READY);   
220
221   if (b64writer)
222     {
223       rc = gpgsm_finish_writer (b64writer);
224       if (rc) 
225         {
226           log_error ("write failed: %s\n", gnupg_strerror (rc));
227           goto leave;
228         }
229     }
230
231   if (data_fd != -1 && !is_detached)
232     {
233       log_error ("data given for a non-detached signature\n");
234       rc = GNUPG_Conflict;
235       goto leave;
236     }
237
238   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
239     {
240       /* Fixme: it might be better to check the validity of the
241          certificate first before entering it into the DB.  This way
242          we would avoid cluttering the DB with invalid
243          certificates. */
244       keydb_store_cert (cert);
245       ksba_cert_release (cert);
246     }
247
248   cert = NULL;
249   err = 0;
250   for (signer=0; signer < 1; signer++)
251     {
252       char *issuer = NULL;
253       KsbaSexp sigval = NULL;
254       time_t sigtime;
255       KsbaSexp serial;
256       char *msgdigest = NULL;
257       size_t msgdigestlen;
258
259       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
260       if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
261         {
262           log_info ("certs-only message accepted\n");
263           err = 0;
264           break;
265         }
266       if (err)
267         break;
268       log_debug ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]");
269       log_debug ("signer %d - serial: ", signer);
270       gpgsm_dump_serial (serial);
271       log_printf ("\n");
272
273       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
274       if (err)
275         {
276           log_debug ("error getting signing time: %s\n", ksba_strerror (err));
277           sigtime = (time_t)-1;
278         }
279       log_debug ("signer %d - sigtime: ", signer);
280       gpgsm_dump_time (sigtime);  
281       log_printf ("\n");
282
283
284       err = ksba_cms_get_message_digest (cms, signer,
285                                          &msgdigest, &msgdigestlen);
286       if (err)
287         break;
288
289       algoid = ksba_cms_get_digest_algo (cms, signer);
290       algo = gcry_md_map_name (algoid);
291       log_debug ("signer %d - digest algo: %d\n", signer, algo);
292       if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
293         {
294           log_debug ("digest algo %d has not been enabled\n", algo);
295           goto next_signer;
296         }
297
298       sigval = ksba_cms_get_sig_val (cms, signer);
299       if (!sigval)
300         {
301           log_error ("no signature value available\n");
302           goto next_signer;
303         }
304       log_debug ("signer %d - signature available", signer);
305
306       /* Find the certificate of the signer */
307       keydb_search_reset (kh);
308       rc = keydb_search_issuer_sn (kh, issuer, serial);
309       if (rc)
310         {
311           log_debug ("failed to find the certificate: %s\n",
312                      gnupg_strerror(rc));
313           goto next_signer;
314         }
315
316       rc = keydb_get_cert (kh, &cert);
317       if (rc)
318         {
319           log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
320           goto next_signer;
321         }
322
323       if (msgdigest)
324         { /* Signed attributes are available. */
325           GCRY_MD_HD md;
326           unsigned char *s;
327
328           /* check that the message digest in the signed attributes
329              matches the one we calculated on the data */
330           s = gcry_md_read (data_md, algo);
331           if ( !s || !msgdigestlen
332                || gcry_md_get_algo_dlen (algo) != msgdigestlen
333                || !s || memcmp (s, msgdigest, msgdigestlen) )
334             {
335               log_error ("invalid signature: message digest attribute "
336                          "does not match calculated one\n");
337               gpgsm_status (ctrl, STATUS_BADSIG, NULL);
338               goto next_signer; 
339             }
340             
341           md = gcry_md_open (algo, 0);
342           if (!md)
343             {
344               log_error ("md_open failed: %s\n", gcry_strerror (-1));
345               goto next_signer;
346             }
347           if (DBG_HASHING)
348             gcry_md_start_debug (md, "vrfy.attr");
349
350           ksba_cms_set_hash_function (cms, HASH_FNC, md);
351           rc = ksba_cms_hash_signed_attrs (cms, signer);
352           if (rc)
353             {
354               log_debug ("hashing signed attrs failed: %s\n",
355                          ksba_strerror (rc));
356               gcry_md_close (md);
357               goto next_signer;
358             }
359           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
360           gcry_md_close (md);
361         }
362       else
363         {
364           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
365         }
366
367       if (rc)
368         {
369           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
370           gpgsm_status (ctrl, STATUS_BADSIG, NULL);
371           goto next_signer;
372         }
373       gpgsm_cert_use_verify_p (cert); /* this displays an info message */
374       log_debug ("signature okay - checking certs\n");
375       gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
376       {
377         char *buf, *fpr, *tstr;
378
379         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
380         tstr = strtimestamp (sigtime);
381         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100);
382         sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime );
383         xfree (tstr);
384         xfree (fpr);
385         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
386         xfree (buf);
387       }
388
389       rc = gpgsm_validate_path (cert);
390       if (rc)
391         {
392           log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
393           if (rc == GNUPG_Bad_Certificate_Path
394               || rc == GNUPG_Bad_Certificate)
395             gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL);
396           else
397             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL);
398           goto next_signer;
399         }
400       log_info ("signature is good\n");
401       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
402           
403
404     next_signer:
405       rc = 0;
406       xfree (issuer);
407       xfree (serial);
408       xfree (sigval);
409       xfree (msgdigest);
410       ksba_cert_release (cert);
411       cert = NULL;
412     }
413   rc = 0;
414   if (err)
415     {
416       log_debug ("ksba error: %s\n", ksba_strerror (err));
417       rc = map_ksba_err (rc);
418     }    
419
420
421
422  leave:
423   ksba_cms_release (cms);
424   gpgsm_destroy_reader (b64reader);
425   gpgsm_destroy_writer (b64writer);
426   keydb_release (kh); 
427   gcry_md_close (data_md);
428   if (fp)
429     fclose (fp);
430   return rc;
431 }
432