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