Mainly changes to adjust for the changed KSBA API.
[gnupg.git] / sm / verify.c
1 /* verify.c - Verify a messages signature
2  *      Copyright (C) 2001, 2002, 2003 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 "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 #include "keydb.h"
35 #include "i18n.h"
36
37 static char *
38 strtimestamp_r (ksba_isotime_t atime)
39 {
40   char *buffer = xmalloc (15);
41   
42   if (!atime || !*atime)
43     strcpy (buffer, "none");
44   else
45     sprintf (buffer, "%.4s-%.2s-%.2s", atime, atime+4, atime+6);
46   return buffer;
47 }
48
49
50
51 /* Hash the data for a detached signature */
52 static void
53 hash_data (int fd, gcry_md_hd_t md)
54 {
55   FILE *fp;
56   char buffer[4096];
57   int nread;
58
59   fp = fdopen ( dup (fd), "rb");
60   if (!fp)
61     {
62       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
63       return;
64     }
65
66   do 
67     {
68       nread = fread (buffer, 1, DIM(buffer), fp);
69       gcry_md_write (md, buffer, nread);
70     }
71   while (nread);
72   if (ferror (fp))
73       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
74   fclose (fp);
75 }
76
77
78
79 \f
80 /* Perform a verify operation.  To verify detached signatures, data_fd
81    must be different than -1.  With OUT_FP given and a non-detached
82    signature, the signed material is written to that stream. */
83 int
84 gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
85 {
86   int i, rc;
87   Base64Context b64reader = NULL;
88   Base64Context b64writer = NULL;
89   KsbaError err;
90   KsbaReader reader;
91   KsbaWriter writer = NULL;
92   KsbaCMS cms = NULL;
93   KsbaStopReason stopreason;
94   KsbaCert cert;
95   KEYDB_HANDLE kh;
96   gcry_md_hd_t data_md = NULL;
97   int signer;
98   const char *algoid;
99   int algo;
100   int is_detached;
101   FILE *fp = NULL;
102   char *p;
103
104   kh = keydb_new (0);
105   if (!kh)
106     {
107       log_error (_("failed to allocated keyDB handle\n"));
108       rc = gpg_error (GPG_ERR_GENERAL);
109       goto leave;
110     }
111
112
113   fp = fdopen ( dup (in_fd), "rb");
114   if (!fp)
115     {
116       rc = gpg_error (gpg_err_code_from_errno (errno));
117       log_error ("fdopen() failed: %s\n", strerror (errno));
118       goto leave;
119     }
120
121   rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
122   if (rc)
123     {
124       log_error ("can't create reader: %s\n", gpg_strerror (rc));
125       goto leave;
126     }
127
128   if (out_fp)
129     {
130       rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
131       if (rc)
132         {
133           log_error ("can't create writer: %s\n", gpg_strerror (rc));
134           goto leave;
135         }
136     }
137
138   err = ksba_cms_new (&cms);
139   if (err)
140     {
141       rc = gpg_error (GPG_ERR_ENOMEM);
142       goto leave;
143     }
144
145   err = ksba_cms_set_reader_writer (cms, reader, writer);
146   if (err)
147     {
148       log_error ("ksba_cms_set_reader_writer failed: %s\n",
149                  gpg_strerror (err));
150       rc = err;
151       goto leave;
152     }
153
154   rc = gcry_md_open (&data_md, 0, 0);
155   if (rc)
156     {
157       log_error ("md_open failed: %s\n", gpg_strerror (rc));
158       goto leave;
159     }
160   if (DBG_HASHING)
161     gcry_md_start_debug (data_md, "vrfy.data");
162
163   is_detached = 0;
164   do 
165     {
166       err = ksba_cms_parse (cms, &stopreason);
167       if (err)
168         {
169           log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (err));
170           rc = err;
171           goto leave;
172         }
173
174       if (stopreason == KSBA_SR_NEED_HASH)
175         {
176           is_detached = 1;
177           if (opt.verbose)
178             log_info ("detached signature\n");
179         }
180
181       if (stopreason == KSBA_SR_NEED_HASH
182           || stopreason == KSBA_SR_BEGIN_DATA)
183         { /* We are now able to enable the hash algorithms */
184           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
185             {
186               algo = gcry_md_map_name (algoid);
187               if (!algo)
188                 log_error ("unknown hash algorithm `%s'\n",
189                            algoid? algoid:"?");
190               else
191                 gcry_md_enable (data_md, algo);
192             }
193           if (is_detached)
194             {
195               if (data_fd == -1)
196                 log_info ("detached signature w/o data "
197                           "- assuming certs-only\n");
198               else
199                 hash_data (data_fd, data_md);  
200             }
201           else
202             {
203               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
204             }
205         }
206       else if (stopreason == KSBA_SR_END_DATA)
207         { /* The data bas been hashed */
208
209         }
210     }
211   while (stopreason != KSBA_SR_READY);   
212
213   if (b64writer)
214     {
215       rc = gpgsm_finish_writer (b64writer);
216       if (rc) 
217         {
218           log_error ("write failed: %s\n", gpg_strerror (rc));
219           goto leave;
220         }
221     }
222
223   if (data_fd != -1 && !is_detached)
224     {
225       log_error ("data given for a non-detached signature\n");
226       rc = gpg_error (GPG_ERR_CONFLICT);
227       goto leave;
228     }
229
230   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
231     {
232       /* Fixme: it might be better to check the validity of the
233          certificate first before entering it into the DB.  This way
234          we would avoid cluttering the DB with invalid
235          certificates. */
236       keydb_store_cert (cert, 0, NULL);
237       ksba_cert_release (cert);
238     }
239
240   cert = NULL;
241   err = 0;
242   for (signer=0; ; signer++)
243     {
244       char *issuer = NULL;
245       KsbaSexp sigval = NULL;
246       ksba_isotime_t sigtime, keyexptime;
247       KsbaSexp serial;
248       char *msgdigest = NULL;
249       size_t msgdigestlen;
250       char *ctattr;
251
252       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
253       if (!signer && gpg_err_code (err) == GPG_ERR_NO_DATA
254           && data_fd == -1 && is_detached)
255         {
256           log_info ("certs-only message accepted\n");
257           err = 0;
258           break;
259         }
260       if (err)
261         {
262           if (signer && err == -1)
263             err = 0;
264           break;
265         }
266       if (DBG_X509)
267         {
268           log_debug ("signer %d - issuer: `%s'\n",
269                      signer, issuer? issuer:"[NONE]");
270           log_debug ("signer %d - serial: ", signer);
271           gpgsm_dump_serial (serial);
272           log_printf ("\n");
273         }
274
275       err = ksba_cms_get_signing_time (cms, signer, sigtime);
276       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
277         *sigtime = 0;
278       else if (err)
279         {
280           log_error ("error getting signing time: %s\n", gpg_strerror (err));
281           *sigtime = 0; /* FIXME: we can't encode an error in the time
282                            string. */
283         }
284
285       err = ksba_cms_get_message_digest (cms, signer,
286                                          &msgdigest, &msgdigestlen);
287       if (!err)
288         {
289           algoid = ksba_cms_get_digest_algo (cms, signer);
290           algo = gcry_md_map_name (algoid);
291           if (DBG_X509)
292             log_debug ("signer %d - digest algo: %d\n", signer, algo);
293           if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
294             {
295               log_error ("digest algo %d has not been enabled\n", algo);
296               goto next_signer;
297             }
298         }
299       else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
300         {
301           assert (!msgdigest);
302           err = 0;
303           algoid = NULL;
304           algo = 0; 
305         }
306       else /* real error */
307         break;
308
309       err = ksba_cms_get_sigattr_oids (cms, signer,
310                                        "1.2.840.113549.1.9.3",&ctattr);
311       if (!err) 
312         {
313           const char *s;
314
315           if (DBG_X509)
316             log_debug ("signer %d - content-type attribute: %s", signer, ctattr);
317           s = ksba_cms_get_content_oid (cms, 1);
318           if (!s || strcmp (ctattr, s))
319             {
320               log_error ("content-type attribute does not match "
321                          "actual content-type\n");
322               ksba_free (ctattr);
323               ctattr = NULL;
324               goto next_signer;
325             }
326           ksba_free (ctattr);
327           ctattr = NULL;
328         }
329       else if (err != -1)
330         {
331           log_error ("error getting content-type attribute: %s\n",
332                      gpg_strerror (err));
333           goto next_signer;
334         }
335       err = 0;
336
337
338       sigval = ksba_cms_get_sig_val (cms, signer);
339       if (!sigval)
340         {
341           log_error ("no signature value available\n");
342           goto next_signer;
343         }
344       if (DBG_X509)
345         log_debug ("signer %d - signature available", signer);
346
347       /* Find the certificate of the signer */
348       keydb_search_reset (kh);
349       rc = keydb_search_issuer_sn (kh, issuer, serial);
350       if (rc)
351         {
352           if (rc == -1)
353             {
354               log_error ("certificate not found\n");
355               rc = gpg_error (GPG_ERR_NO_PUBKEY);
356             }
357           else
358             log_error ("failed to find the certificate: %s\n",
359                        gpg_strerror(rc));
360           {
361             char numbuf[50];
362             sprintf (numbuf, "%d", rc);
363
364             gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
365                            numbuf, NULL);
366           }
367           /* fixme: we might want to append the issuer and serial
368              using our standard notation */
369           goto next_signer;
370         }
371
372       rc = keydb_get_cert (kh, &cert);
373       if (rc)
374         {
375           log_error ("failed to get cert: %s\n", gpg_strerror (rc));
376           goto next_signer;
377         }
378
379       log_info (_("Signature made "));
380       if (*sigtime)
381         gpgsm_dump_time (sigtime);
382       else
383         log_printf (_("[date not given]"));
384       log_printf (_(" using certificate ID %08lX\n"),
385                   gpgsm_get_short_fingerprint (cert));
386
387
388       if (msgdigest)
389         { /* Signed attributes are available. */
390           gcry_md_hd_t md;
391           unsigned char *s;
392
393           /* check that the message digest in the signed attributes
394              matches the one we calculated on the data */
395           s = gcry_md_read (data_md, algo);
396           if ( !s || !msgdigestlen
397                || gcry_md_get_algo_dlen (algo) != msgdigestlen
398                || !s || memcmp (s, msgdigest, msgdigestlen) )
399             {
400               char *fpr;
401
402               log_error ("invalid signature: message digest attribute "
403                          "does not match calculated one\n");
404               fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
405               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
406               xfree (fpr);
407               goto next_signer; 
408             }
409             
410           rc = gcry_md_open (&md, algo, 0);
411           if (rc)
412             {
413               log_error ("md_open failed: %s\n", gpg_strerror (rc));
414               goto next_signer;
415             }
416           if (DBG_HASHING)
417             gcry_md_start_debug (md, "vrfy.attr");
418
419           ksba_cms_set_hash_function (cms, HASH_FNC, md);
420           rc = ksba_cms_hash_signed_attrs (cms, signer);
421           if (rc)
422             {
423               log_error ("hashing signed attrs failed: %s\n",
424                          gpg_strerror (rc));
425               gcry_md_close (md);
426               goto next_signer;
427             }
428           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
429           gcry_md_close (md);
430         }
431       else
432         {
433           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
434         }
435
436       if (rc)
437         {
438           char *fpr;
439
440           log_error ("invalid signature: %s\n", gpg_strerror (rc));
441           fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
442           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
443           xfree (fpr);
444           goto next_signer;
445         }
446       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
447       if (rc)
448         {
449           gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
450                                       gpg_err_code (rc));
451           rc = 0;
452         }
453
454       if (DBG_X509)
455         log_debug ("signature okay - checking certs\n");
456       rc = gpgsm_validate_chain (ctrl, cert, keyexptime);
457       if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
458         {
459           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
460           rc = 0;
461         }
462       else
463         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
464       
465       {
466         char *buf, *fpr, *tstr;
467
468         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
469         tstr = strtimestamp_r (sigtime);
470         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
471         sprintf (buf, "%s %s %s %s", fpr, tstr,
472                  sigtime, keyexptime );
473         xfree (tstr);
474         xfree (fpr);
475         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
476         xfree (buf);
477       }
478
479       if (rc) /* of validate_chain */
480         {
481           log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
482           if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
483               || gpg_err_code (rc) == GPG_ERR_BAD_CERT
484               || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
485               || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
486             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
487                                         gpg_err_code (rc));
488           else
489             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL, 
490                                         gpg_err_code (rc));
491           goto next_signer;
492         }
493
494       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
495         {
496           log_info (!i? _("Good signature from")
497                       : _("                aka"));
498           log_printf (" \"");
499           gpgsm_print_name (log_get_stream (), p);
500           log_printf ("\"\n");
501           ksba_free (p);
502         }
503
504       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
505           
506
507     next_signer:
508       rc = 0;
509       xfree (issuer);
510       xfree (serial);
511       xfree (sigval);
512       xfree (msgdigest);
513       ksba_cert_release (cert);
514       cert = NULL;
515     }
516   rc = 0;
517   if (err)
518     { /* FIXME: still needed? */
519       log_error ("ksba error: %s\n", gpg_strerror (err));
520       rc = err;
521     }    
522
523
524
525  leave:
526   ksba_cms_release (cms);
527   gpgsm_destroy_reader (b64reader);
528   gpgsm_destroy_writer (b64writer);
529   keydb_release (kh); 
530   gcry_md_close (data_md);
531   if (fp)
532     fclose (fp);
533
534   if (rc)
535     {
536       char numbuf[50];
537       sprintf (numbuf, "%d", rc );
538       gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
539                      numbuf, NULL);
540     }
541
542   return rc;
543 }
544