* gpgsm.c (main): Use the log file only in server mode.
[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
261       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
262       if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
263         {
264           log_info ("certs-only message accepted\n");
265           err = 0;
266           break;
267         }
268       if (err)
269         {
270           if (signer && err == -1)
271             err = 0;
272           break;
273         }
274       if (DBG_X509)
275         {
276           log_debug ("signer %d - issuer: `%s'\n",
277                      signer, issuer? issuer:"[NONE]");
278           log_debug ("signer %d - serial: ", signer);
279           gpgsm_dump_serial (serial);
280           log_printf ("\n");
281         }
282
283       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
284       if (err == KSBA_No_Data)
285         sigtime = 0;
286       else if (err)
287         {
288           log_error ("error getting signing time: %s\n", ksba_strerror (err));
289           sigtime = (time_t)-1;
290         }
291
292       err = ksba_cms_get_message_digest (cms, signer,
293                                          &msgdigest, &msgdigestlen);
294       if (!err)
295         {
296           algoid = ksba_cms_get_digest_algo (cms, signer);
297           algo = gcry_md_map_name (algoid);
298           if (DBG_X509)
299             log_debug ("signer %d - digest algo: %d\n", signer, algo);
300           if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
301             {
302               log_error ("digest algo %d has not been enabled\n", algo);
303               goto next_signer;
304             }
305         }
306       else if (err == KSBA_No_Data)
307         {
308           assert (!msgdigest);
309           err = 0;
310           algoid = NULL;
311           algo = 0; 
312         }
313       else /* real error */
314         break;
315
316       sigval = ksba_cms_get_sig_val (cms, signer);
317       if (!sigval)
318         {
319           log_error ("no signature value available\n");
320           goto next_signer;
321         }
322       if (DBG_X509)
323         log_debug ("signer %d - signature available", signer);
324
325       /* Find the certificate of the signer */
326       keydb_search_reset (kh);
327       rc = keydb_search_issuer_sn (kh, issuer, serial);
328       if (rc)
329         {
330           if (rc == -1)
331             {
332               log_error ("certificate not found\n");
333               rc = GNUPG_No_Public_Key;
334             }
335           else
336             log_error ("failed to find the certificate: %s\n",
337                        gnupg_strerror(rc));
338           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
339                          gnupg_error_token (rc), NULL);
340           /* fixme: we might want to append the issuer and serial
341              using our standard notation */
342           goto next_signer;
343         }
344
345       rc = keydb_get_cert (kh, &cert);
346       if (rc)
347         {
348           log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
349           goto next_signer;
350         }
351
352       log_info (_("Signature made "));
353       if (sigtime)
354         gpgsm_dump_time (sigtime);
355       else
356         log_printf (_("[date not given]"));
357       log_printf (_(" using certificate ID %08lX\n"),
358                   gpgsm_get_short_fingerprint (cert));
359
360
361       if (msgdigest)
362         { /* Signed attributes are available. */
363           GCRY_MD_HD md;
364           unsigned char *s;
365
366           /* check that the message digest in the signed attributes
367              matches the one we calculated on the data */
368           s = gcry_md_read (data_md, algo);
369           if ( !s || !msgdigestlen
370                || gcry_md_get_algo_dlen (algo) != msgdigestlen
371                || !s || memcmp (s, msgdigest, msgdigestlen) )
372             {
373               char *fpr;
374
375               log_error ("invalid signature: message digest attribute "
376                          "does not match calculated one\n");
377               fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
378               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
379               xfree (fpr);
380               goto next_signer; 
381             }
382             
383           md = gcry_md_open (algo, 0);
384           if (!md)
385             {
386               log_error ("md_open failed: %s\n", gcry_strerror (-1));
387               goto next_signer;
388             }
389           if (DBG_HASHING)
390             gcry_md_start_debug (md, "vrfy.attr");
391
392           ksba_cms_set_hash_function (cms, HASH_FNC, md);
393           rc = ksba_cms_hash_signed_attrs (cms, signer);
394           if (rc)
395             {
396               log_error ("hashing signed attrs failed: %s\n",
397                          ksba_strerror (rc));
398               gcry_md_close (md);
399               goto next_signer;
400             }
401           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
402           gcry_md_close (md);
403         }
404       else
405         {
406           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
407         }
408
409       if (rc)
410         {
411           char *fpr;
412
413           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
414           fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
415           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
416           xfree (fpr);
417           goto next_signer;
418         }
419       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
420       if (rc)
421         {
422           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.keyusage",
423                          gnupg_error_token (rc), NULL);
424           rc = 0;
425         }
426
427       if (DBG_X509)
428         log_debug ("signature okay - checking certs\n");
429       rc = gpgsm_validate_chain (ctrl, cert, &keyexptime);
430       if (rc == GNUPG_Certificate_Expired)
431         {
432           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
433           rc = 0;
434         }
435       else
436         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
437       
438       {
439         char *buf, *fpr, *tstr;
440
441         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
442         tstr = strtimestamp (sigtime);
443         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
444         sprintf (buf, "%s %s %lu %lu", fpr, tstr,
445                  (unsigned long)sigtime, (unsigned long)keyexptime );
446         xfree (tstr);
447         xfree (fpr);
448         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
449         xfree (buf);
450       }
451
452       if (rc) /* of validate_chain */
453         {
454           log_error ("invalid certification chain: %s\n", gnupg_strerror (rc));
455           if (rc == GNUPG_Bad_Certificate_Chain
456               || rc == GNUPG_Bad_Certificate
457               || rc == GNUPG_Bad_CA_Certificate
458               || rc == GNUPG_Certificate_Revoked)
459             gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc));
460           else
461             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc));
462           goto next_signer;
463         }
464
465       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
466         {
467           log_info (!i? _("Good signature from")
468                       : _("                aka"));
469           log_printf (" \"");
470           gpgsm_print_name (log_get_stream (), p);
471           log_printf ("\"\n");
472           ksba_free (p);
473         }
474
475       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
476           
477
478     next_signer:
479       rc = 0;
480       xfree (issuer);
481       xfree (serial);
482       xfree (sigval);
483       xfree (msgdigest);
484       ksba_cert_release (cert);
485       cert = NULL;
486     }
487   rc = 0;
488   if (err)
489     {
490       log_error ("ksba error: %s\n", ksba_strerror (err));
491       rc = map_ksba_err (rc);
492     }    
493
494
495
496  leave:
497   ksba_cms_release (cms);
498   gpgsm_destroy_reader (b64reader);
499   gpgsm_destroy_writer (b64writer);
500   keydb_release (kh); 
501   gcry_md_close (data_md);
502   if (fp)
503     fclose (fp);
504
505   if (rc)
506     gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
507                    gnupg_error_token (rc), NULL);
508   return rc;
509 }
510