* base64.c: New. Changed all other functions to use this instead
authorWerner Koch <wk@gnupg.org>
Tue, 27 Nov 2001 17:40:09 +0000 (17:40 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 27 Nov 2001 17:40:09 +0000 (17:40 +0000)
of direct creation of ksba_reader/writer.
* gpgsm.c (main): Set ctrl.auto_encoding unless --no-armor is used.
This way we can feed PEM encoded stuff to --verify.

sm/ChangeLog
sm/Makefile.am
sm/base64.c [new file with mode: 0644]
sm/encrypt.c [new file with mode: 0644]
sm/gpgsm.c
sm/gpgsm.h
sm/import.c
sm/server.c
sm/sign.c
sm/verify.c

index f0d7c2f..9ca9886 100644 (file)
@@ -1,3 +1,9 @@
+2001-11-27  Werner Koch  <wk@gnupg.org>
+
+       * base64.c: New.  Changed all other functions to use this instead
+       of direct creation of ksba_reader/writer.
+       * gpgsm.c (main): Set ctrl.auto_encoding unless --no-armor is used.
+
 2001-11-26  Werner Koch  <wk@gnupg.org>
 
        * gpgsm.c: New option --agent-program
index c6aecdb..fbfe31a 100644 (file)
@@ -31,12 +31,14 @@ gpgsm_SOURCES = \
        server.c \
        call-agent.c \
        fingerprint.c \
+       base64.c \
        certdump.c \
        certcheck.c \
        certpath.c \
        keylist.c \
        verify.c \
        sign.c \
+       encrypt.c \
        import.c 
 
 
diff --git a/sm/base64.c b/sm/base64.c
new file mode 100644 (file)
index 0000000..f60015d
--- /dev/null
@@ -0,0 +1,401 @@
+/* base64.c 
+ *     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 <ksba.h>
+
+#include "gpgsm.h"
+#include "i18n.h"
+
+
+/* data used by the reader callbacks */
+struct reader_cb_parm_s {
+  FILE *fp;
+  unsigned char line[1024];
+  int linelen;
+  int readpos;
+  int have_lf;
+  unsigned long line_counter;
+
+  int autodetect; /* try to detect the input encoding */
+  int assume_pem; /* assume input encoding is PEM */
+  int assume_base64; /* assume inpout is base64 encoded */
+
+  int identified;
+  int is_pem;
+  int stop_seen;
+
+  struct {
+    int idx;
+    unsigned char val;
+    int stop_seen;
+  } base64;
+};
+
+
+struct base64_context_s {
+  struct reader_cb_parm_s rparm;
+};
+
+
+/* The base-64 character list */
+static unsigned char bintoasc[64] = 
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
+       "abcdefghijklmnopqrstuvwxyz" 
+       "0123456789+/"; 
+/* The reverse base-64 list */
+static unsigned char asctobin[256] = {
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
+  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
+  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
+  0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
+  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
+  0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff
+};
+
+
+
+static int
+base64_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, c2;
+
+  *nread = 0;
+  if (!buffer)
+    return -1; /* not supported */
+
+ next:
+  if (!parm->linelen)
+    {
+      /* read an entire line or up to the size of the buffer */
+      parm->line_counter++;
+      parm->have_lf = 0;
+      for (n=0; n < DIM(parm->line);)
+        {
+          c = getc (parm->fp);
+          if (c == EOF)
+            {
+              if (ferror (parm->fp))
+                return -1;
+              break; 
+            }
+          parm->line[n++] = c;
+          if (c == '\n')
+            {
+              parm->have_lf = 1;
+              /* FIXME: we need to skip overlong lines while detecting
+                 the dashed lines */
+              break;
+            }
+        }
+      parm->linelen = n;
+      if (!n)
+        return -1; /* eof */
+      parm->readpos = 0;
+    }
+
+  if (!parm->identified)
+    {
+      if (parm->line_counter == 1 && !parm->have_lf)
+        {
+          /* first line too long - assume DER encoding */
+          parm->is_pem = 0;
+        }
+      else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
+        {
+          /* the very first bytes does pretty much look like a SEQUENCE tag*/
+          parm->is_pem = 0;
+        }
+      else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
+                && strncmp (parm->line+11, "PGP ", 4) )
+        {
+          /* Fixme: we must only compare if the line really starts at
+             the beginning */
+          parm->is_pem = 1;
+          parm->linelen = parm->readpos = 0;
+        }
+      else
+        {
+          parm->linelen = parm->readpos = 0;
+          goto next;
+        }
+      parm->identified = 1;
+      parm->base64.stop_seen = 0;
+      parm->base64.idx = 0;
+    }
+  
+
+  n = 0;
+  if (parm->is_pem)
+    {  
+      if (parm->have_lf && !strncmp (parm->line, "-----END ", 9))
+        { 
+          parm->identified = 0;
+          parm->linelen = parm->readpos = 0;
+          /* let us return 0 */
+        }
+      else if (parm->stop_seen)
+        { /* skip the rest of the line */
+          parm->linelen = parm->readpos = 0;
+        }
+      else
+        {
+          int idx = parm->base64.idx;
+          unsigned char val = parm->base64.val;
+
+          while (n < count && parm->readpos < parm->linelen )
+            {
+              c = parm->line[parm->readpos++];
+              if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
+                continue;
+              if (c == '=')
+                { /* pad character: stop */
+                  if (idx == 1)
+                    buffer[n++] = val; 
+                  parm->stop_seen = 1;
+                  break;
+                }
+              if( (c = asctobin[(c2=c)]) == 255 ) 
+                {
+                  log_error (_("invalid radix64 character %02x skipped\n"),
+                             c2);
+                  continue;
+                }
+              switch (idx) 
+                {
+                case 0: 
+                  val = c << 2;
+                  break;
+                case 1: 
+                  val |= (c>>4)&3;
+                  buffer[n++] = val;
+                  val = (c<<4)&0xf0;
+                  break;
+                case 2: 
+                  val |= (c>>2)&15;
+                  buffer[n++] = val;
+                  val = (c<<6)&0xc0;
+                  break;
+                case 3: 
+                  val |= c&0x3f;
+                  buffer[n++] = val;
+                  break;
+                }
+              idx = (idx+1) % 4;
+            }
+          if (parm->readpos == parm->linelen)
+            parm->linelen = parm->readpos = 0;
+
+          parm->base64.idx = idx;
+          parm->base64.val = val;
+        }
+    }
+  else
+    { /* DER encoded */
+      while (n < count && parm->readpos < parm->linelen)
+          buffer[n++] = parm->line[parm->readpos++];
+      if (parm->readpos == parm->linelen)
+        parm->linelen = parm->readpos = 0;
+    }
+
+  *nread = n;
+  return 0;
+}
+
+
+
+static int
+simple_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;
+}
+
+
+
+
+\f
+/* Create a reader for the given file descriptor.  Depending on the
+   control information an input decoding is automagically choosen.
+   The function returns a Base64Context object which must be passed to
+   the gpgme_destroy_reader function.  The created KsbaReader object
+   is also returned, but the caller must not call the
+   ksba_reader_release function on. */
+int
+gpgsm_create_reader (Base64Context *ctx,
+                     CTRL ctrl, FILE *fp, KsbaReader *r_reader)
+{
+  int rc;
+  KsbaReader r;
+
+  *r_reader = NULL;
+  *ctx = xtrycalloc (1, sizeof **ctx);
+  if (!*ctx)
+    return seterr (Out_Of_Core);
+
+  r = ksba_reader_new ();
+  if (!r)
+    {
+      xfree (*ctx); *ctx = NULL;
+      return seterr (Out_Of_Core);
+    }
+
+  (*ctx)->rparm.fp = fp;
+  if (ctrl->is_pem)
+    {
+      (*ctx)->rparm.assume_pem = 1;
+      (*ctx)->rparm.assume_base64 = 1;
+      rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm);
+    }
+  else if (ctrl->is_base64)
+    {
+      (*ctx)->rparm.assume_base64 = 1;
+      rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm);
+    }
+  else if (ctrl->autodetect_encoding)
+    {
+      (*ctx)->rparm.autodetect = 1;
+      rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm);
+    }
+  else
+      rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->rparm);
+
+  if (rc)
+    {
+      ksba_reader_release (r);
+      xfree (*ctx); *ctx = NULL;
+      return map_ksba_err (rc);
+    }
+
+  *r_reader = r;
+  return 0;
+}
+
+
+void
+gpgsm_destroy_reader (Base64Context ctx)
+{
+  xfree (ctx);
+}
+
+
+\f
+/* Create a writer for the given stream.  Depending on the control
+   information an output encoding is automagically choosen.  The
+   function returns a Base64Context object which must be passed to the
+   gpgme_destroy_writer function.  The created KsbaWriter object is
+   also returned, but the caller must not call the ksba_reader_release
+   function on. */
+int
+gpgsm_create_writer (Base64Context *ctx,
+                     CTRL ctrl, FILE *fp, KsbaWriter *r_writer)
+{
+  int rc;
+  KsbaWriter w;
+
+  *r_writer = NULL;
+  *ctx = xtrycalloc (1, sizeof **ctx);
+  if (!*ctx)
+    return seterr (Out_Of_Core);
+
+  w = ksba_writer_new ();
+  if (!w)
+    {
+      xfree (*ctx); *ctx = NULL;
+      return seterr (Out_Of_Core);
+    }
+
+  if (ctrl->create_pem || ctrl->create_base64)
+    {
+      return seterr (Not_Implemented);
+    }
+  else
+    rc = ksba_writer_set_file (w, fp);
+
+  if (rc)
+    {
+      ksba_writer_release (w);
+      xfree (*ctx); *ctx = NULL;
+      return map_ksba_err (rc);
+    }
+
+  *r_writer = w;
+  return 0;
+}
+
+
+void
+gpgsm_destroy_writer (Base64Context ctx)
+{
+  xfree (ctx);
+}
+
+
+
+
+
diff --git a/sm/encrypt.c b/sm/encrypt.c
new file mode 100644 (file)
index 0000000..2b30463
--- /dev/null
@@ -0,0 +1,256 @@
+/* encrypt.c - Encrypt 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"
+
+
+KsbaCert
+get_default_recipient (void)
+{
+  return NULL;
+}
+
+
+\f
+/* Perform an encrypt operation.  
+
+   Encrypt the data received on DATA-FD and write it to OUT_FP.  The
+   recipients are hardwired for now. */
+int
+gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp)
+{
+  int i, rc;
+  Base64Context b64reader = NULL;
+  Base64Context b64writer = NULL;
+  KsbaError err;
+  KsbaWriter writer;
+  KsbaReader reader;
+  KsbaCMS cms = NULL;
+  KsbaStopReason stopreason;
+  KsbaCert cert;
+  KEYDB_HANDLE kh = NULL;
+  GCRY_MD_HD data_md = NULL;
+  int signer;
+  const char *algoid;
+  FILE *data_fp = NULL;
+  int algo;
+
+
+  kh = keydb_new (0);
+  if (!kh)
+    {
+      log_error (_("failed to allocated keyDB handle\n"));
+      rc = GNUPG_General_Error;
+      goto leave;
+    }
+
+  data_fp = fdopen ( dup (data_fd), "rb");
+  if (!data_fp)
+    {
+      log_error ("fdopen() failed: %s\n", strerror (errno));
+      rc = seterr (IO_Error);
+      goto leave;
+    }
+
+  rc = gpgsm_create_reader (&b64reader, ctrl, data_fp, &reader);
+  if (rc)
+    {
+      log_error ("can't create reader: %s\n", gnupg_strerror (rc));
+      goto leave;
+    }
+
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+  if (rc)
+    {
+      log_error ("can't create writer: %s\n", gnupg_strerror (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;
+    }
+
+  /* We are going to create signed data with data as encap. content */
+  err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
+  if (!err)
+    err = ksba_cms_set_content_type (cms, 1, KSBA_CT_ENCRYPTED_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 recipients and store them in the CMS object */
+  cert = get_default_recipient ();
+  if (!cert)
+    {
+      log_error ("no default recipient 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 */
+
+  /* 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 = GNUPG_Bug;
+          goto leave;
+        }
+      gcry_md_enable (data_md, algo);
+    }
+
+  signer = 0;
+  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)
+        { 
+        }
+      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 = NULL;
+            if (!cert)
+              {
+                log_error ("oops - failed to get cert again\n");
+                rc = seterr (General_Error);
+                goto leave;
+              }
+
+            sigval = NULL;
+            rc = gpgsm_create_cms_signature (cert, md, algo, &sigval);
+            if (rc)
+              {
+                ksba_cert_release (cert);
+                goto leave;
+              }
+
+            err = ksba_cms_set_sig_val (cms, signer, sigval);
+            xfree (sigval);
+            if (err)
+              {
+                log_error ("failed to store the signature: %s\n",
+                           ksba_strerror (err));
+                rc = map_ksba_err (err);
+                goto leave;
+              }
+          }
+        }
+    }
+  while (stopreason != KSBA_SR_READY);   
+
+  log_info ("signature created\n");
+
+ leave:
+  ksba_cms_release (cms);
+  gpgsm_destroy_writer (b64writer);
+  gpgsm_destroy_reader (b64reader);
+  keydb_release (kh); 
+  gcry_md_close (data_md);
+  if (data_fp)
+    fclose (data_fp);
+  return rc;
+}
index 0b6b7c2..f6cf4ae 100644 (file)
@@ -591,6 +591,7 @@ main ( int argc, char **argv)
   memset (&ctrl, 0, sizeof ctrl);
   ctrl.no_server = 1;
   ctrl.status_fd = -1; /* not status output */
+  ctrl.autodetect_encoding = 1;
 
   /* set the default option file */
   if (default_config )
@@ -661,7 +662,10 @@ main ( int argc, char **argv)
         case aVerify: set_cmd (&cmd, aVerify); break;
 
         case oArmor: opt.armor = 1; opt.no_armor=0; break;
-        case oNoArmor: opt.no_armor=1; opt.armor=0; break;
+        case oNoArmor: 
+          ctrl.autodetect_encoding = 0;
+          opt.no_armor=1; opt.armor=0; 
+          break;
         case oOutput: opt.outfile = pargs.r.ret_str; break;
         case oQuiet: opt.quiet = 1; break;
         case oNoTTY: /* fixme:tty_no_terminal(1);*/ break;
index 00ae32e..916a2cd 100644 (file)
@@ -45,7 +45,7 @@ struct {
 
   int fingerprint;  /* list fingerprints in all key listings */
 
-  int armor;        /* force base64 armoring */
+  int armor;        /* force base64 armoring (see also ctrl.with_base64) */
   int no_armor;     /* don't try to figure out whether data is base64 armored*/
 
   int def_cipher_algo;    /* cipher algorithm to use if nothing else is know */
@@ -89,9 +89,20 @@ struct server_control_s {
   int  status_fd;    /* only for non-server mode */
   struct server_local_s *server_local;
   int with_colons;  /* use column delimited output format */
+
+  int autodetect_encoding; /* try to detect the input encoding */
+  int is_pem;         /* Is in PEM format */
+  int is_base64;      /* is in plain base-64 format */
+
+  int create_base64;  /* Create base64 encoded output */
+  int create_pem;     /* create PEM output */
 };
 typedef struct server_control_s *CTRL;
 
+/* data structure osed in base64.c */
+typedef struct base64_context_s *Base64Context;
+
 
 /*-- gpgsm.c --*/
 void gpgsm_exit (int rc);
@@ -107,6 +118,14 @@ char *gpgsm_get_fingerprint_hexstring (KsbaCert cert, int algo);
 char *gpgsm_get_keygrip (KsbaCert cert, char *array);
 char *gpgsm_get_keygrip_hexstring (KsbaCert cert);
 
+/*-- base64.c --*/
+int  gpgsm_create_reader (Base64Context *ctx,
+                          CTRL ctrl, FILE *fp, KsbaReader *r_reader);
+void gpgsm_destroy_reader (Base64Context ctx);
+int  gpgsm_create_writer (Base64Context *ctx,
+                          CTRL ctrl, FILE *fp, KsbaWriter *r_writer);
+void gpgsm_destroy_writer (Base64Context ctx);
+
 
 /*-- certdump.c --*/
 void gpgsm_dump_cert (const char *text, KsbaCert cert);
index fc628a6..0e9618c 100644 (file)
 #include "keydb.h"
 #include "i18n.h"
 
-struct reader_cb_parm_s {
-  FILE *fp;
-  unsigned char line[1024];
-  int linelen;
-  int readpos;
-  int have_lf;
-  unsigned long line_counter;
-
-  int identified;
-  int is_pem;
-  int stop_seen;
-
-  struct {
-    int idx;
-    unsigned char val;
-    int stop_seen;
-  } base64;
-
-
-};
-
-/*  static unsigned char bintoasc[] =  */
-/*  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
-/*  "abcdefghijklmnopqrstuvwxyz" */
-/*  "0123456789+/"; */
-
-static unsigned char asctobin[256] = {
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
-  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
-  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
-  0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
-  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
-  0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-  0xff, 0xff, 0xff, 0xff
-};
-
-
-
-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, c2;
-
-  *nread = 0;
-  if (!buffer)
-    return -1; /* not supported */
-
- next:
-  if (!parm->linelen)
-    {
-      /* read an entire line or up to the size of the buffer */
-      parm->line_counter++;
-      parm->have_lf = 0;
-      for (n=0; n < DIM(parm->line);)
-        {
-          c = getc (parm->fp);
-          if (c == EOF)
-            {
-              if (ferror (parm->fp))
-                return -1;
-              break; 
-            }
-          parm->line[n++] = c;
-          if (c == '\n')
-            {
-              parm->have_lf = 1;
-              /* FIXME: we need to skip overlong lines while detecting
-                 the dashed lines */
-              break;
-            }
-        }
-      parm->linelen = n;
-      if (!n)
-        return -1; /* eof */
-      parm->readpos = 0;
-    }
-
-  if (!parm->identified)
-    {
-      if (parm->line_counter == 1 && !parm->have_lf)
-        {
-          /* first line too long - assume DER encoding */
-          parm->is_pem = 0;
-        }
-      else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
-        {
-          /* the very first bytes does pretty much look like a SEQUENCE tag*/
-          parm->is_pem = 0;
-        }
-      else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
-                && strncmp (parm->line+11, "PGP ", 4) )
-        {
-          /* Fixme: we must only compare if the line really starts at
-             the beginning */
-          parm->is_pem = 1;
-          parm->linelen = parm->readpos = 0;
-        }
-      else
-        {
-          parm->linelen = parm->readpos = 0;
-          goto next;
-        }
-      parm->identified = 1;
-      parm->base64.stop_seen = 0;
-      parm->base64.idx = 0;
-    }
-  
-
-  n = 0;
-  if (parm->is_pem)
-    {  
-      if (parm->have_lf && !strncmp (parm->line, "-----END ", 9))
-        { 
-          parm->identified = 0;
-          parm->linelen = parm->readpos = 0;
-          /* let us return 0 */
-        }
-      else if (parm->stop_seen)
-        { /* skip the rest of the line */
-          parm->linelen = parm->readpos = 0;
-        }
-      else
-        {
-          int idx = parm->base64.idx;
-          unsigned char val = parm->base64.val;
-
-          while (n < count && parm->readpos < parm->linelen )
-            {
-              c = parm->line[parm->readpos++];
-              if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
-                continue;
-              if (c == '=')
-                { /* pad character: stop */
-                  if (idx == 1)
-                    buffer[n++] = val; 
-                  parm->stop_seen = 1;
-                  break;
-                }
-              if( (c = asctobin[(c2=c)]) == 255 ) 
-                {
-                  log_error (_("invalid radix64 character %02x skipped\n"),
-                             c2);
-                  continue;
-                }
-              switch (idx) 
-                {
-                case 0: 
-                  val = c << 2;
-                  break;
-                case 1: 
-                  val |= (c>>4)&3;
-                  buffer[n++] = val;
-                  val = (c<<4)&0xf0;
-                  break;
-                case 2: 
-                  val |= (c>>2)&15;
-                  buffer[n++] = val;
-                  val = (c<<6)&0xc0;
-                  break;
-                case 3: 
-                  val |= c&0x3f;
-                  buffer[n++] = val;
-                  break;
-                }
-              idx = (idx+1) % 4;
-            }
-          if (parm->readpos == parm->linelen)
-            parm->linelen = parm->readpos = 0;
-
-          parm->base64.idx = idx;
-          parm->base64.val = val;
-        }
-    }
-  else
-    { /* DER encoded */
-      while (n < count && parm->readpos < parm->linelen)
-          buffer[n++] = parm->line[parm->readpos++];
-      if (parm->readpos == parm->linelen)
-        parm->linelen = parm->readpos = 0;
-    }
-
-  *nread = n;
-  return 0;
-}
-
 
 static void
 store_cert (KsbaCert cert)
@@ -268,34 +66,23 @@ int
 gpgsm_import (CTRL ctrl, int in_fd)
 {
   int rc;
-  KsbaReader reader = NULL;
+  Base64Context b64reader = NULL;
+  KsbaReader reader;
   KsbaCert cert = NULL;
-  struct reader_cb_parm_s rparm;
-
-  memset (&rparm, 0, sizeof rparm);
+  FILE *fp = NULL;
 
-  rparm.fp = fdopen ( dup (in_fd), "rb");
-  if (!rparm.fp)
+  fp = fdopen ( dup (in_fd), "rb");
+  if (!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 ();
-  if (!reader)
-    {
-      rc = seterr (Out_Of_Core);
-      goto leave;
-    }
-
-  rc = ksba_reader_set_cb (reader, reader_cb, &rparm );
+  rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
   if (rc)
     {
-      ksba_reader_release (reader);
-      rc = map_ksba_err (rc);
+      log_error ("can't create reader: %s\n", gnupg_strerror (rc));
       goto leave;
     }
 
@@ -318,9 +105,9 @@ gpgsm_import (CTRL ctrl, int in_fd)
 
  leave:
   ksba_cert_release (cert);
-  ksba_reader_release (reader);
-  if (rparm.fp)
-    fclose (rparm.fp);
+  gpgsm_destroy_reader (b64reader);
+  if (fp)
+    fclose (fp);
   return rc;
 }
 
index e835060..f4bb409 100644 (file)
@@ -81,6 +81,43 @@ rc_to_assuan_status (int rc)
 }
 
 
+static void
+reset_notify (ASSUAN_CONTEXT ctx)
+{
+}
+
+
+static void
+input_notify (ASSUAN_CONTEXT ctx, const char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+
+  ctrl->autodetect_encoding = 0;
+  ctrl->is_pem = 0;
+  ctrl->is_base64 = 0;
+  if (strstr (line, "--armor"))
+    ctrl->is_pem = 1;  
+  else if (strstr (line, "--base64"))
+    ctrl->is_base64 = 1; 
+  else if (strstr (line, "--binary"))
+    ;
+  else
+    ctrl->autodetect_encoding = 0;
+}
+
+static void
+output_notify (ASSUAN_CONTEXT ctx, const char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+
+  ctrl->create_pem = 0;
+  ctrl->create_base64 = 0;
+  if (strstr (line, "--armor"))
+    ctrl->create_pem = 1;  
+  else if (strstr (line, "--base64"))
+    ctrl->create_base64 = 1; /* just the raw output */
+}
+
 
 
 /*  RECIPIENT <userID>
@@ -103,7 +140,7 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
 }
 
 
-/* ENCRYPT [armor]
+/* ENCRYPT 
 
   Do the actual encryption process. Takes the plaintext from the INPUT
   command, writes to the ciphertext to the file descriptor set with
@@ -115,16 +152,28 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
 
   This command should in general not fail, as all necessary checks
   have been done while setting the recipients.  The input and output
-  pipes are closed.
-
-  The optional armor parameter may be used to request base64 encoded
-  output.  */
+  pipes are closed. */
 static int 
 cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
 {
-  
+  int inp_fd, out_fd;
+  FILE *out_fp;
+  int rc;
 
-  return set_error (Not_Implemented, "fixme");
+  inp_fd = assuan_get_input_fd (ctx);
+  if (inp_fd == -1)
+    return set_error (No_Input, NULL);
+  out_fd = assuan_get_output_fd (ctx);
+  if (out_fd == -1)
+    return set_error (No_Output, NULL);
+
+  out_fp = fdopen ( dup(out_fd), "w");
+  if (!out_fp)
+    return set_error (General_Error, "fdopen() failed");
+  rc = gpgsm_encrypt (assuan_get_pointer (ctx), inp_fd, out_fp);
+  fclose (out_fp);
+
+  return rc_to_assuan_status (rc);
 }
 
 /* DECRYPT
@@ -172,7 +221,7 @@ cmd_verify (ASSUAN_CONTEXT ctx, char *line)
 /* SIGN [--detached]
 
   Sign the data set with the INPUT command and write it to the sink
-  set by OUTPUT.  with "--detached" specified, a detached signature is
+  set by OUTPUT.  With "--detached" specified, a detached signature is
   created (surprise).  */
 static int 
 cmd_sign (ASSUAN_CONTEXT ctx, char *line)
@@ -330,6 +379,10 @@ gpgsm_server (void)
       gpgsm_exit (2);
     }
 
+  assuan_register_reset_notify (ctx, reset_notify);
+  assuan_register_input_notify (ctx, input_notify);
+  assuan_register_output_notify (ctx, output_notify);
+
   assuan_set_pointer (ctx, &ctrl);
   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
   ctrl.server_local->assuan_ctx = ctx;
index a246511..42f409a 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
 #include "i18n.h"
 
 
-
-
-struct reader_cb_parm_s {
-  FILE *fp;
-};
-
-
-
 static void
 hash_data (int fd, GCRY_MD_HD md)
 {
@@ -112,19 +104,17 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
 {
   int i, rc;
   KsbaError err;
-  KsbaWriter writer = NULL;
+  Base64Context b64writer = NULL;
+  KsbaWriter writer;
   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);
@@ -140,25 +130,10 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
       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);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
-      ksba_writer_release (writer);
-      rc = map_ksba_err (rc);
+      log_error ("can't create writer: %s\n", gnupg_strerror (rc));
       goto leave;
     }
 
@@ -357,10 +332,8 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
 
  leave:
   ksba_cms_release (cms);
-  ksba_writer_release (writer);
+  gpgsm_destroy_writer (b64writer);
   keydb_release (kh); 
   gcry_md_close (data_md);
-  if (rparm.fp)
-    fclose (rparm.fp);
   return rc;
 }
index 5b3a5a8..6f4a1d2 100644 (file)
 #include "keydb.h"
 #include "i18n.h"
 
-struct reader_cb_parm_s {
-  FILE *fp;
-};
-
-
 /* FIXME: Move this to jnlib */
 static char *
 strtimestamp (time_t atime)
@@ -46,9 +41,9 @@ strtimestamp (time_t atime)
   char *buffer = xmalloc (15);
   
   if (atime < 0) 
-    {
-      strcpy (buffer, "????" "-??" "-??");
-    }
+    strcpy (buffer, "????" "-??" "-??");
+  else if (!atime)
+    strcpy (buffer, "none");
   else
     {
       struct tm *tp;
@@ -62,38 +57,6 @@ strtimestamp (time_t atime)
 
 
 
-
-/* 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)
@@ -192,21 +155,19 @@ int
 gpgsm_verify (CTRL ctrl, int in_fd, int data_fd)
 {
   int i, rc;
+  Base64Context b64reader = NULL;
   KsbaError err;
-  KsbaReader reader = NULL;
-  KsbaWriter writer = NULL;
+  KsbaReader reader;
   KsbaCMS cms = NULL;
   KsbaStopReason stopreason;
   KsbaCert cert;
   KEYDB_HANDLE kh;
   GCRY_MD_HD data_md = NULL;
-  struct reader_cb_parm_s rparm;
   int signer;
   const char *algoid;
   int algo;
   int is_detached;
-
-  memset (&rparm, 0, sizeof rparm);
+  FILE *fp = NULL;
 
   kh = keydb_new (0);
   if (!kh)
@@ -217,29 +178,18 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd)
     }
 
 
-  rparm.fp = fdopen ( dup (in_fd), "rb");
-  if (!rparm.fp)
+  fp = fdopen ( dup (in_fd), "rb");
+  if (!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 );
+  rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
   if (rc)
     {
-      ksba_reader_release (reader);
-      rc = map_ksba_err (rc);
+      log_error ("can't create reader: %s\n", gnupg_strerror (rc));
       goto leave;
     }
 
@@ -250,7 +200,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd)
       goto leave;
     }
 
-  err = ksba_cms_set_reader_writer (cms, reader, writer);
+  err = ksba_cms_set_reader_writer (cms, reader, NULL);
   if (err)
     {
       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
@@ -454,9 +404,9 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd)
         char *buf, *fpr, *tstr;
 
         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
-        tstr = strtimestamp ( 42 /*fixme: get right time */);
+        tstr = strtimestamp (sigtime);
         buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100);
-        sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)42 );
+        sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime );
         xfree (tstr);
         xfree (fpr);
         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
@@ -498,11 +448,11 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd)
 
  leave:
   ksba_cms_release (cms);
-  ksba_reader_release (reader);
+  gpgsm_destroy_reader (b64reader);
   keydb_release (kh); 
   gcry_md_close (data_md);
-  if (rparm.fp)
-    fclose (rparm.fp);
+  if (fp)
+    fclose (fp);
   return rc;
 }