A small step for GnuPG but a huge leap for error codes.
[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 <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 = gpg_error (GPG_ERR_GENERAL);
118       goto leave;
119     }
120
121
122   fp = fdopen ( dup (in_fd), "rb");
123   if (!fp)
124     {
125       rc = gpg_error (gpg_err_code_from_errno (errno));
126       log_error ("fdopen() failed: %s\n", strerror (errno));
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 = gpg_error (GPG_ERR_ENOMEM);
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 = gpg_error (GPG_ERR_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       char *ctattr;
261
262       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
263       if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
264         {
265           log_info ("certs-only message accepted\n");
266           err = 0;
267           break;
268         }
269       if (err)
270         {
271           if (signer && err == -1)
272             err = 0;
273           break;
274         }
275       if (DBG_X509)
276         {
277           log_debug ("signer %d - issuer: `%s'\n",
278                      signer, issuer? issuer:"[NONE]");
279           log_debug ("signer %d - serial: ", signer);
280           gpgsm_dump_serial (serial);
281           log_printf ("\n");
282         }
283
284       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
285       if (err == KSBA_No_Data)
286         sigtime = 0;
287       else if (err)
288         {
289           log_error ("error getting signing time: %s\n", ksba_strerror (err));
290           sigtime = (time_t)-1;
291         }
292
293       err = ksba_cms_get_message_digest (cms, signer,
294                                          &msgdigest, &msgdigestlen);
295       if (!err)
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       else if (err == KSBA_No_Data)
308         {
309           assert (!msgdigest);
310           err = 0;
311           algoid = NULL;
312           algo = 0; 
313         }
314       else /* real error */
315         break;
316
317       err = ksba_cms_get_sigattr_oids (cms, signer,
318                                        "1.2.840.113549.1.9.3",&ctattr);
319       if (!err) 
320         {
321           const char *s;
322
323           if (DBG_X509)
324             log_debug ("signer %d - content-type attribute: %s", signer, ctattr);
325           s = ksba_cms_get_content_oid (cms, 1);
326           if (!s || strcmp (ctattr, s))
327             {
328               log_error ("content-type attribute does not match "
329                          "actual content-type\n");
330               ksba_free (ctattr);
331               ctattr = NULL;
332               goto next_signer;
333             }
334           ksba_free (ctattr);
335           ctattr = NULL;
336         }
337       else if (err != -1)
338         {
339           log_error ("error getting content-type attribute: %s\n",
340                      ksba_strerror (err));
341           goto next_signer;
342         }
343       err = 0;
344
345
346       sigval = ksba_cms_get_sig_val (cms, signer);
347       if (!sigval)
348         {
349           log_error ("no signature value available\n");
350           goto next_signer;
351         }
352       if (DBG_X509)
353         log_debug ("signer %d - signature available", signer);
354
355       /* Find the certificate of the signer */
356       keydb_search_reset (kh);
357       rc = keydb_search_issuer_sn (kh, issuer, serial);
358       if (rc)
359         {
360           if (rc == -1)
361             {
362               log_error ("certificate not found\n");
363               rc = gpg_error (GPG_ERR_NO_PUBKEY);
364             }
365           else
366             log_error ("failed to find the certificate: %s\n",
367                        gnupg_strerror(rc));
368           {
369             char numbuf[50];
370             sprintf (numbuf, "%d", rc);
371
372             gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
373                            numbuf, NULL);
374           }
375           /* fixme: we might want to append the issuer and serial
376              using our standard notation */
377           goto next_signer;
378         }
379
380       rc = keydb_get_cert (kh, &cert);
381       if (rc)
382         {
383           log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
384           goto next_signer;
385         }
386
387       log_info (_("Signature made "));
388       if (sigtime)
389         gpgsm_dump_time (sigtime);
390       else
391         log_printf (_("[date not given]"));
392       log_printf (_(" using certificate ID %08lX\n"),
393                   gpgsm_get_short_fingerprint (cert));
394
395
396       if (msgdigest)
397         { /* Signed attributes are available. */
398           GCRY_MD_HD md;
399           unsigned char *s;
400
401           /* check that the message digest in the signed attributes
402              matches the one we calculated on the data */
403           s = gcry_md_read (data_md, algo);
404           if ( !s || !msgdigestlen
405                || gcry_md_get_algo_dlen (algo) != msgdigestlen
406                || !s || memcmp (s, msgdigest, msgdigestlen) )
407             {
408               char *fpr;
409
410               log_error ("invalid signature: message digest attribute "
411                          "does not match calculated one\n");
412               fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
413               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
414               xfree (fpr);
415               goto next_signer; 
416             }
417             
418           md = gcry_md_open (algo, 0);
419           if (!md)
420             {
421               log_error ("md_open failed: %s\n", gcry_strerror (-1));
422               goto next_signer;
423             }
424           if (DBG_HASHING)
425             gcry_md_start_debug (md, "vrfy.attr");
426
427           ksba_cms_set_hash_function (cms, HASH_FNC, md);
428           rc = ksba_cms_hash_signed_attrs (cms, signer);
429           if (rc)
430             {
431               log_error ("hashing signed attrs failed: %s\n",
432                          ksba_strerror (rc));
433               gcry_md_close (md);
434               goto next_signer;
435             }
436           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
437           gcry_md_close (md);
438         }
439       else
440         {
441           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
442         }
443
444       if (rc)
445         {
446           char *fpr;
447
448           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
449           fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
450           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
451           xfree (fpr);
452           goto next_signer;
453         }
454       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
455       if (rc)
456         {
457           gpgsm_status2 (ctrl, STATUS_ERROR, "verify.keyusage",
458                          gnupg_error_token (rc), NULL);
459           rc = 0;
460         }
461
462       if (DBG_X509)
463         log_debug ("signature okay - checking certs\n");
464       rc = gpgsm_validate_chain (ctrl, cert, &keyexptime);
465       if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
466         {
467           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
468           rc = 0;
469         }
470       else
471         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
472       
473       {
474         char *buf, *fpr, *tstr;
475
476         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
477         tstr = strtimestamp (sigtime);
478         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
479         sprintf (buf, "%s %s %lu %lu", fpr, tstr,
480                  (unsigned long)sigtime, (unsigned long)keyexptime );
481         xfree (tstr);
482         xfree (fpr);
483         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
484         xfree (buf);
485       }
486
487       if (rc) /* of validate_chain */
488         {
489           log_error ("invalid certification chain: %s\n", gnupg_strerror (rc));
490           if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
491               || gpg_err_code (rc) == GPG_ERR_BAD_CERT
492               || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
493               || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
494             gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc));
495           else
496             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc));
497           goto next_signer;
498         }
499
500       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
501         {
502           log_info (!i? _("Good signature from")
503                       : _("                aka"));
504           log_printf (" \"");
505           gpgsm_print_name (log_get_stream (), p);
506           log_printf ("\"\n");
507           ksba_free (p);
508         }
509
510       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
511           
512
513     next_signer:
514       rc = 0;
515       xfree (issuer);
516       xfree (serial);
517       xfree (sigval);
518       xfree (msgdigest);
519       ksba_cert_release (cert);
520       cert = NULL;
521     }
522   rc = 0;
523   if (err)
524     {
525       log_error ("ksba error: %s\n", ksba_strerror (err));
526       rc = map_ksba_err (rc);
527     }    
528
529
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