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