* cipher.c (setup_cipher_table): #ifdef IDEA.
[gnupg.git] / sm / verify.c
1 /* verify.c - Verify a messages signature
2  *      Copyright (C) 2001, 2002 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   char *p;
112
113   kh = keydb_new (0);
114   if (!kh)
115     {
116       log_error (_("failed to allocated keyDB handle\n"));
117       rc = GNUPG_General_Error;
118       goto leave;
119     }
120
121
122   fp = fdopen ( dup (in_fd), "rb");
123   if (!fp)
124     {
125       log_error ("fdopen() failed: %s\n", strerror (errno));
126       rc = seterr (IO_Error);
127       goto leave;
128     }
129
130   rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
131   if (rc)
132     {
133       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
134       goto leave;
135     }
136
137   if (out_fp)
138     {
139       rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
140       if (rc)
141         {
142           log_error ("can't create writer: %s\n", gnupg_strerror (rc));
143           goto leave;
144         }
145     }
146
147   cms = ksba_cms_new ();
148   if (!cms)
149     {
150       rc = seterr (Out_Of_Core);
151       goto leave;
152     }
153
154   err = ksba_cms_set_reader_writer (cms, reader, writer);
155   if (err)
156     {
157       log_error ("ksba_cms_set_reader_writer failed: %s\n",
158                  ksba_strerror (err));
159       rc = map_ksba_err (err);
160       goto leave;
161     }
162
163   data_md = gcry_md_open (0, 0);
164   if (!data_md)
165     {
166       rc = map_gcry_err (gcry_errno());
167       log_error ("md_open failed: %s\n", gcry_strerror (-1));
168       goto leave;
169     }
170   if (DBG_HASHING)
171     gcry_md_start_debug (data_md, "vrfy.data");
172
173   is_detached = 0;
174   do 
175     {
176       err = ksba_cms_parse (cms, &stopreason);
177       if (err)
178         {
179           log_error ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
180           rc = map_ksba_err (err);
181           goto leave;
182         }
183
184       if (stopreason == KSBA_SR_NEED_HASH)
185         {
186           is_detached = 1;
187           if (opt.verbose)
188             log_info ("detached signature\n");
189         }
190
191       if (stopreason == KSBA_SR_NEED_HASH
192           || stopreason == KSBA_SR_BEGIN_DATA)
193         { /* We are now able to enable the hash algorithms */
194           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
195             {
196               algo = gcry_md_map_name (algoid);
197               if (!algo)
198                 log_error ("unknown hash algorithm `%s'\n",
199                            algoid? algoid:"?");
200               else
201                 gcry_md_enable (data_md, algo);
202             }
203           if (is_detached)
204             {
205               if (data_fd == -1)
206                 log_info ("detached signature w/o data "
207                           "- assuming certs-only\n");
208               else
209                 hash_data (data_fd, data_md);  
210             }
211           else
212             {
213               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
214             }
215         }
216       else if (stopreason == KSBA_SR_END_DATA)
217         { /* The data bas been hashed */
218
219         }
220     }
221   while (stopreason != KSBA_SR_READY);   
222
223   if (b64writer)
224     {
225       rc = gpgsm_finish_writer (b64writer);
226       if (rc) 
227         {
228           log_error ("write failed: %s\n", gnupg_strerror (rc));
229           goto leave;
230         }
231     }
232
233   if (data_fd != -1 && !is_detached)
234     {
235       log_error ("data given for a non-detached signature\n");
236       rc = GNUPG_Conflict;
237       goto leave;
238     }
239
240   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
241     {
242       /* Fixme: it might be better to check the validity of the
243          certificate first before entering it into the DB.  This way
244          we would avoid cluttering the DB with invalid
245          certificates. */
246       keydb_store_cert (cert, 0, NULL);
247       ksba_cert_release (cert);
248     }
249
250   cert = NULL;
251   err = 0;
252   for (signer=0; ; signer++)
253     {
254       char *issuer = NULL;
255       KsbaSexp sigval = NULL;
256       time_t sigtime, keyexptime;
257       KsbaSexp serial;
258       char *msgdigest = NULL;
259       size_t msgdigestlen;
260       char *ctattr;
261
262       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
263       if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
264         {
265           log_info ("certs-only message accepted\n");
266           err = 0;
267           break;
268         }
269       if (err)
270         {
271           if (signer && err == -1)
272             err = 0;
273           break;
274         }
275       if (DBG_X509)
276         {
277           log_debug ("signer %d - issuer: `%s'\n",
278                      signer, issuer? issuer:"[NONE]");
279           log_debug ("signer %d - serial: ", signer);
280           gpgsm_dump_serial (serial);
281           log_printf ("\n");
282         }
283
284       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
285       if (err == KSBA_No_Data)
286         sigtime = 0;
287       else if (err)
288         {
289           log_error ("error getting signing time: %s\n", ksba_strerror (err));
290           sigtime = (time_t)-1;
291         }
292
293       err = ksba_cms_get_message_digest (cms, signer,
294                                          &msgdigest, &msgdigestlen);
295       if (!err)
296         {
297           algoid = ksba_cms_get_digest_algo (cms, signer);
298           algo = gcry_md_map_name (algoid);
299           if (DBG_X509)
300             log_debug ("signer %d - digest algo: %d\n", signer, algo);
301           if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
302             {
303               log_error ("digest algo %d has not been enabled\n", algo);
304               goto next_signer;
305             }
306         }
307       else if (err == KSBA_No_Data)
308         {
309           assert (!msgdigest);
310           err = 0;
311           algoid = NULL;
312           algo = 0; 
313         }
314       else /* real error */
315         break;
316
317       err = ksba_cms_get_sigattr_oids (cms, signer,
318                                        "1.2.840.113549.1.9.3",&ctattr);
319       if (!err) 
320         {
321           const char *s;
322
323           if (DBG_X509)
324             log_debug ("signer %d - content-type attribute: %s", signer, ctattr);
325           s = ksba_cms_get_content_oid (cms, 1);
326           if (!s || strcmp (ctattr, s))
327             {
328               log_error ("content-type attribute does not match "
329                          "actual content-type\n");
330               ksba_free (ctattr);
331               ctattr = NULL;
332               goto next_signer;
333             }
334           ksba_free (ctattr);
335           ctattr = NULL;
336         }
337       else if (err != -1)
338         {
339           log_error ("error getting content-type attribute: %s\n",
340                      ksba_strerror (err));
341           goto next_signer;
342         }
343       err = 0;
344
345
346       sigval = ksba_cms_get_sig_val (cms, signer);
347       if (!sigval)
348         {
349           log_error ("no signature value available\n");
350           goto next_signer;
351         }
352       if (DBG_X509)
353         log_debug ("signer %d - signature available", signer);
354
355       /* Find the certificate of the signer */
356       keydb_search_reset (kh);
357       rc = keydb_search_issuer_sn (kh, issuer, serial);
358       if (rc)
359         {
360           if (rc == -1)
361             {
362               log_error ("certificate not found\n");
363               rc = GNUPG_No_Public_Key;
364             }
365           else
366             log_error ("failed to find the certificate: %s\n",
367                        gnupg_strerror(rc));
368           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
369                          gnupg_error_token (rc), NULL);
370           /* fixme: we might want to append the issuer and serial
371              using our standard notation */
372           goto next_signer;
373         }
374
375       rc = keydb_get_cert (kh, &cert);
376       if (rc)
377         {
378           log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
379           goto next_signer;
380         }
381
382       log_info (_("Signature made "));
383       if (sigtime)
384         gpgsm_dump_time (sigtime);
385       else
386         log_printf (_("[date not given]"));
387       log_printf (_(" using certificate ID %08lX\n"),
388                   gpgsm_get_short_fingerprint (cert));
389
390
391       if (msgdigest)
392         { /* Signed attributes are available. */
393           GCRY_MD_HD md;
394           unsigned char *s;
395
396           /* check that the message digest in the signed attributes
397              matches the one we calculated on the data */
398           s = gcry_md_read (data_md, algo);
399           if ( !s || !msgdigestlen
400                || gcry_md_get_algo_dlen (algo) != msgdigestlen
401                || !s || memcmp (s, msgdigest, msgdigestlen) )
402             {
403               char *fpr;
404
405               log_error ("invalid signature: message digest attribute "
406                          "does not match calculated one\n");
407               fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
408               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
409               xfree (fpr);
410               goto next_signer; 
411             }
412             
413           md = gcry_md_open (algo, 0);
414           if (!md)
415             {
416               log_error ("md_open failed: %s\n", gcry_strerror (-1));
417               goto next_signer;
418             }
419           if (DBG_HASHING)
420             gcry_md_start_debug (md, "vrfy.attr");
421
422           ksba_cms_set_hash_function (cms, HASH_FNC, md);
423           rc = ksba_cms_hash_signed_attrs (cms, signer);
424           if (rc)
425             {
426               log_error ("hashing signed attrs failed: %s\n",
427                          ksba_strerror (rc));
428               gcry_md_close (md);
429               goto next_signer;
430             }
431           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
432           gcry_md_close (md);
433         }
434       else
435         {
436           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
437         }
438
439       if (rc)
440         {
441           char *fpr;
442
443           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
444           fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
445           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
446           xfree (fpr);
447           goto next_signer;
448         }
449       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
450       if (rc)
451         {
452           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.keyusage",
453                          gnupg_error_token (rc), NULL);
454           rc = 0;
455         }
456
457       if (DBG_X509)
458         log_debug ("signature okay - checking certs\n");
459       rc = gpgsm_validate_chain (ctrl, cert, &keyexptime);
460       if (rc == GNUPG_Certificate_Expired)
461         {
462           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
463           rc = 0;
464         }
465       else
466         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
467       
468       {
469         char *buf, *fpr, *tstr;
470
471         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
472         tstr = strtimestamp (sigtime);
473         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
474         sprintf (buf, "%s %s %lu %lu", fpr, tstr,
475                  (unsigned long)sigtime, (unsigned long)keyexptime );
476         xfree (tstr);
477         xfree (fpr);
478         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
479         xfree (buf);
480       }
481
482       if (rc) /* of validate_chain */
483         {
484           log_error ("invalid certification chain: %s\n", gnupg_strerror (rc));
485           if (rc == GNUPG_Bad_Certificate_Chain
486               || rc == GNUPG_Bad_Certificate
487               || rc == GNUPG_Bad_CA_Certificate
488               || rc == GNUPG_Certificate_Revoked)
489             gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc));
490           else
491             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc));
492           goto next_signer;
493         }
494
495       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
496         {
497           log_info (!i? _("Good signature from")
498                       : _("                aka"));
499           log_printf (" \"");
500           gpgsm_print_name (log_get_stream (), p);
501           log_printf ("\"\n");
502           ksba_free (p);
503         }
504
505       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
506           
507
508     next_signer:
509       rc = 0;
510       xfree (issuer);
511       xfree (serial);
512       xfree (sigval);
513       xfree (msgdigest);
514       ksba_cert_release (cert);
515       cert = NULL;
516     }
517   rc = 0;
518   if (err)
519     {
520       log_error ("ksba error: %s\n", ksba_strerror (err));
521       rc = map_ksba_err (rc);
522     }    
523
524
525
526  leave:
527   ksba_cms_release (cms);
528   gpgsm_destroy_reader (b64reader);
529   gpgsm_destroy_writer (b64writer);
530   keydb_release (kh); 
531   gcry_md_close (data_md);
532   if (fp)
533     fclose (fp);
534
535   if (rc)
536     gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
537                    gnupg_error_token (rc), NULL);
538   return rc;
539 }
540