2005-04-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / verify.c
blob410e86de7ed8da32cf6d47e5d3f7b1f1276a9787
1 /* verify.c - Verify a messages signature
2 * Copyright (C) 2001, 2002, 2003 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 "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
34 #include "keydb.h"
35 #include "i18n.h"
37 static char *
38 strtimestamp_r (ksba_isotime_t atime)
40 char *buffer = xmalloc (15);
42 if (!atime || !*atime)
43 strcpy (buffer, "none");
44 else
45 sprintf (buffer, "%.4s-%.2s-%.2s", atime, atime+4, atime+6);
46 return buffer;
51 /* Hash the data for a detached signature */
52 static void
53 hash_data (int fd, gcry_md_hd_t md)
55 FILE *fp;
56 char buffer[4096];
57 int nread;
59 fp = fdopen ( dup (fd), "rb");
60 if (!fp)
62 log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
63 return;
66 do
68 nread = fread (buffer, 1, DIM(buffer), fp);
69 gcry_md_write (md, buffer, nread);
71 while (nread);
72 if (ferror (fp))
73 log_error ("read error on fd %d: %s\n", fd, strerror (errno));
74 fclose (fp);
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)
86 int i, rc;
87 Base64Context b64reader = NULL;
88 Base64Context b64writer = NULL;
89 ksba_reader_t reader;
90 ksba_writer_t writer = NULL;
91 ksba_cms_t cms = NULL;
92 ksba_stop_reason_t stopreason;
93 ksba_cert_t cert;
94 KEYDB_HANDLE kh;
95 gcry_md_hd_t data_md = NULL;
96 int signer;
97 const char *algoid;
98 int algo;
99 int is_detached;
100 FILE *fp = NULL;
101 char *p;
103 kh = keydb_new (0);
104 if (!kh)
106 log_error (_("failed to allocated keyDB handle\n"));
107 rc = gpg_error (GPG_ERR_GENERAL);
108 goto leave;
112 fp = fdopen ( dup (in_fd), "rb");
113 if (!fp)
115 rc = gpg_error (gpg_err_code_from_errno (errno));
116 log_error ("fdopen() failed: %s\n", strerror (errno));
117 goto leave;
120 rc = gpgsm_create_reader (&b64reader, ctrl, fp, 0, &reader);
121 if (rc)
123 log_error ("can't create reader: %s\n", gpg_strerror (rc));
124 goto leave;
127 if (out_fp)
129 rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
130 if (rc)
132 log_error ("can't create writer: %s\n", gpg_strerror (rc));
133 goto leave;
137 rc = ksba_cms_new (&cms);
138 if (rc)
139 goto leave;
141 rc = ksba_cms_set_reader_writer (cms, reader, writer);
142 if (rc)
144 log_error ("ksba_cms_set_reader_writer failed: %s\n",
145 gpg_strerror (rc));
146 goto leave;
149 rc = gcry_md_open (&data_md, 0, 0);
150 if (rc)
152 log_error ("md_open failed: %s\n", gpg_strerror (rc));
153 goto leave;
155 if (DBG_HASHING)
156 gcry_md_start_debug (data_md, "vrfy.data");
158 is_detached = 0;
161 rc = ksba_cms_parse (cms, &stopreason);
162 if (rc)
164 log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
165 goto leave;
168 if (stopreason == KSBA_SR_NEED_HASH)
170 is_detached = 1;
171 if (opt.verbose)
172 log_info ("detached signature\n");
175 if (stopreason == KSBA_SR_NEED_HASH
176 || stopreason == KSBA_SR_BEGIN_DATA)
177 { /* We are now able to enable the hash algorithms */
178 for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
180 algo = gcry_md_map_name (algoid);
181 if (!algo)
182 log_error ("unknown hash algorithm `%s'\n",
183 algoid? algoid:"?");
184 else
185 gcry_md_enable (data_md, algo);
187 if (is_detached)
189 if (data_fd == -1)
190 log_info ("detached signature w/o data "
191 "- assuming certs-only\n");
192 else
193 hash_data (data_fd, data_md);
195 else
197 ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
200 else if (stopreason == KSBA_SR_END_DATA)
201 { /* The data bas been hashed */
205 while (stopreason != KSBA_SR_READY);
207 if (b64writer)
209 rc = gpgsm_finish_writer (b64writer);
210 if (rc)
212 log_error ("write failed: %s\n", gpg_strerror (rc));
213 goto leave;
217 if (data_fd != -1 && !is_detached)
219 log_error ("data given for a non-detached signature\n");
220 rc = gpg_error (GPG_ERR_CONFLICT);
221 goto leave;
224 for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
226 /* Fixme: it might be better to check the validity of the
227 certificate first before entering it into the DB. This way
228 we would avoid cluttering the DB with invalid
229 certificates. */
230 keydb_store_cert (cert, 0, NULL);
231 ksba_cert_release (cert);
234 cert = NULL;
235 for (signer=0; ; signer++)
237 char *issuer = NULL;
238 ksba_sexp_t sigval = NULL;
239 ksba_isotime_t sigtime, keyexptime;
240 ksba_sexp_t serial;
241 char *msgdigest = NULL;
242 size_t msgdigestlen;
243 char *ctattr;
245 rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
246 if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
247 && data_fd == -1 && is_detached)
249 log_info ("certs-only message accepted\n");
250 rc = 0;
251 break;
253 if (rc)
255 if (signer && rc == -1)
256 rc = 0;
257 break;
260 gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
262 if (DBG_X509)
264 log_debug ("signer %d - issuer: `%s'\n",
265 signer, issuer? issuer:"[NONE]");
266 log_debug ("signer %d - serial: ", signer);
267 gpgsm_dump_serial (serial);
268 log_printf ("\n");
271 rc = ksba_cms_get_signing_time (cms, signer, sigtime);
272 if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
273 *sigtime = 0;
274 else if (rc)
276 log_error ("error getting signing time: %s\n", gpg_strerror (rc));
277 *sigtime = 0; /* (we can't encode an error in the time string.) */
280 rc = ksba_cms_get_message_digest (cms, signer,
281 &msgdigest, &msgdigestlen);
282 if (!rc)
284 size_t is_enabled;
286 algoid = ksba_cms_get_digest_algo (cms, signer);
287 algo = gcry_md_map_name (algoid);
288 if (DBG_X509)
289 log_debug ("signer %d - digest algo: %d\n", signer, algo);
290 is_enabled = sizeof algo;
291 if ( gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED,
292 &algo, &is_enabled)
293 || !is_enabled)
295 log_error ("digest algo %d has not been enabled\n", algo);
296 goto next_signer;
299 else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
301 assert (!msgdigest);
302 rc = 0;
303 algoid = NULL;
304 algo = 0;
306 else /* real error */
307 break;
309 rc = ksba_cms_get_sigattr_oids (cms, signer,
310 "1.2.840.113549.1.9.3", &ctattr);
311 if (!rc)
313 const char *s;
315 if (DBG_X509)
316 log_debug ("signer %d - content-type attribute: %s",
317 signer, ctattr);
319 s = ksba_cms_get_content_oid (cms, 1);
320 if (!s || strcmp (ctattr, s))
322 log_error ("content-type attribute does not match "
323 "actual content-type\n");
324 ksba_free (ctattr);
325 ctattr = NULL;
326 goto next_signer;
328 ksba_free (ctattr);
329 ctattr = NULL;
331 else if (rc != -1)
333 log_error ("error getting content-type attribute: %s\n",
334 gpg_strerror (rc));
335 goto next_signer;
337 rc = 0;
340 sigval = ksba_cms_get_sig_val (cms, signer);
341 if (!sigval)
343 log_error ("no signature value available\n");
344 goto next_signer;
346 if (DBG_X509)
347 log_debug ("signer %d - signature available", signer);
349 /* Find the certificate of the signer */
350 keydb_search_reset (kh);
351 rc = keydb_search_issuer_sn (kh, issuer, serial);
352 if (rc)
354 if (rc == -1)
356 log_error ("certificate not found\n");
357 rc = gpg_error (GPG_ERR_NO_PUBKEY);
359 else
360 log_error ("failed to find the certificate: %s\n",
361 gpg_strerror(rc));
363 char numbuf[50];
364 sprintf (numbuf, "%d", rc);
366 gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
367 numbuf, NULL);
369 /* fixme: we might want to append the issuer and serial
370 using our standard notation */
371 goto next_signer;
374 rc = keydb_get_cert (kh, &cert);
375 if (rc)
377 log_error ("failed to get cert: %s\n", gpg_strerror (rc));
378 goto next_signer;
381 log_info (_("Signature made "));
382 if (*sigtime)
383 gpgsm_dump_time (sigtime);
384 else
385 log_printf (_("[date not given]"));
386 log_printf (_(" using certificate ID %08lX\n"),
387 gpgsm_get_short_fingerprint (cert));
390 if (msgdigest)
391 { /* Signed attributes are available. */
392 gcry_md_hd_t md;
393 unsigned char *s;
395 /* check that the message digest in the signed attributes
396 matches the one we calculated on the data */
397 s = gcry_md_read (data_md, algo);
398 if ( !s || !msgdigestlen
399 || gcry_md_get_algo_dlen (algo) != msgdigestlen
400 || !s || memcmp (s, msgdigest, msgdigestlen) )
402 char *fpr;
404 log_error ("invalid signature: message digest attribute "
405 "does not match calculated one\n");
406 fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
407 gpgsm_status (ctrl, STATUS_BADSIG, fpr);
408 xfree (fpr);
409 goto next_signer;
412 rc = gcry_md_open (&md, algo, 0);
413 if (rc)
415 log_error ("md_open failed: %s\n", gpg_strerror (rc));
416 goto next_signer;
418 if (DBG_HASHING)
419 gcry_md_start_debug (md, "vrfy.attr");
421 ksba_cms_set_hash_function (cms, HASH_FNC, md);
422 rc = ksba_cms_hash_signed_attrs (cms, signer);
423 if (rc)
425 log_error ("hashing signed attrs failed: %s\n",
426 gpg_strerror (rc));
427 gcry_md_close (md);
428 goto next_signer;
430 rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
431 gcry_md_close (md);
433 else
435 rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
438 if (rc)
440 char *fpr;
442 log_error ("invalid signature: %s\n", gpg_strerror (rc));
443 fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
444 gpgsm_status (ctrl, STATUS_BADSIG, fpr);
445 xfree (fpr);
446 goto next_signer;
448 rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
449 if (rc)
451 gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
452 gpg_err_code (rc));
453 rc = 0;
456 if (DBG_X509)
457 log_debug ("signature okay - checking certs\n");
458 rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL, 0);
459 if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
461 gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
462 rc = 0;
464 else
465 gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
468 char *buf, *fpr, *tstr;
470 fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
471 tstr = strtimestamp_r (sigtime);
472 buf = xmalloc ( strlen(fpr) + strlen (tstr) + 120);
473 sprintf (buf, "%s %s %s %s", fpr, tstr,
474 *sigtime? sigtime : "0",
475 *keyexptime? keyexptime : "0" );
476 xfree (tstr);
477 xfree (fpr);
478 gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
479 xfree (buf);
482 if (rc) /* of validate_chain */
484 log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
485 if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
486 || gpg_err_code (rc) == GPG_ERR_BAD_CERT
487 || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
488 || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
489 gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
490 gpg_err_code (rc));
491 else
492 gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL,
493 gpg_err_code (rc));
494 goto next_signer;
497 for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
499 log_info (!i? _("Good signature from")
500 : _(" aka"));
501 log_printf (" \"");
502 gpgsm_print_name (log_get_stream (), p);
503 log_printf ("\"\n");
504 ksba_free (p);
507 gpgsm_status (ctrl, STATUS_TRUST_FULLY, NULL);
510 next_signer:
511 rc = 0;
512 xfree (issuer);
513 xfree (serial);
514 xfree (sigval);
515 xfree (msgdigest);
516 ksba_cert_release (cert);
517 cert = NULL;
519 rc = 0;
521 leave:
522 ksba_cms_release (cms);
523 gpgsm_destroy_reader (b64reader);
524 gpgsm_destroy_writer (b64writer);
525 keydb_release (kh);
526 gcry_md_close (data_md);
527 if (fp)
528 fclose (fp);
530 if (rc)
532 char numbuf[50];
533 sprintf (numbuf, "%d", rc );
534 gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
535 numbuf, NULL);
538 return rc;