2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / verify.c
blobf4d80393aaad68d94ee320c2e74c481d31692f3d
1 /* verify.c - Verify a messages signature
2 * Copyright (C) 2001 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
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>
30 #include <gcrypt.h>
31 #include <ksba.h>
33 #include "gpgsm.h"
34 #include "keydb.h"
35 #include "i18n.h"
37 /* fixme: Move this to jnlib */
38 static char *
39 strtimestamp (time_t atime)
41 char *buffer = xmalloc (15);
43 if (atime < 0)
44 strcpy (buffer, "????" "-??" "-??");
45 else if (!atime)
46 strcpy (buffer, "none");
47 else
49 struct tm *tp;
51 tp = gmtime( &atime );
52 sprintf (buffer, "%04d-%02d-%02d",
53 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday);
55 return buffer;
60 /* Hash the data for a detached signature */
61 static void
62 hash_data (int fd, GCRY_MD_HD md)
64 FILE *fp;
65 char buffer[4096];
66 int nread;
68 fp = fdopen ( dup (fd), "rb");
69 if (!fp)
71 log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
72 return;
75 do
77 nread = fread (buffer, 1, DIM(buffer), fp);
78 gcry_md_write (md, buffer, nread);
80 while (nread);
81 if (ferror (fp))
82 log_error ("read error on fd %d: %s\n", fd, strerror (errno));
83 fclose (fp);
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)
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;
112 kh = keydb_new (0);
113 if (!kh)
115 log_error (_("failed to allocated keyDB handle\n"));
116 rc = GNUPG_General_Error;
117 goto leave;
121 fp = fdopen ( dup (in_fd), "rb");
122 if (!fp)
124 log_error ("fdopen() failed: %s\n", strerror (errno));
125 rc = seterr (IO_Error);
126 goto leave;
129 rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
130 if (rc)
132 log_error ("can't create reader: %s\n", gnupg_strerror (rc));
133 goto leave;
136 if (out_fp)
138 rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
139 if (rc)
141 log_error ("can't create writer: %s\n", gnupg_strerror (rc));
142 goto leave;
146 cms = ksba_cms_new ();
147 if (!cms)
149 rc = seterr (Out_Of_Core);
150 goto leave;
153 err = ksba_cms_set_reader_writer (cms, reader, writer);
154 if (err)
156 log_debug ("ksba_cms_set_reader_writer failed: %s\n",
157 ksba_strerror (err));
158 rc = map_ksba_err (err);
159 goto leave;
162 data_md = gcry_md_open (0, 0);
163 if (!data_md)
165 rc = map_gcry_err (gcry_errno());
166 log_error ("md_open failed: %s\n", gcry_strerror (-1));
167 goto leave;
169 if (DBG_HASHING)
170 gcry_md_start_debug (data_md, "vrfy.data");
172 is_detached = 0;
175 err = ksba_cms_parse (cms, &stopreason);
176 if (err)
178 log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
179 rc = map_ksba_err (err);
180 goto leave;
183 if (stopreason == KSBA_SR_NEED_HASH)
185 is_detached = 1;
186 log_debug ("Detached signature\n");
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++)
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);
201 if (is_detached)
203 if (data_fd == -1)
204 log_info ("detached signature w/o data "
205 "- assuming certs-only\n");
206 else
207 hash_data (data_fd, data_md);
209 else
211 ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
214 else if (stopreason == KSBA_SR_END_DATA)
215 { /* The data bas been hashed */
219 while (stopreason != KSBA_SR_READY);
221 if (b64writer)
223 rc = gpgsm_finish_writer (b64writer);
224 if (rc)
226 log_error ("write failed: %s\n", gnupg_strerror (rc));
227 goto leave;
231 if (data_fd != -1 && !is_detached)
233 log_error ("data given for a non-detached signature\n");
234 rc = GNUPG_Conflict;
235 goto leave;
238 for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
240 /* Fixme: it might be better to check the validity of the
241 certificate first before entering it into the DB. This way
242 we would avoid cluttering the DB with invalid
243 certificates. */
244 keydb_store_cert (cert);
245 ksba_cert_release (cert);
248 cert = NULL;
249 err = 0;
250 for (signer=0; signer < 1; signer++)
252 char *issuer = NULL;
253 KsbaSexp sigval = NULL;
254 time_t sigtime;
255 KsbaSexp serial;
256 char *msgdigest = NULL;
257 size_t msgdigestlen;
259 err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
260 if (!signer && err == KSBA_No_Data && data_fd == -1 && is_detached)
262 log_info ("certs-only message accepted\n");
263 err = 0;
264 break;
266 if (err)
267 break;
268 log_debug ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]");
269 log_debug ("signer %d - serial: ", signer);
270 gpgsm_dump_serial (serial);
271 log_printf ("\n");
273 err = ksba_cms_get_signing_time (cms, signer, &sigtime);
274 if (err)
276 log_debug ("error getting signing time: %s\n", ksba_strerror (err));
277 sigtime = (time_t)-1;
279 log_debug ("signer %d - sigtime: ", signer);
280 gpgsm_dump_time (sigtime);
281 log_printf ("\n");
284 err = ksba_cms_get_message_digest (cms, signer,
285 &msgdigest, &msgdigestlen);
286 if (err)
287 break;
289 algoid = ksba_cms_get_digest_algo (cms, signer);
290 algo = gcry_md_map_name (algoid);
291 log_debug ("signer %d - digest algo: %d\n", signer, algo);
292 if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
294 log_debug ("digest algo %d has not been enabled\n", algo);
295 goto next_signer;
298 sigval = ksba_cms_get_sig_val (cms, signer);
299 if (!sigval)
301 log_error ("no signature value available\n");
302 goto next_signer;
304 log_debug ("signer %d - signature available", signer);
306 /* Find the certificate of the signer */
307 keydb_search_reset (kh);
308 rc = keydb_search_issuer_sn (kh, issuer, serial);
309 if (rc)
311 log_debug ("failed to find the certificate: %s\n",
312 gnupg_strerror(rc));
313 goto next_signer;
316 rc = keydb_get_cert (kh, &cert);
317 if (rc)
319 log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
320 goto next_signer;
323 if (msgdigest)
324 { /* Signed attributes are available. */
325 GCRY_MD_HD md;
326 unsigned char *s;
328 /* check that the message digest in the signed attributes
329 matches the one we calculated on the data */
330 s = gcry_md_read (data_md, algo);
331 if ( !s || !msgdigestlen
332 || gcry_md_get_algo_dlen (algo) != msgdigestlen
333 || !s || memcmp (s, msgdigest, msgdigestlen) )
335 log_error ("invalid signature: message digest attribute "
336 "does not match calculated one\n");
337 gpgsm_status (ctrl, STATUS_BADSIG, NULL);
338 goto next_signer;
341 md = gcry_md_open (algo, 0);
342 if (!md)
344 log_error ("md_open failed: %s\n", gcry_strerror (-1));
345 goto next_signer;
347 if (DBG_HASHING)
348 gcry_md_start_debug (md, "vrfy.attr");
350 ksba_cms_set_hash_function (cms, HASH_FNC, md);
351 rc = ksba_cms_hash_signed_attrs (cms, signer);
352 if (rc)
354 log_debug ("hashing signed attrs failed: %s\n",
355 ksba_strerror (rc));
356 gcry_md_close (md);
357 goto next_signer;
359 rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
360 gcry_md_close (md);
362 else
364 rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
367 if (rc)
369 log_error ("invalid signature: %s\n", gnupg_strerror (rc));
370 gpgsm_status (ctrl, STATUS_BADSIG, NULL);
371 goto next_signer;
373 gpgsm_cert_use_verify_p (cert); /* this displays an info message */
374 log_debug ("signature okay - checking certs\n");
375 gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
377 char *buf, *fpr, *tstr;
379 fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
380 tstr = strtimestamp (sigtime);
381 buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100);
382 sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime );
383 xfree (tstr);
384 xfree (fpr);
385 gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
386 xfree (buf);
389 rc = gpgsm_validate_path (cert);
390 if (rc)
392 log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
393 if (rc == GNUPG_Bad_Certificate_Path
394 || rc == GNUPG_Bad_Certificate)
395 gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL);
396 else
397 gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL);
398 goto next_signer;
400 log_info ("signature is good\n");
401 gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
404 next_signer:
405 rc = 0;
406 xfree (issuer);
407 xfree (serial);
408 xfree (sigval);
409 xfree (msgdigest);
410 ksba_cert_release (cert);
411 cert = NULL;
413 rc = 0;
414 if (err)
416 log_debug ("ksba error: %s\n", ksba_strerror (err));
417 rc = map_ksba_err (rc);
422 leave:
423 ksba_cms_release (cms);
424 gpgsm_destroy_reader (b64reader);
425 gpgsm_destroy_writer (b64writer);
426 keydb_release (kh);
427 gcry_md_close (data_md);
428 if (fp)
429 fclose (fp);
430 return rc;