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