Just a Backup. We can now write out a basic signature which in turn
authorWerner Koch <wk@gnupg.org>
Fri, 23 Nov 2001 17:12:37 +0000 (17:12 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 23 Nov 2001 17:12:37 +0000 (17:12 +0000)
exhibits a bug in --verify.

sm/Makefile.am
sm/gpgsm.c
sm/gpgsm.h
sm/sign.c [new file with mode: 0644]
sm/verify.c

index 00bb6d9..67cd8c7 100644 (file)
@@ -36,8 +36,10 @@ gpgsm_SOURCES = \
        certpath.c \
        keylist.c \
        verify.c \
+       sign.c \
        import.c 
 
+
 gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a ../kbx/libkeybox.a \
               ../../libksba/src/.libs/libksba.a \
               ../../libgcrypt/src/.libs/libgcrypt.so.1 
index 72e6d41..c7ee419 100644 (file)
@@ -884,6 +884,16 @@ main ( int argc, char **argv)
 #endif
 
     case aSign: /* sign the given file */
+      /* FIXME: we can only do detached sigs for now and we don't
+         handle --output yet. We should also allow to concatenate
+         multiple files for signins because that is what gpg does.*/
+      if (!argc)
+        gpgsm_sign (&ctrl, 0, 1, stdout); /* create from stdin */
+      else if (argc == 1)
+        gpgsm_sign (&ctrl, open_read (*argv), 1, stdout); /* from file */
+      else
+        wrong_args (_("--sign [datafile]"));
+      break;
 #if 0
       sl = NULL;
       if (detached_sig)
index f262281..3444a27 100644 (file)
@@ -41,6 +41,7 @@ enum {
   GPGSM_Bad_Signature = 11,
   GPGSM_Not_Implemented = 12,
   GPGSM_Conflict = 13,
+  GPGSM_Bug = 14
 };
 
 /* Status codes (shared with gpg) */
@@ -214,6 +215,8 @@ int gpgsm_import (CTRL ctrl, int in_fd);
 /*-- verify.c --*/
 int gpgsm_verify (CTRL ctrl, int in_fd, int data_fd);
 
+/*-- sign.c --*/
+int gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp);
 
 
 
diff --git a/sm/sign.c b/sm/sign.c
new file mode 100644 (file)
index 0000000..0949d06
--- /dev/null
+++ b/sm/sign.c
@@ -0,0 +1,356 @@
+/* sign.c - Sign a message
+ *     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;
+};
+
+
+static int
+do_sign(KsbaCert cert, GCRY_MD_HD md, int algo, char **r_sigval)
+{
+  return 0;
+}
+
+
+
+static void
+hash_data (int fd, GCRY_MD_HD md)
+{
+  FILE *fp;
+  char buffer[4096];
+  int nread;
+
+  fp = fdopen ( dup (fd), "rb");
+  if (!fp)
+    {
+      log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
+      return;
+    }
+
+  do 
+    {
+      nread = fread (buffer, 1, DIM(buffer), fp);
+      gcry_md_write (md, buffer, nread);
+    }
+  while (nread);
+  if (ferror (fp))
+      log_error ("read error on fd %d: %s\n", fd, strerror (errno));
+  fclose (fp);
+}
+
+
+static KsbaCert
+get_default_signer (void)
+{
+  const char key[] = "1.2.840.113549.1.9.1=#7472757374407765622E6465#,CN=WEB.DE TrustCenter,OU=TrustCenter,O=WEB.DE AG,L=D-76227 Karlsruhe,C=DE";
+  KsbaCert cert = NULL;
+  KEYDB_HANDLE kh = NULL;
+  int rc;
+
+  kh = keydb_new (0);
+  if (!kh)
+    return NULL;
+
+  rc = keydb_search_subject (kh, key);
+  if (rc)
+    {
+      log_debug ("failed to find default certificate: rc=%d\n", rc);
+    }
+  else 
+    {
+      rc = keydb_get_cert (kh, &cert);
+      if (rc)
+        {
+          log_debug ("failed to get cert: rc=%d\n", rc);
+        }
+    }
+
+  keydb_release (kh);
+  return cert;
+}
+
+
+\f
+/* Perform a sign operation.  
+
+   Sign the data received on DATA-FD in embedded mode or in deatched
+   mode when DETACHED is true.  Write the signature to OUT_FP The key
+   used to sign is the default - we will extend the fucntion to take a
+   list of fingerprints in the future. */
+int
+gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
+{
+  int i, rc;
+  KsbaError err;
+  KsbaWriter writer = NULL;
+  KsbaCMS cms = NULL;
+  KsbaStopReason stopreason;
+  KsbaCert cert;
+  KEYDB_HANDLE kh = NULL;
+  GCRY_MD_HD data_md = NULL;
+  struct reader_cb_parm_s rparm;
+  int signer;
+  const char *algoid;
+  int algo;
+
+  memset (&rparm, 0, sizeof rparm);
+
+  if (!detached)
+    {
+       rc = seterr (Not_Implemented);
+       goto leave;
+    }
+
+
+  kh = keydb_new (0);
+  if (!kh)
+    {
+      log_error (_("failed to allocated keyDB handle\n"));
+      rc = GPGSM_General_Error;
+      goto leave;
+    }
+
+  rparm.fp = fdopen ( dup (data_fd), "rb");
+  if (!rparm.fp)
+    {
+      log_error ("fdopen() failed: %s\n", strerror (errno));
+      rc = seterr (IO_Error);
+      goto leave;
+    }
+
+  writer = ksba_writer_new ();
+  if (!writer)
+    {
+      rc = seterr (Out_Of_Core);
+      goto leave;
+    }
+  rc = ksba_writer_set_file (writer, out_fp);
+  if (rc)
+    {
+      ksba_writer_release (writer);
+      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, NULL, writer);
+  if (err)
+    {
+      log_debug ("ksba_cms_set_reader_writer failed: %s\n",
+                 ksba_strerror (err));
+      rc = map_ksba_err (err);
+      goto leave;
+    }
+
+  /* We are going to create signed data with data as encap. content */
+  err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA);
+  if (!err)
+    err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
+  if (err)
+    {
+      log_debug ("ksba_cms_set_content_type failed: %s\n",
+                 ksba_strerror (err));
+      rc = map_ksba_err (err);
+      goto leave;
+    }
+
+
+  /* gather certificates of signers  and store in theCMS object */
+  /* fixme: process a list of fingerprints and store the certificate of
+     each given fingerprint */
+  cert = get_default_signer ();
+  if (!cert)
+    {
+      log_error ("no default signer found\n");
+      rc = seterr (General_Error);
+      goto leave;
+    }
+  err = ksba_cms_add_signer (cms, cert);
+  if (err)
+    {
+      log_debug ("ksba_cms_add_signer failed: %s\n",  ksba_strerror (err));
+      rc = map_ksba_err (err);
+      goto leave;
+    }
+  cert = NULL; /* cms does now own the certificate */
+
+  /* fixme: We might want to include a list of certificate which are
+     put as info into the signed data object - maybe we should add a
+     flag to ksba_cms_add_signer to decider whether this cert should
+     be send along with the signature */
+  
+  /* Set the hash algorithm we are going to use */
+  err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/);
+  if (err)
+    {
+      log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err));
+      rc = map_ksba_err (err);
+      goto leave;
+    }
+
+  /* Prepare hashing (actually we are figuring out what we have set above)*/
+  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;
+    }
+  for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
+    {
+      algo = gcry_md_map_name (algoid);
+      if (!algo)
+        {
+          log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
+          rc = GPGSM_Bug;
+          goto leave;
+        }
+      gcry_md_enable (data_md, algo);
+    }
+
+  if (detached)
+    { /* we hash the data right now so tha we can store the message
+         digest.  ksba_cms_build() takes this as an flag that deatched
+         data is expected. */
+      unsigned char *digest;
+      size_t digest_len;
+      /* Fixme do this for all signers and get the algo to use from
+         the signer's certificate - does not make mich sense, bu we
+         should do this consistent as we have already done it above */
+      signer = 0;
+      algo = GCRY_MD_SHA1; 
+      hash_data (data_fd, data_md);
+      digest = gcry_md_read (data_md, algo);
+      digest_len = gcry_md_get_algo_dlen (algo);
+      if ( !digest || !digest_len)
+        {
+          log_error ("problem getting the hash of the data\n");
+          rc = GPGSM_Bug;
+          goto leave;
+        }
+      err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
+      if (err)
+        {
+          log_error ("ksba_cms_set_message_digest failed: %s\n",
+                     ksba_strerror (err));
+          rc = map_ksba_err (err);
+          goto leave;
+        }
+    }
+
+
+
+  do 
+    {
+      err = ksba_cms_build (cms, &stopreason);
+      if (err)
+        {
+          log_debug ("ksba_cms_build failed: %s\n", ksba_strerror (err));
+          rc = map_ksba_err (err);
+          goto leave;
+        }
+      log_debug ("ksba_cms_build - stop reason %d\n", stopreason);
+
+      if (stopreason == KSBA_SR_BEGIN_DATA)
+        { /* hash the data and store the message digest */
+          assert (!detached);
+        }
+      else if (stopreason == KSBA_SR_NEED_SIG)
+        { /* calculate the signature for all signers */
+          GCRY_MD_HD md;
+
+          algo = GCRY_MD_SHA1;
+          signer = 0;
+          md = gcry_md_open (algo, 0);
+          if (!md)
+            {
+              log_error ("md_open failed: %s\n", gcry_strerror (-1));
+              goto leave;
+            }
+          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 leave;
+            }
+          
+          { /* This is all an temporary hack */
+            char *sigval;
+
+            cert = get_default_signer ();
+            if (!cert)
+              {
+                log_error ("oops - failed to get cert again\n");
+                rc = seterr (General_Error);
+                goto leave;
+              }
+
+            sigval = NULL;
+            rc = do_sign (cert, md, algo, &sigval);
+            if (rc)
+              {
+                ksba_cert_release (cert);
+                goto leave;
+              }
+
+            log_debug ("sigval=`%s'\n", sigval);
+            xfree (sigval);
+          }
+        }
+    }
+  while (stopreason != KSBA_SR_READY);   
+
+  log_info ("signature created\n");
+
+ leave:
+  ksba_cms_release (cms);
+  ksba_writer_release (writer);
+  keydb_release (kh); 
+  gcry_md_close (data_md);
+  if (rparm.fp)
+    fclose (rparm.fp);
+  return rc;
+}
index 7a576cf..325c759 100644 (file)
@@ -40,7 +40,7 @@ struct reader_cb_parm_s {
 
 
 /* FIXME: Move this to jnlib */
-char *
+static char *
 strtimestamp (time_t atime)
 {
   char *buffer = xmalloc (15);