* import.c (gpgsm_import): Try to identify the type of input and
[gnupg.git] / sm / import.c
index ba21312..1463407 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;
-
-
-};
+\f
+int
+gpgsm_import (CTRL ctrl, int in_fd)
+{
+  int rc;
+  Base64Context b64reader = NULL;
+  KsbaReader reader;
+  KsbaCert cert = NULL;
+  KsbaCMS cms = NULL;
+  FILE *fp = NULL;
+  KsbaContentType ct;
 
-/*  static unsigned char bintoasc[] =  */
-/*  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
-/*  "abcdefghijklmnopqrstuvwxyz" */
-/*  "0123456789+/"; */
+  fp = fdopen ( dup (in_fd), "rb");
+  if (!fp)
+    {
+      log_error ("fdopen() failed: %s\n", strerror (errno));
+      rc = seterr (IO_Error);
+      goto leave;
+    }
 
-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
-};
+  rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
+  if (rc)
+    {
+      log_error ("can't create reader: %s\n", gnupg_strerror (rc));
+      goto leave;
+    }
 
+  ct = ksba_cms_identify (reader);
+  if (ct == KSBA_CT_SIGNED_DATA)
+    { /* This is probably a signed-only message - import the certs */
+      KsbaStopReason stopreason;
+      int i;
 
+      cms = ksba_cms_new ();
+      if (!cms)
+        {
+          rc = seterr (Out_Of_Core);
+          goto leave;
+        }
 
-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;
+      rc = ksba_cms_set_reader_writer (cms, reader, NULL);
+      if (rc)
+        {
+          log_error ("ksba_cms_set_reader_writer failed: %s\n",
+                     ksba_strerror (rc));
+          rc = map_ksba_err (rc);
+          goto leave;
+        }
 
-  *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);)
+      do 
         {
-          c = getc (parm->fp);
-          if (c == EOF)
+          rc = ksba_cms_parse (cms, &stopreason);
+          if (rc)
             {
-              if (ferror (parm->fp))
-                return -1;
-              break; 
+              log_error ("ksba_cms_parse failed: %s\n", ksba_strerror (rc));
+              rc = map_ksba_err (rc);
+              goto leave;
             }
-          parm->line[n++] = c;
-          if (c == '\n')
+
+          if (stopreason == KSBA_SR_BEGIN_DATA)
+              log_info ("not a certs-only message\n");
+        }
+      while (stopreason != KSBA_SR_READY);   
+      
+      for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
+        {
+          if ( !gpgsm_basic_cert_check (cert) )
             {
-              parm->have_lf = 1;
-              /* FIXME: we need to skip overlong lines while detecting
-                 the dashed lines */
-              break;
+              if (!keydb_store_cert (cert))
+                {
+                  if (opt.verbose)
+                    log_info ("certificate imported\n");
+                }
             }
+          ksba_cert_release (cert); 
+          cert = NULL;
         }
-      parm->linelen = n;
-      if (!n)
-        return -1; /* eof */
-      parm->readpos = 0;
+
     }
+  else if (ct == KSBA_CT_NONE)
+    { /* Failed to identify this message - assume a certificate */
 
-  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
+      cert = ksba_cert_new ();
+      if (!cert)
         {
-          parm->linelen = parm->readpos = 0;
-          goto next;
+          rc = seterr (Out_Of_Core);
+          goto leave;
         }
-      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;
+      rc = ksba_cert_read_der (cert, reader);
+      if (rc)
+        {
+          rc = map_ksba_err (rc);
+          goto leave;
         }
-      else
+      
+      if ( !gpgsm_basic_cert_check (cert) )
         {
-          int idx = parm->base64.idx;
-          unsigned char val = parm->base64.val;
-
-          while (n < count && parm->readpos < parm->linelen )
+          if (!keydb_store_cert (cert))
             {
-              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 (opt.verbose)
+                log_info ("certificate imported\n");
             }
-          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)
-{
-  KEYDB_HANDLE kh;
-  int rc;
-
-  kh = keydb_new (0);
-  if (!kh)
     {
-      log_error (_("failed to allocated keyDB handle\n"));
-      return;
+      log_error ("can't extract certificates from input\n");
+      rc = GNUPG_No_Data;
     }
-  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);               
-}
-
-
-
-\f
-int
-gpgsm_import (CTRL ctrl, int in_fd)
-{
-  int rc;
-  KsbaReader reader = NULL;
-  KsbaCert cert = NULL;
-  struct reader_cb_parm_s rparm;
-
-  memset (&rparm, 0, sizeof rparm);
-
-  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 ();
-  if (!reader)
-    {
-      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;
-    }
-
-  cert = ksba_cert_new ();
-  if (!cert)
-    {
-      rc = seterr (Out_Of_Core);
-      goto leave;
-    }
-
-  rc = ksba_cert_read_der (cert, reader);
-  if (rc)
-    {
-      rc = map_ksba_err (rc);
-      goto leave;
-    }
-
-  if ( !gpgsm_validate_path (cert) )
-    store_cert (cert);
+   
 
  leave:
+  ksba_cms_release (cms);
   ksba_cert_release (cert);
-  ksba_reader_release (reader);
-  if (rparm.fp)
-    fclose (rparm.fp);
+  gpgsm_destroy_reader (b64reader);
+  if (fp)
+    fclose (fp);
   return rc;
 }
 
 
+
+