Base code for gpgsm --verify does work
authorWerner Koch <wk@gnupg.org>
Fri, 16 Nov 2001 17:56:23 +0000 (17:56 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 16 Nov 2001 17:56:23 +0000 (17:56 +0000)
13 files changed:
kbx/keybox-search-desc.h
kbx/keybox-search.c
sm/Makefile.am
sm/certchain.c
sm/certcheck.c
sm/certdump.c
sm/certpath.c
sm/gpgsm.c
sm/gpgsm.h
sm/keydb.c
sm/keydb.h
sm/server.c
sm/verify.c [new file with mode: 0644]

index 22bcba6..88ffde8 100644 (file)
@@ -42,6 +42,7 @@ typedef enum {
   KEYDB_SEARCH_MODE_FPR,
   KEYDB_SEARCH_MODE_ISSUER,
   KEYDB_SEARCH_MODE_ISSUER_SN,
+  KEYDB_SEARCH_MODE_SUBJECT,
   KEYDB_SEARCH_MODE_FIRST,
   KEYDB_SEARCH_MODE_NEXT
 } KeydbSearchMode;
index 3468a8e..2a4ceca 100644 (file)
@@ -205,6 +205,20 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn)
           && blob_cmp_name (blob, 0 /* issuer */, name, namelen));
 }
 
+static int
+has_subject (KEYBOXBLOB blob, const char *name)
+{
+  size_t namelen;
+
+  return_val_if_fail (name, 0);
+
+  if (blob_get_type (blob) != BLOBTYPE_X509)
+    return 0;
+
+  namelen = strlen (name);
+  return blob_cmp_name (blob, 1 /* subject */, name, namelen);
+}
+
 
 \f
 /*
@@ -316,6 +330,10 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               if (has_issuer_sn (blob, desc[n].u.name, desc[n].sn))
                 goto found;
               break;
+            case KEYDB_SEARCH_MODE_SUBJECT:
+              if (has_subject (blob, desc[n].u.name))
+                goto found;
+              break;
             case KEYDB_SEARCH_MODE_SHORT_KID: 
 /*                if (has_short_kid (blob, desc[n].u.kid[1])) */
 /*                  goto found; */
index ab34f10..4b74672 100644 (file)
@@ -34,6 +34,7 @@ gpgsm_SOURCES = \
        certdump.c \
        certcheck.c \
        certpath.c \
+       verify.c \
        import.c 
 
 gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a ../kbx/libkeybox.a \
index aef1612..518acfe 100644 (file)
@@ -50,8 +50,7 @@ gpgsm_validate_path (KsbaCert cert)
       goto leave;
     }
 
-  log_debug ("validate path for certificate:\n");
-  gpgsm_dump_cert (cert);
+  gpgsm_dump_cert ("subject", cert);
 
   subject_cert = cert;
 
@@ -87,7 +86,7 @@ gpgsm_validate_path (KsbaCert cert)
 
       /* find the next cert up the tree */
       keydb_search_reset (kh);
-      rc = keydb_search_issuer (kh, issuer);
+      rc = keydb_search_subject (kh, issuer);
       if (rc)
         {
           log_debug ("failed to find issuer's certificate: rc=%d\n", rc);
@@ -105,7 +104,7 @@ gpgsm_validate_path (KsbaCert cert)
         }
 
       log_debug ("got issuer's certificate:\n");
-      gpgsm_dump_cert (issuer_cert);
+      gpgsm_dump_cert ("issuer", issuer_cert);
 
       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
         {
index a86aa2d..8a9c2c2 100644 (file)
 #include "keydb.h"
 #include "i18n.h"
 
+
 static int
-do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
-             const byte *asn, size_t asnlen, GCRY_MPI *r_val)
+do_encode_md (GCRY_MD_HD md, int algo,  unsigned int nbits,
+              GCRY_MPI *r_val)
 {
   int nframe = (nbits+7) / 8;
   byte *frame;
   int i, n;
+  byte asn[100];
+  size_t asnlen;
+  size_t len;
+
+  asnlen = DIM(asn);
+  if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+    {
+      log_error ("No object identifier for algo %d\n", algo);
+      return GPGSM_Internal_Error;
+    }
+
+  len = gcry_md_get_algo_dlen (algo);
   
   if ( len + asnlen + 4  > nframe )
     {
@@ -68,6 +81,15 @@ do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
   memcpy ( frame+n, asn, asnlen ); n += asnlen;
   memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
   assert ( n == nframe );
+  if (DBG_X509)
+    {
+      int j;
+      log_debug ("encoded hash:");
+      for (j=0; j < nframe; j++)
+        log_printf (" %02X", frame[j]);
+      log_printf ("\n");
+    }
+      
   gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe);
   xfree (frame);
   return 0;
@@ -81,12 +103,6 @@ do_encode_md (GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
 int
 gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
 {
-  /* OID for MD5 as defined in PKCS#1 (rfc2313) */
-  static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 (md5) */
-  { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48,
-    0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
-  };
-
   GCRY_MD_HD md;
   int rc, algo;
   GCRY_MPI frame;
@@ -120,12 +136,19 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
       return map_gcry_err (rc);
     }
-  /*gcry_sexp_dump (s_sig);*/
 
+  p = ksba_cert_get_public_key (issuer_cert);
+  if (DBG_X509)
+    log_debug ("issuer public key: %s\n", p);
 
-  /* FIXME: need to map the algo to the ASN OID - we assume a fixed
-     one for now */
-  rc = do_encode_md (md, algo, 16, 2048, asn, DIM(asn), &frame);
+  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p));
+  if (rc)
+    {
+      log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
+      return map_gcry_err (rc);
+    }
+
+  rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
   if (rc)
     {
       /* fixme: clean up some things */
@@ -134,11 +157,35 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
   /* put hash into the S-Exp s_hash */
   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
     BUG ();
-  /*fputs ("hash:\n", stderr); gcry_sexp_dump (s_hash);*/
 
-  p = ksba_cert_get_public_key (issuer_cert);
+  
+  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
+  if (DBG_CRYPTO)
+      log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc));
+  return map_gcry_err (rc);
+}
+
+
+
+int
+gpgsm_check_cms_signature (KsbaCert cert, const char *sigval,
+                           GCRY_MD_HD md, int algo)
+{
+  int rc;
+  GCRY_MPI frame;
+  char *p;
+  GCRY_SEXP s_sig, s_hash, s_pkey;
+
+  rc = gcry_sexp_sscan (&s_sig, NULL, sigval, strlen(sigval));
+  if (rc)
+    {
+      log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
+      return map_gcry_err (rc);
+    }
+
+  p = ksba_cert_get_public_key (cert);
   if (DBG_X509)
-    log_debug ("issuer public key: %s\n", p);
+    log_debug ("public key: %s\n", p);
 
   rc = gcry_sexp_sscan ( &s_pkey, NULL, p, strlen(p));
   if (rc)
@@ -146,7 +193,18 @@ gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
       log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
       return map_gcry_err (rc);
     }
-  /*gcry_sexp_dump (s_pkey);*/
+  
+
+  rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
+  if (rc)
+    {
+      /* fixme: clean up some things */
+      return rc;
+    }
+  /* put hash into the S-Exp s_hash */
+  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
+    BUG ();
+
   
   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
   if (DBG_CRYPTO)
index 5dfce2a..9685b1a 100644 (file)
@@ -39,12 +39,12 @@ print_integer (unsigned char *p)
   unsigned long len;
 
   if (!p)
-    fputs ("none", stdout);
+    log_printf ("none");
   else
     {
       len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
       for (p+=4; len; len--, p++)
-        printf ("%02X", *p);
+        log_printf ("%02X", *p);
     }
 }
 
@@ -53,17 +53,17 @@ print_time (time_t t)
 {
 
   if (!t)
-    fputs ("none", stdout);
+    log_printf ("none");
   else if ( t == (time_t)(-1) )
-    fputs ("error", stdout);
+    log_printf ("error");
   else
     {
       struct tm *tp;
 
       tp = gmtime (&t);
-      printf ("%04d-%02d-%02d %02d:%02d:%02d",
-              1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
-              tp->tm_hour, tp->tm_min, tp->tm_sec);
+      log_printf ("%04d-%02d-%02d %02d:%02d:%02d",
+                  1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+                  tp->tm_hour, tp->tm_min, tp->tm_sec);
       assert (!tp->tm_isdst);
     }
 }
@@ -71,61 +71,55 @@ print_time (time_t t)
 static void
 print_dn (char *p)
 {
-
   if (!p)
-    fputs ("error", stdout);
+    log_printf ("error");
   else
-    printf ("`%s'", p);
+    log_printf ("`%s'", p);
 }
 
 
 void 
-gpgsm_dump_cert (KsbaCert cert)
+gpgsm_dump_cert (const char *text, KsbaCert cert)
 {
   unsigned char *p;
   char *dn;
   time_t t;
 
-  if (!cert)
+  log_debug ("BEGIN Certificate `%s':\n", text? text:"");
+  if (cert)
     {
-      fputs ("[no certificate]\n", stdout);
-      return;
-    }
-    
-  p = ksba_cert_get_serial (cert);
-  fputs ("serial: ", stdout);
-  print_integer (p);
-  ksba_free (p);
-  putchar ('\n');
-
-  t = ksba_cert_get_validity (cert, 0);
-  fputs ("notBefore: ", stdout);
-  print_time (t);
-  putchar ('\n');
-  t = ksba_cert_get_validity (cert, 1);
-  fputs ("notAfter: ", stdout);
-  print_time (t);
-  putchar ('\n');
+      p = ksba_cert_get_serial (cert);
+      log_debug ("  serial: ");
+      print_integer (p);
+      ksba_free (p);
+      log_printf ("\n");
+
+      t = ksba_cert_get_validity (cert, 0);
+      log_debug ("  notBefore: ");
+      print_time (t);
+      log_printf ("\n");
+      t = ksba_cert_get_validity (cert, 1);
+      log_debug ("  notAfter: ");
+      print_time (t);
+      log_printf ("\n");
+
+      dn = ksba_cert_get_issuer (cert);
+      log_debug ("  issuer: ");
+      print_dn (dn);
+      ksba_free (dn);
+      log_printf ("\n");
     
-  dn = ksba_cert_get_issuer (cert);
-  fputs ("issuer: ", stdout);
-  print_dn (dn);
-  ksba_free (dn);
-  putchar ('\n');
-    
-  dn = ksba_cert_get_subject (cert);
-  fputs ("subject: ", stdout);
-  print_dn (dn);
-  ksba_free (dn);
-  putchar ('\n');
+      dn = ksba_cert_get_subject (cert);
+      log_debug ("  subject: ");
+      print_dn (dn);
+      ksba_free (dn);
+      log_printf ("\n");
 
-  printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert));
+      log_debug ("  hash algo: %d\n", ksba_cert_get_digest_algo (cert));
 
-  p = gpgsm_get_fingerprint_string (cert, 0);
-  printf ("SHA1 Fingerprint=%s\n", p);
-  xfree (p);
+      p = gpgsm_get_fingerprint_string (cert, 0);
+      log_debug ("  SHA1 Fingerprint: %s\n", p);
+      xfree (p);
+    }
+  log_debug ("END Certificate\n");
 }
-
-
-
-
index aef1612..518acfe 100644 (file)
@@ -50,8 +50,7 @@ gpgsm_validate_path (KsbaCert cert)
       goto leave;
     }
 
-  log_debug ("validate path for certificate:\n");
-  gpgsm_dump_cert (cert);
+  gpgsm_dump_cert ("subject", cert);
 
   subject_cert = cert;
 
@@ -87,7 +86,7 @@ gpgsm_validate_path (KsbaCert cert)
 
       /* find the next cert up the tree */
       keydb_search_reset (kh);
-      rc = keydb_search_issuer (kh, issuer);
+      rc = keydb_search_subject (kh, issuer);
       if (rc)
         {
           log_debug ("failed to find issuer's certificate: rc=%d\n", rc);
@@ -105,7 +104,7 @@ gpgsm_validate_path (KsbaCert cert)
         }
 
       log_debug ("got issuer's certificate:\n");
-      gpgsm_dump_cert (issuer_cert);
+      gpgsm_dump_cert ("issuer", issuer_cert);
 
       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
         {
index 39db243..53b8dcd 100644 (file)
@@ -912,6 +912,7 @@ main ( int argc, char **argv)
       break;
 
     case aVerify:
+      gpgsm_verify (0);
 /*        if ((rc = verify_signatures( argc, argv ) )) */
 /*          log_error ("verify signatures failed: %s\n", gpg_errstr(rc) ); */
       break;
@@ -1023,6 +1024,8 @@ gpgsm_exit (int rc)
 #warning no update_random_seed_file
   update_random_seed_file();
   #endif
+#if 0
+  /* at this time a bit annoying */
   if (opt.debug & DBG_MEMSTAT_VALUE)
     {
       gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
@@ -1030,6 +1033,7 @@ gpgsm_exit (int rc)
     }
   if (opt.debug)
     gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
+#endif
   gcry_control (GCRYCTL_TERM_SECMEM );
   rc = rc? rc : log_get_errorcount(0)? 2 : gpgsm_errors_seen? 1 : 0;
   exit (rc);
index a4361dc..d60eb03 100644 (file)
@@ -106,10 +106,12 @@ char *gpgsm_get_fingerprint (KsbaCert cert, int algo, char *array, int *r_len);
 char *gpgsm_get_fingerprint_string (KsbaCert cert, int algo);
 
 /*-- certdump.c --*/
-void gpgsm_dump_cert (KsbaCert cert);
+void gpgsm_dump_cert (const char *text, KsbaCert cert);
 
 /*-- certcheck.c --*/
 int gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert);
+int gpgsm_check_cms_signature (KsbaCert cert, const char *sigval,
+                               GCRY_MD_HD md, int hash_algo);
 
 
 /*-- certpath.c --*/
@@ -121,6 +123,9 @@ int gpgsm_validate_path (KsbaCert cert);
 /*-- import.c --*/
 int gpgsm_import (int in_fd);
 
+/*-- verify.c --*/
+int gpgsm_verify (int in_fd);
+
 
 
 
index ef839ed..6ca7a33 100644 (file)
@@ -852,5 +852,18 @@ keydb_search_issuer_sn (KEYDB_HANDLE hd,
   return rc;
 }
 
+int
+keydb_search_subject (KEYDB_HANDLE hd, const char *name)
+{
+  KEYDB_SEARCH_DESC desc;
+  int rc;
+  
+  memset (&desc, 0, sizeof desc);
+  desc.mode = KEYDB_SEARCH_MODE_SUBJECT;
+  desc.u.name = name;
+  rc = keydb_search (hd, &desc, 1);
+  return rc;
+}
+
 
 
index 71f457f..7029d07 100644 (file)
@@ -58,6 +58,7 @@ int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
 int keydb_search_issuer (KEYDB_HANDLE hd, const char *issuer);
 int keydb_search_issuer_sn (KEYDB_HANDLE hd,
                             const char *issuer, const unsigned char *serial);
+int keydb_search_subject (KEYDB_HANDLE hd, const char *issuer);
 
 
 #endif /*GNUPG_KEYDB_H*/
index daea496..7c4318b 100644 (file)
@@ -97,14 +97,21 @@ cmd_decrypt (ASSUAN_CONTEXT ctx, char *line)
   This does a verify operation on the message send to the input-FD.
   The result is written out using status lines.  If an output FD was
   given, the signed text will be written to that.
-
-  The behavior for detached signatures has not yet been specified.  */
+  
+  If the signature is a detached one, the server will inquire about
+  the signed material and the client must provide it.
+  */
 static int 
 cmd_verify (ASSUAN_CONTEXT ctx, char *line)
 {
-  
+  int fd = assuan_get_input_fd (ctx);
 
-  return set_error (Not_Implemented, "fixme");
+  if (fd == -1)
+    return set_error (No_Input, NULL);
+
+  gpgsm_verify (fd);
+
+  return 0;
 }
 
 
diff --git a/sm/verify.c b/sm/verify.c
new file mode 100644 (file)
index 0000000..31e7fcf
--- /dev/null
@@ -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);
+    }
+}
+
+
+
+
+\f
+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;
+}
+
+