dirmngr/src (ChangeLog dirmngr-client.c)

cvs user wk cvs at cvs.gnupg.org
Mon Jan 3 21:36:30 CET 2005


    Date: Monday, January 3, 2005 @ 21:42:46
  Author: wk
    Path: /cvs/dirmngr/dirmngr/src

Modified: ChangeLog dirmngr-client.c

(read_pem_certificate): New.
(read_certificate): Divert to it depending on pem option.
(squid_loop_body): New.
(main): New options --pem and --squid-mode.


------------------+
 ChangeLog        |    7 +
 dirmngr-client.c |  254 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 257 insertions(+), 4 deletions(-)


Index: dirmngr/src/ChangeLog
diff -u dirmngr/src/ChangeLog:1.39 dirmngr/src/ChangeLog:1.40
--- dirmngr/src/ChangeLog:1.39	Fri Dec 17 16:16:12 2004
+++ dirmngr/src/ChangeLog	Mon Jan  3 21:42:46 2005
@@ -1,3 +1,10 @@
+2005-01-03  Werner Koch  <wk at g10code.com>
+
+	* dirmngr-client.c (read_pem_certificate): New.
+	(read_certificate): Divert to it depending on pem option.
+	(squid_loop_body): New.
+	(main): New options --pem and --squid-mode.
+
 2004-12-17  Werner Koch  <wk at g10code.com>
 
 	* dirmngr.c (launch_ripper_thread): Renamed to launch_reaper_thread.
Index: dirmngr/src/dirmngr-client.c
diff -u dirmngr/src/dirmngr-client.c:1.6 dirmngr/src/dirmngr-client.c:1.7
--- dirmngr/src/dirmngr-client.c:1.6	Fri Dec  3 15:42:36 2004
+++ dirmngr/src/dirmngr-client.c	Mon Jan  3 21:42:46 2005
@@ -55,7 +55,10 @@
     oCacheCert,
     oValidate,
     oLookup,
-    oLoadCRL
+    oLoadCRL,
+    oSquidMode,
+    oPEM,
+    oEscapedPEM,
   };
 
 
@@ -69,7 +72,9 @@
   { oValidate, "validate",  0, N_("validate a certificate")},
   { oLookup,   "lookup",    0, N_("lookup a certificate")},
   { oLoadCRL,  "load-crl",  0, N_("load a CRL into the dirmngr")},
-  {0}
+  { oSquidMode,"squid-mode",0, N_("special mode for use by Squid")},
+  { oPEM,      "pem",       0, N_("certificates are expected in PEM format")},
+  { 0 }
 };
  
 #define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
@@ -81,6 +86,8 @@
   int verbose;
   const char *dirmngr_program;
   int force_pipe_server;
+  int pem;
+  int escaped_pem; /* PEM is additional percent encoded.  */
 
   int use_ocsp;
 
@@ -96,6 +103,13 @@
 };
 
 
+/* Base64 conversion tables. */
+static unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                  "abcdefghijklmnopqrstuvwxyz"
+			          "0123456789+/";
+static unsigned char asctobin[256]; /* runtime initialized */
+
+
 /* Prototypes.  */
 static assuan_context_t start_dirmngr (int only_daemon);
 static gpg_error_t read_certificate (const char *fname,
@@ -108,6 +122,7 @@
                                 const unsigned char *cert, size_t certlen);
 static gpg_error_t do_loadcrl (assuan_context_t ctx, const char *filename);
 static gpg_error_t do_lookup (assuan_context_t ctx, const char *pattern);
+static gpg_error_t squid_loop_body (assuan_context_t ctx);
 
 
 
@@ -173,6 +188,7 @@
   int cmd_validate = 0;
   int cmd_lookup = 0;
   int cmd_loadcrl = 0;
+  int cmd_squid_mode = 0;
 
   set_strusage (my_strusage);
   log_set_prefix ("dirmngr-client",
@@ -202,6 +218,12 @@
         case oValidate: cmd_validate = 1; break;
         case oLookup: cmd_lookup = 1; break;
         case oLoadCRL: cmd_loadcrl = 1; break;
+        case oPEM: opt.pem = 1; break;
+        case oSquidMode: 
+          opt.pem = 1;
+          opt.escaped_pem = 1;
+          cmd_squid_mode = 1;
+          break;
 
         default : pargs.err = 2; break;
 	}
@@ -209,6 +231,19 @@
   if (log_get_errorcount (0))
     exit (2);
 
+  /* Build the helptable for radix64 to bin conversion. */
+  if (opt.pem) 
+    {
+      int i;
+      unsigned char *s;
+      
+      for (i=0; i < 256; i++ )
+        asctobin[i] = 255; /* Used to detect invalid characters. */
+      for (s=bintoasc, i=0; *s; s++, i++)
+        asctobin[*s] = i;
+    }
+
+
   if (cmd_ping)
     err = 0;
   else if (cmd_lookup || cmd_loadcrl)
@@ -217,6 +252,12 @@
         usage (1);
       err = 0;
     }
+  else if (cmd_squid_mode)
+    {
+      err = 0;
+      if (argc)
+        usage (1);
+    }
   else if (!argc)
     {
       err = read_certificate (NULL, &certbuf, &certbuflen);
@@ -252,6 +293,13 @@
 
   if (cmd_ping)
     ;
+  else if (cmd_squid_mode)
+    {
+      while (!(err = squid_loop_body (ctx)))
+        ;
+      if (gpg_err_code (err) == GPG_ERR_EOF)
+        err = 0;
+    }
   else if (cmd_lookup)
     {
       int last_err = 0;
@@ -307,7 +355,7 @@
         log_info (_("a dirmngr daemon is up and running\n"));
       return 0;
     }
-  else if (cmd_lookup||cmd_loadcrl)
+  else if (cmd_lookup||cmd_loadcrl||cmd_squid_mode)
     return err? 1:0;
   else if (cmd_cache_cert)
     {
@@ -488,9 +536,159 @@
 }
 
 
+/* Read the first PEM certificate from the file FNAME.  If fname is
+   NULL the next certificate is read from stdin.  The certificate is
+   returned in an alloced buffer whose address will be returned in
+   RBUF and its length in RBUFLEN.  */
+static gpg_error_t
+read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
+{
+  FILE *fp;
+  int c;
+  int pos;
+  int value;
+  unsigned char *buf;
+  size_t bufsize, buflen;
+  enum {
+    s_init, s_idle, s_lfseen, s_begin,
+    s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+    s_waitend
+  } state = s_init;
+
+  fp = fname? fopen (fname, "r") : stdin;
+  if (!fp)
+    return gpg_error_from_errno (errno);
+
+  pos = 0;
+  value = 0;
+  bufsize = 8192;
+  buf = xmalloc (bufsize);
+  buflen = 0;
+  while ((c=getc (fp)) != EOF)
+    {
+      if (opt.escaped_pem)
+        {
+          if (c == '%')
+            {
+              char tmp[2];
+              if ((c = getc(fp)) == EOF)
+                break;
+              tmp[0] = c;
+              if ((c = getc(fp)) == EOF)
+                break;
+              tmp[1] = c;
+              if (!hexdigitp (tmp) || !hexdigitp (tmp+1))
+                {
+                  log_error ("invalid percent escape sequence\n");
+                  state = s_idle; /* Force an error. */
+                  break;
+                }
+              c = xtoi_2 (tmp);
+            }
+          else if (c == '\n')
+            goto ready; /* Ready.  */
+        }
+      switch (state)
+        {
+        case s_idle:
+          if (c == '\n')
+            {
+              state = s_lfseen;
+              pos = 0;
+            }
+          break;
+        case s_init:
+          state = s_lfseen;
+        case s_lfseen:
+          if (c != "-----BEGIN "[pos])
+            state = s_idle;
+          else if (pos == 10)
+            state = s_begin;
+          else
+            pos++;
+          break;
+        case s_begin:
+          if (c == '\n')
+            state = s_b64_0;
+          break;
+        case s_b64_0:
+        case s_b64_1:
+        case s_b64_2:
+        case s_b64_3:
+          {
+            if (buflen >= bufsize)
+              {
+                bufsize += 8192;
+                buf = xrealloc (buf, bufsize);
+              }
+
+            if (c == '-')
+              state = s_waitend;
+            else if ((c = asctobin[c & 0xff]) == 255 )
+              ; /* Just skip invalid base64 characters. */
+            else if (state == s_b64_0)
+              {
+                value = c << 2;
+                state = s_b64_1;
+              }
+            else if (state == s_b64_1)
+              {
+                value |= (c>>4)&3;
+                buf[buflen++] = value;
+                value = (c<<4)&0xf0;
+                state = s_b64_2;
+              }
+            else if (state == s_b64_2)
+              {
+                value |= (c>>2)&15;
+                buf[buflen++] = value;
+                value = (c<<6)&0xc0;
+                state = s_b64_3;
+              }
+            else
+              {
+                value |= c&0x3f;
+                buf[buflen++] = value;
+                state = s_b64_0;
+              }
+          }
+          break;
+        case s_waitend:
+          /* Note that we do not check whether the END line really
+             follows, nor did we check that the base64 decoder was
+             left in the expected state.  We assume that the PEM
+             header is just fine. */
+          if (c== '\n')
+            goto ready;
+          break; 
+        default: 
+          BUG();
+        }
+    }
+ ready:
+  if (fname)
+    fclose (fp);
+
+  if (state == s_init && c == EOF)
+    {
+      xfree (buf);
+      return gpg_error (GPG_ERR_EOF);
+    }
+  else if (state != s_waitend)
+    {
+      log_error ("no certificate or invalid encoded\n");
+      xfree (buf);
+      return gpg_error (GPG_ERR_INV_ARMOR);
+    }
+
+  *rbuf = buf;
+  *rbuflen = buflen;
+  return 0;
+}
+
 /* Read a binary certificate from the file FNAME.  If fname is NULL the
    file is read from stdin.  The certificate is returned in an alloced
-   buffer whos address will be returned in RBUF and its length in
+   buffer whose address will be returned in RBUF and its length in
    RBUFLEN.  */
 static gpg_error_t
 read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
@@ -500,6 +698,9 @@
   unsigned char *buf;
   size_t nread, bufsize, buflen;
 
+  if (opt.pem)
+    return read_pem_certificate (fname, rbuf, rbuflen);
+
   fp = fname? fopen (fname, "rb") : stdin;
   if (!fp)
     return gpg_error_from_errno (errno);
@@ -733,3 +934,48 @@
   xfree (line);
   return ae? map_assuan_err (ae) : err;
 }
+
+/* The body of an endless loop: Read a line from stdin, retrieve the
+   certificate from it, validate it and print "ERR" or "OK" to stdout.
+   Continue.  */
+static gpg_error_t
+squid_loop_body (assuan_context_t ctx)
+{
+  gpg_error_t err;
+  unsigned char *certbuf;
+  size_t certbuflen = 0;
+  
+  err = read_pem_certificate (NULL, &certbuf, &certbuflen);
+  if (gpg_err_code (err) == GPG_ERR_EOF)
+    return err;
+  if (err)
+    {
+      log_error (_("error reading certificate from stdin: %s\n"),
+                 gpg_strerror (err));
+      puts ("ERROR");
+      return 0;
+    }
+
+  err = do_check (ctx, certbuf, certbuflen);
+  xfree (certbuf);
+  if (!err)
+    {
+      if (opt.verbose)
+        log_info (_("certificate is valid\n"));
+      puts ("OK");
+    }
+  else 
+    {
+      if (!opt.quiet)
+        {
+          if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
+            log_info (_("certificate has been revoked\n"));
+          else
+            log_error (_("certificate check failed: %s\n"),
+                       gpg_strerror (err));
+        }
+      puts ("ERROR");
+    }
+  
+  return 0;
+}




More information about the Gnupg-commits mailing list