aboutsummaryrefslogtreecommitdiffstats
path: root/sm/verify.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-11-16 17:56:23 +0000
committerWerner Koch <[email protected]>2001-11-16 17:56:23 +0000
commit0f26760d9f550fd9aaa7d0c4f18f8571b7818142 (patch)
treef4c3c0756bdd5df1a9c370947c269fdd997542bb /sm/verify.c
parentWe have reached a state where we are able to import certs and (diff)
downloadgnupg-0f26760d9f550fd9aaa7d0c4f18f8571b7818142.tar.gz
gnupg-0f26760d9f550fd9aaa7d0c4f18f8571b7818142.zip
Base code for gpgsm --verify does work
Diffstat (limited to '')
-rw-r--r--sm/verify.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/sm/verify.c b/sm/verify.c
new file mode 100644
index 000000000..31e7fcf8f
--- /dev/null
+++ b/sm/verify.c
@@ -0,0 +1,374 @@
+/* verify.c - Verify a messages signature
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <assert.h>
+
+#include <gcrypt.h>
+#include <ksba.h>
+
+#include "gpgsm.h"
+#include "keydb.h"
+#include "i18n.h"
+
+struct reader_cb_parm_s {
+ FILE *fp;
+};
+
+/* FIXME: We need to write a generic reader callback which should be able
+ to detect and convert base-64 */
+static int
+reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
+{
+ struct reader_cb_parm_s *parm = cb_value;
+ size_t n;
+ int c = 0;
+
+ *nread = 0;
+ if (!buffer)
+ return -1; /* not supported */
+
+ for (n=0; n < count; n++)
+ {
+ c = getc (parm->fp);
+ if (c == EOF)
+ {
+ if ( ferror (parm->fp) )
+ return -1;
+ if (n)
+ break; /* return what we have before an EOF */
+ return -1;
+ }
+ *(byte *)buffer++ = c;
+ }
+
+ *nread = n;
+ return 0;
+}
+
+/* fixme: duplicated from import.c */
+static void
+store_cert (KsbaCert cert)
+{
+ KEYDB_HANDLE kh;
+ int rc;
+
+ kh = keydb_new (0);
+ if (!kh)
+ {
+ log_error (_("failed to allocated keyDB handle\n"));
+ return;
+ }
+ rc = keydb_locate_writable (kh, 0);
+ if (rc)
+ log_error (_("error finding writable keyDB: %s\n"), gpgsm_strerror (rc));
+
+ rc = keydb_insert_cert (kh, cert);
+ if (rc)
+ {
+ log_error (_("error storing certificate: %s\n"), gpgsm_strerror (rc));
+ }
+ keydb_release (kh);
+}
+
+
+
+static void
+print_integer (unsigned char *p)
+{
+ unsigned long len;
+
+ if (!p)
+ printf ("none");
+ else
+ {
+ len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ for (p+=4; len; len--, p++)
+ printf ("%02X", *p);
+ }
+}
+
+
+
+
+
+int
+gpgsm_verify (int in_fd)
+{
+ int i, rc;
+ KsbaError err;
+ KsbaReader reader = NULL;
+ KsbaWriter writer = NULL;
+ KsbaCMS cms = NULL;
+ KsbaStopReason stopreason;
+ KsbaCert cert;
+ KEYDB_HANDLE kh;
+ GCRY_MD_HD data_md = NULL;
+ struct reader_cb_parm_s rparm;
+ int signer;
+ int algo;
+ int is_detached;
+
+ memset (&rparm, 0, sizeof rparm);
+
+ kh = keydb_new (0);
+ if (!kh)
+ {
+ log_error (_("failed to allocated keyDB handle\n"));
+ rc = GPGSM_General_Error;
+ goto leave;
+ }
+
+
+ rparm.fp = fdopen ( dup (in_fd), "rb");
+ if (!rparm.fp)
+ {
+ log_error ("fdopen() failed: %s\n", strerror (errno));
+ rc = seterr (IO_Error);
+ goto leave;
+ }
+
+ /* setup a skaba reader which uses a callback function so that we can
+ strip off a base64 encoding when necessary */
+ reader = ksba_reader_new ();
+ writer = ksba_writer_new ();
+ if (!reader || !writer)
+ {
+ rc = seterr (Out_Of_Core);
+ goto leave;
+ }
+
+ rc = ksba_reader_set_cb (reader, reader_cb, &rparm );
+ if (rc)
+ {
+ ksba_reader_release (reader);
+ rc = map_ksba_err (rc);
+ goto leave;
+ }
+
+ cms = ksba_cms_new ();
+ if (!cms)
+ {
+ rc = seterr (Out_Of_Core);
+ goto leave;
+ }
+
+ err = ksba_cms_set_reader_writer (cms, reader, writer);
+ if (err)
+ {
+ log_debug ("ksba_cms_set_reader_writer failed: %s\n",
+ ksba_strerror (err));
+ rc = map_ksba_err (err);
+ goto leave;
+ }
+
+ data_md = gcry_md_open (0, 0);
+ if (!data_md)
+ {
+ rc = map_gcry_err (gcry_errno());
+ log_error ("md_open failed: %s\n", gcry_strerror (-1));
+ goto leave;
+ }
+
+ is_detached = 0;
+ do
+ {
+ err = ksba_cms_parse (cms, &stopreason);
+ if (err)
+ {
+ log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
+ rc = map_ksba_err (err);
+ goto leave;
+ }
+ log_debug ("ksba_cms_parse - stop reason %d\n", stopreason);
+ if (stopreason == KSBA_SR_NEED_HASH)
+ {
+ is_detached = 1;
+ log_debug ("Detached signature\n");
+ }
+ if (stopreason == KSBA_SR_BEGIN_DATA)
+ log_error ("error: only detached signatuires are supportted\n");
+
+ if (stopreason == KSBA_SR_NEED_HASH
+ || stopreason == KSBA_SR_BEGIN_DATA)
+ { /* We are now able to enable the hash algorithms */
+ for (i=0; (algo = ksba_cms_get_digest_algo_list (cms, i)) >= 0; i++)
+ {
+ if (algo)
+ gcry_md_enable (data_md, algo);
+ }
+ }
+
+
+ }
+ while (stopreason != KSBA_SR_READY);
+
+ for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
+ {
+ log_debug ("storing certifcate %d\n", i);
+ /* Fixme: we should mark the stored certificates as temporary
+ and put them in a cache first */
+ store_cert (cert);
+ ksba_cert_release (cert);
+ }
+
+ cert = NULL;
+ err = 0;
+ for (signer=0; signer < 1; signer++)
+ {
+ char *issuer = NULL;
+ char *sigval = NULL;
+ unsigned char *serial;
+ char *msgdigest = NULL;
+ size_t msgdigestlen;
+
+ err = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
+ if (err)
+ break;
+ printf ("signer %d - issuer: `%s'\n", signer, issuer? issuer:"[NONE]");
+ printf ("signer %d - serial: ", signer);
+ print_integer (serial);
+ putchar ('\n');
+
+ err = ksba_cms_get_message_digest (cms, signer,
+ &msgdigest, &msgdigestlen);
+ if (err)
+ break;
+
+ algo = ksba_cms_get_digest_algo (cms, signer);
+ printf ("signer %d - digest algo: %d\n", signer, algo);
+ if ( !gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, &algo, NULL) )
+ {
+ log_debug ("digest algo %d has not been enabled\n", algo);
+ goto next_signer;
+ }
+
+ sigval = ksba_cms_get_sig_val (cms, signer);
+ printf ("signer %d - signature: `%s'\n",
+ signer, sigval? sigval: "[ERROR]");
+
+ /* Find the certificate of the signer */
+ keydb_search_reset (kh);
+ rc = keydb_search_issuer_sn (kh, issuer, serial);
+ if (rc)
+ {
+ log_debug ("failed to find the certificate: %s\n",
+ gpgsm_strerror(rc));
+ goto next_signer;
+ }
+
+ rc = keydb_get_cert (kh, &cert);
+ if (rc)
+ {
+ log_debug ("failed to get cert: %s\n", gpgsm_strerror (rc));
+ goto next_signer;
+ }
+
+ if (msgdigest)
+ { /* Signed attributes are available. */
+ GCRY_MD_HD md;
+ unsigned char *s;
+
+ /* check that the message digest in the signed attributes
+ matches the one we calculated on the data */
+ s = gcry_md_read (data_md, algo);
+ if ( !s || !msgdigestlen
+ || gcry_md_get_algo_dlen (algo) != msgdigestlen
+ || !s || memcmp (s, msgdigest, msgdigestlen) )
+ {
+ log_error ("message digest attribute does not "
+ "match calculated one\n");
+ /*goto next_signer; FIXME: only for debugging commented*/
+ }
+
+ md = gcry_md_open (algo, 0);
+ if (!md)
+ {
+ log_error ("md_open failed: %s\n", gcry_strerror (-1));
+ goto next_signer;
+ }
+ ksba_cms_set_hash_function (cms, HASH_FNC, md);
+ rc = ksba_cms_hash_signed_attrs (cms, signer);
+ if (rc)
+ {
+ log_debug ("hashing signed attrs failed: %s\n",
+ ksba_strerror (rc));
+ gcry_md_close (md);
+ goto next_signer;
+ }
+ rc = gpgsm_check_cms_signature (cert, sigval, md, algo);
+ gcry_md_close (md);
+ }
+ else
+ {
+ rc = gpgsm_check_cms_signature (cert, sigval, data_md, algo);
+ }
+
+ if (rc)
+ {
+ log_error ("invalid signature: %s\n", gpgsm_strerror (rc));
+ goto next_signer;
+ }
+ log_debug ("signature is good - checking certs\n");
+ /* FIXME: validate_path */
+ rc = gpgsm_validate_path (cert);
+ if (rc)
+ {
+ log_error ("invalid certification path: %s\n", gpgsm_strerror (rc));
+ goto next_signer;
+ }
+ log_info ("signature is good\n");
+
+
+ next_signer:
+ rc = 0;
+ xfree (issuer);
+ xfree (serial);
+ xfree (sigval);
+ xfree (msgdigest);
+ ksba_cert_release (cert);
+ cert = NULL;
+ }
+ rc = 0;
+ if (err)
+ {
+ log_debug ("ksba error: %s\n", ksba_strerror (err));
+ rc = map_ksba_err (rc);
+ }
+
+
+
+ leave:
+ ksba_cms_release (cms);
+ ksba_reader_release (reader);
+ keydb_release (kh);
+ gcry_md_close (data_md);
+ if (rparm.fp)
+ fclose (rparm.fp);
+ return rc;
+}
+
+