* verify.c (gpgsm_verify): Implemented non-detached signature
[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 /* fixme: duplicated from import.c */
61 static void
62 store_cert (KsbaCert cert)
63 {
64   KEYDB_HANDLE kh;
65   int rc;
66
67   kh = keydb_new (0);
68   if (!kh)
69     {
70       log_error (_("failed to allocated keyDB handle\n"));
71       return;
72     }
73   rc = keydb_locate_writable (kh, 0);
74   if (rc)
75       log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
76
77   rc = keydb_insert_cert (kh, cert);
78   if (rc)
79     {
80       log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
81     }
82   keydb_release (kh);               
83 }
84
85
86 /* Hash the data for a detached signature */
87 static void
88 hash_data (int fd, GCRY_MD_HD md)
89 {
90   FILE *fp;
91   char buffer[4096];
92   int nread;
93
94   fp = fdopen ( dup (fd), "rb");
95   if (!fp)
96     {
97       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
98       return;
99     }
100
101   do 
102     {
103       nread = fread (buffer, 1, DIM(buffer), fp);
104       gcry_md_write (md, buffer, nread);
105     }
106   while (nread);
107   if (ferror (fp))
108       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
109   fclose (fp);
110 }
111
112
113
114 \f
115 /* Perform a verify operation.  To verify detached signatures, data_fd
116    must be different than -1.  With OUT_FP given and a non-detached
117    signature, the signed material is written to that stream. */
118 int
119 gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
120 {
121   int i, rc;
122   Base64Context b64reader = NULL;
123   Base64Context b64writer = NULL;
124   KsbaError err;
125   KsbaReader reader;
126   KsbaWriter writer = NULL;
127   KsbaCMS cms = NULL;
128   KsbaStopReason stopreason;
129   KsbaCert cert;
130   KEYDB_HANDLE kh;
131   GCRY_MD_HD data_md = NULL;
132   int signer;
133   const char *algoid;
134   int algo;
135   int is_detached;
136   FILE *fp = NULL;
137
138   kh = keydb_new (0);
139   if (!kh)
140     {
141       log_error (_("failed to allocated keyDB handle\n"));
142       rc = GNUPG_General_Error;
143       goto leave;
144     }
145
146
147   fp = fdopen ( dup (in_fd), "rb");
148   if (!fp)
149     {
150       log_error ("fdopen() failed: %s\n", strerror (errno));
151       rc = seterr (IO_Error);
152       goto leave;
153     }
154
155   rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
156   if (rc)
157     {
158       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
159       goto leave;
160     }
161
162   if (out_fp)
163     {
164       rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
165       if (rc)
166         {
167           log_error ("can't create writer: %s\n", gnupg_strerror (rc));
168           goto leave;
169         }
170     }
171
172   cms = ksba_cms_new ();
173   if (!cms)
174     {
175       rc = seterr (Out_Of_Core);
176       goto leave;
177     }
178
179   err = ksba_cms_set_reader_writer (cms, reader, writer);
180   if (err)
181     {
182       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
183                  ksba_strerror (err));
184       rc = map_ksba_err (err);
185       goto leave;
186     }
187
188   data_md = gcry_md_open (0, 0);
189   if (!data_md)
190     {
191       rc = map_gcry_err (gcry_errno());
192       log_error ("md_open failed: %s\n", gcry_strerror (-1));
193       goto leave;
194     }
195   if (DBG_HASHING)
196     gcry_md_start_debug (data_md, "vrfy.data");
197
198   is_detached = 0;
199   do 
200     {
201       err = ksba_cms_parse (cms, &stopreason);
202       if (err)
203         {
204           log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
205           rc = map_ksba_err (err);
206           goto leave;
207         }
208
209       if (stopreason == KSBA_SR_NEED_HASH)
210         {
211           is_detached = 1;
212           log_debug ("Detached signature\n");
213         }
214
215       if (stopreason == KSBA_SR_NEED_HASH
216           || stopreason == KSBA_SR_BEGIN_DATA)
217         { /* We are now able to enable the hash algorithms */
218           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
219             {
220               algo = gcry_md_map_name (algoid);
221               if (!algo)
222                 log_error ("unknown hash algorithm `%s'\n",
223                            algoid? algoid:"?");
224               else
225                 gcry_md_enable (data_md, algo);
226             }
227           if (is_detached)
228             {
229               if (data_fd == -1)
230                 {
231                   log_error ("detached signature but no data given\n");
232                   rc = GNUPG_Bad_Signature;
233                   goto leave;
234                 }
235               hash_data (data_fd, data_md);  
236             }
237           else
238             {
239               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
240             }
241         }
242       else if (stopreason == KSBA_SR_END_DATA)
243         { /* The data bas been hashed */
244
245         }
246     }
247   while (stopreason != KSBA_SR_READY);   
248
249   if (b64writer)
250     {
251       rc = gpgsm_finish_writer (b64writer);
252       if (rc) 
253         {
254           log_error ("write failed: %s\n", gnupg_strerror (rc));
255           goto leave;
256         }
257     }
258
259   if (data_fd != -1 && !is_detached)
260     {
261       log_error ("data given for a non-detached signature\n");
262       rc = GNUPG_Conflict;
263       goto leave;
264     }
265
266   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
267     {
268       log_debug ("storing certifcate %d\n", i);
269       /* Fixme: we should mark the stored certificates as temporary
270          and put them in a cache first */
271       store_cert (cert);
272       ksba_cert_release (cert);
273     }
274
275   cert = NULL;
276   err = 0;
277   for (signer=0; signer < 1; signer++)
278     {
279       char *issuer = NULL;
280       KsbaSexp sigval = NULL;
281       time_t sigtime;
282       KsbaSexp serial;
283       char *msgdigest = NULL;
284       size_t msgdigestlen;
285
286       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
287       if (err)
288         break;
289       log_debug ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]");
290       log_debug ("signer %d - serial: ", signer);
291       gpgsm_dump_serial (serial);
292       log_printf ("\n");
293
294       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
295       if (err)
296         {
297           log_debug ("error getting signing time: %s\n", ksba_strerror (err));
298           sigtime = (time_t)-1;
299         }
300       log_debug ("signer %d - sigtime: ", signer);
301       gpgsm_dump_time (sigtime);  
302       log_printf ("\n");
303
304
305       err = ksba_cms_get_message_digest (cms, signer,
306                                          &msgdigest, &msgdigestlen);
307       if (err)
308         break;
309
310       algoid = ksba_cms_get_digest_algo (cms, signer);
311       algo = gcry_md_map_name (algoid);
312       log_debug ("signer %d - digest algo: %d\n", signer, algo);
313       if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
314         {
315           log_debug ("digest algo %d has not been enabled\n", algo);
316           goto next_signer;
317         }
318
319       sigval = ksba_cms_get_sig_val (cms, signer);
320       if (!sigval)
321         {
322           log_error ("no signature value available\n");
323           goto next_signer;
324         }
325       log_debug ("signer %d - signature available", signer);
326
327       /* Find the certificate of the signer */
328       keydb_search_reset (kh);
329       rc = keydb_search_issuer_sn (kh, issuer, serial);
330       if (rc)
331         {
332           log_debug ("failed to find the certificate: %s\n",
333                      gnupg_strerror(rc));
334           goto next_signer;
335         }
336
337       rc = keydb_get_cert (kh, &cert);
338       if (rc)
339         {
340           log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
341           goto next_signer;
342         }
343
344       if (msgdigest)
345         { /* Signed attributes are available. */
346           GCRY_MD_HD md;
347           unsigned char *s;
348
349           /* check that the message digest in the signed attributes
350              matches the one we calculated on the data */
351           s = gcry_md_read (data_md, algo);
352           if ( !s || !msgdigestlen
353                || gcry_md_get_algo_dlen (algo) != msgdigestlen
354                || !s || memcmp (s, msgdigest, msgdigestlen) )
355             {
356               log_error ("message digest attribute does not "
357                          "match calculated one\n");
358               gpgsm_status (ctrl, STATUS_BADSIG, NULL);
359               goto next_signer; 
360             }
361             
362           md = gcry_md_open (algo, 0);
363           if (!md)
364             {
365               log_error ("md_open failed: %s\n", gcry_strerror (-1));
366               goto next_signer;
367             }
368           if (DBG_HASHING)
369             gcry_md_start_debug (md, "vrfy.attr");
370
371           ksba_cms_set_hash_function (cms, HASH_FNC, md);
372           rc = ksba_cms_hash_signed_attrs (cms, signer);
373           if (rc)
374             {
375               log_debug ("hashing signed attrs failed: %s\n",
376                          ksba_strerror (rc));
377               gcry_md_close (md);
378               goto next_signer;
379             }
380           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
381           gcry_md_close (md);
382         }
383       else
384         {
385           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
386         }
387
388       if (rc)
389         {
390           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
391           gpgsm_status (ctrl, STATUS_BADSIG, NULL);
392           goto next_signer;
393         }
394       log_debug ("signature okay - checking certs\n");
395       gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
396       {
397         char *buf, *fpr, *tstr;
398
399         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
400         tstr = strtimestamp (sigtime);
401         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100);
402         sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime );
403         xfree (tstr);
404         xfree (fpr);
405         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
406         xfree (buf);
407       }
408
409       rc = gpgsm_validate_path (cert);
410       if (rc)
411         {
412           log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
413           if (rc == GNUPG_Bad_Certificate_Path
414               || rc == GNUPG_Bad_Certificate)
415             gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL);
416           else
417             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL);
418           goto next_signer;
419         }
420       log_info ("signature is good\n");
421       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
422           
423
424     next_signer:
425       rc = 0;
426       xfree (issuer);
427       xfree (serial);
428       xfree (sigval);
429       xfree (msgdigest);
430       ksba_cert_release (cert);
431       cert = NULL;
432     }
433   rc = 0;
434   if (err)
435     {
436       log_debug ("ksba error: %s\n", ksba_strerror (err));
437       rc = map_ksba_err (rc);
438     }    
439
440
441
442  leave:
443   ksba_cms_release (cms);
444   gpgsm_destroy_reader (b64reader);
445   gpgsm_destroy_writer (b64writer);
446   keydb_release (kh); 
447   gcry_md_close (data_md);
448   if (fp)
449     fclose (fp);
450   return rc;
451 }
452
453