* certpath.c (check_cert_policy): New.
[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_debug ("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_debug ("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           log_debug ("Detached signature\n");
187         }
188
189       if (stopreason == KSBA_SR_NEED_HASH
190           || stopreason == KSBA_SR_BEGIN_DATA)
191         { /* We are now able to enable the hash algorithms */
192           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
193             {
194               algo = gcry_md_map_name (algoid);
195               if (!algo)
196                 log_error ("unknown hash algorithm `%s'\n",
197                            algoid? algoid:"?");
198               else
199                 gcry_md_enable (data_md, algo);
200             }
201           if (is_detached)
202             {
203               if (data_fd == -1)
204                 {
205                   log_error ("detached signature but no data given\n");
206                   rc = GNUPG_Bad_Signature;
207                   goto leave;
208                 }
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 = GNUPG_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);
247       ksba_cert_release (cert);
248     }
249
250   cert = NULL;
251   err = 0;
252   for (signer=0; signer < 1; signer++)
253     {
254       char *issuer = NULL;
255       KsbaSexp sigval = NULL;
256       time_t sigtime;
257       KsbaSexp serial;
258       char *msgdigest = NULL;
259       size_t msgdigestlen;
260
261       err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
262       if (err)
263         break;
264       log_debug ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]");
265       log_debug ("signer %d - serial: ", signer);
266       gpgsm_dump_serial (serial);
267       log_printf ("\n");
268
269       err = ksba_cms_get_signing_time (cms, signer, &sigtime);
270       if (err)
271         {
272           log_debug ("error getting signing time: %s\n", ksba_strerror (err));
273           sigtime = (time_t)-1;
274         }
275       log_debug ("signer %d - sigtime: ", signer);
276       gpgsm_dump_time (sigtime);  
277       log_printf ("\n");
278
279
280       err = ksba_cms_get_message_digest (cms, signer,
281                                          &msgdigest, &msgdigestlen);
282       if (err)
283         break;
284
285       algoid = ksba_cms_get_digest_algo (cms, signer);
286       algo = gcry_md_map_name (algoid);
287       log_debug ("signer %d - digest algo: %d\n", signer, algo);
288       if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
289         {
290           log_debug ("digest algo %d has not been enabled\n", algo);
291           goto next_signer;
292         }
293
294       sigval = ksba_cms_get_sig_val (cms, signer);
295       if (!sigval)
296         {
297           log_error ("no signature value available\n");
298           goto next_signer;
299         }
300       log_debug ("signer %d - signature available", signer);
301
302       /* Find the certificate of the signer */
303       keydb_search_reset (kh);
304       rc = keydb_search_issuer_sn (kh, issuer, serial);
305       if (rc)
306         {
307           log_debug ("failed to find the certificate: %s\n",
308                      gnupg_strerror(rc));
309           goto next_signer;
310         }
311
312       rc = keydb_get_cert (kh, &cert);
313       if (rc)
314         {
315           log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
316           goto next_signer;
317         }
318
319       if (msgdigest)
320         { /* Signed attributes are available. */
321           GCRY_MD_HD md;
322           unsigned char *s;
323
324           /* check that the message digest in the signed attributes
325              matches the one we calculated on the data */
326           s = gcry_md_read (data_md, algo);
327           if ( !s || !msgdigestlen
328                || gcry_md_get_algo_dlen (algo) != msgdigestlen
329                || !s || memcmp (s, msgdigest, msgdigestlen) )
330             {
331               log_error ("message digest attribute does not "
332                          "match calculated one\n");
333               gpgsm_status (ctrl, STATUS_BADSIG, NULL);
334               goto next_signer; 
335             }
336             
337           md = gcry_md_open (algo, 0);
338           if (!md)
339             {
340               log_error ("md_open failed: %s\n", gcry_strerror (-1));
341               goto next_signer;
342             }
343           if (DBG_HASHING)
344             gcry_md_start_debug (md, "vrfy.attr");
345
346           ksba_cms_set_hash_function (cms, HASH_FNC, md);
347           rc = ksba_cms_hash_signed_attrs (cms, signer);
348           if (rc)
349             {
350               log_debug ("hashing signed attrs failed: %s\n",
351                          ksba_strerror (rc));
352               gcry_md_close (md);
353               goto next_signer;
354             }
355           rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
356           gcry_md_close (md);
357         }
358       else
359         {
360           rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
361         }
362
363       if (rc)
364         {
365           log_error ("invalid signature: %s\n", gnupg_strerror (rc));
366           gpgsm_status (ctrl, STATUS_BADSIG, NULL);
367           goto next_signer;
368         }
369       log_debug ("signature okay - checking certs\n");
370       gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
371       {
372         char *buf, *fpr, *tstr;
373
374         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
375         tstr = strtimestamp (sigtime);
376         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100);
377         sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime );
378         xfree (tstr);
379         xfree (fpr);
380         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
381         xfree (buf);
382       }
383
384       rc = gpgsm_validate_path (cert);
385       if (rc)
386         {
387           log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
388           if (rc == GNUPG_Bad_Certificate_Path
389               || rc == GNUPG_Bad_Certificate)
390             gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL);
391           else
392             gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL);
393           goto next_signer;
394         }
395       log_info ("signature is good\n");
396       gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
397           
398
399     next_signer:
400       rc = 0;
401       xfree (issuer);
402       xfree (serial);
403       xfree (sigval);
404       xfree (msgdigest);
405       ksba_cert_release (cert);
406       cert = NULL;
407     }
408   rc = 0;
409   if (err)
410     {
411       log_debug ("ksba error: %s\n", ksba_strerror (err));
412       rc = map_ksba_err (rc);
413     }    
414
415
416
417  leave:
418   ksba_cms_release (cms);
419   gpgsm_destroy_reader (b64reader);
420   gpgsm_destroy_writer (b64writer);
421   keydb_release (kh); 
422   gcry_md_close (data_md);
423   if (fp)
424     fclose (fp);
425   return rc;
426 }
427
428