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