* verify.c (gpgsm_verify): Extend the STATUS_BADSIG line with
[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_error ("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_error ("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           if (opt.verbose)
187             log_info ("detached signature\n");
188         }
189
190       if (stopreason == KSBA_SR_NEED_HASH
191           || stopreason == KSBA_SR_BEGIN_DATA)
192         { /* We are now able to enable the hash algorithms */
193           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
194             {
195               algo = gcry_md_map_name (algoid);
196               if (!algo)
197                 log_error ("unknown hash algorithm `%s'\n",
198                            algoid? algoid:"?");
199               else
200                 gcry_md_enable (data_md, algo);
201             }
202           if (is_detached)
203             {
204               if (data_fd == -1)
205                 log_info ("detached signature w/o data "
206                           "- assuming certs-only\n");
207               else
208                 hash_data (data_fd, data_md);  
209             }
210           else
211             {
212               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
213             }
214         }
215       else if (stopreason == KSBA_SR_END_DATA)
216         { /* The data bas been hashed */
217
218         }
219     }
220   while (stopreason != KSBA_SR_READY);   
221
222   if (b64writer)
223     {
224       rc = gpgsm_finish_writer (b64writer);
225       if (rc) 
226         {
227           log_error ("write failed: %s\n", gnupg_strerror (rc));
228           goto leave;
229         }
230     }
231
232   if (data_fd != -1 && !is_detached)
233     {
234       log_error ("data given for a non-detached signature\n");
235       rc = GNUPG_Conflict;
236       goto leave;
237     }
238
239   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
240     {
241       /* Fixme: it might be better to check the validity of the
242          certificate first before entering it into the DB.  This way
243          we would avoid cluttering the DB with invalid
244          certificates. */
245       keydb_store_cert (cert, 0, NULL);
246       ksba_cert_release (cert);
247     }
248
249   cert = NULL;
250   err = 0;
251   for (signer=0; signer < 1; signer++)
252     {
253       char *issuer = NULL;
254       KsbaSexp sigval = NULL;
255       time_t sigtime, keyexptime;
256       KsbaSexp serial;
257       char *msgdigest = NULL;
258       size_t msgdigestlen;
259
260       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
261       if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
262         {
263           log_info ("certs-only message accepted\n");
264           err = 0;
265           break;
266         }
267       if (err)
268         break;
269       if (DBG_X509)
270         {
271           log_debug ("signer %d - issuer: `%s'\n",
272                      signer, issuer? issuer:"[NONE]");
273           log_debug ("signer %d - serial: ", signer);
274           gpgsm_dump_serial (serial);
275           log_printf ("\n");
276         }
277
278       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
279       if (err)
280         {
281           log_error ("error getting signing time: %s\n", ksba_strerror (err));
282           sigtime = (time_t)-1;
283         }
284       if (DBG_X509)
285         {
286           log_debug ("signer %d - sigtime: ", signer);
287           gpgsm_dump_time (sigtime);  
288           log_printf ("\n");
289         }
290
291       err = ksba_cms_get_message_digest (cms, signer,
292                                          &msgdigest, &msgdigestlen);
293       if (err)
294         break;
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       sigval = ksba_cms_get_sig_val (cms, signer);
307       if (!sigval)
308         {
309           log_error ("no signature value available\n");
310           goto next_signer;
311         }
312       if (DBG_X509)
313         log_debug ("signer %d - signature available", signer);
314
315       /* Find the certificate of the signer */
316       keydb_search_reset (kh);
317       rc = keydb_search_issuer_sn (kh, issuer, serial);
318       if (rc)
319         {
320           if (rc == -1)
321             {
322               log_error ("certificate not found\n");
323               rc = GNUPG_No_Public_Key;
324             }
325           else
326             log_error ("failed to find the certificate: %s\n",
327                        gnupg_strerror(rc));
328           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
329                          gnupg_error_token (rc), NULL);
330           /* fixme: we might want to append the issuer and serial
331              using our standard notation */
332           goto next_signer;
333         }
334
335       rc = keydb_get_cert (kh, &cert);
336       if (rc)
337         {
338           log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
339           goto next_signer;
340         }
341
342       if (msgdigest)
343         { /* Signed attributes are available. */
344           GCRY_MD_HD md;
345           unsigned char *s;
346
347           /* check that the message digest in the signed attributes
348              matches the one we calculated on the data */
349           s = gcry_md_read (data_md, algo);
350           if ( !s || !msgdigestlen
351                || gcry_md_get_algo_dlen (algo) != msgdigestlen
352                || !s || memcmp (s, msgdigest, msgdigestlen) )
353             {
354               char *fpr;
355
356               log_error ("invalid signature: message digest attribute "
357                          "does not match calculated one\n");
358               fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
359               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
360               xfree (fpr);
361               goto next_signer; 
362             }
363             
364           md = gcry_md_open (algo, 0);
365           if (!md)
366             {
367               log_error ("md_open failed: %s\n", gcry_strerror (-1));
368               goto next_signer;
369             }
370           if (DBG_HASHING)
371             gcry_md_start_debug (md, "vrfy.attr");
372
373           ksba_cms_set_hash_function (cms, HASH_FNC, md);
374           rc = ksba_cms_hash_signed_attrs (cms, signer);
375           if (rc)
376             {
377               log_error ("hashing signed attrs failed: %s\n",
378                          ksba_strerror (rc));
379               gcry_md_close (md);
380               goto next_signer;
381             }
382           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
383           gcry_md_close (md);
384         }
385       else
386         {
387           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
388         }
389
390       if (rc)
391         {
392           char *fpr;
393
394           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
395           fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
396           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
397           xfree (fpr);
398           goto next_signer;
399         }
400       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
401       if (rc)
402         {
403           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.keyusage",
404                          gnupg_error_token (rc), NULL);
405           rc = 0;
406         }
407
408       if (DBG_X509)
409         log_debug ("signature okay - checking certs\n");
410       rc = gpgsm_validate_path (ctrl, cert, &keyexptime);
411       if (rc == GNUPG_Certificate_Expired)
412         {
413           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
414           rc = 0;
415         }
416       else
417         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
418       
419       {
420         char *buf, *fpr, *tstr;
421
422         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
423         tstr = strtimestamp (sigtime);
424         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
425         sprintf (buf, "%s %s %lu %lu", fpr, tstr,
426                  (unsigned long)sigtime, (unsigned long)keyexptime );
427         xfree (tstr);
428         xfree (fpr);
429         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
430         xfree (buf);
431       }
432
433       if (rc) /* of validate_path */
434         {
435           log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
436           if (rc == GNUPG_Bad_Certificate_Path
437               || rc == GNUPG_Bad_Certificate
438               || rc == GNUPG_Bad_CA_Certificate
439               || rc == GNUPG_Certificate_Revoked)
440             gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc));
441           else
442             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc));
443           goto next_signer;
444         }
445       log_info ("signature is good\n");
446       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
447           
448
449     next_signer:
450       rc = 0;
451       xfree (issuer);
452       xfree (serial);
453       xfree (sigval);
454       xfree (msgdigest);
455       ksba_cert_release (cert);
456       cert = NULL;
457     }
458   rc = 0;
459   if (err)
460     {
461       log_error ("ksba error: %s\n", ksba_strerror (err));
462       rc = map_ksba_err (rc);
463     }    
464
465
466
467  leave:
468   ksba_cms_release (cms);
469   gpgsm_destroy_reader (b64reader);
470   gpgsm_destroy_writer (b64writer);
471   keydb_release (kh); 
472   gcry_md_close (data_md);
473   if (fp)
474     fclose (fp);
475
476   if (rc)
477     gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
478                    gnupg_error_token (rc), NULL);
479   return rc;
480 }
481