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